From 223644ebb8c5546c7b55ea86ff972898c0de835a Mon Sep 17 00:00:00 2001
From: zhangchen <1652267879@qq.com>
Date: 星期四, 24 七月 2025 21:09:30 +0800
Subject: [PATCH] ID1625-暂存

---
 src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue        |   12 +
 src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue |  334 +++++++++++++++++++++++++++++++++++++
 src/views/mobile/bedsideAuxiliaryScreen/pages/UnderTreatment.vue     |   29 +-
 src/views/mobile/bedsideAuxiliaryScreen/components/TimePicker.vue    |  119 +++++++++++++
 4 files changed, 479 insertions(+), 15 deletions(-)

diff --git a/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue b/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue
index 515c59b..f8d9a68 100644
--- a/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue
+++ b/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue
@@ -26,7 +26,7 @@
       </template>
     </div>
     <div class="header-right">
-      <img :src="atRegularTimeImg" class="btn-img" alt="" />
+      <img :src="atRegularTimeImg" class="btn-img" alt="" @click="openScheduledTaskDialog" />
       <img
         :src="setUpImg"
         class="btn-img"
@@ -38,6 +38,8 @@
   </div>
   <!-- 设置设备编号组件 -->
   <SettingDeviceDialog ref="settingDeviceDialogRef" />
+  <!-- 定时任务组件 -->
+  <ScheduledTaskDialog ref="scheduledTaskDialogRef" />
 </template>
 
 <script lang="ts" setup name="Header">
@@ -45,6 +47,9 @@
 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";
@@ -56,6 +61,7 @@
 const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore();
 
 const settingDeviceDialogRef = ref<any>(null);
