-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
255 lines (234 loc) · 12.9 KB
/
index.html
File metadata and controls
255 lines (234 loc) · 12.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="baidu-site-verification" content="xJ100gOsD1">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=yes">
<title>燕儿归</title>
<link rel="icon" type="image/svg+xml" href="favicon.svg">
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Microsoft YaHei',sans-serif;background:#f0f4f8;color:#1f2937;min-height:100vh;overflow-x:hidden}
/* 粒子背景 */
.bg-particles{position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:0}
.bg-particles span{position:absolute;border-radius:50%;background:rgba(99,102,241,.12);animation:float linear infinite}
@keyframes float{0%{transform:translateY(100vh) scale(0);opacity:0}10%{opacity:1}90%{opacity:1}100%{transform:translateY(-10vh) scale(1);opacity:0}}
.container{position:relative;z-index:1;max-width:1200px;margin:0 auto;padding:30px 20px 80px}
/* 头部 */
.header{text-align:center;padding:50px 0 40px}
.header h1{font-size:2.8em;background:linear-gradient(135deg,#2563eb,#7c3aed,#db2777);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;letter-spacing:4px;margin-bottom:12px;animation:glow 3s ease-in-out infinite alternate}
@keyframes glow{from{filter:brightness(1)}to{filter:brightness(1.3)}}
.header p{color:#6b7280;font-size:14px}
/* Tab切换 */
.tabs{display:flex;justify-content:center;gap:12px;margin-bottom:30px}
.tab-btn{padding:12px 36px;border:1px solid #d1d5db;background:rgba(255,255,255,.85);color:#6b7280;border-radius:10px;cursor:pointer;font-size:15px;transition:all .3s;backdrop-filter:blur(10px)}
.tab-btn:hover{border-color:#2563eb;color:#2563eb}
.tab-btn.active{background:linear-gradient(135deg,rgba(37,99,235,.08),rgba(124,58,237,.08));border-color:#2563eb;color:#2563eb;box-shadow:0 0 20px rgba(37,99,235,.1)}
/* 搜索框 */
.search-box{max-width:600px;margin:0 auto 30px;position:relative}
.search-box input{width:100%;padding:16px 24px 16px 50px;border:1px solid #d1d5db;background:rgba(255,255,255,.95);color:#1f2937;border-radius:14px;font-size:16px;outline:none;transition:all .3s;backdrop-filter:blur(10px)}
.search-box input:focus{border-color:#2563eb;box-shadow:0 0 30px rgba(37,99,235,.12)}
.search-box input::placeholder{color:#9ca3af}
.search-icon{position:absolute;left:18px;top:50%;transform:translateY(-50%);color:#9ca3af;font-size:18px}
.search-tip{text-align:center;color:#9ca3af;font-size:12px;margin-top:8px}
/* 统计 */
.stats{text-align:center;margin-bottom:20px;color:#6b7280;font-size:13px}
.stats em{color:#2563eb;font-style:normal;font-weight:bold}
/* 表格 */
.table-wrap{overflow-x:auto;border-radius:12px;border:1px solid #e5e7eb;background:rgba(255,255,255,.85);backdrop-filter:blur(10px);box-shadow:0 1px 3px rgba(0,0,0,.06)}
table{width:100%;border-collapse:collapse;min-width:800px}
thead th{padding:14px 16px;text-align:left;font-size:13px;color:#6b7280;border-bottom:1px solid #e5e7eb;background:rgba(249,250,251,.95);position:sticky;top:0;white-space:nowrap}
tbody td{padding:12px 16px;border-bottom:1px solid #f3f4f6;font-size:13px;transition:background .2s}
tbody tr:hover td{background:rgba(37,99,235,.04)}
tbody tr{animation:fadeIn .3s ease}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
.code-tag{display:inline-block;padding:2px 8px;background:rgba(37,99,235,.08);color:#2563eb;border-radius:6px;font-family:monospace;font-weight:bold;font-size:13px}
/* 无结果 */
.no-result{text-align:center;padding:60px 20px;color:#9ca3af;font-size:15px}
/* 底部 */
.footer{position:fixed;bottom:0;left:0;width:100%;text-align:center;padding:14px;background:rgba(255,255,255,.92);border-top:1px solid #e5e7eb;color:#9ca3af;font-size:12px;backdrop-filter:blur(10px);z-index:10}
/* 加载 */
.loading{text-align:center;padding:60px;color:#6b7280}
.loading .spinner{display:inline-block;width:30px;height:30px;border:3px solid #e5e7eb;border-top-color:#2563eb;border-radius:50%;animation:spin .8s linear infinite;margin-bottom:12px}
@keyframes spin{to{transform:rotate(360deg)}}
/* 高亮 */
mark{background:rgba(245,158,11,.2);color:#b45309;border-radius:2px;padding:0 1px}
</style>
</head>
<body>
<div class="bg-particles" id="particles"></div>
<div class="container">
<div class="header">
<h1>✈ 燕儿归</h1>
<p>机场 & 航司速查工具</p>
</div>
<div class="tabs">
<button class="tab-btn active" data-tab="airport">🛫 机场查询</button>
<button class="tab-btn" data-tab="airline">🏢 航司查询</button>
</div>
<div class="search-box">
<span class="search-icon">🔍</span>
<input type="text" id="searchInput" placeholder="输入关键词搜索..." autocomplete="off">
<div class="search-tip" id="searchTip">Threecode / City 严格匹配,其他字段模糊搜索</div>
</div>
<div class="stats" id="stats"></div>
<div id="content"><div class="loading"><div class="spinner"></div><br>加载数据中...</div></div>
</div>
<div class="footer">津ICP备16000999号-1</div>
<script>
// ===== 粒子背景 =====
(function(){
const box=document.getElementById('particles');
for(let i=0;i<30;i++){
const s=document.createElement('span');
const size=Math.random()*4+2;
s.style.cssText=`width:${size}px;height:${size}px;left:${Math.random()*100}%;animation-duration:${Math.random()*15+10}s;animation-delay:${Math.random()*10}s`;
box.appendChild(s);
}
})();
// ===== 全局状态 =====
let airportData=[], airlineData=[];
let currentTab='airport';
let debounceTimer=null;
// ===== 加载数据 =====
Promise.all([
fetch('airport.json').then(r=>r.json()),
fetch('airline.json').then(r=>r.json())
]).then(([ap,al])=>{
airportData=ap; airlineData=al;
doSearch();
}).catch(e=>{
document.getElementById('content').innerHTML='<div class="no-result">数据加载失败: '+e.message+'</div>';
});
// ===== Tab切换 =====
document.querySelectorAll('.tab-btn').forEach(btn=>{
btn.addEventListener('click',function(){
document.querySelectorAll('.tab-btn').forEach(b=>b.classList.remove('active'));
this.classList.add('active');
currentTab=this.dataset.tab;
const tip=document.getElementById('searchTip');
tip.textContent=currentTab==='airport'?'Threecode / City 严格匹配,其他字段模糊搜索':'AirlineCode 严格匹配,其他字段模糊搜索';
document.getElementById('searchInput').placeholder=currentTab==='airport'?'输入三字码、城市、机场名称...':'输入航司代码、航司名称、国家...';
doSearch();
});
});
// ===== 搜索输入 =====
document.getElementById('searchInput').addEventListener('input',function(){
clearTimeout(debounceTimer);
debounceTimer=setTimeout(doSearch,200);
});
// ===== 高亮文本 =====
function hl(text,kw){
if(!kw||!text) return text||'';
text=String(text);
const idx=text.toLowerCase().indexOf(kw.toLowerCase());
if(idx===-1) return text;
return text.substring(0,idx)+'<mark>'+text.substring(idx,idx+kw.length)+'</mark>'+text.substring(idx+kw.length);
}
// ===== 搜索优先级评分 =====
// 优先级: 严格匹配代码 > 名称开头匹配 > 名称包含匹配 > 其他字段匹配
function scoreAirport(item,kwUp,kwLow){
if(!kwLow) return 0;
if(item.Threecode&&item.Threecode.toUpperCase()===kwUp) return 100;
if(item.City&&item.City.toUpperCase()===kwUp) return 90;
const name=(item.ThreecodeName||'').toLowerCase();
const ename=(item.EnglishNameOfThreecodeName||'').toLowerCase();
const city=(item.ChineseNameOfCity||'').toLowerCase();
const ecity=(item.EnglishNameOfCity||'').toLowerCase();
if(city===kwLow||ecity===kwLow) return 80;
if(name.startsWith(kwLow)||ename.startsWith(kwLow)||city.startsWith(kwLow)||ecity.startsWith(kwLow)) return 60;
if(name.includes(kwLow)||ename.includes(kwLow)||city.includes(kwLow)||ecity.includes(kwLow)) return 40;
return 10;
}
function scoreAirline(item,kwUp,kwLow){
if(!kwLow) return 0;
if(item.AirlineCode&&item.AirlineCode.toUpperCase()===kwUp) return 100;
const name=(item.AirlineName||'').toLowerCase();
const ename=(item.AirlineEnglishName||'').toLowerCase();
if(name===kwLow||ename===kwLow) return 80;
if(name.startsWith(kwLow)||ename.startsWith(kwLow)) return 60;
if(name.includes(kwLow)||ename.includes(kwLow)) return 40;
return 10;
}
// ===== 搜索逻辑 =====
function doSearch(){
const kw=document.getElementById('searchInput').value.trim();
const kwUp=kw.toUpperCase();
const kwLow=kw.toLowerCase();
let results=[];
if(currentTab==='airport'){
results=airportData.filter(item=>{
if(!kw) return true;
if(item.Threecode && item.Threecode.toUpperCase()===kwUp) return true;
if(item.City && item.City.toUpperCase()===kwUp) return true;
const fields=[item.ChineseNameOfCity,item.EnglishNameOfCity,item.Country,item.CountryCode,item.Province,item.Position,item.ThreecodeName,item.EnglishNameOfThreecodeName];
return fields.some(f=>f&&String(f).toLowerCase().includes(kwLow));
});
if(kw) results.sort((a,b)=>scoreAirport(b,kwUp,kwLow)-scoreAirport(a,kwUp,kwLow));
renderAirport(results,kw);
}else{
results=airlineData.filter(item=>{
if(!kw) return true;
if(item.AirlineCode && item.AirlineCode.toUpperCase()===kwUp) return true;
const fields=[item.AirlineName,item.AirlineEnglishName,item.AirlineCountry,item.WaybillCode];
return fields.some(f=>f&&String(f).toLowerCase().includes(kwLow));
});
if(kw) results.sort((a,b)=>scoreAirline(b,kwUp,kwLow)-scoreAirline(a,kwUp,kwLow));
renderAirline(results,kw);
}
document.getElementById('stats').innerHTML='找到 <em>'+results.length+'</em> 条结果';
}
// ===== 渲染机场表 =====
function renderAirport(data,kw){
if(!data.length){
document.getElementById('content').innerHTML='<div class="no-result">没有找到匹配的机场信息</div>';
return;
}
const show=data.slice(0,200);
let html='<div class="table-wrap"><table><thead><tr>';
html+='<th>三字码</th><th>城市码</th><th>城市</th><th>英文城市</th><th>机场名称</th><th>英文机场名</th><th>省份</th><th>国家</th>';
html+='</tr></thead><tbody>';
show.forEach(item=>{
const isExact=kw&&(item.Threecode&&item.Threecode.toUpperCase()===kw.toUpperCase()||item.City&&item.City.toUpperCase()===kw.toUpperCase());
html+='<tr>';
html+='<td><span class="code-tag">'+(isExact&&item.Threecode.toUpperCase()===kw.toUpperCase()?'<mark>'+item.Threecode+'</mark>':item.Threecode)+'</span></td>';
html+='<td><span class="code-tag">'+(isExact&&item.City.toUpperCase()===kw.toUpperCase()?'<mark>'+item.City+'</mark>':item.City)+'</span></td>';
html+='<td>'+hl(item.ChineseNameOfCity,kw)+'</td>';
html+='<td>'+hl(item.EnglishNameOfCity,kw)+'</td>';
html+='<td>'+hl(item.ThreecodeName,kw)+'</td>';
html+='<td>'+hl(item.EnglishNameOfThreecodeName,kw)+'</td>';
html+='<td>'+hl(item.Province,kw)+'</td>';
html+='<td>'+hl(item.Country,kw)+'</td>';
html+='</tr>';
});
html+='</tbody></table></div>';
if(data.length>200) html+='<div class="no-result">仅显示前200条,请缩小搜索范围</div>';
document.getElementById('content').innerHTML=html;
}
// ===== 渲染航司表 =====
function renderAirline(data,kw){
if(!data.length){
document.getElementById('content').innerHTML='<div class="no-result">没有找到匹配的航司信息</div>';
return;
}
const show=data.slice(0,200);
let html='<div class="table-wrap"><table><thead><tr>';
html+='<th>航司代码</th><th>航司名称</th><th>英文名称</th><th>国家</th><th>运单前缀</th>';
html+='</tr></thead><tbody>';
show.forEach(item=>{
const isExact=kw&&item.AirlineCode&&item.AirlineCode.toUpperCase()===kw.toUpperCase();
html+='<tr>';
html+='<td><span class="code-tag">'+(isExact?'<mark>'+item.AirlineCode+'</mark>':item.AirlineCode)+'</span></td>';
html+='<td>'+hl(item.AirlineName,kw)+'</td>';
html+='<td>'+hl(item.AirlineEnglishName,kw)+'</td>';
html+='<td>'+hl(item.AirlineCountry,kw)+'</td>';
html+='<td>'+(item.WaybillCode?hl(item.WaybillCode,kw):'<span style="color:#d1d5db">-</span>')+'</td>';
html+='</tr>';
});
html+='</tbody></table></div>';
if(data.length>200) html+='<div class="no-result">仅显示前200条,请缩小搜索范围</div>';
document.getElementById('content').innerHTML=html;
}
</script>
</body>
</html>