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

619 lines
19 KiB
Vue
Raw Normal View History

2026-01-09 16:23:18 +08:00
<!-- 护嘱 -->
<template>
<view class="right-container" :style="isshow?{opacity: `1`}:{opacity: `0`}">
<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 timeArray" :key="index">
<view class="boom-son">
<text class="boom-text">
{{item}}
</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: 1165rpx;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="title-time-blue"
v-show="saveEditIndex.index0 == index0 && saveEditIndex.index1 == index1 && isRule">
</view>
<view :class="getClass(item1,index0,index1)"
style="font-size: 30rpx;overflow: hidden;"
:style="{ animationDelay:`-${computeDelay(index0, index1).toFixed(2)}s` }">
<view class="title-time" v-if="item1.startTime"
style="flex-direction: column;">
<view v-if="item1.startTime"
class="title-time-font-rel">
{{ item1.directiveName?splitString(item1.directiveName)[0]:""}}
</view>
<view
v-if="item1.startTime&&splitString(item1.directiveName)[1]"
class="title-time-font-tags">
({{ item1.directiveName?splitString(item1.directiveName)[1]:""}})
</view>
<view v-if="item1.startTime" :class="getFontClass(item1)" >
{{ `${parseHourMinutestring(item1.startTime).hour}:${parseHourMinutestring(item1.startTime).minute}-${parseHourMinutestring(item1.endTime).hour}:${parseHourMinutestring(item1.endTime).minute}` }}
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</scroll-view>
</view>
<view class="right-order">
<view class="order-title">
<view class="order-month">
{{ selectdata.month }}
</view>
<scroll-view class="order-day" scroll-with-animation :scroll-x="true"
:scroll-left="movetime">
<view class="days-father">
<view :class="daytarget===index? `targetdays` :`days`"
v-for="(item,index) in daysarray" :key="index" @click="clickday(item,index)">
{{ item }}
</view>
</view>
</scroll-view>
</view>
</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, getDirectiveOrders } from "./api.js";
import { myArray } from './yaoshandiao.js';
const props = defineProps({
isshow: {
type: Boolean,
required: true,
},
});
// watch(
// () => props.isshow,
// (newVal, oldVal) => {
// // 只有当新旧值不相同时才执行
// if (newVal !== oldVal) {
// }
// }
// )
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 hournow = ref(new Date().getHours());
// 获得现在的年月日
const dateref = ref(getTodayObj())
function getTodayObj() {
const d = new Date()
const month = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return {
year: d.getFullYear(),
month,
day
}
}
const selectdata = ref({
year: 0,
month: "",
day: ""
})
const daysarray = ref([]);
const movetime = ref(0)
function generateDayArray() {
const selY = Number(selectdata.value.year)
const selM = Number(selectdata.value.month)
// 校验:年/月 必须是有效数字且月在1-12之间
if (!Number.isFinite(selY) || !Number.isFinite(selM) || selM < 1 || selM > 12) {
return []
}
const todayY = Number(dateref.value.year)
const todayM = Number(dateref.value.month) // dateref.month 可能是字符串 "01"
const todayD = Number(dateref.value.day)
let endDay = 0
if (selY === todayY && selM === todayM) {
// 同年同月:到今天为止
endDay = todayD;
} else {
// 不同:计算该月总天数。注意 new Date(year, month, 0).getDate()
// 这里 month 要传 1-12这个构造会返回该月最后一天
endDay = new Date(selY, selM, 0).getDate()
}
daysarray.value = Array.from({ length: endDay }, (_, i) => String(i + 1).padStart(2, '0'))
// console.log("看看生成的咋样", daysarray.value)
if (selY === todayY && selM === todayM) {
movetime.value = 9998;
daytarget.value = daysarray.value.length - 1
} else {
movetime.value = 0.001;
daytarget.value = 0
setTimeout(() => {
movetime.value = 0;
}, 50)
}
// 生成字符串数组 ["01","02",...]
}
const daytarget = ref(0)
const clickday = (item : string, index : number) => {
daytarget.value = index
}
const facedonghua = ref(false)
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 getFontClass = (item:any) => {
switch (item.executeStatus) {
case 'hisFaild':
return 'card-time-red';
case 'current':
return 'card-time-blue';
default:
return 'card-time';
}
}
// 这是二级菜单的动画的模板
const secondtemp = ref([])
// 上次点击时间
const lastTap = ref(0)
// 双击的最大间隔ms可根据体验调整
const DOUBLE_TAP_DELAY = 300
//变更左侧菜单
const isempty = ref(false);
const isRule = ref(false);
const topindex = ref(-1)
const isDelete = ref(false);
// 给抖动用的
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) {
switch (item.executeStatus) {
case 'hisOk':
return 'title-time-border-hisOk';
case 'hisFaild':
return 'title-time-border-hisFaild';
case 'current':
return 'title-time-border-current';
case 'future':
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 upmenuIndex = ref<number>(1);
const downmenuIndex = ref<number>(0);
const downdonghua = ref(-1);
const thirdmenuIndex = ref<number>(0);
const forthmenuIndex = ref<number>(0);
const saveEditIndex = ref({
index0: -1,
index1: -1
})
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 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;
}
const shakyTable = ref(false);
const saveX = ref(0);
const saveY = ref(0);
const indexsave = ref([-1, -1]);
const buttonBlue = ref(false)
let animTimer = null
// 暂存器
const saveRulerTime = ref({
index0: -1,
index1: -1
})
const targetRuler = ref({
index0: -1,
index1: -1,
current: -1,
bordershow: true
})
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 geteverything = () => {
if (uni.getStorageSync('nuId') && uni.getStorageSync('elderId')) {
getTable()
}
}
// 处理分钟和小时的函数
function parseHourMinutestring(startTime) {
// 假设格式固定为 "YYYY-MM-DD HH:MM:SS"
const parts = startTime.split(' ');
if (parts.length < 2) return { hour: NaN, minute: NaN };
const [hh, mm] = parts[1].split(':');
return { hour: hh, minute: mm };
}
// 处理分钟和小时的函数(number)
function parseHourMinute(startTime) {
// 假设格式固定为 "YYYY-MM-DD HH:MM:SS"
const parts = startTime.split(' ');
if (parts.length < 2) return { hour: NaN, minute: NaN };
const [hh, mm] = parts[1].split(':');
return { hour: Number(hh), minute: Number(mm) };
}
const getTable = () => {
let time = `${selectdata.value.year}-${selectdata.value.month}-${selectdata.value.day}`
getDirectiveOrders(time).then((data) => {
// console.log("data",data.result.all)
timearr.value = Array.from({ length: 24 }, (_, hour) => ({
positioning: hour.toString(),
children: minuteArr.map(time => ({
// tagName: time, // 表示分钟,如 '00', '05' 等
directiveName: '' // 默认的 directiveName
}))
}))
data.result.all.forEach((element : any) => {
element.positioning = parseHourMinute(element.startTime).hour;
element.positioningLong = parseHourMinute(element.startTime).minute / 5;
timearr.value[element.positioning].children[element.positioningLong] = element;
})
})
}
const savePackagelist = ref([]);
onMounted(() => {
selectdata.value = dateref.value;
generateDayArray()
savePackagelist.value = uni.getStorageSync('Packagelist') || []
let res = uni.getStorageSync('saveTree0')
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) {
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()
scrollTop.value = 0.001
nextTick(() => {
scrollTop.value = 0
timeNowMove()
})
})
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 = 1455; // 可视区域宽度 (rpx),基于 scalcType * widthType ≈ 2220
const visibleHeight = 1170; // 可视区域高度 (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) * 290;
const cellCenterY = (saveEditIndex.value.index1 + 0.5) * 234;
// 计算 scrollLeft 和 scrollTop使格子中心位于可视区域中心
cardLeft.value = cellCenterX - visibleWidth / 2;
scrollTop.value = cellCenterY - visibleHeight / 2;
// 计算网格总宽高
const totalWidth = totalColumns * 290;
const totalHeight = totalRows * 234;
// 限制 scrollLeft 和 scrollTop 在有效范围内
cardLeft.value = Math.max(0, Math.min(cardLeft.value, totalWidth - visibleWidth)) / 2 + 0.7;
// scrollTop.value = 0
scrollTop.value = Math.max(0, Math.min(scrollTop.value, totalHeight - visibleHeight)) / 2;
}
}
// 表格进来就给我居中
function timeNowMove() {
const cellCenterX = (hournow.value + 0.5) * 290;
let width = cellCenterX - visibleWidth / 2;
const totalWidth = totalColumns * 290;
cardLeft.value = Math.max(0, Math.min(width, totalWidth - visibleWidth)) / 2 + 0.7;
}
const iszhiling = ref(false)
const zhilingbao = () => {
iszhiling.value = !iszhiling.value
forthmenuIndex.value = 0;
}
const deletedonghua = ref(false);
</script>
<style lang="less" scoped>
// 主页的css
@import './bigindex';
</style>