+const scheduledTaskDialogRef = ref<any>(null);
 
 const pageType = computed(() => {
   return bedsideAuxiliaryScreenStore.deviceData.pageType;
@@ -80,6 +86,10 @@
   settingDeviceDialogRef.value?.openDialog();
 };
 
+const openScheduledTaskDialog = () => {
+  scheduledTaskDialogRef.value?.openDialog();
+};
+
 const openLoginDialog = () => {
   ElMessage({
     message: "功能开发中,敬请期待!",
diff --git a/src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue b/src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue
index e69de29..f284fa8 100644
--- a/src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue
+++ b/src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue
@@ -0,0 +1,334 @@
+<template>
+  <div class="scheduled-task-container">
+    <el-dialog
+      v-model="isShow"
+      center
+      title="定时任务"
+      width="80%"
+      :show-close="false"
+    >
+      <template #header>
+        <div class="scheduled-task-header">
+          <span class="header-title">创建定时任务</span>
+          <img
+            :src="closeImg"
+            class="header-close"
+            @click="handleCancel"
+            alt=""
+          />
+        </div>
+      </template>
+      <div class="scheduled-task-content">
+        <div class="content-left">
+          <div class="content-left-date">
+            <TimePicker v-model="timeValue" />
+            <div class="date-btn"></div>
+          </div>
+          <div class="content-left-stereotyped-writing">
+            <div class="stereotyped-writing">
+              <input
+                v-model="taskName"
+                type="text"
+                :disabled="isInpDisabled"
+                class="stereotyped-writing-input"
+                placeholder="请输入自定义内容"
+              />
+            </div>
+            <div class="stereotyped-writing-list">
+              <div
+                v-for="(item, index) in taskOptions"
+                :key="index"
+                class="my-button list-item"
+                @click="onStereotypedWritingClick(item)"
+                :class="taskItemCheck === item.value ? 'check' : ''"
+              >
+                {{ item.label }}
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="content-right"></div>
+      </div>
+      <template #footer>
+        <div class="my-button cancel" @click="handleCancel">取消</div>
+        <div class="my-button confirm" @click="handleConfirm">确认</div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { computed, ref } from "vue";
+// @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";
+
+interface TaskItem {
+  label: string;
+  value: string;
+  backgroundColor: string;
+  promptTone: string;
+}
+
+interface DateItem {
+    label: string;
+    value: number;
+}
+
+const isShow = ref(false);
+
+const taskName = ref(""); // 任务名称
+const isInpDisabled = ref(false); // 输入框是否禁用
+
+const timeValue = ref('19:16');
+
+const detaCheck = ref<number | null>(); // 这个是判断时间按钮的
+
+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 },
+    { label: '30分钟', value: 30 },
+    { label: '45分钟', value: 45 },
+    { label: '60分钟', value: 60 },
+]);
+
+const taskItemCheck = computed(() => {
+  return taskOptions.value.find((e) => e.value === taskName.value)?.value || "";
+});
+
+const openDialog = () => {
+  isShow.value = true;
+};
+
+const onStereotypedWritingClick = (item: TaskItem) => {
+  if (taskName.value === item.value) {
+    taskName.value = "";
+    isInpDisabled.value = false;
+  } else {
+    taskName.value = item.value;
+    isInpDisabled.value = true;
+  }
+};
+
+const handleCancel = () => {
+  isShow.value = false;
+};
+
+const handleConfirm = () => {};
+
+defineExpose({
+  openDialog,
+});
+</script>
+
+<style lang="less" scoped>
+* {
+  box-sizing: border-box;
+}
+.scheduled-task-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;
+  }
+  .scheduled-task-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);
+      }
+    }
+  }
+  .scheduled-task-content {
+    padding: 0 12px 0px;
+    margin-bottom: 4px;
+    border-bottom: 1px solid #d8d8d8;
+    display: flex;
+    .content-left {
+      flex: 1;
+      border-right: 1px solid #d8d8d8;
+      padding-bottom: 6px;
+      padding-right: 12px;
+      .content-left-date {
+        border-bottom: 1px solid #d8d8d8;
+        
+      }
+      .content-left-stereotyped-writing {
+        .stereotyped-writing {
+          position: relative;
+          height: 16px;
+          padding-top: 6px;
+          margin-bottom: 6px;
+          border-radius: 2px;
+          border: 1px solid #979797;
+          overflow: hidden;
+          .stereotyped-writing-input {
+            position: absolute;
+            left: 0;
+            top: 0;
+            width: 100%;
+            height: 100%;
+            border: none;
+            outline: none;
+            padding: 0 4px;
+            line-height: 16px;
+            font-size: 9px;
+            font-family: PingFangSC, PingFang SC;
+            vertical-align: middle;
+            box-sizing: border-box; // 避免padding撑高
+
+            &::placeholder {
+              font-family: inherit;
+              font-size: inherit;
+              line-height: inherit;
+              color: #aaaaaa;
+              opacity: 1;
+            }
+            &:disabled {
+              background-color: #f5f5f5; // 灰色背景
+              color: #999999; // 灰色文字
+              cursor: not-allowed;
+            }
+          }
+        }
+        .stereotyped-writing-list {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 7px;
+          .list-item {
+            width: 40px;
+            margin-left: 0;
+            padding-left: 0;
+            padding-right: 0;
+            background-color: #e6a23c;
+            &.check {
+              background-color: #bbc6dd;
+            }
+          }
+        }
+      }
+    }
+    .content-right {
+      width: 59px;
+    }
+  }
+  .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;
+    }
+    &.cancel {
+      background: #bbc6dd;
+    }
+    &.confirm {
+      background: #769aff;
+    }
+    &.refresh {
+      background: #e6a23c;
+    }
+  }
+}
+</style>
\ No newline at end of file
diff --git a/src/views/mobile/bedsideAuxiliaryScreen/components/TimePicker.vue b/src/views/mobile/bedsideAuxiliaryScreen/components/TimePicker.vue
new file mode 100644
index 0000000..74479f7
--- /dev/null
+++ b/src/views/mobile/bedsideAuxiliaryScreen/components/TimePicker.vue
@@ -0,0 +1,119 @@
+<template>
+  <div class="time-picker">
+    <div class="picker-column" ref="hourRef" @scroll="onScroll('hour')">
+      <div v-for="h in hours" :key="h" class="picker-item" :class="{ active: h === selectedHour }">{{ h.toString().padStart(2, '0') }}</div>
+    </div>
+    <span class="colon">:</span>
+    <div class="picker-column" ref="minuteRef" @scroll="onScroll('minute')">
+      <div v-for="m in minutes" :key="m" class="picker-item" :class="{ active: m === selectedMinute }">{{ m.toString().padStart(2, '0') }}</div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, watch, onMounted, nextTick } from 'vue'
+
+interface Props {
+  modelValue: string // 格式为 "HH:mm"
+}
+const props = defineProps<Props>()
+const emit = defineEmits(['update:modelValue'])
+
+const selectedHour = ref(0)
+const selectedMinute = ref(0)
+const hourRef = ref<HTMLDivElement | null>(null)
+const minuteRef = ref<HTMLDivElement | null>(null)
+
+const hours = Array.from({ length: 24 }, (_, i) => i)
+const minutes = Array.from({ length: 60 }, (_, i) => i)
+
+function scrollTo(refEl: HTMLDivElement | null, index: number) {
+  if (!refEl) return
+  refEl.scrollTo({ top: index * 40, behavior: 'smooth' })
+}
+
+function updateModel() {
+  const value = `${selectedHour.value.toString().padStart(2, '0')}:${selectedMinute.value.toString().padStart(2, '0')}`
+  emit('update:modelValue', value)
+}
+
+function onScroll(type: 'hour' | 'minute') {
+  const el = type === 'hour' ? hourRef.value : minuteRef.value
+  if (!el) return
+
+  clearTimeout((el as any)._timer)
+  ;(el as any)._timer = setTimeout(() => {
+    const index = Math.round(el.scrollTop / 40)
+    if (type === 'hour') {
+      selectedHour.value = hours[index]
+      scrollTo(hourRef.value, index)
+    } else {
+      selectedMinute.value = minutes[index]
+      scrollTo(minuteRef.value, index)
+    }
+    updateModel()
+  }, 100)
+}
+
+watch(
+  () => props.modelValue,
+  (newVal) => {
+    if (!newVal) return
+    const [h, m] = newVal.split(':').map(Number)
+    selectedHour.value = h
+    selectedMinute.value = m
+    nextTick(() => {
+      scrollTo(hourRef.value, h)
+      scrollTo(minuteRef.value, m)
+    })
+  },
+  { immediate: true }
+)
+</script>
+
+<style scoped>
+.time-picker {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 200px;
+  background: #e6efff;
+  font-family: sans-serif;
+}
+
+.picker-column {
+  width: 60px;
+  height: 200px;
+  overflow-y: scroll;
+  scroll-snap-type: y mandatory;
+  -webkit-overflow-scrolling: touch;
+  text-align: center;
+  position: relative;
+  padding-top: 80px;
+  padding-bottom: 80px;
+}
+
+.picker-item {
+  height: 40px;
+  line-height: 40px;
+  font-size: 14px;
+  color: #666;
+  scroll-snap-align: center;
+  transition: all 0.2s;
+  transform: scale(0.8);
+  opacity: 0.5;
+}
+
+.picker-item.active {
+  font-size: 24px;
+  font-weight: bold;
+  color: #333;
+  transform: scale(1.2);
+  opacity: 1;
+}
+
+.colon {
+  font-size: 24px;
+  margin: 0 10px;
+}
+</style>
diff --git a/src/views/mobile/bedsideAuxiliaryScreen/pages/UnderTreatment.vue b/src/views/mobile/bedsideAuxiliaryScreen/pages/UnderTreatment.vue
index 2c67b9e..b05d642 100644
--- a/src/views/mobile/bedsideAuxiliaryScreen/pages/UnderTreatment.vue
+++ b/src/views/mobile/bedsideAuxiliaryScreen/pages/UnderTreatment.vue
@@ -394,9 +394,13 @@
   );
 });
 
