hldy_app_mini/pages/NursingNew/component/nurse/newindex.vue

1488 lines
46 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="right-container" :style="isshow?{opacity: `1`}:{opacity: `0`}"
@click="bottomisShaking=false;shakyTable = false">
<severcard ></severcard>
<view class="doctorsay-container-view">
<view class="doctorsay-container-container">
<view class="super-card">
<view class="boom-father">
<view class="boom" :style="{ transform: transformStyle }">
<view>
<view v-for="(item,index) in timearr[0]?.children" :key="index">
<view class="boom-son" v-show="item.tagName">
<text class="boom-text">
{{item.tagName}}
</text>
</view>
</view>
</view>
</view>
</view>
<view class="super-card-container">
<scroll-view style="width: 100%;" scroll-with-animation :scroll-left="cardLeft" scroll-x
@scroll="handleTop" :show-scrollbar="false">
<view style="display: flex;width:4824rpx;">
<view v-for="(item0,index0) in timearr" :key="index0" class="super-card-right">
<view class="super-card-time">
{{(item0.positioning.length == 1 ? ('0' + item0.positioning) : item0.positioning) + ":00"}}
</view>
</view>
</view>
<view style="display: flex;height: 1225rpx;position: relative;">
<view class="xian-bian"></view>
<scroll-view style="height: 100%;width:6960rpx;background-color: #fff;"
:scroll-top="scrollTop" scroll-with-animation :scroll-y="true"
@scroll="handleScrolltime" :show-scrollbar="false">
<view style="display: flex;height: 100%;">
<view v-for="(item0,index0) in timearr" :key="index0">
<view class="super-card-time-und">
<view v-for="(item1,index1) in item0?.children" style="width: 100%;"
:key="index1">
<view
:class=" targetRuler.index0 === index0 && targetRuler.index1 === index1 ? targetRuler.index1 ?`title-time-border-big`:`title-time-border-big-top` : `super-card-time-card` "
:style="!targetRuler.bordershow && saveRulerTime.index0 === index0 && saveRulerTime.index1 === index1 ? {zIndex:999} : {borderBottom: '1rpx solid transparent'}"
:id="`a${index0}_${index1}`" style="position: relative;"
@click="rulerTouchClick(item1,index0,index1)"
:data-index0="index0" :data-index1="index1">
<view class="time-button-orange-spe"
:style="{left:flyNumber.index0?`-130rpx`:`0`}"
v-if="flyNumber.index0 === index0 && flyNumber.index1 === index1 && index1==0">
请选择服务指令迁移的目标单元格
</view>
<view class="time-button-orange"
:style="{left:flyNumber.index0?`-130rpx`:`0`}"
v-if="flyNumber.index0 === index0 && flyNumber.index1 === index1 && index1">
请选择服务指令迁移的目标单元格
</view>
<view class="title-time-blue"
v-show="saveEditIndex.index0 == index0 && saveEditIndex.index1 == index1 && isRule">
<image class="blue-img" lazy-load
src="/static/index/bluetarget.png" />
</view>
<view :class="getClass(item1,index0,index1)"
style="font-size: 30rpx;overflow: hidden;"
:style="{ animationDelay:`-${computeDelay(index0, index1).toFixed(2)}s`,border:saveEditIndex.index0 == index0 && saveEditIndex.index1 == index1? `2rpx solid #46B2F6`:'' }">
<view class="title-time" v-if="item1.startTime"
style="flex-direction: column;">
<image v-show="item1.startTime"
style="width: 50rpx;height: 50rpx;margin: 0 auto;margin-top: 20rpx"
:src="item1.netImmediateFile?item1.netImmediateFile:`/static/logo.png`" />
<view class="title-time-time" style="font-size: 30rpx;">
{{item1.startTime + `-` + item1.endTime}}
</view>
<image class="title-time-button"
style="width: 80rpx;height: 50rpx;"
v-if="item1.cycleTypeId!=1"
src="/static/index/newruler/jiao.png" />
<view class="title-time-font"
style="right: 10rpx;top: 5rpx;"
v-if="item1.cycleTypeId!=1">
{{item1.cycleType}}
</view>
</view>
<view v-if="item1.startTime" class="title-time-font-rel">
{{splitString(item1.directiveName)[0]}}
</view>
<view
v-if="saveEditIndex.index0 == index0 && saveEditIndex.index1 == index1 && isRule && !item1.startTime"
class="pulic-time">
{{(item0.positioning.length == 1 ? ('0' + item0.positioning) : item0.positioning) + ":" + timeArray[index1]}}
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</scroll-view>
</view>
<view class="right-order">
<view class="right-tags">
<view class="right-tags-title">
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 点击的弹出层 -->
<view v-show="isopen" class="popup-overlay" @click="isopen=false;flyNumber.index0=999;touchindex1=-1">
<view class="popup-overlay-content" style="height: 390rpx;" popup-overlay:class="getjiao"
v-if="timearr[showDetail[0]]?.children[showDetail[1]]?.izPackage==='N'"
:style="{ top: (2*openY - 350) + 'rpx',left: (2*openX - 780) + 'rpx',opacity: isopacity ? 1 : 0 }"
@click.stop>
<view class="popup-overlay-content-left">
<image class="popup-overlay-content-left-img"
:src="timearr[showDetail[0]]?.children[showDetail[1]]?.netImmediateFileFocus" />
</view>
<view class="popup-overlay-content-right">
<view class="time-font">
{{ timearr[showDetail[0]]?.children[showDetail[1]]?.startTime }} -
{{ timearr[showDetail[0]]?.children[showDetail[1]]?.endTime }}
</view>
<view class="time-text">
{{ timearr[showDetail[0]]?.children[showDetail[1]]?.directiveName }}
</view>
</view>
</view>
<view class="popup-overlay-content" :class="getjiao" v-else
:style="{ top: (2*openY - 350) + 'rpx',left: (2*openX - 780) + 'rpx',opacity: isopacity ? 1 : 0 }"
@click.stop>
<view class="specia-onshow">
<view class="specia-title">
{{ timearr[showDetail[0]]?.children[showDetail[1]]?.startTime }} -
{{ timearr[showDetail[0]]?.children[showDetail[1]]?.endTime }}
</view>
<view class="specia-cards" v-if="timearr[showDetail[0]]?.children[showDetail[1]]?.directivesList">
<view class="title-time-border-yellow"
style="font-size: 30rpx;overflow: hidden;width: 232rpx;height: 150rpx;"
v-for="(item1,index1) in timearr[showDetail[0]]?.children[showDetail[1]]?.directivesList"
:key="index1">
<view class="title-time" style="flex-direction: column;">
<image style="width: 60rpx;height: 60rpx;margin: 0 auto;margin-top: 10rpx"
:src="item1.netImmediateFile" />
<view class="title-time-time" style="font-size: 30rpx;">
{{item1.serviceDuration + "分钟"}}
</view>
<image class="title-time-button" style="width: 80rpx;height: 48rpx;"
src="/static/index/newruler/jiao.png" />
<view class="title-time-font" style="right: 10rpx;top: 5rpx;font-size: 23rpx;">
{{ item1.cycleType }}
</view>
</view>
<view class="title-time-font-rel">
{{splitString(item1.directiveName)[0]}}
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 替换表格的的弹出层 -->
<view v-show="sayisopen" class="popup-say" @click="sayisopen=false">
<view class="popup-say-content" style="padding: 30rpx 0;" :style="{ opacity: sayisopacity ? 1 : 0 }"
@click.stop>
<view style="margin-top: 20rpx;margin-bottom: 20rpx;;margin-left: 30rpx;font-size: 32rpx;">
<view>
体型标签
</view>
</view>
<view style="display: flex;flex-wrap: wrap;">
<view v-for="(item,index) in nameArray.slice(0,5)" :key="index">
<view class="tags-father">
<image class="tags-img" :src="`/static/index/tagNames/${index}0.png`" />
<view class="tags-font">{{item}}</view>
</view>
</view>
</view>
<view style="margin-top: 40rpx;margin-bottom: 20rpx;;margin-left: 30rpx;font-size: 32rpx;">
<view>
情绪标签
</view>
</view>
<view style="display: flex;flex-wrap: wrap;">
<view v-for="(item,index) in nameArray.slice(5,12)" :key="index">
<view class="tags-father">
<image class="tags-img" :src="`/static/index/tagNames/${index+5}0.png`" />
<view class="tags-font">{{item}}</view>
</view>
</view>
</view>
<view class="popup-say-three"></view>
</view>
</view>
<!-- 分享的弹出层 -->
<view v-show="shareShow" class="popup-share" @click="shareShow=false">
<view class="popup-share-content" :style="{ opacity: deletedownisopacity ? 1 : 0 }" @click.stop>
<view class="share-other">
<view class="share-title">
<image style="width: 50rpx;height: 50rpx;" src="/static/index/sharelogo.png" />
<view style="font-weight: 600;margin-left: 15rpx;">
护理单元
</view>
</view>
<view class="share-others">
<view style="font-weight: 600;font-size: 45rpx;">
护理流程
</view>
<view style="margin-top: 30rpx;">
{{uni.getStorageSync('nuName')}}
<text style="color: #1083F8;">
{{uni.getStorageSync('NUall').elderInfo?uni.getStorageSync('NUall').elderInfo.name:""}}
</text>
</view>
<view class="blue-button">
分享
</view>
</view>
</view>
</view>
</view>
<view :class="['neuro-wrapper', deletedonghua ? 'is-active' : '']" v-if="isDelete">
<!-- 遮罩层,点击触发关闭 -->
<view class="neuro-mask" @click="isDelete=false"></view>
<!-- 拟态框,阻止冒泡点击 -->
<view class="neuro-box" @click.stop>
<view class="delete-button-father">
<view class="button-white" @click="isDelete=false">取消</view>
<view class="button" @click="openDelete()">确定</view>
</view>
<view class="title">确定要删除指令吗</view>
<view class="title-time-border-yellow"
style="font-size: 30rpx;overflow: hidden;width: 240rpx;height: 170rpx;">
<view class="title-time" style="flex-direction: column;">
<image style="width: 60rpx;height: 60rpx;margin: 0 auto;margin-top: 10rpx"
:src="timearr[saveEditIndex.index0]?.children[saveEditIndex.index1].netImmediateFile?timearr[saveEditIndex.index0].children[saveEditIndex.index1].netImmediateFile:`/static/logo.png`" />
<view class="title-time-time" style="font-size: 30rpx;">
{{timearr[saveEditIndex.index0].children[saveEditIndex.index1].startTime + `-` + timearr[saveEditIndex.index0].children[saveEditIndex.index1].endTime}}
</view>
<image class="title-time-button" style="width: 80rpx;height: 48rpx;"
v-if="timearr[saveEditIndex.index0]?.children[saveEditIndex.index1].cycleTypeId!=1"
src="/static/index/newruler/jiao.png" />
<view class="title-time-font" style="right: 10rpx;top: 5rpx;font-size: 23rpx;"
v-if="timearr[saveEditIndex.index0].children[saveEditIndex.index1].cycleTypeId!=1">
{{ timearr[saveEditIndex.index0]?.children[saveEditIndex.index1].cycleType }}
</view>
</view>
<view class="title-time-font-rel">
{{splitString(timearr[saveEditIndex.index0]?.children[saveEditIndex.index1].directiveName)[0]}}
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, computed, nextTick, watch } from 'vue';
import { onShow, onHide } from '@dcloudio/uni-app';
import { getNclist, addBatch, addDirective, addInstant, deleteDirective, deleteInstant, editDirective } from "./api.js";
import { myArray } from './yaoshandiao.js';
const props = defineProps({
isshow: {
type: Boolean,
required: true,
},
});
const bodystatus = ref(false);
const bodystatustarget = ref(-1);
const facestatus = ref(false);
const facestatustarget = ref(-1);
/* ---- 用于 transform 的响应式字符串 ----
注意虽然这是响应式但我们只在 rAF 里更新它受控更新避免频繁触发 Vue 渲染 */
const transformStyle = ref('translate3d(0, 0, 0)');
/* rAF / 计数器变量 */
let lastY = 0;
let ticking = false;
const bodydonghua = ref(false)
const openbody = ref(false)
const openface = ref(false)
const facedonghua = ref(false)
const bodytarget = ref([]);
const facetarget = ref([]);
const addbody = (index : number) => {
if (bodyTagList.value[index].izSelected == 'Y') {
bodyTagList.value[index].izSelected = 'N';
} else {
let targetNumber = 0;
bodyTagList.value.forEach((element : any) => {
if (element.izSelected == 'Y') {
targetNumber++
}
})
if (targetNumber > 1) {
uni.showToast({
title: "每种标签最多只能添加两个",
icon: 'none',
duration: 3000
})
return
} else {
bodyTagList.value[index].izSelected = 'Y';
}
}
saveAll()
}
const addface = (index : number) => {
if (emotionTagList.value[index].izSelected == 'Y') {
emotionTagList.value[index].izSelected = 'N'
} else {
let targetNumber = 0;
emotionTagList.value.forEach((element : any) => {
if (element.izSelected == 'Y') {
targetNumber++
}
})
if (targetNumber > 1) {
uni.showToast({
title: "标签最多只能添加两个",
icon: 'none',
duration: 3000
})
return
} else {
emotionTagList.value[index].izSelected = 'Y';
}
}
saveAll()
}
const open = ref(false);
const bottomItems = ref([])
const nameArray = [
`标准`, `超重`, `强直`, `偏瘫`, `佝偻`, `稳定`, `焦虑`, `抑郁`, `暴力`, `恐惧`, `烦躁`, `易怒`, `臆想`,
]
const timeArray = [
`00`, `05`, `10`, `15`, `20`, `25`, `30`, `35`, `40`, `45`, `50`, `55`
];
const weekDays = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];
const days = Array.from({ length: 31 }, (_, i) => (i + 1).toString().padStart(2, "0"));
const isweek = ref(true);
// 是否周期
const iszhouqi = ref(false);
//高度回到最高
const firsttop = ref(0);
const secondtop = ref(0);
const scrollLeft = ref(0);
const cardLeft = ref(678);
//移动表格
const scrollTop = ref(0)
//左下的数组
const downList = ref<any>()
const isop = ref(false);
const bigArray = ref([]);
const isopen = ref(false)
const songisopen = ref(false)
const isopacity = ref(false)
const songisopacity = ref(false)
// 删除表格弹窗
const deleteisopen = ref(false);
const deletename = ref("")
const deleteisopacity = ref(false)
// 解释图标弹窗
const sayisopen = ref(false);
const sayname = ref("")
const sayisopacity = ref(false)
const saveleft = ref(6);
const saveright = ref(11);
const savetop = ref(0);
const savebottom = ref(3);
const isMove = ref(false);
const getjiao = computed(() => {
if (jiao.value[0] && jiao.value[1]) {
return "left-bottom"
} else if (!jiao.value[0] && jiao.value[1]) {
return "right-bottom"
} else if (jiao.value[0] && !jiao.value[1]) {
return "left-top"
} else {
return "right-top"
}
})
// 这是二级菜单的动画的模板
const secondtemp = ref([])
// 上次点击时间
const lastTap = ref(0)
// 双击的最大间隔ms可根据体验调整
const DOUBLE_TAP_DELAY = 300
function onTap(e) {
const now = Date.now()
thirdmenuIndex.value = e
// console.log("????",thirdmenuIndex.value)
if (now - lastTap.value < DOUBLE_TAP_DELAY) {
// 双击成立
thirdmenuIndex.value = e
addnew()
// 重置,避免多次触发
lastTap.value = 0
} else {
thirdmenuIndex.value = e
// 记录本次时间,等待下次点击
lastTap.value = now
}
}
// 替换新的
const getNew = () => {
if (flyNumber.value.index0 === saveEditIndex.value.index0 && flyNumber.value.index1 === saveEditIndex.value.index1) {
isMove.value = false;
flyNumber.value.index0 = -1;
flyNumber.value.index1 = -1;
return
}
if (timearr.value[saveEditIndex.value.index0]?.children[saveEditIndex.value.index1].id) {
deleteDirective(timearr.value[saveEditIndex.value.index0]?.children[saveEditIndex.value.index1]).then((res : any) => {
doChangeNew()
})
} else {
doChangeNew()
}
}
const doChangeNew = () => {
let object = JSON.parse(JSON.stringify(timearr.value[flyNumber.value.index0]?.children[flyNumber.value.index1]))
indexsave.value = [saveEditIndex.value.index0, saveEditIndex.value.index1]
// 旧的tagName保存了
let tagName = timearr.value[flyNumber.value.index0]?.children[flyNumber.value.index1].tagName
timearr.value[flyNumber.value.index0].children[flyNumber.value.index1] = { directiveName: '', tagName: tagName }
//然后保存新的
let newtagName = timearr.value[indexsave.value[0]].children[indexsave.value[1]].tagName
timearr.value[indexsave.value[0]].children[indexsave.value[1]] = object
timearr.value[indexsave.value[0]].children[indexsave.value[1]].tagName = newtagName
let startTime = timearr.value[indexsave.value[0]].children[indexsave.value[1]].startTime;
let endTime = timearr.value[indexsave.value[0]].children[indexsave.value[1]].endTime;
let positioning = timearr.value[indexsave.value[0]].positioning;
// 解析原始时间(健壮地 trim
const parseTime = (t) => {
const parts = String(t || '').split(':').map(s => s.trim());
const h = Number(parts[0] ?? 0);
const m = Number(parts[1] ?? 0);
return {
hour: Number.isFinite(h) ? h : 0,
minute: Number.isFinite(m) ? m : 0
};
};
const sOrig = parseTime(startTime);
const eOrig = parseTime(endTime);
// 计算时长(分钟)。若发生负值,认为跨天(加 24*60
let duration = (eOrig.hour * 60 + eOrig.minute) - (sOrig.hour * 60 + sOrig.minute);
if (duration < 0) duration += 24 * 60; // 假设结束是在次日或跨日
// 解析新的起始分钟和小时positioning 可能是字符串)
const newStartMin = Number(String(newtagName).trim());
const newHour = Number(String(positioning).trim());
// 校验
if (!Number.isFinite(newStartMin) || newStartMin < 0 || newStartMin >= 60) {
throw new Error('newtagName 必须是 0-59 的数字字符串或数字');
}
if (!Number.isFinite(newHour) || newHour < 0) {
throw new Error('positioning 必须是有效小时(数字或数字字符串)');
}
// 计算新的起止总分钟
const newStartTotal = newHour * 60 + newStartMin;
const newEndTotal = newStartTotal + duration;
// 处理跨小时/跨天
const newEndHour = Math.floor(newEndTotal / 60) % 24; // 保持在 0-23
const newEndMin = newEndTotal % 60;
// 格式化字符串
const pad2 = (n) => String(n).padStart(2, '0');
timearr.value[indexsave.value[0]].children[indexsave.value[1]].startTime =
`${String(newHour)}:${pad2(newStartMin)}`;
timearr.value[indexsave.value[0]].children[indexsave.value[1]].endTime =
`${String(newEndHour)}:${pad2(newEndMin)}`;
flyNumber.value.index1 = -1;
isMove.value = false;
let data = {
index0: saveEditIndex.value.index0,
index1: saveEditIndex.value.index1
}
whereEvent(data);
let infoValue = timearr.value[saveEditIndex.value.index0].children[saveEditIndex.value.index1]
infoValue.positioning = saveEditIndex.value.index0;
infoValue.positioningLong = saveEditIndex.value.index1;
editDirective(infoValue).then((res : any) => {
if (res.success) {
geteverything()
}
})
}
//变更左侧菜单
const changLeft = (index : number) => {
if (index === 5) {
uni.navigateTo({
url: "/pages/watch/full"
})
return
}
iszhouqi.value = false;
weekIndex.value = -1;
monthIndex.value = -1;
weekValue.value = "";
monthValue.value = "";
secondtop.value = 0.01
firsttop.value = 0.01
//这个东西完全是为了给动画用的因为downmenuIndex这个吊东西其他地方在用所以需要再整一个属性。
downdonghua.value = -1;
nextTick(() => {
secondtop.value = 0
firsttop.value = 0
downdonghua.value = 0;
})
downmenuIndex.value = 0;
upmenuIndex.value = index
downList.value = bigArray.value[index]?.children
thirdmenuIndex.value = 0;
}
const isempty = ref(false);
const changecard = () => {
isDelete.value = false;
open.value = false;
if (isMove.value) {
getNew()
} else {
if (timearr.value[saveEditIndex.value.index0]?.children[saveEditIndex.value.index1].directiveName) {
flyNumber.value.index0 = saveEditIndex.value.index0;
flyNumber.value.index1 = saveEditIndex.value.index1;
isMove.value = true
}
else {
isempty.value = true;
setTimeout(() => {
isempty.value = false;
}, 1500)
}
}
}
const isRule = ref(false);
const topindex = ref(-1)
const weekValue = ref("");
const weekIndex = ref(-1);
const monthValue = ref("");
const monthIndex = ref(-1);
const clickWeek = (item, index) => {
const now = Date.now()
if (now - lastTap.value < DOUBLE_TAP_DELAY) {
// 双击成立
weekValue.value = item;
weekIndex.value = index;
addnew()
// 重置,避免多次触发
lastTap.value = 0
} else {
weekValue.value = item;
weekIndex.value = index;
// 记录本次时间,等待下次点击
lastTap.value = now
}
}
const clickMonth = (item, index) => {
const now = Date.now()
if (now - lastTap.value < DOUBLE_TAP_DELAY) {
// 双击成立
monthValue.value = item;
monthIndex.value = index;
addnew()
// 重置,避免多次触发
lastTap.value = 0
} else {
monthValue.value = item;
monthIndex.value = index;
// 记录本次时间,等待下次点击
lastTap.value = now
}
}
const isDelete = ref(false);
const openDelete = () => {
flyNumber.value.index0 = -1
flyNumber.value.index1 = -1
isMove.value = false;
open.value = false
if (timearr.value[saveEditIndex.value.index0]?.children[saveEditIndex.value.index1].directiveName) {
if (!isDelete.value) {
isDelete.value = true;
setTimeout(() => deletedonghua.value = true, 50)
} else {
isDelete.value = false;
deleteRuler(saveEditIndex.value.index0, saveEditIndex.value.index1);
}
} else {
isempty.value = true;
setTimeout(() => {
isempty.value = false;
}, 1500)
}
}
// 给抖动用的
function pseudoRandom(index0, index1) {
const seed = index0 * 55.9898 + index1 * 78.233;
// 产生一个伪随机数,取小数部分
return Math.abs(Math.sin(seed) * 43758.5453) % 1;
}
function computeDelay(index0, index1) {
const range = 2; // 延迟范围 0 ~ 2 秒
return pseudoRandom(index0, index1) * range;
}
// 在作用域中声明一个定时器变量
let throttleTimer = null;
//监听拖拽
/* 兼容:如果不支持 requestAnimationFrame就用 setTimeout */
const requestAnimationFrame =
typeof window !== 'undefined' && window.requestAnimationFrame
? window.requestAnimationFrame
: (cb) => setTimeout(cb, 16);
function handleScrolltime(e) {
// uni-app 的 scroll 事件通常把位置放在 e.detail.scrollTop
// 为保险,先做容错判断
const scrollTop = (e && e.detail && (e.detail.scrollTop ?? e.detail.scrollY)) || 0;
lastY = scrollTop;
// 如果还在等待上一帧更新,就直接返回;否则安排下一帧更新
if (!ticking) {
ticking = true;
requestAnimationFrame(() => {
// 把 transform 更新为负的 scrollTop向上平移
// 使用 translate3d 触发 GPU 合成层
transformStyle.value = `translate3d(0, -${lastY}px, 0)`;
ticking = false;
});
}
}
const leftIn = ref(0)
function handleTop(e) {
leftIn.value = e.detail.scrollLeft
}
// 方法:根据条件返回不同的类名
const getClass = (item, index0, index1) => {
if (item.startTime) {
if (flyNumber.value.index0 === (index0) && flyNumber.value.index1 === index1) {
return 'title-time-border-yellow-active-transparent';
} else if (shakyTable.value) {
return 'title-time-border-yellow-active';
} else {
return 'title-time-border-yellow';
}
}
return 'title-time-border';
}
// 通用的生成函数
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 doctorsayList = ref([
{
url: genPaths(
'/static/index/newruler',
'daily_',
6, // 张数
'png',
1, // 起始索引
false // 不补零
), name: '日常'
},
{
url: genPaths(
'/static/index/newruler',
'clean_',
8, // 张数
'png',
1, // 起始索引
false // 不补零
), name: '清洁'
},
{
url: genPaths(
'/static/index/newruler',
'diet_',
7, // 张数
'png',
1, // 起始索引
false // 不补零
), name: '饮食'
},
{
url: genPaths(
'/static/index/newruler',
'sleep_',
5, // 张数
'png',
1, // 起始索引
false // 不补零
), name: '睡眠'
},
{
url: genPaths(
'/static/index/newruler',
'defecate_',
5, // 张数
'png',
1, // 起始索引
false // 不补零
), name: '排泄'
},
]);
// 当前选中的菜单索引
const upmenuIndex = ref<number>(1);
const downmenuIndex = ref<number>(0);
const downdonghua = ref(-1);
const thirdmenuIndex = ref<number>(0);
const forthmenuIndex = ref<number>(0);
const clickzhilingbao = (e : number) => {
const now = Date.now()
forthmenuIndex.value = e
if (now - lastTap.value < DOUBLE_TAP_DELAY) {
// 双击成立
addnew()
// 重置,避免多次触发
lastTap.value = 0
} else {
// 记录本次时间,等待下次点击
lastTap.value = now
}
}
const saveEditIndex = ref({
index0: -1,
index1: -1
})
const secondContant = (index : number) => {
iszhouqi.value = false;
weekIndex.value = -1;
monthIndex.value = -1;
weekValue.value = "";
monthValue.value = "";
downmenuIndex.value = index;
downdonghua.value = index;
thirdmenuIndex.value = 0;
firsttop.value = 0.01;
nextTick(() => {
firsttop.value = 0;
})
}
const timer = ref(null);//计时器
const elementsInfo = ref({})//所有表格的信息
const moveX = ref(0)
const moveY = ref(0)
const openX = ref(0)
const openY = ref(0)
const flyNumber = ref({
index0: 999,
index1: 999,
tagName: ''
})
const deletedownisopacity = ref(false);
const touchindex1 = ref(-1);
// 分享矩阵到微信
const shareShow = ref(false);
const shareToWeixin = () => {
shareShow.value = true;
deletedownisopacity.value = false;
setTimeout(() => {
deletedownisopacity.value = true
}, 100)
}
const clickshare = () => {
uni.share({
provider: "weixin",
scene: "WXSceneSession",
type: 0,
href: "http://192.168.2.31:3101/daytoday",
title: "护理日程分享",
summary: "九泰护理日程测试",
imageUrl: "https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/uni@2x.png",
success: function (res) {
console.log("success:");
},
fail: function (err) {
console.log("fail:");
}
});
}
const jiao = ref([false, false])
//表格点击开始
const showDetail = ref([-1, -1])
const rulerTouchClick = (item : any, index0 : number, index1 : number) => {
isDelete.value = false;
saveEditIndex.value.index0 = index0;
saveEditIndex.value.index1 = index1;
centerCell();
isRule.value = true;
setTimeout(() => {
if (item.directiveName && open.value) {
touchindex1.value = index1;
const query = uni.createSelectorQuery()
query
.selectAll('.super-card-time-card')
.boundingClientRect((data : any) => {
data.forEach(async (res : any) => {
// 根据你的条件筛选元素
if (res.left > 100 && res.left < 1067 && res.top < 670 && res.top > 50 && res.dataset.index0 == index0 && res.dataset.index1 == index1) {
if (res.left > 100 && res.left < 500) {
// 表格太靠左侧,修改到右面
openX.value = Math.floor(res.left) + 528;
jiao.value[0] = true
} else {
openX.value = Math.floor(res.left) - 18
jiao.value[0] = false
}
if (res.top > 300) {
// 表格太靠上侧,修改到下面
openY.value = Math.floor(res.top) + 100;
jiao.value[1] = true
} else {
openY.value = Math.floor(res.top) + 180
jiao.value[1] = false
}
await nextTick()
isopen.value = true;
showDetail.value[0] = index0;
showDetail.value[1] = index1;
// console.log("shaa",timearr.value[showDetail.value[0]]?.children[showDetail.value[1]]?.izPackage)
isopacity.value = false;
//加动画
setTimeout(() => {
isopacity.value = true;
}, 100)
}
})
})
.exec()
}
}, 400)
}
const shakyTable = ref(false);
const reldata = ref([]);
const deleteRuler = (index0 : number, index1 : number) => {
deleteDirective(timearr.value[index0]?.children[index1]).then((res : any) => {
if (res.success) {
geteverything()
}
})
}
const saveX = ref(0);
const saveY = ref(0);
const bottomTimer = ref(null);
const bottomisShaking = ref(false);
const bottomTouchStart = (e) => {
saveX.value = Math.floor(e.touches[0].pageX);
saveY.value = Math.floor(e.touches[0].pageY);
// 2秒后触发抖动效果
bottomTimer.value = setTimeout(() => {
bottomisShaking.value = true
}, 500)
}
const bottomTouchMove = (e) => {
const moveX = Math.floor(e.touches[0].pageX);
const moveY = Math.floor(e.touches[0].pageY);
// 计算移动距离
if (
Math.abs(moveX - saveX.value) > 0 ||
Math.abs(moveY - saveY.value) > 0
) {
if (bottomTimer.value) {
clearTimeout(bottomTimer.value)
bottomTimer.value = null
}
}
}
const bottomTouchEnd = () => {
if (bottomTimer.value) {
clearTimeout(bottomTimer.value)
bottomTimer.value = null
}
}
const indexsave = ref([-1, -1]);
const opensay = () => {
sayisopacity.value = false;
sayisopen.value = true;
setTimeout(() => {
sayisopacity.value = true
}, 50)
}
const buttonBlue = ref(false)
let animTimer = null
async function addnewbutton() {
// 清定时器(防止残留)
if (animTimer) {
clearTimeout(animTimer)
animTimer = null
}
// 先把状态设为 false等待 DOM 更新后再设为 true —— 达到重启动画的效果
buttonBlue.value = false
await nextTick() // 等待下一帧,确保样式被移除
// 重新打开动画
buttonBlue.value = true
addnew()
// 1s 后还原(与动画时长保持一致)
animTimer = setTimeout(() => {
buttonBlue.value = false
animTimer = null
}, 1000)
}
const doaddDirective = (element : any) => {
addDirective(element).then((res) => {
if (res.success) {
geteverything()
}
})
}
const killjishi = (id : string) => {
deleteInstant({ id: id }).then((res) => {
if (res.success) {
geteverything()
}
})
}
const addnew = () => {
if (isDelete.value) {
isDelete.value = false;
deleteRuler(saveEditIndex.value.index0, saveEditIndex.value.index1);
return
}
if (isMove.value) {
getNew()
return
}
let haveValue = false;
if (timearr.value[saveEditIndex.value.index0]?.children[saveEditIndex.value.index1].directiveName) {
haveValue = true
}
// return
if (iszhiling.value) {
let allobject = savePackagelist.value[forthmenuIndex.value];
if (saveEditIndex.value.index1 === -1 && saveEditIndex.value.index0 === -1) {
return
}
if (isDelete.value) {
isDelete.value = false;
deleteRuler(saveEditIndex.value.index0, saveEditIndex.value.index1);
return
}
if (isMove.value) {
getNew()
return
}
flyNumber.value.index0 = -1;
flyNumber.value.index1 = -1;
isMove.value = false;
let cycleType = `打包`;
let cycleValue = "";
const startHour = Number(saveEditIndex.value.index0)
const startMinute = Number(timearr.value[saveEditIndex.value.index0]?.children[saveEditIndex.value.index1].tagName)
const endMinute = startMinute + Number(allobject.serviceDuration)
const endHour = startHour + Math.floor(endMinute / 60)
const formattedStart = `${String(startHour)}:${String(startMinute).padStart(2, '0')}`
const formattedEnd = `${String(endHour)}:${String(endMinute % 60).padStart(2, '0')}`
let param = {
id: haveValue ? timearr.value[saveEditIndex.value.index0]?.children[saveEditIndex.value.index1].id : "",
nuId: uni.getStorageSync('nuId'),
nuName: uni.getStorageSync('nuName'),
elderId: uni.getStorageSync('elderId'),
elderName: uni.getStorageSync('NUall').elderInfo.name,
directiveId: allobject.id,
directiveName: allobject.packageName,
typeId: "",
typeName: "",
categoryId: "",
categoryName: "",
cycleTypeId: "",
cycleType: cycleType,
cycleValue: cycleValue,
startTime: formattedStart,
endTime: formattedEnd,
serviceDuration: allobject.serviceDuration,
positioning: saveEditIndex.value.index0.toString(),
positioningLong: saveEditIndex.value.index1.toString(),
izPackage: 'Y',
previewFile: "",
previewFileSmall: "",
netPreviewFile: "",
netPreviewFileSmall: "",
immediateFile: "",
immediateFileFocus: "",
netImmediateFileFocus: "",
netImmediateFile: "",
tagName: timearr.value[saveEditIndex.value.index0]?.children[saveEditIndex.value.index1].tagName,
mp3File: allobject.mp3File,
netMp3File: allobject.netMp3File,
mp4File: allobject.mp4File,
netMp4File: allobject.netMp4File,
serviceContent: allobject.serviceContent,
}
//给表格赋值
timearr.value[saveEditIndex.value.index0].children[saveEditIndex.value.index1] = param;
let data = {
index0: saveEditIndex.value.index0,
index1: saveEditIndex.value.index1
}
whereEvent(data);
if (haveValue) {
editDirective(param).then((res : any) => {
if (res.success) {
geteverything()
}
})
} else {
doaddDirective(param);
}
return
}
let stopIt = false;
let allobject = bigArray.value[upmenuIndex.value].children[downmenuIndex.value].children[thirdmenuIndex.value]
if (allobject.cycleTypeId == 3) {
scrollLeft.value = 1;
bottomItems.value.forEach((element : any, index : number) => {
if (element.directiveName == allobject.title) {
stopIt = true
}
})
nextTick(() => {
if (!stopIt) {
scrollLeft.value = 0;
if (bottomItems.value.length && bottomItems.value[0].target === "#03a4ff") {
bottomItems.value[0].target = "#fff"
clearTimeout(cleansettimeout.value);
}
let pushValue = allobject;
pushValue.directiveId = allobject.id;
pushValue.directiveName = allobject.title;
pushValue.serviceDuration = allobject.serviceDuration;
pushValue.target = `#03a4ff`
pushValue.id = ""
pushValue.nuId = uni.getStorageSync('nuId');
pushValue.nuName = uni.getStorageSync('nuName');
pushValue.elderId = uni.getStorageSync('elderId');
pushValue.elderName = uni.getStorageSync('NUall').elderInfo.name;
bottomItems.value.unshift(pushValue)
// 实现即时指令动画
cleansettimeout.value = setTimeout(() => {
bottomItems.value[0].target = `#fff`;
console.log("即时指令看看进入了啥", pushValue)
addInstant(pushValue).then((res : any) => {
if (res.success) {
geteverything()
}
})
}, 1500)
} else {
clearTimeout(cleansettimeoutrel.value);
isop.value = true;
cleansettimeoutrel.value = setTimeout(() => {
isop.value = false;
// saveAll()
}, 1500)
}
})
return
}
if (saveEditIndex.value.index1 === -1 && saveEditIndex.value.index0 === -1) {
return
}
flyNumber.value.index0 = -1;
flyNumber.value.index1 = -1;
isMove.value = false;
if (allobject.cycleTypeId == 2 && iszhouqi.value && weekIndex.value == -1 && monthIndex.value == -1) {
return
}
else if (allobject.cycleTypeId == 2 && !iszhouqi.value) {
iszhouqi.value = true
return
}
let cycleType = "";
let cycleValue = "";
if (allobject.cycleTypeId == 1) {
cycleType = "日常"
} else {
if (weekIndex.value != -1) {
cycleType = weekValue.value
let cycleTypeIndex = 0;
weekDays.forEach((element : any, index : any) => {
if (element == weekValue.value) {
cycleTypeIndex = index
}
})
cycleValue = cycleTypeIndex.toString()
} else {
cycleType = monthValue.value + "号";
cycleValue = monthValue.value
}
iszhouqi.value = false;
weekIndex.value = -1;
monthIndex.value = -1;
weekValue.value = "";
monthValue.value = "";
}
const startHour = Number(saveEditIndex.value.index0)
const startMinute = Number(timearr.value[saveEditIndex.value.index0].children[saveEditIndex.value.index1].tagName)
const endMinute = startMinute + Number(allobject.serviceDuration)
const endHour = startHour + Math.floor(endMinute / 60)
const formattedStart = `${String(startHour)}:${String(startMinute).padStart(2, '0')}`
const formattedEnd = `${String(endHour)}:${String(endMinute % 60).padStart(2, '0')}`
let param = {
id: haveValue ? timearr.value[saveEditIndex.value.index0].children[saveEditIndex.value.index1].id : "",
nuId: uni.getStorageSync('nuId'),
nuName: uni.getStorageSync('nuName'),
elderId: uni.getStorageSync('elderId'),
elderName: uni.getStorageSync('NUall').elderInfo.name,
directiveId: allobject.id,
directiveName: allobject.title,
typeId: allobject.typeId,
typeName: allobject.typeName,
categoryId: allobject.categoryId,
categoryName: allobject.categoryName,
cycleTypeId: allobject.cycleTypeId,
cycleType: cycleType,
cycleValue: cycleValue,
startTime: formattedStart,
endTime: formattedEnd,
positioning: saveEditIndex.value.index0.toString(),
positioningLong: saveEditIndex.value.index1.toString(),
izPackage: 'N',
previewFile: allobject.previewFile,
previewFileSmall: allobject.previewFileSmall,
serviceDuration: allobject.serviceDuration,
immediateFile: allobject.immediateFile,
immediateFileFocus: allobject.immediateFileFocus,
netImmediateFileFocus: allobject.netImmediateFileFocus,
netImmediateFile: allobject.netImmediateFile,
tagName: timearr.value[saveEditIndex.value.index0].children[saveEditIndex.value.index1].tagName,
mp3File: allobject.mp3File,
netMp3File: allobject.netMp3File,
mp4File: allobject.mp4File,
netMp4File: allobject.netMp4File,
serviceContent: allobject.serviceContent,
netPreviewFile: allobject.netPreviewFile,
netPreviewFileSmall: allobject.netPreviewFileSmall,
}
//给表格赋值
timearr.value[saveEditIndex.value.index0].children[saveEditIndex.value.index1] = param;
let data = {
index0: saveEditIndex.value.index0,
index1: saveEditIndex.value.index1
}
whereEvent(data);
if (haveValue) {
editDirective(param).then((res : any) => {
if (res.success) {
geteverything()
}
})
} else {
doaddDirective(param);
}
}
const cleansettimeout = ref(null);
const cleansettimeoutrel = ref(null);
const saveAll = () => {
if (!cansumit.value) {
return
}
let info = []
bodyTagList.value.forEach((element : any) => {
if (element.izSelected == 'Y') {
info.push(element)
}
})
emotionTagList.value.forEach((element : any) => {
if (element.izSelected == 'Y') {
info.push(element)
}
})
let allvalue = {
nuId: uni.getStorageSync('nuId'),
nuName: uni.getStorageSync('nuName'),
elderId: uni.getStorageSync('elderId'),
elderName: uni.getStorageSync('NUall').elderInfo.name,
tagList: info
}
addBatch(allvalue).then(() => {
geteverything()
})
}
const routerPush = () => {
uni.navigateTo({
url: `/pages/timeMatrix/indexnew`
})
}
// 暂存器
const saveRulerTime = ref({
index0: -1,
index1: -1
})
const targetRuler = ref({
index0: -1,
index1: -1,
current: -1,
bordershow: true
})
const solveWatch = ref(0)
const whereEvent = (data : any) => {
saveEditIndex.value.index0 = data.index0;
saveEditIndex.value.index1 = data.index1;
centerCell();
targetRuler.value.index0 = data.index0;
targetRuler.value.index1 = data.index1;
saveRulerTime.value.index0 = targetRuler.value.index0;
saveRulerTime.value.index1 = targetRuler.value.index1;
targetRuler.value.bordershow = false;
setTimeout(() => {
targetRuler.value.index0 = -1;
targetRuler.value.index1 = -1;
targetRuler.value.current = -1
}, 400)
setTimeout(() => {
targetRuler.value.bordershow = true;
saveRulerTime.value.index0 = -1;
saveRulerTime.value.index1 = -1;
}, 1000)
}
// 定义每小时中的分钟数组,表示每 5 分钟一个时间段,总共 12 个
const minuteArr = ['00', '05', '10', '15', '20', '25', '30', '35', '40', '45', '50', '55']
const timearr = ref(
Array.from({ length: 24 }, (_, hour) => ({
positioning: hour.toString(),
children: minuteArr.map(time => ({
tagName: time, // 表示分钟,如 '00', '05' 等
directiveName: '' // 默认的 directiveName
}))
}))
)
const emotionTagList = ref([]);
const bodyTagList = ref([]);
const geteverything = () => {
if (uni.getStorageSync('nuId') && uni.getStorageSync('elderId')) {
getNclist(uni.getStorageSync('nuId'), uni.getStorageSync('elderId')).then((res : any) => {
timearr.value = Array.from({ length: 24 }, (_, hour) => ({
positioning: hour.toString(),
children: minuteArr.map(time => ({
tagName: time, // 表示分钟,如 '00', '05' 等
directiveName: '' // 默认的 directiveName
}))
}))
res.result.serviceList.forEach((res : any) => {
timearr.value[res.positioning].children[res.positioningLong] = res;
})
bottomItems.value = res.result.instantList
cansumit.value = true;
emotionTagList.value = res.result.emotionTagList;
emotionTagListLook.value = []
bodyTagListLook.value = []
res.result.emotionTagList.forEach((res : any) => {
if (res.izSelected == 'Y') {
emotionTagListLook.value.push(res.netPic)
}
})
bodyTagList.value = res.result.bodyTagList
res.result.bodyTagList.forEach((res : any) => {
if (res.izSelected == 'Y') {
bodyTagListLook.value.push(res.netPic)
}
})
})
}
}
const savePackagelist = ref([]);
onMounted(() => {
savePackagelist.value = uni.getStorageSync('Packagelist') || []
let res = uni.getStorageSync('saveTree0')
// console.log("00000",res)
let goodArray = []
myArray.forEach((element : any) => {
element.children.forEach((element1 : any) => {
goodArray.push({
name: element1.title,
url: element1.url,
})
})
})
secondtemp.value = goodArray
if (res.result) {
res.result.forEach((element : any) => {
if (element.netFlag == '0') {
doctorsayList.value.forEach((res : any) => {
if (res.name == element.title) {
element.url = res.url
}
})
} else {
element.url = element.animationPath
}
element.children.forEach((res1 : any) => {
if (res1.netFlag == '0') {
secondtemp.value.forEach((res2 : any) => {
if (res2.name == res1.title) {
res1.url = res2.url
}
})
} else {
res1.url = res1.animationPath
}
})
})
bigArray.value = res.result;
}
downList.value = bigArray.value[0].children
upmenuIndex.value = -1;
downdonghua.value = -1;
setTimeout(() => {
upmenuIndex.value = 0;
downdonghua.value = 0;
}, 50)
uni.$on('where', findback);
downdonghua.value = 0;
geteverything()
nextTick(() => {
timeNowMove()
})
})
const hournow = ref(new Date().getHours());
// 表格进来就给我居中
function timeNowMove() {
const cellCenterX = (hournow.value + 0.5) * 259;
let width = cellCenterX - visibleWidth / 2;
const totalWidth = totalColumns * 259;
cardLeft.value = Math.max(0, Math.min(width, totalWidth - visibleWidth)) / 2;
}
const bodyTagListLook = ref([]);
const emotionTagListLook = ref([]);
const cansumit = ref(false);
onBeforeUnmount(() => {
if (animTimer) clearTimeout(animTimer)
uni.$off('where', findback);
ticking = false;
})
function findback(data : any) {
solveWatch.value = 3;
whereEvent(data)
}
// 切割bigArray
function splitString(str) {
// 使用正则表达式找到所有括号的内容
let result = [];
let remainingStr = str;
// 正则匹配最外层括号(支持全角和半角)
let regex = /([^(]*)[(]([^)]+)[)]/;
while (regex.test(remainingStr)) {
let match = remainingStr.match(regex);
if (match) {
// 添加括号前的部分(去掉空白)
if (match[1].trim()) {
result.push(match[1].trim());
}
// 添加括号内的内容
if (match[2].trim()) {
result.push(match[2].trim());
}
// 更新剩余的字符串
remainingStr = remainingStr.replace(match[0], '').trim();
}
}
// 如果最后还有剩余部分,也加入结果
if (remainingStr.trim()) {
result.push(remainingStr.trim());
}
return result;
}
const totalColumns = 24; // 总列数
const totalRows = 11; // 总行数
const visibleWidth = 1295; // 可视区域宽度 (rpx),基于 scalcType * widthType ≈ 2220
const visibleHeight = 1225; // 可视区域高度 (rpx)假设显示约5行时 heightType = 102.5
function centerCell() {
if (saveEditIndex.value.index0 >= 0 && saveEditIndex.value.index0 <= totalColumns && saveEditIndex.value.index1 >= 0 && saveEditIndex.value.index1 <= totalRows) {
// 计算点击格子的中心位置 (rpx)
const cellCenterX = (saveEditIndex.value.index0 + 0.5) * 259;
const cellCenterY = (saveEditIndex.value.index1 + 0.5) * 245;
// 计算 scrollLeft 和 scrollTop使格子中心位于可视区域中心
cardLeft.value = cellCenterX - visibleWidth / 2;
scrollTop.value = cellCenterY - visibleHeight / 2;
// 计算网格总宽高
const totalWidth = totalColumns * 259;
const totalHeight = totalRows * 245;
// 限制 scrollLeft 和 scrollTop 在有效范围内
cardLeft.value = Math.max(0, Math.min(cardLeft.value, totalWidth - visibleWidth)) / 2;
// scrollTop.value = 0
scrollTop.value = Math.max(0, Math.min(scrollTop.value, totalHeight - visibleHeight)) / 2;
}
}
const iszhiling = ref(false)
const zhilingbao = () => {
iszhiling.value = !iszhiling.value
forthmenuIndex.value = 0;
}
const deletedonghua = ref(false);
</script>
<style lang="less" scoped>
// 主页的css
@import './index';
</style>