diff --git a/other-module/emergency-screen/xian-center/index-v3.html b/other-module/emergency-screen/xian-center/index-v3.html index 65cd687..10d4f6a 100644 --- a/other-module/emergency-screen/xian-center/index-v3.html +++ b/other-module/emergency-screen/xian-center/index-v3.html @@ -279,14 +279,50 @@ @keyframes planRouteDash{0%{stroke-dashoffset:0;}100%{stroke-dashoffset:-20;}} .plan-endpoint{transform-origin:center;animation:planEndpointPulse 1.6s ease-in-out infinite;} @keyframes planEndpointPulse{0%,100%{opacity:1;}50%{opacity:0.55;}} - .plan-route-info{position:absolute;top:104px;right:12px;z-index:18;display:none; - background:rgba(10,22,48,0.88);border:1px solid var(--panel-border);border-radius:8px; - padding:8px 12px;font-size:11px;color:var(--text-sub);min-width:130px; - backdrop-filter:blur(6px);box-shadow:0 4px 16px rgba(0,0,0,0.4);} - .plan-route-info--show{display:block;} - .plan-route-info__title{font-size:12px;color:var(--text-main);font-weight:600;margin-bottom:4px;} - .plan-route-info__row{display:flex;justify-content:space-between;gap:12px;line-height:1.6;} - .plan-route-info__row b{color:#fff;font-weight:600;} + /* ========== 路径规划:纵向导航步骤卡片 ========== */ + .plan-route-info{position:absolute;top:104px;right:12px;z-index:18;display:none;flex-direction:column; + width:238px;max-height:calc(100% - 170px); + background:rgba(10,22,48,0.92);border:1px solid var(--panel-border);border-radius:10px; + backdrop-filter:blur(10px);box-shadow:0 6px 22px rgba(0,0,0,0.5),0 0 16px rgba(0,229,255,0.12);overflow:hidden;} + .plan-route-info--show{display:flex;} + .plan-route-info__header{display:flex;align-items:center;gap:6px;padding:9px 8px 9px 12px; + border-bottom:1px solid var(--panel-border);} + .plan-route-info__title{flex:1;display:flex;align-items:center;gap:6px; + font-size:13px;color:var(--text-main);font-weight:600;letter-spacing:0.5px;} + .plan-route-info__title .ic{width:14px;height:14px;color:var(--cyan);} + .plan-route-info__close{width:22px;height:22px;display:flex;align-items:center;justify-content:center; + border:none;background:transparent;color:var(--text-sub);cursor:pointer;border-radius:4px;transition:all .2s;} + .plan-route-info__close:hover{color:var(--danger);background:rgba(255,77,79,0.12);} + .plan-route-info__summary{display:flex;gap:8px;padding:8px 12px;border-bottom:1px solid var(--panel-border); + background:rgba(24,144,255,0.06);} + .plan-route-info__summary-item{flex:1;display:flex;flex-direction:column;align-items:center;gap:2px;} + .plan-route-info__summary-num{font-size:15px;font-weight:700;color:var(--cyan);line-height:1;font-variant-numeric:tabular-nums;} + .plan-route-info__summary-label{font-size:10px;color:var(--text-sub);} + .plan-route-info__list{flex:1;overflow-y:auto;padding:4px 6px 10px 0;} + .plan-route-info__list::-webkit-scrollbar{width:5px;} + .plan-route-info__list::-webkit-scrollbar-thumb{background:rgba(24,144,255,0.25);border-radius:3px;} + .plan-route-info__list::-webkit-scrollbar-track{background:transparent;} + + /* 单步:左侧时间轴(图标+连线) + 右侧文案 */ + .plan-route-step{display:flex;gap:9px;padding:7px 6px 0 10px;} + .plan-route-step__rail{display:flex;flex-direction:column;align-items:center;flex-shrink:0;width:20px;} + .plan-route-step__icon{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center; + background:rgba(24,144,255,0.16);color:var(--primary);flex-shrink:0;z-index:1;} + .plan-route-step__icon svg{width:11px;height:11px;} + .plan-route-step__line{width:2px;flex:1;min-height:10px; + background:linear-gradient(180deg,rgba(24,144,255,0.45),rgba(24,144,255,0.1));margin:2px 0;} + .plan-route-step:last-child .plan-route-step__line{display:none;} + .plan-route-step__body{flex:1;padding-bottom:9px;} + .plan-route-step__title{font-size:12px;color:var(--text-main);line-height:1.45;} + .plan-route-step__title b{font-weight:600;color:#fff;} + .plan-route-step__dist{display:inline-block;margin-left:2px;font-size:11px;font-weight:700;color:var(--cyan);font-variant-numeric:tabular-nums;} + /* 起点/终点/拐弯 配色 */ + .plan-route-step--start .plan-route-step__icon{background:rgba(82,196,26,0.2);color:var(--success);} + .plan-route-step--end .plan-route-step__icon{background:rgba(255,77,79,0.2);color:var(--danger);} + .plan-route-step--turn .plan-route-step__icon{background:rgba(250,173,20,0.2);color:var(--warning);} + .plan-route-step--start .plan-route-step__title{color:var(--success);font-weight:600;} + .plan-route-step--end .plan-route-step__title{color:var(--danger);font-weight:600;} + .plan-route-step--turn .plan-route-step__title b{color:var(--warning);} /* ========== 通用面板(增强) ========== */ .panel{background:var(--panel-bg);border:1px solid var(--panel-border);border-radius:10px; @@ -452,6 +488,8 @@ @keyframes radarPulse{0%,100%{fill-opacity:0.15;}50%{fill-opacity:0.30;}} .exam-radar__point{fill:var(--primary);r:3;stroke:#fff;stroke-width:1.5;filter:drop-shadow(0 0 4px rgba(24,144,255,0.6));} .exam-radar__label{font-size:10px;fill:var(--text-sub);text-anchor:middle;dominant-baseline:middle;} + .exam-radar__label-value{font-size:10px;fill:#fff;font-weight:700;font-variant-numeric:tabular-nums;margin-left:2px;} + .exam-radar__label-unit{font-size:10px;fill:var(--text-sub);font-weight:400;} .exam-radar__value{font-size:9px;fill:#fff;font-weight:600;text-anchor:middle;dominant-baseline:middle;} .exam-radar-legend{display:flex;flex-wrap:wrap;gap:6px 12px;margin-top:6px;justify-content:center;} .exam-radar-legend__item{display:flex;align-items:center;gap:4px;font-size:10px;color:var(--text-sub);} @@ -553,7 +591,7 @@ .event-item__desc{font-size:11px;color:var(--text-sub);margin-top:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;} .event-item__loc{font-size:10px;color:var(--text-dim);margin-top:2px;} - /* ========== 左下:人员现状监测(环形图) ========== */ + /* ========== 左下:人群现状(环形图) ========== */ .panel--health-monitor .panel__body{padding:6px 8px 8px;overflow:hidden;} .health-monitor{display:flex;align-items:center;justify-content:center;gap:6px;padding:0;} .health-monitor__chart{position:relative;width:208px;height:208px;flex-shrink:0;} @@ -564,6 +602,7 @@ .health-monitor__chart .hm-label-line{fill:none;stroke-width:1;opacity:.72;stroke-linecap:round;stroke-linejoin:round;} .health-monitor__chart .hm-value-label{font-size:11px;font-weight:700;font-variant-numeric:tabular-nums; paint-order:stroke;stroke:#071224;stroke-width:4px;stroke-linejoin:round;} + .health-monitor__chart .hm-value-unit{font-size:9px;font-weight:400;} .health-monitor__center{position:absolute;inset:0;display:flex;flex-direction:column; align-items:center;justify-content:center;pointer-events:none;text-align:center;} .health-monitor__center-label{font-size:10px;color:var(--text-sub);letter-spacing:1.5px;} @@ -588,6 +627,7 @@ .wearable-stat-chart__bar{height:10px;border-radius:2px 5px 5px 2px;transition:width .6s ease;min-width:4px;position:relative;box-shadow:0 0 6px currentColor;} .wearable-stat-chart__bar::after{content:'';position:absolute;top:0;left:0;bottom:0;width:20px;background:linear-gradient(90deg,rgba(255,255,255,0.3),transparent);border-radius:2px 0 0 5px;} .wearable-stat-chart__bar-value{font-size:10px;color:#fff;font-weight:600;text-shadow:0 0 6px rgba(0,0,0,0.4);white-space:nowrap;min-width:20px;text-align:left;line-height:1;} + .wearable-stat-chart__bar-unit{font-size:10px;color:var(--text-sub);font-weight:400;margin-left:1px;} /* ========== AI智能预警分析 ========== */ .panel--ai-analysis .panel__body{padding:8px 10px 10px;overflow:hidden;} @@ -1096,42 +1136,42 @@
-
45
+
45
体温异常
-
28
+
28
血氧异常
-
35
+
35
压力异常
-
18
+
18
一键告警
-
12
+
12
摔倒
-
8
+
8
@@ -1202,11 +1242,11 @@ - +
- 人员现状监测 + 人群现状
@@ -1241,11 +1281,11 @@ - 580 - 1,860 - 620 - 376 - 9,420 + 580 + 1,860 + 620 + 376 + 9,420
总人数 @@ -1389,11 +1429,32 @@
- +
-
规划路线
-
总距离--
-
预计用时--
+
+
+ + 导航路线 +
+ +
+
+
+ -- + 总距离 +
+
+ -- + 预计用时 +
+
+ -- + 途经步骤 +
+
+
@@ -1770,9 +1831,10 @@
体重管理数据 - + @@ -3285,17 +3347,18 @@ function switchConsultPeriod(period){ } /* ========== 体重管理数据 时间段切换 ========== */ -/* [数据] 近一周/近一月/近一年,吃记录/动记录/体重记录 的已记录、未记录人数 */ -var currentWeightPeriod = 'week'; +/* [数据] 今日/近一周/近一月/近一年,吃记录/动记录/体重记录 的已记录、未记录人数 */ +var currentWeightPeriod = 'today'; var WEIGHT_DATA = { + today: { eatDone:28, eatUndone:9, exerciseDone:21, exerciseUndone:16, weightDone:31, weightUndone:6 }, week: { eatDone:186, eatUndone:54, exerciseDone:142, exerciseUndone:98, weightDone:203, weightUndone:37 }, month: { eatDone:642, eatUndone:208, exerciseDone:498, exerciseUndone:352, weightDone:712, weightUndone:138 }, year: { eatDone:7680,eatUndone:2460,exerciseDone:5964,exerciseUndone:4176,weightDone:8532,weightUndone:1612 } }; function switchWeightPeriod(period){ - /* [交互] 根据 period('week'/'month'/'year') 刷新体重管理数据卡片 */ - currentWeightPeriod = period || 'week'; + /* [交互] 根据 period('today'/'week'/'month'/'year') 刷新体重管理数据卡片 */ + currentWeightPeriod = period || 'today'; var data = WEIGHT_DATA[currentWeightPeriod]; /* 按 DOM 顺序:吃记录(已/未)、动记录(已/未)、体重记录(已/未) */ var nums = document.querySelectorAll('.panel--weight-data .weight-data__stat-num'); @@ -3308,6 +3371,9 @@ function switchWeightPeriod(period){ nums[5].textContent = data.weightUndone.toLocaleString(); } } +/* 页面加载时按默认时间段(今日)刷新一次,使显示与默认选中项一致 */ +if(document.readyState !== 'loading'){switchWeightPeriod('today');} +else{document.addEventListener('DOMContentLoaded', function(){switchWeightPeriod('today');});} /* ========== 医疗点数据:时间段切换 ========== */ /* [数据] 近一周/近一月/近一年各医疗点指标(慢病服务人数/就诊次数/随访次数) */ @@ -3463,25 +3529,14 @@ function updateExamRadarChart(){ return ''; }).join(''); - /* 标签 */ + /* 标签:医院名称 + 数值(数值紧跟在名称后面) */ var labels = ''; for(var i = 0; i < count; i++){ var a = i * angleStep - Math.PI / 2; var labelR = radius + 18; var lx = cx + labelR * Math.cos(a); var ly = cy + labelR * Math.sin(a); - labels += '' + hospitals[i] + ''; - } - - /* 数值标签(在数据点旁边) */ - var valueLabels = ''; - for(var i = 0; i < pointCoords.length; i++){ - var p = pointCoords[i]; - var a = i * angleStep - Math.PI / 2; - var vr = 12; - var vx = parseFloat(p.x) + vr * Math.cos(a) * 0.3; - var vy = parseFloat(p.y) + vr * Math.sin(a) * 0.3; - valueLabels += '' + p.val.toLocaleString('zh-CN') + ''; + labels += '' + hospitals[i] + ' ' + values[i].toLocaleString('zh-CN') + ''; } container.innerHTML = @@ -3491,13 +3546,7 @@ function updateExamRadarChart(){ area + dots + labels + - valueLabels + - ''+ - '
'+ - '体检总人数'+ - '' + total.toLocaleString('zh-CN') + ''+ - ''+ - '
'; + ''; } /* [初始化] 页面加载时默认渲染体检数据雷达图 */ @@ -3563,6 +3612,99 @@ var PLAN_POINTS = { aed2: {x:68, y:47, name:'AED-002'} }; +/* ========== 路径规划:逐步导航生成 ========== + 基于起点/终点的相对方位(Δx/Δy),将路线拆为若干「沿某路·某方向·某米」的直行段, + 并在方向改变处插入「在某路口左/右转/直行」的拐弯提示,最后到达终点。 */ +var PLAN_ROAD_NAMES = ['长庆大道','油田路','兴庆路','矿区环线','靖边街','姬塬路','采油大道','高陵快速路']; +/* 八方向文案(屏幕坐标:x→右=东,y→下=南) */ +var DIR_MATRIX = [ + {dx: 1, dy: 0, name:'向东'}, + {dx: 1, dy: 1, name:'向东南'}, + {dx: 0, dy: 1, name:'向南'}, + {dx:-1, dy: 1, name:'向西南'}, + {dx:-1, dy: 0, name:'向西'}, + {dx:-1, dy:-1, name:'向西北'}, + {dx: 0, dy:-1, name:'向北'}, + {dx: 1, dy:-1, name:'向东北'} +]; +var TURN_ICON = { + left: '', + right:'', + straight:'' +}; +var STEP_ICON = { + start:'', + end: '', + road: '' +}; +/* 计算由 from→to 的主导八方向 */ +function planDir(from,to){ + var dx=to.x-from.x, dy=to.y-from.y; + if(Math.abs(dx)<0.001 && Math.abs(dy)<0.001) return DIR_MATRIX[0]; + var ang=Math.atan2(dy,dx); /* -π..π,0=东 */ + var idx=Math.round(ang/(Math.PI/4)); /* -4..4 */ + if(idx<0) idx+=8; + return DIR_MATRIX[idx%8]; +} +/* 计算两方向夹角对应的左转/右转/直行 */ +function planTurnType(prevDir,curDir){ + var pi=DIR_MATRIX.indexOf(prevDir), ci=DIR_MATRIX.indexOf(curDir); + if(pi<0||ci<0) return 'straight'; + var diff=ci-pi; + if(diff>4) diff-=8; if(diff<-4) diff+=8; /* 归一到 -4..4 */ + if(diff===0) return 'straight'; + return diff>0 ? 'right' : 'left'; /* y轴朝下:顺时针角增=右转 */ +} +/* 在 path 上取等分中间折点,让路名随距离逐段变化 */ +function buildRouteSteps(s,e,totalMeters){ + /* 折点数量:长则多分段,控制在 2~4 段直行 */ + var segs = totalMeters>1500 ? 4 : totalMeters>700 ? 3 : 2; + var pts=[{x:s.x,y:s.y}]; + for(var i=1;i'+PLAN_ROAD_NAMES[roadIdx%PLAN_ROAD_NAMES.length]+'路口'+({left:'左转',right:'右转',straight:'继续直行'}[tt])+''}); + roadIdx++; + } + var roadName=PLAN_ROAD_NAMES[roadIdx%PLAN_ROAD_NAMES.length]; + steps.push({type:'road', icon:STEP_ICON.road, + title:'沿'+roadName+''+dir.name+'行驶', dist:dist}); + prevDir=dir; roadIdx++; + } + return steps; +} +/* 把单步渲染成 HTML */ +function renderRouteStep(step){ + var cls = step.type; /* start / road / turn / end */ + var distHtml = (step.type==='road' && step.dist) ? ''+step.dist+' 米' : ''; + return '
' + +'
' + +'
'+step.icon+'
' + +'
' + +'
' + +'
' + +'
'+step.title+distHtml+'
' + +'
' + +'
'; +} + /* 切换路径规划 Tab:展开/收起规划面板,并保持所有地图标记可见 */ function toggleRoutePlan(el){ var tab=document.getElementById('planTab'); @@ -3601,16 +3743,18 @@ function clearRoutePlan(){ var svg=document.getElementById('planRouteSvg'); var path=document.getElementById('planRoutePath'); var info=document.getElementById('planRouteInfo'); + var list=document.getElementById('planRouteList'); var sd=document.getElementById('planStartDot'); var ed=document.getElementById('planEndDot'); if(svg)svg.classList.remove('plan-route-svg--show'); if(path)path.setAttribute('opacity','0'); if(info)info.classList.remove('plan-route-info--show'); + if(list)list.innerHTML=''; if(sd)sd.setAttribute('opacity','0'); if(ed)ed.setAttribute('opacity','0'); } -/* 执行路径规划:根据起点终点绘制曲线路径并显示距离与用时 */ +/* 执行路径规划:根据起点终点绘制曲线路径,并按纵向步骤展示逐段导航(路/方向/米/拐弯) */ function executeRoutePlan(){ var sk=document.getElementById('planStart').value; var ek=document.getElementById('planEnd').value; @@ -3620,6 +3764,7 @@ function executeRoutePlan(){ var path=document.getElementById('planRoutePath'); var svg=document.getElementById('planRouteSvg'); var info=document.getElementById('planRouteInfo'); + var list=document.getElementById('planRouteList'); var sd=document.getElementById('planStartDot'); var ed=document.getElementById('planEndDot'); /* 二次贝塞尔曲线:控制点垂直偏移,使路径呈现弧形而非直线 */ @@ -3631,12 +3776,22 @@ function executeRoutePlan(){ sd.setAttribute('cx',s.x);sd.setAttribute('cy',s.y);sd.setAttribute('opacity','1'); ed.setAttribute('cx',e.x);ed.setAttribute('cy',e.y);ed.setAttribute('opacity','1'); svg.classList.add('plan-route-svg--show'); - /* Mock 距离/用时:按 viewBox 距离换算 */ + /* Mock 距离/用时:按 viewBox 距离换算为米 */ var dx=s.x-e.x, dy=s.y-e.y, dist=Math.sqrt(dx*dx+dy*dy); - var km=(dist*0.15).toFixed(1); - var min=Math.max(1,Math.round(dist*0.6)); + var totalMeters=Math.max(120, Math.round(dist*150)); + var km=(totalMeters/1000).toFixed(1); + var min=Math.max(1,Math.round(totalMeters/180)); /* 约 10.8km/h 综合车速 */ document.getElementById('planRouteDist').textContent=km+' km'; document.getElementById('planRouteTime').textContent=min+' 分钟'; + + /* 生成纵向导航步骤:起点 → 各直行段(沿X路·向X方向·X米) → 拐弯 → 终点 */ + var legs=buildRouteSteps(s,e,totalMeters); + var html=''; + html+=renderRouteStep({type:'start', icon:STEP_ICON.start, title:'从'+s.name+'出发'}); + html+=legs.map(renderRouteStep).join(''); + html+=renderRouteStep({type:'end', icon:STEP_ICON.end, title:'到达'+e.name+''}); + if(list)list.innerHTML=html; + document.getElementById('planRouteSteps').textContent=legs.length+2; info.classList.add('plan-route-info--show'); }