hldy_app/pages/watch/index.vue

1802 lines
43 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="view">
<view class="view-left">
<view class="title-father">
<image class="title-img" src="/static/index/watch/uni.png" />
<view class="title-font">
护理单元
</view>
</view>
<view class="zhezhao-top"></view>
<view class="zhezhao-bottom"></view>
<scroll-view class="menus-father" scroll-y :scroll-top="topnum">
<view v-for="(item,index) in filteredMenu" :key="index" class="menu"
:class="{warning: item.izWarning == '1',target: index === leftTargetIndex}" :style="[
index === menuIndex ? { backgroundColor: '#fff' } : {},
leftTargetIndex === index ? { backgroundColor: '#ddf0ff' } : {}
]" @click="menuIndex=index;cleanandopen();leftTargetIndex = index;changeLeftMenu(item,index)">
<view class="menu-img">
<donghua :width="`55rpx`" :height="`55rpx`" :links="item.url" :playing="menuIndex===index" />
</view>
<view style="margin-left: 10rpx;">
<view
style="font-size: 28rpx;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;width: 270rpx;"
:style="index === menuIndex?{color:`#017DE9 `}:{} ">
{{item.nuName}}
</view>
</view>
</view>
<!-- 解决margin重叠问题 -->
<view style="height: 45rpx;"></view>
</scroll-view>
</view>
<view class="view-right">
<view class="scroll-vi">
<view class="zhezhao-left"></view>
<view class="zhezhao-right"></view>
<scroll-view scroll-x="true" style="width: 66%;height: 100%;">
<view style="display: flex;align-items: center;margin-top: 3rpx;">
<view v-for="(item,index) in typeArray" :key="index" class="menu"
:style="topTargetIndex === index ? { backgroundColor: '#ddf0ff' } : {}"
:class="{target: index === topTargetIndex}" @click="typeNow=index;clickTopMenu(index)">
<donghua :links="item.url" :playing="typeNow===index" v-if="item.url" />
<text class="menu-font" :class="{ zoom: typeNow===index }"
:style="typeNow===index?{color:`#008FF5`}:{}" v-if="item.url">
{{item.name}}
</text>
<view v-if="!item.url">
<image style="width: 50rpx;height: 50rpx;" src="/static/index/watch/more.png" />
</view>
</view>
</view>
</scroll-view>
<view class="right-father">
<view style="font-weight: 600;font-size: 60rpx;margin-right: 15rpx;">
{{ time }}
</view>
<view class="" style="font-weight: 600;margin-right: 30rpx;font-size: 25rpx;">
<view>{{ date }}</view>
<view>{{ week }}</view>
</view>
<view :class="{ targetbutton: shezhi }" style="display: flex;align-items: center;">
<image style="width: 55rpx;height: 55rpx;" src="/static/index/newindex/curve/shezhi.png"
@click="goback" />
<view style="font-size: 32rpx;margin-left: 10rpx;" @click="goback">
设置
</view>
</view>
</view>
</view>
<view class="big-bgc">
<view
style="width: 100%;height: 100%;z-index: 1;display: flex;justify-content: center;align-items: center;background-color: rgba(226, 227, 231, 0.5);">
<view style="position: relative;">
<image style="width: 600rpx;height: 600rpx;" src="/static/nocamera.png" />
<view
style="color: #4D5561;font-size: 32rpx;position: absolute;left: 50%;bottom: 100rpx;transform: translateX(-50%);">
暂无视频内容显示
</view>
</view>
</view>
</view>
<view class="picture">
<view class="picture-card" v-for="(item,index) in downpicture" :key="index"
:style="{color:downtarget===index?'#1486EB':''}" @click="clickDownCard(index)">
<view class="bgc-card" :style="{background:downtarget===index?'#E2EDFC':''}"
:class="{target: index === bottomTargetIndex}">
<image style="width: 90rpx;height: 90rpx;"
:src="`/static/index/picture/${index}${downtarget===index?1:0}.png`" />
</view>
{{item}}
</view>
</view>
<view class="right-right">
<view class="red-kuang" v-if="typeNow===0">
<image style="width: 70rpx;height: 85rpx;margin-left: 40rpx;margin-top: 0rpx;"
src="/static/index/watch/laotai.png" v-if="filteredMenu[menuIndex]?.elderInfo" />
<view class="" v-if="filteredMenu[menuIndex]?.elderInfo">
<view style="margin-left: 20rpx;display: flex;align-items: center;width: 100%;position: relative;">
<view class="font-weight">
{{ filteredMenu[menuIndex].elderInfo ? filteredMenu[menuIndex].elderInfo.name:'' }}
</view>
<view class="blue-bgc" style="position: absolute;right: -20rpx;top: 0rpx;">
当日指令
</view>
</view>
<view class="font-small" style="margin-left: 20rpx;margin-top: 0rpx;">
{{ filteredMenu[menuIndex].elderInfo ? filteredMenu[menuIndex].elderInfo.sex:'' }}
<text style="margin-left: 5rpx;">
{{ filteredMenu[menuIndex].elderInfo ? getAgeYears(filteredMenu[menuIndex].elderInfo.dateOfBirth):'' }}岁
</text>
</view>
<view class="font-small" style="margin-left: 20rpx;margin-top: 0rpx;">
入住时间:{{ filteredMenu[menuIndex].elderInfo ? filteredMenu[menuIndex].elderInfo.createTime.slice(0,10):'' }}
</view>
</view>
</view>
<view class="red-kuang" v-if="typeNow===1">
<image style="width: 110rpx;height: 140rpx;margin-left: 40rpx;margin-top: -10rpx;"
src="/static/index/watch/laotou.png" v-if="filteredMenu[menuIndex]?.elderInfo" />
<view class="" v-if="filteredMenu[menuIndex]?.elderInfo">
<view
style="margin-left: 20rpx;display: flex;align-items: center;margin-bottom: 5rpx;margin-top: 25rpx;height: 60rpx;">
<view class="font-weight">
{{ filteredMenu[menuIndex].elderInfo ? filteredMenu[menuIndex].elderInfo.name:'' }}
</view>
<view class="font-small" style="margin-left: 10rpx;">
{{ filteredMenu[menuIndex].elderInfo ? filteredMenu[menuIndex].elderInfo.sex:'' }}
{{ filteredMenu[menuIndex].elderInfo ? getAgeYears(filteredMenu[menuIndex].elderInfo.dateOfBirth):'' }}岁
</view>
</view>
<view class="font-small" style="margin-left: 20rpx;margin-top: 25rpx;">
入职时间:{{ filteredMenu[menuIndex].elderInfo ? filteredMenu[menuIndex].elderInfo.createTime.slice(0,10):'' }}
</view>
</view>
</view>
<view class="states-father" v-if="typeNow===0">
<view class="states" :class="item.error?`warning`:``" v-for="(item,index) in iconArray"
:key="index">
<image style="width: 35rpx;height: 35rpx;" :src="item.url" />
<view style="color: #555555;margin-left: 5rpx;font-size: 18rpx;">
{{ item.name }}
</view>
</view>
</view>
<view class="states-father" v-if="typeNow===1">
<view class="phone-number">
<image class="bgc-image" src="/static/index/watch/phonebgc.png" />
<image style="width: 20rpx;height: 35rpx;margin-left: 40rpx;"
src="/static/index/watch/phone.png" />
<view class="font-phone">
<view v-if="filteredMenu[menuIndex]?.elderInfo">
{{ filteredMenu[menuIndex].elderInfo ? filteredMenu[menuIndex].elderInfo.guardianPhone:'' }}
</view>
</view>
<image class="phone-ball" src="/static/index/watch/phoneball.png" />
</view>
</view>
<view class="big-view">
<view class="font-weight">
{{ serveritem.startTime }} - {{ serveritem.endTime }}
</view>
<view class="pao">
<image style="width: 100%;height: 100%;position: absolute;top: 0;left: 0;"
src="/static/index/watch/pao.png" />
<view style="font-size: 20rpx;z-index: 1;">
待进行
</view>
</view>
<view class="juzhong" style="z-index: 2;margin-top: 130rpx;">
<image style="width: 100rpx;height: 100rpx;"
:src="`https://www.focusnu.com/nursingunit101/sys/common/static/${serveritem.immediateFile}`" />
</view>
<!-- <view style="height: 150rpx;">
</view> -->
<!-- <view class="juzhong" style="top: -120rpx;">
<donghua :width="`600rpx`" :height="`500rpx`" :links="blueArray" :playing="photoplay"
:loop="true" :interval="120" />
</view>
<view class="juzhong" style="z-index: 2;margin-top: 50rpx;">
<donghua :width="`300rpx`" :height="`200rpx`" :links="bluesmallArray" :playing="photoplay"
:loop="true" :interval="120" />
</view> -->
<!-- <image style="width: 300rpx;height: 200rpx;" src="/static/index/newindex/wendu/2.png" /> -->
<view style="font-size: 25rpx;padding-top: 150rpx;">
{{ serveritem.typeName }}
</view>
</view>
<view class="bottom-view">
<view v-for="(item,index) in cameraArray" class="button-father" @click="clickcamera(index)">
<view class="bottom-button"
:style="{backgroundColor:cameratarget.includes(index)?`#DDE9F0`:`` }">
<image style="width: 70%;height: 70%"
:src="`/static/index/camera/${index}${cameratarget.includes(index)?1:0}.png`" />
</view>
<view style="font-size: 25rpx;" :style="{color:cameratarget.includes(index)?`#0E86EA`:`` }">
{{item}}
</view>
</view>
<view class="jump-white" v-show="jumpopen">
<view
style="display: flex;justify-content: space-around;height: 100rpx;width: 100%;align-items: center;">
<view class="">
翻转
</view>
<image style="width: 40rpx;height: 40rpx" src="/static/index/camera/back.png"
@click="jumpopen=false" />
</view>
<view class="jump-item" v-for="(item,index) in where" :key="index" @click="clickjump(index)"
:style="{backgroundColor:wheretarget===index?'#E5E8EE':''}">
<image style="width: 50rpx;height: 50rpx;margin-right: 10rpx;margin-left:-10rpx"
:src="wheretarget===index?item.target:item.url" />
<view :style="{color:wheretarget===index?'#0E86EA':''}">
{{item.name}}
</view>
</view>
</view>
</view>
</view>
</view>
<!-- <specialDrawerVue ref="gobackdrawer" :circletarget="openright" @open="cleanandopen">
<bigroll ref="wheelRef" :opensecondmenu="opensecondmenu" @firstIndex="firstIndex"
@secondIndex="secondIndex" />
</specialDrawerVue> -->
<arrowkeys @movecard="movecard" :getblue="getblue" :moveleft="5" />
<joysticknew @movecard="movecamera" v-show="!cameratarget.includes(5)" />
</view>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, computed, reactive } from 'vue';
import { onShow, onLoad, onHide } from "@dcloudio/uni-app"
// import specialDrawerVue from '../../component/public/specialDrawer.vue';
// import bigroll from './drawer/index.vue';
import { movedirection, queryPadPageList } from './api/lunpan.js'
import joysticknew from '@/component/public/newgame/joysticknew.vue';
const cameraArray = ref([])
onLoad(() => {
cameraArray.value = cameraSmall;
})
const zyupgrade = ref(null);
const menuIndex = ref(-1);
const typeNow = ref(-1);
const photoplay = ref(false);
const getblue = ref(false);
const gobackdrawer = ref(null);
const wheelRef = ref(null);
const topnum = ref(0); // scroll-top (px)
const itemHeight = 100; // 每项高度 (px)
const containerHeight = 400; // scroll-view 高度 (px)
const wheretarget = ref(3);
const where = [
{
name: "左右翻转",
url: "/static/index/camera/800.png",
target: "/static/index/camera/801.png",
},
{
name: "上下翻转",
url: "/static/index/camera/810.png",
target: "/static/index/camera/811.png",
},
{
name: "中心翻转",
url: "/static/index/camera/820.png",
target: "/static/index/camera/821.png",
},
{
name: "不翻转",
url: "/static/index/camera/830.png",
target: "/static/index/camera/831.png",
},
]
const downpicture = [
"原图",
"全景拉伸",
"四分屏",
"180°全景",
"360°全景"
]
const cameratarget = ref([]);
const cameraBig = [
"截图",
"录制",
"对讲",
"静音",
"预警",
"关闭",
"图片",
"视频",
"清晰度",
"翻转",
]
const cameraSmall = [
"截图",
"录制",
"对讲",
"静音",
"预警",
"展开",
]
const downtarget = ref(0)
const cleanAll = () => {
wheretarget.value = 3;
cameratarget.value = [];
downtarget.value = 0;
cameraArray.value = cameraSmall
}
const jumpToCeshi = () => {
uni.navigateTo({
url: '/pages/denglu'
})
}
const clickDownCard = (index : number) => {
cleanandopen()
bottomTargetIndex.value = index;
// clickDownCard(0)
downtarget.value = index;
switch (index) {
case 0:
uni.$emit('monitor:switchDisplay', 0)
break
case 1:
uni.$emit('monitor:switchDisplay', 4)
break
case 2:
uni.$emit('monitor:switchDisplay', 1)
break
case 3:
uni.$emit('monitor:switchDisplay', 2)
break
case 4:
uni.$emit('monitor:switchDisplay', 3)
break
}
}
const first = ref(5);
const second = ref(0);
const firstIndex = (index : number) => {
first.value = index;
yuntai.value = false;
}
const secondIndex = (index : number) => {
second.value = index;
yuntai.value = false;
}
function parseToMinutes(t : string) : number {
const [h, m] = t.split(':').map(Number)
return h * 60 + m
}
function findClosestItem(list : any[], nowStr : string) {
const now = parseToMinutes(nowStr)
let closest = null
let minDiff = Infinity
list.forEach((element) => {
const val = parseToMinutes(element.startTime)
// 计算差值,取 24 小时范围内的最小绝对差
let diff = Math.abs(val - now)
if (diff > 720) diff = 1440 - diff // 跨天时比如23:50和00:10
if (diff < minDiff) {
minDiff = diff
closest = element
}
})
return closest
}
const serveritem = ref({
startTime: "",
endTime: "",
typeName: "",
immediateFile: ""
})
const changeLeftMenu = (item : any, index : number) => {
if (item?.elderServerEntityList) {
//给屏幕右侧数据用的
const nearest = findClosestItem(item?.elderServerEntityList, time.value)
// console.log("zzzzaaa", item)
if (!nearest) {
serveritem.value = {
startTime: "",
endTime: "",
typeName: "",
immediateFile: ""
}
} else {
serveritem.value = nearest
}
} else {
serveritem.value = {
startTime: "",
endTime: "",
typeName: "",
immediateFile: ""
}
}
cleanAll()
uni.$emit('monitor:killView');
if (item?.cameraInfo !== null && item?.cameraInfo[0].deviceName) {
uni.$emit('monitor:isshow', true);
// 加点延迟吧
setTimeout(() => {
uni.$emit('monitor:changeinit', item?.cameraInfo[0].deviceIndex);
}, 100)
} else {
uni.$emit('monitor:isshow', false)
}
}
const clickTopMenu = (index : number) => {
cleanandopen();
topTargetIndex.value = index;
changeLeftMenu(filteredMenu.value[0], 0)
}
// const change
const opendrawer = () => {
gobackdrawer.value.openDrawer();
}
function clamp(v, a, b) { return Math.max(a, Math.min(b, v)); }
// 确保 idx 可见:若在上方/下方不可见则调整 topnum
function ensureVisible(idx) {
// 逐步算数(清晰、稳妥)
const targetTop = idx * itemHeight; // idx乘以每项高度
const viewTop = topnum.value; // 视图当前顶部位置
const viewBottom = viewTop + containerHeight; // 视图底部位置
if (targetTop < viewTop) {
// 目标在上方:把顶部滚到目标的 top
topnum.value = clamp(targetTop, 0, filteredMenu.value.length * itemHeight - containerHeight);
} else if (targetTop + itemHeight > viewBottom) {
// 目标在下方:滚动使目标完全显示在视图底部
const needTop = targetTop + itemHeight - containerHeight;
topnum.value = clamp(needTop, 0, filteredMenu.value.length * itemHeight - containerHeight);
}
// 否则已可见,无动作
}
// 通用的生成函数
function genPaths(base, prefix, count, ext = 'png', startIndex = 0, pad = false) {
return Array.from({ length: count }, (_, i) => {
const idx = pad
? String(i + startIndex).padStart(2, '0')
: i + startIndex
return `${base}/${prefix}${idx}.${ext}`
})
}
const base = genPaths(
'/static/index/newindex/curve',
'curve_',
9,
'png',
1,
false
)
const blueArray = ref([
...base,
...[...base].reverse() // 先拷贝一份再反转,避免修改原 base
])
const basesmall = genPaths(
'/static/index/newindex/curve',
'breathe_',
9,
'png',
1,
false
)
const bluesmallArray = ref([
...basesmall,
...[...basesmall].reverse() // 先拷贝一份再反转,避免修改原 base
])
const peopleArray = ref([
{
name: "王金福",
url: "/static/index/watch/people0.png"
},
{
name: "李宝田",
url: "/static/index/watch/people1.png"
},
])
const iconArray = ref([
{
name: "省医保",
url: "/static/index/watch/00.png",
error: false
},
{
name: "重度失能",
url: "/static/index/watch/01.png",
error: false
},
{
name: "欠费",
url: "/static/index/watch/03.png",
error: true
},
])
const typeArray = ref(
[
{
name: '护理单元',
url: genPaths(
'/static/index/watch',
'nurs_',
10, // 张数
'png',
1, // 起始索引为 1
false // 不补零
)
},
{
name: '配务室',
url: genPaths(
'/static/index/watch',
'delivery_',
5, // 张数
'png',
1, // 起始索引为 1
false // 不补零
)
},
{
name: '库房',
url: genPaths(
'/static/index/watch',
'warehouse_',
6, // 张数
'png',
1, // 起始索引为 1
false // 不补零
)
},
{
name: '消洗区',
url: genPaths(
'/static/index/watch',
'service_',
5, // 张数
'png',
1, // 起始索引为 1
false // 不补零
)
},
{
name: '',
url: ""
},
]
)
const leftMenuArray = ref([
{
name: '护理单元01',
NUID: "2508000001",
url: genPaths(
'/static/index/watch',
'nurs_',
10, // 张数
'png',
1, // 起始索引为 1
false // 不补零
),
warning: false, type: 0
},
{
name: '护理单元02',
NUID: "2508000002",
url: genPaths(
'/static/index/watch',
'nurs_',
10, // 张数
'png',
1, // 起始索引为 1
false // 不补零
),
warning: false, type: 0
},
{
name: '护理单元03',
NUID: "2508000003",
url: genPaths(
'/static/index/watch',
'nurs_',
10, // 张数
'png',
1, // 起始索引为 1
false // 不补零
),
warning: true, type: 0
},
{
name: '仓库01',
NUID: "2508000001",
url: genPaths(
'/static/index/watch',
'warehouse_',
6, // 张数
'png',
1, // 起始索引为 1
false // 不补零
),
warning: false, type: 1
},
{
name: '配务室',
NUID: "2508000001",
url: genPaths(
'/static/index/watch',
'delivery_',
5, // 张数
'png',
1, // 起始索引为 1
false // 不补零
),
warning: false, type: 2
},
{
name: '服务大厅',
NUID: "2508000001",
url: genPaths(
'/static/index/watch',
'service_',
5, // 张数
'png',
1, // 起始索引为 1
false // 不补零
),
warning: false, type: 3
},
])
onMounted(() => {
// 触发监听
menuIndex.value = 0;
typeNow.value = 0;
photoplay.value = true;
getblue.value = true;
})
const leftTargetIndex = ref(0);
const topTargetIndex = ref(-1);
const bottomTargetIndex = ref(-1)
const shezhi = ref(false)
const cleanandopen = () => {
leftTargetIndex.value = -1;
topTargetIndex.value = -1;
bottomTargetIndex.value = -1;
shezhi.value = false;
}
const movecamera = (type : number) => {
handleKey(type)
}
const savetypeNow = ref(0);
const movecard = (type : number) => {
if (leftTargetIndex.value !== -1) {
switch (type) {
case 0:
if (menuIndex.value > 0) {
leftTargetIndex.value--
menuIndex.value = leftTargetIndex.value
ensureVisible(menuIndex.value)
changeLeftMenu(filteredMenu.value[leftTargetIndex.value], leftTargetIndex.value)
} else {
topTargetIndex.value = typeNow.value
leftTargetIndex.value = -1
}
break
case 1:
topTargetIndex.value = typeNow.value
leftTargetIndex.value = -1
break
case 2:
if (menuIndex.value < filteredMenu.value.length - 1) {
menuIndex.value++
leftTargetIndex.value = menuIndex.value
ensureVisible(menuIndex.value)
changeLeftMenu(filteredMenu.value[leftTargetIndex.value], leftTargetIndex.value)
}
break
case 3:
break
case 4:
savetypeNow.value = leftTargetIndex.value
uni.setStorageSync('nuId', filteredMenu.value[savetypeNow.value].nuId);
uni.setStorageSync('nuName', filteredMenu.value[savetypeNow.value].nuName);
uni.setStorageSync('customerId', filteredMenu.value[savetypeNow.value].elderInfo ? filteredMenu.value[savetypeNow.value].elderInfo?.id : null);
uni.setStorageSync('NUall', filteredMenu.value[savetypeNow.value]);
// console.log("??????1111",filteredMenu.value[savetypeNow.value])
if (!typeNow.value) {
uni.navigateTo({
url: '/pages/NursingNew/index'
})
} else if (typeNow.value === 2) {
uni.navigateTo({
url: '/pages/Warehousing/index'
})
}
break
}
} else if (topTargetIndex.value !== -1) {
switch (type) {
case 0:
break
case 1:
if (typeNow.value < typeArray.value.length - 2) {
// console.log("???", typeArray.value.length)
typeNow.value++
topTargetIndex.value = typeNow.value
changeLeftMenu(filteredMenu.value[0], 0)
} else {
shezhi.value = true
topTargetIndex.value = -1
}
break
case 2:
// topTargetIndex.value = -1
// menuIndex.value = 0
// leftTargetIndex.value = menuIndex.value
// ensureVisible(menuIndex.value)
// if (filteredMenu.value.length) {
// topTargetIndex.value = -1
// menuIndex.value = 0
// leftTargetIndex.value = menuIndex.value
// ensureVisible(menuIndex.value)
// }
cleanandopen()
bottomTargetIndex.value = 0;
clickDownCard(0)
break
case 3:
if (typeNow.value) {
typeNow.value--
topTargetIndex.value = typeNow.value
changeLeftMenu(filteredMenu.value[0], 0)
} else {
topTargetIndex.value = -1
menuIndex.value = 0
typeNow.value = 0
leftTargetIndex.value = menuIndex.value
ensureVisible(menuIndex.value)
}
break
case 5:
topTargetIndex.value = -1
menuIndex.value = 0
leftTargetIndex.value = menuIndex.value
ensureVisible(menuIndex.value)
break
}
} else if (shezhi.value) {
switch (type) {
case 0:
break
case 1:
break
case 2:
cleanandopen()
bottomTargetIndex.value = 0;
clickDownCard(0)
break
case 3:
typeNow.value = 3
topTargetIndex.value = typeNow.value
shezhi.value = false;
break
case 4:
goback()
break
case 5:
topTargetIndex.value = -1
menuIndex.value = 0
leftTargetIndex.value = menuIndex.value
ensureVisible(menuIndex.value)
shezhi.value = false;
break
}
} else if (bottomTargetIndex.value !== -1) {
switch (type) {
case 0:
cleanandopen()
topTargetIndex.value = typeNow.value;
break
case 1:
if (bottomTargetIndex.value < 4) {
bottomTargetIndex.value++
clickDownCard(bottomTargetIndex.value)
}
break
case 2:
break
case 3:
if (bottomTargetIndex.value) {
bottomTargetIndex.value--
clickDownCard(bottomTargetIndex.value)
} else {
let menunumber = menuIndex.value
cleanandopen()
menuIndex.value = menunumber;
leftTargetIndex.value = menunumber;
changeLeftMenu(filteredMenu.value[menuIndex.value], menuIndex.value)
}
break
case 4:
goback()
break
case 5:
// topTargetIndex.value = -1
// menuIndex.value = 0
// leftTargetIndex.value = menuIndex.value
// ensureVisible(menuIndex.value)
// shezhi.value = false;
break
}
}
}
const removeTimers = new Map<number, ReturnType<typeof setTimeout>>();
onBeforeUnmount(() => {
for (const t of removeTimers.values()) {
clearTimeout(t)
}
removeTimers.clear()
})
const removeIndexOnce = (index : number) => {
const pos = cameratarget.value.indexOf(index)
if (pos !== -1) {
cameratarget.value.splice(pos, 1) // 从 pos 开始删除 1 个元素
}
}
const jumpopen = ref(false);
const clickcamera = (index : number) => {
// uni.$emit('monitor:isshow', false)
switch (index) {
case 0:
// 触发快照事件
uni.$emit('monitor:doSnapshot')
// 如果数组里不存在就 push避免重复
if (!cameratarget.value.includes(index)) {
cameratarget.value.push(index)
}
// 如果之前有定时器,先清掉(实现“重新计时”)
if (removeTimers.has(index)) {
clearTimeout(removeTimers.get(index)!)
}
// 新建一个 1s 后移除的定时器
const timerId = setTimeout(() => {
const pos = cameratarget.value.indexOf(index)
if (pos !== -1) {
cameratarget.value.splice(pos, 1)
}
removeTimers.delete(index)
}, 500)
removeTimers.set(index, timerId)
break
case 1:
if (cameratarget.value.includes(index)) {
uni.$emit('monitor:stopRecord');
removeIndexOnce(index)
} else {
uni.$emit('monitor:startRecord');
cameratarget.value.push(index)
}
break
case 2:
if (cameratarget.value.includes(index)) {
uni.$emit('monitor:stopTalk');
removeIndexOnce(index)
} else {
uni.$emit('monitor:openTalk');
cameratarget.value.push(index)
}
break
case 3:
if (cameratarget.value.includes(index)) {
uni.$emit('monitor:toggleVolume');
removeIndexOnce(index)
} else {
uni.$emit('monitor:toggleVolume');
cameratarget.value.push(index)
}
break
case 4:
if (cameratarget.value.includes(index)) {
uni.$emit('monitor:stopAlarm')
removeIndexOnce(index)
} else {
uni.$emit('monitor:startAlarm')
cameratarget.value.push(index)
}
break
case 5:
if (cameratarget.value.includes(index)) {
cameraArray.value = cameraSmall
removeIndexOnce(index)
} else {
cameraArray.value = cameraBig
cameratarget.value.push(index)
}
jumpopen.value = false;
break
case 6:
if (cameratarget.value.includes(index)) {
removeIndexOnce(index)
} else {
cameratarget.value.push(index)
}
break
case 7:
if (cameratarget.value.includes(index)) {
removeIndexOnce(index)
} else {
cameratarget.value.push(index)
}
break
case 8:
if (cameratarget.value.includes(index)) {
uni.$emit('monitor:changeQuality');
removeIndexOnce(index)
} else {
uni.$emit('monitor:changeQuality');
cameratarget.value.push(index)
}
break
case 9:
jumpopen.value = true
break
}
}
const clickjump = (index : number) => {
wheretarget.value = index;
if (index === 3) {
uni.$emit('monitor:flipImage', 6)
removeIndexOnce(9)
} else {
uni.$emit('monitor:flipImage', index)
cameratarget.value.push(9)
}
}
// 对 moveFirstUp / moveFirstDown 包装防抖
const moveUpDebounced = useThrottle(() => wheelRef.value?.moveFirstUp(), 400)
const moveDownDebounced = useThrottle(() => wheelRef.value?.moveFirstDown(), 400)
const moveUpsecond = useThrottle(() => wheelRef.value?.moveSecondUp(), 400)
const moveDownsecond = useThrottle(() => wheelRef.value?.moveSecondDown(), 400)
const clickDownsecond = useThrottle(() => doSomething(), 700)
const gaoqing = ref(0);
const yuntai = ref(false);
const savefirst = ref(-1);
function doSomething() {
wheelRef.value?.startchange()
// console.log("???",first.value)
if (first.value === 0) {
if (second.value) {
uni.$emit('monitor:toggleVolume');
} else {
uni.$emit('monitor:toggleVolume');
}
}
if (first.value === 1) {
if (second.value) {
uni.$emit('monitor:stopTalk');
} else {
uni.$emit('monitor:openTalk');
}
}
if (first.value === 2) {
uni.$emit('monitor:doSnapshot');
}
if (first.value === 3) {
if (second.value) {
uni.$emit('monitor:stopRecord');
} else {
uni.$emit('monitor:startRecord');
}
}
if (first.value === 4) {
if (!second.value) {
savefirst.value = first.value
first.value = -1;
yuntai.value = true;
} else {
}
}
if (first.value === 5) {
if (gaoqing.value !== second.value) {
gaoqing.value = second.value
uni.$emit('monitor:changeQuality'); // 发起截图请求,不关心回调
}
}
if (first.value === 6) {
uni.$emit('monitor:switchDisplay', second.value)
}
if (first.value === 7) {
if (second.value === 3) {
uni.$emit('monitor:flipImage', 6)
} else {
uni.$emit('monitor:flipImage', second.value)
}
}
if (first.value === 8) {
if (second.value) {
uni.$emit('monitor:stopAlarm')
} else {
uni.$emit('monitor:startAlarm')
}
}
}
function useThrottle(fn : () => void, delay = 1000) {
let throttling = false
return () => {
if (throttling) return
fn()
throttling = true
setTimeout(() => {
throttling = false
}, delay)
}
}
const filteredMenu = computed(() => {
menuIndex.value = -1
setTimeout(() => {
menuIndex.value = 0;
}, 50)
return leftMenuArray.value.filter(item => Number(item.areaFlag) - 1 === typeNow.value);
});
const goback = () => {
uni.navigateTo({
url: '/pages/watch/settings/settings'
})
}
// state
const time = ref('')
const date = ref('')
const week = ref('')
let timerId0 = null
const pad = (n) => String(n).padStart(2, '0')
const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
function updateClock() {
const d = new Date()
time.value = `${pad(d.getHours())}:${pad(d.getMinutes())}`
date.value = `${d.getMonth() + 1}-${d.getDate()}`
week.value = weekdays[d.getDay()]
}
// 生命周期钩子
onShow(() => {
updateClock()
// 立即更新一次,然后每秒更新
timerId0 = setInterval(updateClock, 1000)
// console.log("!!!!!!!!!",menuIndex.value,leftTargetIndex.value)
queryPadPageList().then((res => {
leftMenuArray.value = res.result.records;
// console.log("????", leftMenuArray.value)
leftMenuArray.value.forEach((res : any) => {
switch (res.areaFlag) {
case '1':
res.url = genPaths(
'/static/index/watch',
'nurs_',
10, // 张数
'png',
1, // 起始索引为 1
false // 不补零
)
break
case '2':
res.url = genPaths(
'/static/index/watch',
'warehouse_',
6, // 张数
'png',
1, // 起始索引为 1
false // 不补零
)
break
case '3':
res.url = genPaths(
'/static/index/watch',
'delivery_',
5, // 张数
'png',
1, // 起始索引为 1
false // 不补零
)
break
case '4':
res.url = genPaths(
'/static/index/watch',
'service_',
5, // 张数
'png',
1, // 起始索引为 1
false // 不补零
)
break
}
})
changeLeftMenu(filteredMenu.value[leftTargetIndex.value], leftTargetIndex.value)
setTimeout(() => {
menuIndex.value = savetypeNow.value;
leftTargetIndex.value = savetypeNow.value
savetypeNow.value = 0;
}, 100)
// console.log("?????????",menuIndex.value,leftTargetIndex.value)
}))
});
onHide(() => {
if (timerId0) {
clearInterval(timerId0)
timerId0 = null
}
})
// 当前活跃的方向0,1,2,3
// -1 表示没有活跃方向
let activeDir = -1
// 定时器 mapkey = 方向
const stopTimers : Record<number, any> = {}
// 核心逻辑
function handleKey(type : number) {
switch (type) {
case 0: runDirection(1, 0); break // 上
case 1: runDirection(5, 1); break // 右
case 2: runDirection(7, 2); break // 下
case 3: runDirection(3, 3); break // 左
case 4: // 确定
first.value = savefirst.value
yuntai.value = false
savefirst.value = -1
moveUpsecond()
clickDownsecond()
break
case 5: // 取消
first.value = savefirst.value
yuntai.value = false
savefirst.value = -1
moveUpsecond()
clickDownsecond()
break
}
}
// 管理方向的开始/停止
function runDirection(dirCode : number, type : number) {
// 如果换方向,先停掉旧的
if (activeDir !== -1 && activeDir !== type) {
stopDirection(activeDir)
}
activeDir = type
// 执行开始
movedirection(dirCode, 1)
// 重置 stop 计时器
if (stopTimers[type]) clearTimeout(stopTimers[type])
stopTimers[type] = setTimeout(() => {
stopDirection(type)
}, 550) // 如果 550ms 内没有新指令 → 自动停止
}
// 停止动作
function stopDirection(type : number) {
if (type === -1) return
let dirCode = 0
switch (type) {
case 0: dirCode = 1; break
case 1: dirCode = 5; break
case 2: dirCode = 7; break
case 3: dirCode = 3; break
}
movedirection(dirCode, 0).then((res : any) => { })
clearTimeout(stopTimers[type])
stopTimers[type] = null
if (activeDir === type) activeDir = -1
}
//这个函数是计算老人生日的函数
function getAgeYears(birth) {
const b = (birth instanceof Date) ? birth : parseDateFlexible(birth)
const now = new Date()
let years = now.getFullYear() - b.getFullYear()
// 如果今年还没过生日就减 1
if (
now.getMonth() < b.getMonth() ||
(now.getMonth() === b.getMonth() && now.getDate() < b.getDate())
) {
years -= 1
}
return years
}
// 简单的宽松解析函数
function parseDateFlexible(s) {
if (s instanceof Date) return s
if (typeof s !== 'string') throw new Error('birth must be string or Date')
// 支持 "YYYY-MM-DD" 或 "YYYY年MM月DD日" 或 "YYYY/MM/DD"
const m = s.match(/(\d{4})\D+(\d{1,2})\D+(\d{1,2})/)
if (!m) throw new Error('无法解析的日期格式')
return new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]))
}
</script>
<style lang="less" scoped>
.view {
background-color: #eff0f4;
width: 100%;
height: 100vh;
display: flex;
.view-left {
height: 100%;
width: 23%;
.title-father {
padding-top: 100rpx;
padding-bottom: 50rpx;
padding-left: 60rpx;
display: flex;
.title-img {
width: 55rpx;
height: 55rpx;
margin-right: 20rpx;
}
.title-font {
font-size: 32rpx;
font-weight: 800;
}
}
.menus-father {
width: 100%;
height: 900rpx;
.menu {
margin: 45rpx 0;
margin-left: 30rpx;
height: 110rpx;
width: 400rpx;
border-radius: 60rpx;
overflow: hidden;
display: flex;
align-items: center;
.menu-img {
width: 65rpx;
height: 65rpx;
margin-left: 25rpx;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
}
}
}
}
.view-right {
height: 100%;
width: 90%;
position: relative;
.scroll-vi {
height: 100rpx;
width: 100%;
margin-left: 0rpx;
margin-top: 80rpx;
position: relative;
display: flex;
.menu {
flex: 0 0 auto; // 👈 关键点
height: 90rpx;
width: 240rpx;
border-radius: 50rpx;
margin-left: 20rpx;
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
padding-top: 9rpx;
.menu-img {
width: 55rpx;
height: 55rpx;
margin-right: 15rpx;
}
.menu-font {
margin-top: 18rpx;
font-size: 25rpx;
}
}
}
}
}
.new-weight {
margin: 0 30rpx;
margin-top: 40rpx;
font-size: 32rpx;
}
.big-bgc {
margin-left: -10rpx;
margin-top: 30rpx;
width: 1350rpx;
height: 1040rpx;
border-radius: 55rpx;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
@keyframes glowFlash {
0%,
100% {
box-shadow:
0 0 4rpx #f1d7da,
0 0 8rpx #f1d7da,
0 0 12rpx #f1d7da;
}
50% {
box-shadow:
0 0 10rpx #f1d7da,
0 0 20rpx #f1d7da,
0 0 30rpx #f1d7da;
}
}
.right-right {
position: absolute;
right: -20rpx;
top: 210rpx;
height: calc(100% - 250rpx);
width: 570rpx;
.red-kuang {
// margin-top: 0rpx;
margin-left: 90rpx;
width: 430rpx;
height: 120rpx;
border-radius: 30rpx;
position: relative;
display: flex;
align-items: center;
background-color: rgba(226, 227, 231, 0.5);
.blue-bgc {
width: 120rpx;
height: 50rpx;
display: flex;
justify-content: center;
align-items: center;
z-index: 1;
font-size: 23rpx;
background-color: rgba(248, 249, 250, 0.5);
color: #017DE9;
border-radius: 20rpx;
// margin-left: 30rpx;
}
.font-weight {
font-size: 30rpx;
font-weight: 600;
}
.font-small {
font-size: 22rpx;
}
}
}
.states-father {
display: flex;
margin-top: 20rpx;
margin-left: 90rpx;
width: 100%;
.states {
width: 135rpx;
margin-right: 15rpx;
height: 60rpx;
border-radius: 60rpx;
background-color: rgba(226, 227, 231, 0.5);
display: flex;
justify-content: center;
align-items: center;
}
.phone-number {
width: 100%;
height: 80rpx;
display: flex;
align-items: center;
position: relative;
}
}
.bottom-view {
margin-left: 90rpx;
margin-top: 20rpx;
width: 440rpx;
height: 690rpx;
border-radius: 50rpx;
background-color: rgba(226, 227, 231, 0.5);
position: relative;
display: flex;
flex-wrap: wrap;
overflow: hidden;
align-items: flex-start;
align-content: flex-start;
.button-father {
margin-top: 20rpx;
margin-bottom: 0;
margin-left: 28rpx;
text-align: center;
.bottom-button {
background-color: #F2F2F4;
display: flex;
justify-content: center;
align-items: center;
width: 110rpx;
height: 110rpx;
border: 1rpx solid #CDD3DD;
border-radius: 35rpx;
margin-bottom: 5rpx;
}
}
}
.big-view {
margin-left: 90rpx;
margin-top: 20rpx;
width: 440rpx;
height: 340rpx;
border-radius: 50rpx;
background-color: rgba(226, 227, 231, 0.5);
position: relative;
display: flex;
flex-direction: column;
align-items: center;
overflow: hidden;
.font-weight {
font-size: 40rpx;
margin-top: 50rpx;
font-weight: 600;
}
.pao {
position: absolute;
right: 40rpx;
top: 20rpx;
width: 85rpx;
height: 40rpx;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
}
}
.small-button {
margin-top: 10rpx;
height: 70rpx;
display: flex;
.gray-ball {
display: flex;
justify-content: center;
align-items: center;
background-color: #F8F9FA;
width: 60rpx;
height: 60rpx;
border-radius: 50%;
margin: 0 10rpx;
.laba-img {
width: 35rpx;
height: 35rpx;
}
}
}
.right-bottom {
margin-left: 50rpx;
margin-top: 30rpx;
width: 550rpx;
height: 240rpx;
border-radius: 50rpx;
background-color: rgba(226, 227, 231, 0.5);
position: relative;
.bottom-img {
width: 60rpx;
height: 60rpx;
margin-bottom: 30rpx;
}
.people-card {
width: 245rpx;
height: 100rpx;
border-radius: 25rpx;
background-color: rgba(248, 249, 250, 0.5);
margin-left: 20rpx;
display: flex;
justify-content: center;
align-items: center;
}
}
.right-father {
width: 500rpx;
position: absolute;
right: 0rpx;
top: 0;
display: flex;
justify-content: center;
align-items: center;
}
.warning {
animation: glowFlash 1.2s infinite ease-in-out;
border: 1rpx solid #ff5757;
background-color: rgba(239, 240, 244, 0.5);
}
.zoom {
transform: scale(1.2);
transform-origin: bottom left;
transition: transform 1s ease;
}
.juzhong {
position: absolute;
top: 0%;
left: 50%;
transform: translateX(-50%);
}
.zhezhao-left {
position: absolute;
top: 0rpx;
left: 0%;
height: 100%;
width: 120rpx;
background: linear-gradient(to right,
rgba(239, 240, 244, 1) 0%,
/* #eff0f4 全不透明 */
rgba(239, 240, 244, 0) 100%
/* #eff0f4 完全透明 */
);
z-index: 4;
pointer-events: none;
}
.zhezhao-right {
position: absolute;
top: 0rpx;
right: 34%;
height: 100%;
width: 120rpx;
background: linear-gradient(to left,
rgba(239, 240, 244, 1) 0%,
/* #eff0f4 全不透明 */
rgba(239, 240, 244, 0) 100%
/* #eff0f4 完全透明 */
);
z-index: 4;
pointer-events: none;
}
.zhezhao-top {
position: absolute;
top: 200rpx;
left: 0%;
width: 450rpx;
height: 120rpx;
background: linear-gradient(to bottom,
rgba(239, 240, 244, 1) 0%,
/* #eff0f4 全不透明 */
rgba(239, 240, 244, 0) 100%
/* #eff0f4 完全透明 */
);
z-index: 4;
pointer-events: none;
}
.zhezhao-bottom {
position: absolute;
bottom: 380rpx;
left: 0%;
width: 450rpx;
height: 120rpx;
// background-color: red;
background: linear-gradient(to top,
rgba(239, 240, 244, 1) 0%,
/* #eff0f4 全不透明 */
rgba(239, 240, 244, 0) 100%
/* #eff0f4 完全透明 */
);
z-index: 4;
pointer-events: none;
}
.bgc-image {
width: 500rpx;
height: 200rpx;
position: absolute;
top: -50rpx;
left: 0;
}
.font-phone {
font-size: 35rpx;
font-weight: 600;
margin-left: 30rpx;
}
.phone-ball {
width: 50rpx;
height: 50rpx;
position: absolute;
top: 50%;
transform: translateY(-50%);
right: 130rpx;
}
.target {
--color: #99C9FD;
--thick: 2px;
--radius: 60rpx;
--outline-offset: 0rpx;
/* 外扩多少 */
/* 内层虚线(你现在用的) */
border-radius: var(--radius);
background-color: #ddf0ff;
/* 内部背景 */
animation: scalePulse 360ms cubic-bezier(.2, .8, .2, 1);
/* 外层虚线:放在 outline不会影响元素尺寸 */
outline: var(--thick) dashed var(--color);
outline-offset: var(--outline-offset);
/* 保证文本 / 子元素在最上层 */
position: relative;
z-index: 1;
}
.targetbutton {
--color: #99C9FD;
--thick: 2px;
--radius: 60rpx;
--outline-offset: 10rpx;
/* 外扩多少 */
/* 内层虚线(你现在用的) */
border-radius: var(--radius);
// background-color: #ddf0ff;
/* 内部背景 */
animation: scalePulse 360ms cubic-bezier(.2, .8, .2, 1);
/* 外层虚线:放在 outline不会影响元素尺寸 */
outline: var(--thick) dashed var(--color);
outline-offset: var(--outline-offset);
/* 保证文本 / 子元素在最上层 */
position: relative;
z-index: 1;
}
.picture {
display: flex;
margin-top: 40rpx;
.picture-card {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-left: 20rpx;
margin-right: 10rpx;
width: 200rpx;
.bgc-card {
width: 100%;
height: 130rpx;
background-color: rgba(226, 227, 231, 0.5);
border-radius: 30rpx;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 10rpx;
}
}
}
.jump-white {
position: absolute;
bottom: 20rpx;
left: 50rpx;
width: 300rpx;
height: 400rpx;
background-color: #fff;
border-radius: 30rpx;
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1)
}
.jump-item {
margin: 10rpx 10rpx;
height: 60rpx;
justify-content: center;
width: 93%;
display: flex;
border-radius: 20rpx;
align-items: center;
}
</style>