-watch(() => pageData.value.ktvList, (newVal) => {
+watch(
+  () => pageData.value.ktvList,
+  (newVal) => {
     generateKtvListEchart(newVal);
-}, { deep: true });
+  },
+  { deep: true }
+);
 
 watch(
   () => pageData.value.monitoringRecord,
@@ -487,9 +491,9 @@
 
   const option = {
     grid: [
-      { top: "20%", height: "27%", left: 30, right: 20 }, // 伸缩压
-      { top: "45%", height: "27%", left: 30, right: 20 }, // 舒张压
-      { top: "67%", height: "27%", left: 30, right: 20 }, // 脉搏
+      { top: "10%", height: "25%", left: 30, right: 20 },
+      { top: "38%", height: "25%", left: 30, right: 20 },
+      { top: "66%", height: "25%", left: 30, right: 20 },
     ],
     tooltip: {
       trigger: "axis",
@@ -534,9 +538,8 @@
         axisTick: { show: false },
         axisLabel: { show: false },
         splitLine: { show: false },
-        min: 80,
-        max: 180,
-        interval: 20,
+        min: "dataMin", // 自动以数据最小值为最小值
+        max: "dataMax",
         gridIndex: 0,
       },
       {
@@ -546,9 +549,8 @@
         axisTick: { show: false },
         axisLabel: { show: false },
         splitLine: { show: false },
-        min: 40,
-        max: 120,
-        interval: 20,
+        min: "dataMin", // 自动以数据最小值为最小值
+        max: "dataMax",
         gridIndex: 1,
       },
       {
@@ -558,9 +560,8 @@
         axisTick: { show: false },
         axisLabel: { show: false },
         splitLine: { show: false },
-        min: 40,
-        max: 140,
-        interval: 20,
+        min: "dataMin", // 自动以数据最小值为最小值
+        max: "dataMax",
         gridIndex: 2,
       },
     ],

--
Gitblit v1.8.0