@@ -87,6 +87,16 @@ const AMAP = {
8787} ;
8888const AMAP_SUBS = [ '1' , '2' , '3' , '4' ] ;
8989
90+ /* 车辆图标 SVG(默认卡片与历史轨迹共用) */
91+ const CAR_SVG =
92+ '<svg viewBox="0 0 64 64" width="16" height="16" fill="none" ' +
93+ 'stroke="currentColor" stroke-width="5" stroke-linecap="round" stroke-linejoin="round">' +
94+ '<circle cx="32" cy="24" r="6" />' +
95+ '<path d="M14 24 L27 24" /><path d="M37 24 L50 24" />' +
96+ '<path d="M22 36 Q22 30 28 30 H36 Q42 30 42 36 V50 Q42 56 36 56 H28 Q22 56 22 50 Z" />' +
97+ '<rect x="26" y="50" width="12" height="14" rx="6" />' +
98+ '</svg>' ;
99+
90100/* ============================================================
91101 * iframe 内部 HTML 生成
92102 * ============================================================ */
@@ -255,6 +265,7 @@ function buildHistoryIframeHtml(mode, tracks, currentPos) {
255265 document.querySelectorAll('.basemap-switch button').forEach(function(b) {
256266 b.classList.toggle('active', b.dataset.mode === mode);
257267 });
268+ try { parent.postMessage({ type: 'tailg-basemap', mode: mode }, '*'); } catch (e) {}
258269 setTimeout(function() { map.invalidateSize(); }, 50);
259270 }
260271
@@ -415,16 +426,6 @@ function buildHistoryIframeHtml(mode, tracks, currentPos) {
415426 ` , mode ) ;
416427}
417428
418- /* 车辆图标 SVG(复用于默认卡片与历史轨迹) */
419- const CAR_SVG =
420- '<svg viewBox="0 0 64 64" width="16" height="16" fill="none" ' +
421- 'stroke="currentColor" stroke-width="5" stroke-linecap="round" stroke-linejoin="round">' +
422- '<circle cx="32" cy="24" r="6" />' +
423- '<path d="M14 24 L27 24" /><path d="M37 24 L50 24" />' +
424- '<path d="M22 36 Q22 30 28 30 H36 Q42 30 42 36 V50 Q42 56 36 56 H28 Q22 56 22 50 Z" />' +
425- '<rect x="26" y="50" width="12" height="14" rx="6" />' +
426- '</svg>' ;
427-
428429/* ============================================================
429430 * iframe 通用外壳
430431 * ============================================================ */
@@ -682,6 +683,9 @@ class TailgHistoryDialog extends LitElement {
682683 _loading : { type : Boolean } ,
683684 _baseMode : { type : String } ,
684685 _iframeSrcdoc : { type : String } ,
686+ _trackLoading : { type : Boolean } ,
687+ _trackLoaded : { type : Number } ,
688+ _trackTotal : { type : Number } ,
685689 } ;
686690 }
687691
@@ -725,6 +729,42 @@ class TailgHistoryDialog extends LitElement {
725729 }
726730 .map-wrap iframe { width: 100%; height: 100%; border: none; display: block; }
727731
732+ .track-loading {
733+ position: absolute; inset: 0;
734+ z-index: 500;
735+ display: flex; flex-direction: column;
736+ align-items: center; justify-content: center;
737+ gap: 10px;
738+ background: rgba(15,23,42,.55);
739+ backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
740+ color: #f1f5f9;
741+ pointer-events: none;
742+ }
743+ .track-loading .spinner {
744+ width: 32px; height: 32px;
745+ border: 3px solid rgba(255,255,255,.25);
746+ border-top-color: #3b82f6;
747+ border-radius: 50%;
748+ animation: tlSpin .8s linear infinite;
749+ }
750+ .track-loading .label {
751+ font-size: 13px; font-weight: 600;
752+ font-variant-numeric: tabular-nums;
753+ text-shadow: 0 1px 3px rgba(0,0,0,.6);
754+ }
755+ .track-loading .bar {
756+ width: 160px; height: 4px;
757+ background: rgba(255,255,255,.2);
758+ border-radius: 2px; overflow: hidden;
759+ }
760+ .track-loading .bar > i {
761+ display: block; height: 100%;
762+ background: #3b82f6;
763+ border-radius: 2px;
764+ transition: width .2s;
765+ }
766+ @keyframes tlSpin { to { transform: rotate(360deg); } }
767+
728768 .list-wrap {
729769 flex: 1 1 auto; min-height: 0;
730770 display: flex; flex-direction: column;
@@ -882,6 +922,10 @@ class TailgHistoryDialog extends LitElement {
882922 this . _currentTracks = [ ] ;
883923 this . _historyPushed = false ;
884924 this . _onPopState = null ;
925+ this . _onBasemapMsg = null ;
926+ this . _trackLoading = false ;
927+ this . _trackLoaded = 0 ;
928+ this . _trackTotal = 0 ;
885929 }
886930
887931 connectedCallback ( ) {
@@ -890,13 +934,22 @@ class TailgHistoryDialog extends LitElement {
890934 history . pushState ( { tailgDialog : true } , '' ) ;
891935 this . _historyPushed = true ;
892936 } catch ( e ) { console . warn ( '[tailg-history] pushState 失败' , e ) ; }
937+
893938 this . _onPopState = ( ) => {
894939 if ( this . _historyPushed ) {
895940 this . _historyPushed = false ;
896941 this . _closeInternal ( ) ;
897942 }
898943 } ;
899944 window . addEventListener ( 'popstate' , this . _onPopState ) ;
945+
946+ // 同步 iframe 内的底图模式切换
947+ this . _onBasemapMsg = ( e ) => {
948+ if ( e . data && e . data . type === 'tailg-basemap' && e . data . mode ) {
949+ this . _baseMode = e . data . mode ;
950+ }
951+ } ;
952+ window . addEventListener ( 'message' , this . _onBasemapMsg ) ;
900953 }
901954
902955 disconnectedCallback ( ) {
@@ -905,6 +958,10 @@ class TailgHistoryDialog extends LitElement {
905958 window . removeEventListener ( 'popstate' , this . _onPopState ) ;
906959 this . _onPopState = null ;
907960 }
961+ if ( this . _onBasemapMsg ) {
962+ window . removeEventListener ( 'message' , this . _onBasemapMsg ) ;
963+ this . _onBasemapMsg = null ;
964+ }
908965 }
909966
910967 _closeInternal ( ) {
@@ -1019,23 +1076,39 @@ class TailgHistoryDialog extends LitElement {
10191076
10201077 async _loadDayTracks ( day ) {
10211078 const tripsReversed = day . trips . slice ( ) . reverse ( ) ;
1022- const allTracks = [ ] ;
1023-
1024- for ( let i = 0 ; i < tripsReversed . length ; i ++ ) {
1025- const t = tripsReversed [ i ] ;
1079+ const total = tripsReversed . length ;
1080+
1081+ // 开始加载:先重置为「仅当前位置」+ 显示进度浮层
1082+ this . _trackLoading = true ;
1083+ this . _trackLoaded = 0 ;
1084+ this . _trackTotal = total ;
1085+ this . _activeTrip = - 1 ;
1086+
1087+ this . _currentTracks = [ ] ;
1088+ this . _iframeSrcdoc = buildHistoryIframeHtml ( this . _baseMode , [ ] , this . _getCurrentPosition ( ) ) ;
1089+ this . requestUpdate ( ) ;
1090+ await this . updateComplete ;
1091+
1092+ // 并发拉取所有轨迹段
1093+ const results = await Promise . all ( tripsReversed . map ( async ( t , i ) => {
10261094 let points = [ ] ;
10271095 try {
10281096 const resp = await this . hass . callApi ( "GET" , `tailg/day?id=${ encodeURIComponent ( t . id ) } ` ) ;
10291097 points = resp . data || [ ] ;
10301098 } catch ( err ) {
10311099 console . warn ( "[tailg-history] 拉取轨迹失败" , t . id , err ) ;
1032- continue ;
10331100 }
1034- if ( points . length ) allTracks . push ( { color : colorOf ( i ) , index : i , points } ) ;
1035- }
1036-
1101+ this . _trackLoaded ++ ;
1102+ this . requestUpdate ( ) ;
1103+ return points . length ? { color : colorOf ( i ) , index : i , points } : null ;
1104+ } ) ) ;
1105+
1106+ const allTracks = results . filter ( Boolean ) ;
1107+
10371108 this . _currentTracks = allTracks ;
10381109 this . _iframeSrcdoc = buildHistoryIframeHtml ( this . _baseMode , allTracks , this . _getCurrentPosition ( ) ) ;
1110+ this . _trackLoading = false ;
1111+ this . requestUpdate ( ) ;
10391112 }
10401113
10411114 _onTripClick ( newIndex , e ) {
@@ -1062,6 +1135,10 @@ class TailgHistoryDialog extends LitElement {
10621135
10631136 render ( ) {
10641137 const m = this . _monthSummary ( ) ;
1138+ const pct = this . _trackTotal > 0
1139+ ? Math . round ( this . _trackLoaded / this . _trackTotal * 100 )
1140+ : 0 ;
1141+
10651142 return html `
10661143 < div class ="dialog ">
10671144 < div class ="head ">
@@ -1075,6 +1152,17 @@ class TailgHistoryDialog extends LitElement {
10751152 ${ this . _iframeSrcdoc
10761153 ? html `< iframe .srcdoc =${ this . _iframeSrcdoc } scrolling ="no"> </ iframe > `
10771154 : html `< div style ="display:flex;align-items:center;justify-content:center;height:100%;color:#94a3b8 "> 加载中…</ div > ` }
1155+ ${ this . _trackLoading ? html `
1156+ < div class ="track-loading ">
1157+ < div class ="spinner "> </ div >
1158+ < div class ="label ">
1159+ ${ this . _trackTotal > 0
1160+ ? `加载轨迹 ${ this . _trackLoaded } /${ this . _trackTotal } `
1161+ : '加载轨迹…' }
1162+ </ div >
1163+ ${ this . _trackTotal > 0 ? html `
1164+ < div class ="bar "> < i style ="width:${ pct } % "> </ i > </ div > ` : '' }
1165+ </ div > ` : '' }
10781166 </ div >
10791167
10801168 < div class ="list-wrap ">
0 commit comments