| | |
| | | > |
| | | <template #header> |
| | | <div class="scheduled-task-header"> |
| | | <span class="header-title">创建定时任务</span> |
| | | <span class="header-title">{{ title }}</span> |
| | | <img |
| | | :src="closeImg" |
| | | class="header-close" |
| | |
| | | /> |
| | | </div> |
| | | </template> |
| | | <div class="scheduled-task-content"> |
| | | <div class="scheduled-task-content" v-loading="loading"> |
| | | <div class="content-left"> |
| | | <div class="content-left-date"> |
| | | <TimePicker v-model="timeValue" /> |
| | | <div class="date-btn"> |
| | | <TimePicker v-model="timeValue" :disabled="type === 1" /> |
| | | <!-- 创建的情况 --> |
| | | <div class="date-btn" v-if="type === 0"> |
| | | <div |
| | | v-for="(item, index) in dateOptions" |
| | | :key="index" |
| | |
| | | {{ item.label }} |
| | | </div> |
| | | </div> |
| | | <!-- 查看的情况 --> |
| | | <div class="countdown" v-else> |
| | | <div class="countdown-btn"> |
| | | 剩余时间:{{ formattedCountdown }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="content-left-stereotyped-writing"> |
| | | <div class="stereotyped-writing"> |
| | | <input |
| | | v-model.trim="taskName" |
| | | type="text" |
| | | :disabled="isInpDisabled" |
| | | :disabled="isInpDisabled || type === 1" |
| | | class="stereotyped-writing-input" |
| | | placeholder="请输入自定义内容" |
| | | /> |
| | |
| | | </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> |
| | | <div class="my-button confirm" @click="handleConfirm">确认</div> |
| | | <div |
| | | class="my-button confirm" |
| | | :class="loading ? 'cancel' : ''" |
| | | @click="handleConfirm" |
| | | > |
| | | 确认 |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </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; |
| | |
| | | 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 }, |
| | |
| | | { 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) => { |
| | | if (type.value === 1) return; |
| | | if (taskName.value === item.value) { |
| | | taskName.value = ""; |
| | | isInpDisabled.value = false; |
| | |
| | | }; |
| | | |
| | | const onAddMinutesClick = (item: DateItem) => { |
| | | // if (detaCheck.value === item.value) { |
| | | // detaCheck.value = null; |
| | | // timeValue.value = addMinutes(timeValue.value, -item.value) |
| | | // } else { |
| | | if (type.value === 1) return; |
| | | 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 => { |
| | |
| | | }; |
| | | |
| | | const handleCancel = () => { |
| | | if (loading.value) return; |
| | | isShow.value = false; |
| | | }; |
| | | |
| | | const handleConfirm = async () => { |
| | | if (loading.value) return; |
| | | const today = dayjs().format("YYYY-MM-DD"); |
| | | const fullDateTime = dayjs(`${today} ${timeValue.value}`).second(0).millisecond(0); // 秒和毫秒都去掉,要不然间隔短了就是0分钟 |
| | | const fullDateTime = dayjs(`${today} ${timeValue.value}`) |
| | | .second(0) |
| | | .millisecond(0); // 秒和毫秒都去掉,要不然间隔短了就是0分钟 |
| | | |
| | | const now = dayjs().second(0).millisecond(0);; // 秒和毫秒都去掉 |
| | | const now = dayjs().second(0).millisecond(0); // 秒和毫秒都去掉 |
| | | if (!fullDateTime.isAfter(now)) |
| | | return ElMessage.warning("任务提醒时间不能早于或等于当前时间"); |
| | | if (!taskName.value) return ElMessage.warning("任务内容不能为空"); |
| | |
| | | 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('操作成功'); |
| | | ElMessage.success("操作成功"); |
| | | bedsideAuxiliaryScreenStore.setSyncTask({ |
| | | deviceCode: params.deviceCode, |
| | | recordCode: recordCode, |
| | | taskDate: dayjs(fullDateTime).format("YYYY-MM-DD HH:mm"), |
| | | taskName: params.alertText, |
| | | overdue: false |
| | | deviceCode: params.deviceCode, |
| | | recordCode: recordCode, |
| | | 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, |
| | |
| | | } |
| | | } |
| | | .scheduled-task-content { |
| | | padding: 0 12px 0px; |
| | | padding: 0 12px 0px 12px; |
| | | margin-bottom: 4px; |
| | | border-bottom: 1px solid #d8d8d8; |
| | | display: flex; |
| | |
| | | .date { |
| | | margin-left: 0; |
| | | padding: 0; |
| | | width: 50px; |
| | | height: 23px; |
| | | line-height: 23px; |
| | | width: 44px; |
| | | height: 18px; |
| | | line-height: 18px; |
| | | 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; |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | .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 { |
| | |
| | | &:not(:first-child) { |
| | | margin-left: 6px; |
| | | } |
| | | &.cancel { |
| | | background: #bbc6dd; |
| | | } |
| | | |
| | | &.confirm { |
| | | background: #769aff; |
| | | } |
| | | &.cancel { |
| | | background: #bbc6dd; |
| | | } |
| | | &.refresh { |
| | | background: #e6a23c; |
| | | } |