diff --git a/other-module/emergency-screen/xian-center/cv-monitor.html b/other-module/emergency-screen/xian-center/cv-monitor.html index c1db83a..b2f8319 100644 --- a/other-module/emergency-screen/xian-center/cv-monitor.html +++ b/other-module/emergency-screen/xian-center/cv-monitor.html @@ -117,6 +117,14 @@ .header__btn--main:hover{background:rgba(24,144,255,0.25);box-shadow:0 0 10px rgba(24,144,255,0.2);} .header__runtime{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--text-sub);} .header__runtime-num{font-size:18px;font-weight:700;color:var(--primary);text-shadow:0 0 8px rgba(24,144,255,0.4);} + /* 时间段 Tab(统一控制全屏统计图表的时间范围) */ + .header__tabs{display:flex;align-items:center;gap:2px;padding:3px;background:rgba(10,22,48,0.6); + border:1px solid var(--panel-border);border-radius:16px;} + .header__tab{height:22px;padding:0 12px;border-radius:13px;font-size:11px;cursor:pointer;transition:all .2s; + border:none;background:transparent;color:var(--text-sub);white-space:nowrap;letter-spacing:0.3px; + display:inline-flex;align-items:center;font-family:inherit;} + .header__tab:hover{color:var(--text-main);} + .header__tab--active{background:rgba(24,144,255,0.22);color:#fff;box-shadow:0 0 8px rgba(24,144,255,0.3);} .header__deco{position:absolute;top:6px;width:88px;height:10px;pointer-events:none;z-index:1; background-repeat:no-repeat;background-position:center;background-size:100% 100%;} .header__deco--left{left:32px; @@ -220,7 +228,7 @@ .cv-ring__legend-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;} .cv-ring__legend-value{font-weight:700;color:var(--text-main);font-variant-numeric:tabular-nums;white-space:nowrap;} - /* ========== 睡眠柱图(沿用主屏) ========== */ + /* ========== 睡眠柱图(口径参考求助趋势 help-trend) ========== */ .sleep-chart{display:flex;flex-direction:column;gap:6px;} .sleep-chart__summary{display:flex;justify-content:space-between;align-items:center;gap:8px;font-size:11px;color:var(--text-sub);} .sleep-chart__summary b{color:#fff;font-size:13px;} @@ -229,15 +237,25 @@ .sleep-chart__plot::before,.sleep-chart__plot::after{content:'';position:absolute;left:0;right:0;border-top:1px dashed rgba(24,144,255,0.12);} .sleep-chart__plot::before{top:30px;} .sleep-chart__plot::after{top:60px;} - .sleep-day{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:4px;position:relative;z-index:1;} + .sleep-day{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:4px;position:relative;z-index:1;min-width:0;} .sleep-day__bars{height:72px;display:flex;align-items:flex-end;gap:3px;} .sleep-day__bar{width:7px;border-radius:5px 5px 2px 2px;min-height:6px;box-shadow:0 0 8px currentColor;} .sleep-day__bar--deep{background:#13C2C2;color:#13C2C2;} .sleep-day__bar--light{background:#1890FF;color:#1890FF;} - .sleep-day__label{font-size:10px;color:var(--text-dim);line-height:1;} + .sleep-day__label{font-size:10px;color:var(--text-dim);line-height:1;white-space:nowrap;} .sleep-chart__legend{display:flex;align-items:center;justify-content:center;gap:12px;font-size:10px;color:var(--text-sub);} .sleep-chart__legend span{display:flex;align-items:center;gap:5px;} .sleep-chart__dot{width:8px;height:8px;border-radius:2px;box-shadow:0 0 7px currentColor;} + /* 睡眠柱图悬浮 tip(口径参考求助趋势 help-trend-tip) */ + .sleep-tip{position:fixed;z-index:200;min-width:132px;padding:8px 10px; + background:rgba(10,22,48,0.96);border:1px solid rgba(24,144,255,0.4);border-radius:8px; + box-shadow:0 0 16px rgba(24,144,255,0.25);font-size:11px;color:var(--text-main); + pointer-events:none;backdrop-filter:blur(6px);} + .sleep-tip__head{font-size:12px;font-weight:700;color:#fff;margin-bottom:5px; + padding-bottom:4px;border-bottom:1px solid rgba(24,144,255,0.2);} + .sleep-tip__row{display:flex;align-items:center;gap:6px;line-height:1.6;color:var(--text-sub);} + .sleep-tip__row i{width:8px;height:8px;border-radius:2px;box-shadow:0 0 6px currentColor;flex-shrink:0;} + .sleep-tip__row b{color:#fff;font-weight:700;margin:0 2px;font-variant-numeric:tabular-nums;} /* ========== 步数环形图 ========== */ .steps-ring{display:flex;flex-direction:column;gap:6px;} @@ -331,7 +349,38 @@ display:flex;align-items:center;gap:6px;} .map-title-pill .dot{width:6px;height:6px;border-radius:50%;background:var(--cyan);box-shadow:0 0 6px var(--cyan);} - /* ========== 单位手表配备情况卡片(横向滚动) ========== */ + /* ========== 地图缩放交互(点击手表图标放大居中 + 信息弹窗) ========== */ + .map-stage{position:absolute;inset:0;z-index:1;transform-origin:center center; + transition:transform .55s cubic-bezier(.22,.61,.36,1);} + .map-marker.is-active{z-index:12;} + .map-marker.is-active .map-marker__pin{filter:drop-shadow(0 0 5px rgba(255,255,255,0.95)) drop-shadow(0 0 10px rgba(0,229,255,0.55));} + /* 手表信息弹窗(浮于地图之上,不随缩放变化;由 JS 按地图正中自适应定位) */ + .watch-marker-popup{position:absolute;left:0;top:0;z-index:20;width:290px;padding:12px 14px 13px; + background:rgba(10,22,48,0.96);border:1px solid rgba(24,144,255,0.4);border-radius:10px; + box-shadow:0 0 22px rgba(24,144,255,0.3);backdrop-filter:blur(8px); + font-size:12px;color:var(--text-main);opacity:1;transition:opacity .2s ease; + animation:watchPopIn .26s ease;} + @keyframes watchPopIn{from{opacity:0;transform:translateY(6px);}to{opacity:1;transform:none;}} + .watch-marker-popup__arrow{position:absolute;left:50%;bottom:-7px;width:13px;height:13px; + transform:translateX(-50%) rotate(45deg);background:rgba(10,22,48,0.96); + border-right:1px solid rgba(24,144,255,0.4);border-bottom:1px solid rgba(24,144,255,0.4);} + .watch-marker-popup__close{position:absolute;top:6px;right:8px;font-size:16px;line-height:1; + color:var(--text-dim);cursor:pointer;transition:color .2s;} + .watch-marker-popup__close:hover{color:var(--text-main);} + .watch-marker-popup__title{display:flex;align-items:center;gap:6px;flex-wrap:wrap; + font-size:13px;font-weight:700;color:#fff;margin-bottom:8px;padding-right:16px;} + .watch-marker-popup__status{font-size:10px;font-weight:600;padding:1px 7px;border-radius:4px;margin-left:auto;} + .watch-marker-popup__status--normal{color:var(--success);background:rgba(82,196,26,0.15);border:1px solid rgba(82,196,26,0.3);} + .watch-marker-popup__status--offline{color:var(--text-dim);background:rgba(74,107,138,0.15);border:1px solid rgba(74,107,138,0.3);} + .watch-marker-popup__status--warning{color:var(--warning);background:rgba(250,173,20,0.15);border:1px solid rgba(250,173,20,0.3);} + .watch-marker-popup__status--alarm{color:var(--danger);background:rgba(255,77,79,0.15);border:1px solid rgba(255,77,79,0.3);} + .watch-marker-popup__section{font-size:10px;color:var(--primary);font-weight:600;margin:6px 0 3px; + padding-top:5px;border-top:1px solid rgba(24,144,255,0.12);letter-spacing:0.5px;} + .watch-marker-popup__row{display:flex;align-items:flex-start;gap:8px;line-height:1.7;font-size:11px;} + .watch-marker-popup__k{flex-shrink:0;width:72px;color:var(--text-dim);} + .watch-marker-popup__v{flex:1;min-width:0;color:var(--text-main);word-break:break-all;} + + /* ========== 各单位告警统计卡片(横向滚动,沿用 watch-stat) ========== */ .watch-stat-panel{flex-shrink:0;} .watch-stat-cards{position:relative;overflow:hidden;padding:8px 0;} .watch-stat-cards::before,.watch-stat-cards::after{content:'';position:absolute;top:0;bottom:0;width:36px;z-index:5;pointer-events:none;} @@ -366,8 +415,8 @@ .watch-stat-card__chip{display:flex;flex-direction:column;align-items:center;gap:1px;flex:1;min-width:0;} .watch-stat-card__chip-num{font-size:12px;font-weight:700;color:#fff;font-variant-numeric:tabular-nums;line-height:1;} .watch-stat-card__chip-label{font-size:9px;color:var(--text-dim);white-space:nowrap;} - .watch-stat-card__chip--online .watch-stat-card__chip-num{color:var(--success);} - .watch-stat-card__chip--offline .watch-stat-card__chip-num{color:var(--text-dim);} + .watch-stat-card__chip--wearable .watch-stat-card__chip-num{color:var(--primary);} + .watch-stat-card__chip--cardio .watch-stat-card__chip-num{color:var(--danger);} .watch-stat-card--total{background:linear-gradient(135deg,rgba(0,229,255,0.12),rgba(10,30,60,0.6)); border-color:rgba(0,229,255,0.35);box-shadow:0 0 12px rgba(0,229,255,0.18);} .watch-stat-card--total::before{background:var(--cyan);box-shadow:0 0 10px rgba(0,229,255,0.6);} @@ -461,6 +510,13 @@ 西安应急中心 · 心血管监测副屏
+ +
+ + + + +
系统累计运行 0 @@ -479,12 +535,6 @@
心率区间分布 -
@@ -493,12 +543,6 @@
血氧区间分布 -
@@ -507,12 +551,6 @@
压力区间分布 -
@@ -521,18 +559,12 @@
体温区间分布 -
- +
@@ -563,70 +595,13 @@
-
-
+
+
+
+ +
+
手表位置分布
- - -
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
- -
-
-
- -
-
-
- -
-
-
- -
-
- -
-
正常
@@ -636,11 +611,11 @@
- +
- 单位手表配备情况统计 + 各单位告警统计
@@ -657,11 +632,6 @@
睡眠监测 -
@@ -671,11 +641,6 @@
步数监测 -
@@ -929,10 +894,23 @@ var CV_RING_DATA={ /* 时间范围缩放系数 */ var CV_RANGE_FACTOR={today:0.18,week:1,month:3.4,year:11.6}; +/* 当前统一时间段(由顶部 Tab 切换,默认近一周,对应各模块原下拉默认值) */ +var currentCvPeriod='week'; + +/* [交互] 切换全屏统计图表的时间段:更新选中态并重新渲染各图表 */ +function switchCvPeriod(period,el){ + currentCvPeriod=period||'week'; + var tabs=document.getElementById('cvPeriodTabs'); + if(tabs){tabs.querySelectorAll('.header__tab').forEach(function(t){t.classList.remove('header__tab--active');});} + var target=el||(tabs&&tabs.querySelector('.header__tab[data-period="'+currentCvPeriod+'"]')); + if(target){target.classList.add('header__tab--active');} + renderCvRing('heart');renderCvRing('spo2');renderCvRing('pressure');renderCvRing('temp'); + renderSleepChart(); + renderStepsChart(); +} + function getCvScale(metric){ - var sel=document.getElementById(metric+'RangeSelect'); - var v=sel?sel.value:'week'; - return CV_RANGE_FACTOR[v]||1; + return CV_RANGE_FACTOR[currentCvPeriod]||1; } function formatCvNum(n){return Math.max(1,Math.round(n)).toLocaleString('zh-CN');} @@ -989,46 +967,70 @@ renderCvRing('pressure'); renderCvRing('temp'); /* ========== 右侧睡眠柱图 ========== */ -var SLEEP_DATA={ - today:{days:[{day:'06/26',deep:1.6,light:4.0}],avg:'5.6h'}, - week:{days:[ - {day:'06/20',deep:2.4,light:4.8}, - {day:'06/21',deep:1.7,light:4.1}, - {day:'06/22',deep:2.6,light:5.0}, - {day:'06/23',deep:2.0,light:4.4}, - {day:'06/24',deep:1.8,light:4.2}, - {day:'06/25',deep:2.2,light:4.6}, - {day:'06/26',deep:1.6,light:4.0} - ],avg:'6.7h'}, - month:{days:[ - {day:'05月',deep:2.1,light:4.5}, - {day:'06月上',deep:1.9,light:4.3}, - {day:'06月中',deep:2.3,light:4.7}, - {day:'06月下',deep:2.0,light:4.4} - ],avg:'6.6h'} -}; +/* 睡眠监测数据(按时间段聚合:今日24时 / 近一周7日 / 近一月30日 / 近一年12月) */ +/* 以数据最新日 2026-06-26 为基准生成各粒度深睡/浅睡数据(原型演示数据),口径参考求助趋势 */ +function buildSleepData(){ + function pad(n){return n<10?'0'+n:''+n;} + function dateFrom(daysAgo){var dt=new Date(2026,5,26);dt.setDate(dt.getDate()-daysAgo);return dt;} + function md(dt){return pad(dt.getMonth()+1)+'-'+pad(dt.getDate());} + var data={today:[],week:[],month:[],year:[]}; + /* 今日:24 小时睡眠分布,深夜0-6时与23时为睡眠段,深睡集中在前半夜 */ + var deepShape=[0.3,0.3,0.3,0.3,0.2,0.1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.1]; + var lightShape=[0.6,0.6,0.6,0.6,0.5,0.4,0.3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.4]; + for(var h=0;h<24;h++){data.today.push({label:pad(h)+'时',deep:deepShape[h],light:lightShape[h]});} + /* 近一周:7 日(06-20~06-26) */ + var wk=[[2.4,4.8],[1.7,4.1],[2.6,5.0],[2.0,4.4],[1.8,4.2],[2.2,4.6],[1.6,4.0]]; + for(var d=0;d<7;d++){data.week.push({label:md(dateFrom(6-d)),deep:wk[d][0],light:wk[d][1]});} + /* 近一月:30 日(05-28~06-26),日均深睡~2.0/浅睡~4.5,含周期波动 */ + for(var i=29;i>=0;i--){ + var deep=2.0+Math.round(10*Math.sin(i/3))/10+((i%7===6)?0.3:0); + var light=4.5+Math.round(10*Math.sin(i/2.3))/10+((i%7===5||i%7===6)?0.3:0); + data.month.push({label:md(dateFrom(i)),deep:Math.max(0.5,deep),light:Math.max(2,light)}); + } + /* 近一年:12 月(2025-07~2026-06),冬季睡眠略长,6月与今日一致 */ + var monthLabels=['7月','8月','9月','10月','11月','12月','1月','2月','3月','4月','5月','6月']; + var yr=[[2.0,4.6],[1.9,4.5],[2.1,4.7],[2.2,4.8],[2.3,4.9],[2.4,5.0],[2.4,5.0],[2.3,4.8],[2.2,4.7],[2.1,4.6],[2.0,4.5],[1.6,4.0]]; + for(var m=0;m<12;m++){data.year.push({label:monthLabels[m],deep:yr[m][0],light:yr[m][1]});} + return data; +} +var SLEEP_DATA=buildSleepData(); + +/* 睡眠柱图(按时间段渲染深睡/浅睡,布局自适应与求助趋势一致) */ function renderSleepChart(){ - var range=document.getElementById('sleepRangeSelect').value; - var data=SLEEP_DATA[range]||SLEEP_DATA.week; - var maxHour=6; - var daysHtml=data.days.map(function(d){ - var deep=Math.min(maxHour,d.deep); - var light=Math.min(maxHour,d.light); - return '
'+ + var period=currentCvPeriod||'week'; + var buckets=SLEEP_DATA[period]||SLEEP_DATA.week; + var n=buckets.length; + /* 自适应间距与标签步长:桶越多间距越小、标签越稀疏(与求助趋势一致) */ + var gap=n<=7?10:(n<=12?6:2); + var labelStep=n<=12?1:(n===24?6:5); + var periodText={today:'今日24小时',week:'近7日',month:'近30日',year:'近12个月'}[period]||''; + /* 按数据集最大值缩放,使柱体铺满绘图区高度(非固定满量程) */ + var maxVal=0; + buckets.forEach(function(b){if(b.deep>maxVal)maxVal=b.deep;if(b.light>maxVal)maxVal=b.light;}); + var scale=maxVal>0?72/maxVal:0; + var sumDeep=0,sumLight=0; + var barsHtml=buckets.map(function(b,idx){ + sumDeep+=b.deep;sumLight+=b.light; + var dh=b.deep*scale,lh=b.light*scale; + var show=(idx%labelStep===0)||(idx===n-1); + return '
'+ '
'+ - ''+ - ''+ + ''+ + ''+ '
'+ - ''+d.day+''+ + ''+(show?b.label:' ')+''+ '
'; }).join(''); + /* 今日为单日24小时,平均睡眠取合计;其余时间段取日均 */ + var total=sumDeep+sumLight; + var avg=(period==='today'?total:total/n).toFixed(1)+'h'; document.getElementById('sleepChart').innerHTML= '
'+ '
'+ - '按天展示深睡/浅睡'+ - '平均睡眠 '+data.avg+''+ + ''+periodText+'深睡/浅睡分布'+ + '平均睡眠 '+avg+''+ '
'+ - '
'+daysHtml+'
'+ + '
'+barsHtml+'
'+ '
'+ '深睡'+ '浅睡'+ @@ -1037,6 +1039,40 @@ function renderSleepChart(){ } renderSleepChart(); +/* ========== 睡眠柱图悬浮 tip(口径参考求助趋势 help-trend-tip) ========== */ +/* 悬浮某根柱时弹出深睡/浅睡/合计(小时),挂在 #sleepChart 上以代理方式响应(重渲染后仍生效) */ +var sleepTip=document.createElement('div'); +sleepTip.className='sleep-tip'; +sleepTip.style.display='none'; +document.body.appendChild(sleepTip); +var sleepTipDay=null; +function fillSleepTip(dayEl){ + var label=dayEl.getAttribute('data-label'); + var deep=dayEl.getAttribute('data-deep'),light=dayEl.getAttribute('data-light'); + var t=(+deep)+(+light); + sleepTip.innerHTML= + '
'+label+' · 合计 '+t.toFixed(1)+' 小时
'+ + '
深睡 '+deep+' 小时
'+ + '
浅睡 '+light+' 小时
'; +} +function moveSleepTip(x,y){ + var w=sleepTip.offsetWidth||130,h=sleepTip.offsetHeight||70; + var px=x+14,py=y+14; + if(px+w>window.innerWidth) px=x-w-14; + if(py+h>window.innerHeight) py=y-h-14; + sleepTip.style.left=px+'px';sleepTip.style.top=py+'px'; +} +document.getElementById('sleepChart').addEventListener('mousemove',function(e){ + var dayEl=e.target.closest&&e.target.closest('.sleep-day'); + if(!dayEl){ if(sleepTip.style.display!=='none') sleepTip.style.display='none'; sleepTipDay=null; return; } + if(dayEl!==sleepTipDay){ sleepTipDay=dayEl; fillSleepTip(dayEl); } + sleepTip.style.display='block'; + moveSleepTip(e.clientX,e.clientY); +}); +document.getElementById('sleepChart').addEventListener('mouseleave',function(){ + sleepTip.style.display='none';sleepTipDay=null; +}); + /* ========== 右侧步数环形图 ========== */ /* 步数区间分布(单位时间内各步数区间的人数) */ var STEPS_DATA={ @@ -1066,7 +1102,7 @@ var STEPS_DATA={ ],total:6635,avg:'7,775 步'} }; function renderStepsChart(){ - var range=document.getElementById('stepsRangeSelect').value; + var range=currentCvPeriod; var data=STEPS_DATA[range]||STEPS_DATA.week; var total=data.total; var c=2*Math.PI*42; /* r=42 周长 ≈263.9 */ @@ -1113,56 +1149,62 @@ function renderStepsChart(){ } renderStepsChart(); -/* ========== 单位手表配备情况统计 ========== */ -var WATCH_STAT_DATA=[ - {unit:'采油一厂',target:520,deployed:498,online:470,offline:28}, - {unit:'采油二厂',target:480,deployed:455,online:430,offline:25}, - {unit:'采油三厂',target:420,deployed:398,online:375,offline:23}, - {unit:'公司机关',target:380,deployed:372,online:358,offline:14}, - {unit:'兴隆医院',target:160,deployed:155,online:148,offline:7}, - {unit:'宝石花医院',target:180,deployed:170,online:162,offline:8}, - {unit:'高陵医院',target:120,deployed:115,online:108,offline:7}, - {unit:'庆阳医院',target:140,deployed:128,online:118,offline:10} -]; -function renderWatchStatTable(){ +/* ========== 各单位告警统计(横向滚动卡片,口径参考 help-monitor 各单位求助情况) ========== */ +/* 告警类型归口:穿戴告警(摔倒/一键告警)/ 心血管告警(心率/血氧/压力/体温异常) */ +var ALARM_CATEGORY={'摔倒':'wearable','一键告警':'wearable','心率异常':'cardio','血氧异常':'cardio','压力异常':'cardio','体温异常':'cardio'}; +function buildUnitAlarmStats(){ + var unitMap={},detail={}; + ALARM_RECORD_DATA.forEach(function(r){ + var u=r.unit; + if(!unitMap[u]) unitMap[u]=0; + unitMap[u]++; + if(!detail[u]) detail[u]={wearable:0,cardio:0}; + var cat=ALARM_CATEGORY[r.alarmType]||'cardio'; + if(cat==='wearable') detail[u].wearable++; else detail[u].cardio++; + }); + var rows=Object.keys(unitMap).map(function(u){return{unit:u,total:unitMap[u]};}) + .sort(function(a,b){return b.total-a.total;});/* 按告警次数从高到低排序 */ + return{rows:rows,detail:detail}; +} +function renderUnitAlarmStat(){ var track=document.getElementById('watchStatTrack'); - var cards=''; - var sumTarget=0,sumDeployed=0,sumOnline=0,sumOffline=0; - WATCH_STAT_DATA.forEach(function(r){ - var rate=r.target>0?r.deployed/r.target*100:0; - var rateClass=rate>=95?'high':(rate>=85?'mid':'low'); - sumTarget+=r.target;sumDeployed+=r.deployed;sumOnline+=r.online;sumOffline+=r.offline; - cards+='
'+ + if(!track) return; + var stats=buildUnitAlarmStats(),rows=stats.rows,detail=stats.detail; + var maxTotal=Math.max.apply(null,rows.map(function(r){return r.total;}))||1; + var sumTotal=0,sumWearable=0,sumCardio=0; + var cards=rows.map(function(r){ + var d=detail[r.unit]||{wearable:0,cardio:0}; + var rate=maxTotal>0?r.total/maxTotal*100:0; + sumTotal+=r.total;sumWearable+=d.wearable;sumCardio+=d.cardio; + return '
'+ '
'+ ''+r.unit+''+ - ''+rate.toFixed(1)+'%'+ + ''+r.total+''+ '
'+ '
'+ '
'+ - '
'+r.online.toLocaleString('zh-CN')+'在线
'+ - '
'+r.offline.toLocaleString('zh-CN')+'离线
'+ - '
'+r.target.toLocaleString('zh-CN')+'应配
'+ + '
'+d.wearable+'穿戴告警
'+ + '
'+d.cardio+'心血管告警
'+ + '
'+r.total+'合计
'+ '
'+ '
'; - }); - var totalRate=sumTarget>0?sumDeployed/sumTarget*100:0; - var totalRateClass=totalRate>=95?'high':(totalRate>=85?'mid':'low'); - cards+='
'+ + }).join(''); + var totalRate=maxTotal>0?sumTotal/maxTotal*100:0; + cards+='
'+ '
'+ '合计'+ - ''+totalRate.toFixed(1)+'%'+ + ''+sumTotal+''+ '
'+ '
'+ '
'+ - '
'+sumOnline.toLocaleString('zh-CN')+'在线
'+ - '
'+sumOffline.toLocaleString('zh-CN')+'离线
'+ - '
'+sumTarget.toLocaleString('zh-CN')+'应配
'+ + '
'+sumWearable+'穿戴告警
'+ + '
'+sumCardio+'心血管告警
'+ + '
'+sumTotal+'合计
'+ '
'+ '
'; /* 复制一份用于无缝滚动 */ track.innerHTML=cards+cards; } -renderWatchStatTable(); /* ========== 穿戴告警事件列表点击 → 打开告警记录弹窗 ========== */ document.getElementById('alarmTrack').addEventListener('click',function(e){ @@ -1204,6 +1246,9 @@ var ALARM_RECORD_DATA=[ {name:'贺军',empId:'GL-2021-0634',gender:'男',age:46,unit:'高陵医院',dept:'后勤',alarmType:'压力异常',alarmValue:'170/108 mmHg',alarmTime:'2026-06-20 16:18:59',address:'高陵医院后勤服务楼3层307室'} ]; +/* 渲染各单位告警统计(依赖上方 ALARM_RECORD_DATA,故在数据定义后调用) */ +renderUnitAlarmStat(); + var alarmRecordFilteredData=ALARM_RECORD_DATA.slice(); var alarmRecordPage=1; var alarmRecordPageSizeVal=10; @@ -1316,6 +1361,190 @@ function resetAlarmRecordFilter(){ alarmRecordPage=1; renderAlarmRecordTable(); } + +/* ========== 手表位置标记数据 & 点击交互(参考 help-monitor 地图缩放 + 弹窗) ========== */ +var WATCH_MARKER_DATA = [ + {name:'张建国',gender:'男',age:52,unit:'采油一厂',dept:'生产区', + watchId:'CW-2024-0837',watchModel:'Huawei Watch D2',position:'采油一厂生产基地B区3号井组作业平台', + status:'alarm',alarmType:'心率异常',alarmTime:'2026-06-30 14:32:15',top:38,left:33}, + {name:'李明辉',gender:'男',age:38,unit:'采油一厂',dept:'设备区', + watchId:'CW-2024-0512',watchModel:'Apple Watch Ultra 2',position:'采油一厂设备区2号楼208室', + status:'normal',lastActiveTime:'2026-06-30 14:28:03',top:42,left:38}, + {name:'王芳',gender:'女',age:45,unit:'采油二厂',dept:'行政楼', + watchId:'CW-2024-0128',watchModel:'Xiaomi Watch S4',position:'采油二厂行政楼5层503室', + status:'warning',riskType:'脑梗',riskLevel:'中危',probability:'42.3%',warningTime:'2026-06-30 13:55:21',top:43,left:63}, + {name:'刘雪梅',gender:'女',age:36,unit:'采油二厂',dept:'行政楼', + watchId:'CW-2024-0442',watchModel:'OPPO Watch 4 Pro',position:'采油二厂行政楼5层503室', + status:'alarm',alarmType:'体温异常',alarmTime:'2026-06-30 13:20:35',top:46,left:67}, + {name:'赵刚',gender:'男',age:29,unit:'采油三厂',dept:'调度室', + watchId:'CW-2024-0305',watchModel:'Huawei Watch D2',position:'采油三厂调度中心大楼2层201室', + status:'normal',lastActiveTime:'2026-06-30 13:58:22',top:78,left:48}, + {name:'杨丽娟',gender:'女',age:31,unit:'采油三厂',dept:'行政楼', + watchId:'CW-2024-0156',watchModel:'Samsung Galaxy Watch7',position:'采油三厂行政楼4层402室', + status:'normal',lastActiveTime:'2026-06-30 14:10:44',top:80,left:52}, + {name:'孙志强',gender:'男',age:47,unit:'兴隆医院',dept:'后勤', + watchId:'CW-2024-0215',watchModel:'Apple Watch Ultra 2',position:'兴隆医院后勤服务楼1层102室', + status:'alarm',alarmType:'心率异常',alarmTime:'2026-06-30 12:55:08',top:14,left:13}, + {name:'许建平',gender:'男',age:53,unit:'高陵医院',dept:'后勤', + watchId:'CW-2024-0589',watchModel:'OPPO Watch 4 Pro',position:'高陵医院后勤服务楼2层205室', + status:'warning',riskType:'心梗',riskLevel:'高危',probability:'67.8%',warningTime:'2026-06-30 11:42:15',top:70,left:15}, + {name:'周丽华',gender:'女',age:33,unit:'宝石花医院',dept:'护理部', + watchId:'CW-2024-0521',watchModel:'Xiaomi Watch S4',position:'宝石花医院护理部大楼3层302室', + status:'normal',lastActiveTime:'2026-06-30 14:15:47',top:16,left:75}, + {name:'吴永强',gender:'男',age:55,unit:'庆阳医院',dept:'急诊科', + watchId:'CW-2024-0193',watchModel:'Samsung Galaxy Watch7',position:'庆阳医院急诊科一楼抢救室', + status:'warning',riskType:'脑出血',riskLevel:'中危',probability:'38.5%',warningTime:'2026-06-30 10:18:33',top:54,left:60}, + {name:'韩雪',gender:'女',age:35,unit:'公司机关',dept:'办公楼', + watchId:'CW-2024-0533',watchModel:'Huawei Watch D2',position:'公司机关办公楼6层602室', + status:'offline',lastActiveTime:'2026-06-29 18:30:12',top:12,left:48}, + {name:'马国强',gender:'男',age:50,unit:'公司机关',dept:'办公楼', + watchId:'CW-2024-0388',watchModel:'Apple Watch Ultra 2',position:'公司机关办公楼大厅一楼东侧走廊', + status:'normal',lastActiveTime:'2026-06-30 14:22:08',top:15,left:52}, + {name:'陈晓东',gender:'男',age:41,unit:'采油一厂',dept:'维修队', + watchId:'CW-2024-0678',watchModel:'OPPO Watch 4 Pro',position:'采油一厂维修队办公楼3层305室', + status:'alarm',alarmType:'压力异常',alarmTime:'2026-06-30 13:42:10',top:40,left:35}, + {name:'郑海龙',gender:'男',age:43,unit:'采油一厂',dept:'生产区', + watchId:'CW-2024-0923',watchModel:'Xiaomi Watch S4',position:'采油一厂生产基地A区1号井组平台', + status:'alarm',alarmType:'体温异常',alarmTime:'2026-06-30 10:45:33',top:45,left:65}, + {name:'冯国强',gender:'男',age:48,unit:'采油三厂',dept:'维修队', + watchId:'CW-2024-0814',watchModel:'Samsung Galaxy Watch7',position:'采油三厂维修车间东区2层平台', + status:'offline',lastActiveTime:'2026-06-29 22:15:40',top:78,left:55} +]; + +var WATCH_STATUS_COLOR={normal:'#52C41A',warning:'#FAAD14',alarm:'#FF4D4F',offline:'#4A6B8A'}; +var WATCH_STATUS_LABEL={normal:'正常',warning:'预警',alarm:'告警',offline:'离线'}; +var WATCH_PULSE_BG={alarm:'rgba(255,77,79,0.25)',warning:'rgba(250,173,20,0.2)',normal:'rgba(82,196,26,0.2)',offline:null}; + +/* 渲染手表位置标记点 */ +function renderCvMapMarkers(){ + var container=document.getElementById('cvMapMarkers'); + if(!container) return; + var html=WATCH_MARKER_DATA.map(function(r,idx){ + var color=WATCH_STATUS_COLOR[r.status]; + var pulseBg=WATCH_PULSE_BG[r.status]; + var pulse= pulseBg ? '
' : ''; + return '
'+ + pulse+ + ''+ + '
'; + }).join(''); + container.innerHTML=html; +} + +/* ========== 点击手表图标:地图放大居中 + 图标上方弹窗 ========== */ +var cvMapScale=2; +function openWatchMarkerPopup(idx){ + var r=WATCH_MARKER_DATA[idx]; + if(!r) return; + var marker=document.querySelector('#cvMapMarkers .map-marker[data-idx="'+idx+'"]'); + if(!marker) return; + var top=parseFloat(marker.getAttribute('data-top')); + var left=parseFloat(marker.getAttribute('data-left')); + /* 以地图中心(50,50)为缩放原点:先 scale(S),再 translate 把 (left,top) 拉到 (50,50) */ + var tx=-(cvMapScale*(left-50)); + var ty=-(cvMapScale*(top-50)); + var stage=document.getElementById('cvMapStage'); + if(stage) stage.style.transform='translate('+tx.toFixed(2)+'%, '+ty.toFixed(2)+'%) scale('+cvMapScale+')'; + /* 选中态高亮 */ + document.querySelectorAll('#cvMapMarkers .map-marker.is-active').forEach(function(m){m.classList.remove('is-active');}); + marker.classList.add('is-active'); + renderWatchMarkerPopup(r); +} +function closeWatchMarkerPopup(){ + var stage=document.getElementById('cvMapStage'); + if(stage) stage.style.transform=''; + document.querySelectorAll('#cvMapMarkers .map-marker.is-active').forEach(function(m){m.classList.remove('is-active');}); + var popup=document.getElementById('watchMarkerPopup'); + if(popup){ + popup.style.opacity='0'; + setTimeout(function(){ var p=document.getElementById('watchMarkerPopup'); if(p) p.remove(); },220); + } +} +function renderWatchMarkerPopup(r){ + var wrap=document.getElementById('cvMapWrap'); + if(!wrap) return; + var old=document.getElementById('watchMarkerPopup'); + if(old) old.remove(); + /* 构建状态相关行 */ + var statusRows=''; + if(r.status==='normal'||r.status==='offline'){ + statusRows='
活跃状态
'+ + '
最近活跃'+r.lastActiveTime+'
'; + }else if(r.status==='warning'){ + statusRows='
预警信息
'+ + '
风险疾病'+r.riskType+'
'+ + '
风险等级'+r.riskLevel+'
'+ + '
预测概率'+r.probability+'
'+ + '
预警时间'+r.warningTime+'
'; + }else if(r.status==='alarm'){ + statusRows='
告警信息
'+ + '
告警类型'+r.alarmType+'
'+ + '
告警时间'+r.alarmTime+'
'; + } + var html=''; + var tmp=document.createElement('div'); + tmp.innerHTML=html; + var popup=tmp.firstElementChild; + wrap.appendChild(popup); + /* 先隐藏布局、量好尺寸再自适应定位,避免闪烁 */ + positionWatchMarkerPopup(popup); + popup.style.visibility='visible'; +} +/* 弹窗自适应定位:图标已居中于地图正中。 + 优先置于图标上方;空间不足改放下方;仍不足则贴顶夹紧。 */ +function positionWatchMarkerPopup(popup){ + var wrap=document.getElementById('cvMapWrap'); + if(!wrap) return; + var wr=wrap.getBoundingClientRect(); + var cx=wr.width/2, cy=wr.height/2; + var pw=popup.offsetWidth, ph=popup.offsetHeight; + var gap=30, margin=8; + var aboveTop=cy-gap-ph; + var belowTop=cy+gap; + var top, placement; + if(aboveTop>=margin){ top=aboveTop; placement='above'; } + else if(belowTop+ph<=wr.height-margin){ top=belowTop; placement='below'; } + else { top=margin; placement='clamp'; } + var left=Math.max(margin, Math.min(cx-pw/2, wr.width-pw-margin)); + popup.style.left=left.toFixed(1)+'px'; + popup.style.top=top.toFixed(1)+'px'; + var arrow=popup.querySelector('.watch-marker-popup__arrow'); + if(arrow){ + if(placement!=='above'){ arrow.style.display='none'; } + else{ + arrow.style.display=''; + var ax=Math.max(10, Math.min(cx-left, pw-10)); + arrow.style.left=ax.toFixed(1)+'px'; + } + } +} +window.addEventListener('resize',function(){ + var p=document.getElementById('watchMarkerPopup'); + if(p) positionWatchMarkerPopup(p); +}); + +/* 初始渲染手表标记 */ +renderCvMapMarkers(); diff --git a/other-module/emergency-screen/xian-center/help-monitor.html b/other-module/emergency-screen/xian-center/help-monitor.html index c6d4cdb..92c044e 100644 --- a/other-module/emergency-screen/xian-center/help-monitor.html +++ b/other-module/emergency-screen/xian-center/help-monitor.html @@ -1207,7 +1207,7 @@ document.getElementById('trendChart').addEventListener('mouseleave',function(){ function renderHourChart(){ var bins=STATS.hourBin; var max=Math.max.apply(null,Object.keys(bins).map(function(k){return bins[k];}))||1; - var colors={'凌晨(00-06)':'#4A6B8A','上午(06-12)':'#1890FF','下午(12-18)':'#FF4D4F','夜间(18-24)':'#b37feb'}; + var colors={'凌晨(00-06)':'#1890FF','上午(06-12)':'#1890FF','下午(12-18)':'#1890FF','夜间(18-24)':'#1890FF'}; var rows=Object.keys(bins).map(function(k){ var v=bins[k]; var pct=max>0?v/max*100:0; diff --git a/other-module/emergency-screen/xian-center/index-v3.html b/other-module/emergency-screen/xian-center/index-v3.html index 12f112d..1e46f7a 100644 --- a/other-module/emergency-screen/xian-center/index-v3.html +++ b/other-module/emergency-screen/xian-center/index-v3.html @@ -1070,7 +1070,7 @@
- 应急求助 + 应急求助数据 (历史记录) @@ -1093,12 +1093,12 @@
应急电话次数
-
+
23
拨打120次数
-
+
3,562
累计工单
@@ -1120,7 +1120,7 @@
- 穿戴告警 + 穿戴告警分布 (历史记录)