You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

1230 lines
40 KiB

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>青核 Youthome - 认证校友地图</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="../colors_and_type.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
body {
font-family: var(--youth-font-base);
background: var(--youth-bg-page);
color: var(--youth-text-primary);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
overflow-x: hidden;}
.app-container {
width: 375px;
height: 812px;
position: relative;
background: var(--youth-bg-page);
overflow: hidden;
border-radius: 40px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
display: flex;
flex-direction: column;
}
/* ===== iOS 状态栏 ===== */
.status-bar {
height: 36px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
font-size: 14px;
font-weight: 600;
color: var(--youth-text-primary);
position: relative;
z-index: 10;
flex-shrink: 0;
}
.status-bar .right-icons {
display: flex;
align-items: center;
gap: 6px;
}
/* ===== 顶部导航 ===== */
.top-nav {
display: flex;
align-items: center;
justify-content: space-between;
padding: 4px 16px 8px;
position: relative;
z-index: 10;
flex-shrink: 0;
height: 44px;
}
.nav-btn {
width: 36px;
height: 36px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
background: var(--youth-gradient-matte-card);
border: 1px solid var(--youth-border-light);
box-shadow: var(--shadow-card), var(--youth-shadow-inset-light);
cursor: pointer;
transition: all 0.2s ease;
color: var(--youth-text-primary);
}
.nav-btn:active {
transform: scale(0.95);
}
.nav-title {
font-size: 17px;
font-weight: 600;
color: var(--youth-text-primary);
letter-spacing: 0.2px;
}
/* ===== 数据统计条 ===== */
.stats-bar {
margin: 0 16px 10px;
padding: 10px 14px;
background: var(--youth-bg-card);
border-radius: 12px;
border: 1px solid var(--youth-border-light);
box-shadow: var(--youth-shadow-card);
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
z-index: 5;
flex-shrink: 0;
}
.stat-item {
display: flex;
flex-direction: column;
gap: 2px;
}
.stat-label {
font-size: 11px;
color: var(--youth-text-tertiary);
font-weight: 500;
}
.stat-value-primary {
font-size: 18px;
font-weight: 700;
color: var(--youth-primary);
line-height: 1.2;
}
.stat-value-secondary {
font-size: 14px;
font-weight: 600;
color: var(--youth-text-primary);
line-height: 1.2;
}
.stat-divider {
width: 1px;
height: 28px;
background: var(--youth-border-light);
}
/* ===== 地图区域 ===== */
.map-container {
position: relative;
flex: 1;
margin: 0 16px;
border-radius: 12px;
overflow: hidden;
background: var(--youth-bg-page);
border: 1px solid var(--youth-border-light);
box-shadow: var(--youth-shadow-card);
min-height: 0;
}
.map-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transition: transform 0.3s ease;
}
.map-svg {
width: 100%;
height: 100%;
}
/* 地图网格 */
.map-grid {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
linear-gradient(var(--youth-border-lighter) 1px, transparent 1px),
linear-gradient(90deg, var(--youth-border-lighter) 1px, transparent 1px);
background-size: 30px 30px;
opacity: 0.5;
}
/* 地图点位 */
.map-point {
position: absolute;
border-radius: 50%;
cursor: pointer;
transform: translate(-50%, -50%);
transition: transform 0.2s ease;
z-index: 3;
}
.map-point:active {
transform: translate(-50%, -50%) scale(1.2);
}
.map-point::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
background: var(--youth-primary);
opacity: 0.3;
animation: point-pulse 2s ease-out infinite;
}
@keyframes point-pulse {
0% {
width: 100%;
height: 100%;
opacity: 0.4;
}
100% {
width: 200%;
height: 200%;
opacity: 0;
}
}
.map-point-large {
width: 28px;
height: 28px;
background: radial-gradient(circle at 30% 30%, #54CAC5, #26C2BB 50%, #1FA39E 100%);
box-shadow:
0 0 20px rgba(38, 194, 187, 0.5),
0 2px 8px rgba(0, 0, 0, 0.15),
inset 0 1px 2px rgba(255, 255, 255, 0.4);
}
.map-point-large::before {
animation-delay: 0s;
}
.map-point-medium {
width: 20px;
height: 20px;
background: radial-gradient(circle at 30% 30%, #6BDBD7, #26C2BB 50%, #1FA39E 100%);
box-shadow:
0 0 14px rgba(38, 194, 187, 0.4),
0 2px 6px rgba(0, 0, 0, 0.12),
inset 0 1px 2px rgba(255, 255, 255, 0.3);
}
.map-point-medium::before {
animation-delay: 0.5s;
}
.map-point-small {
width: 12px;
height: 12px;
background: radial-gradient(circle at 30% 30%, #9AE7E4, #26C2BB 60%, #1FA39E 100%);
box-shadow:
0 0 8px rgba(38, 194, 187, 0.3),
0 1px 4px rgba(0, 0, 0, 0.1),
inset 0 1px 1px rgba(255, 255, 255, 0.3);
}
.map-point-small::before {
animation-delay: 1s;
}
.map-point-label {
position: absolute;
bottom: calc(100% + 4px);
left: 50%;
transform: translateX(-50%);
font-size: 10px;
font-weight: 600;
color: var(--youth-text-secondary);
white-space: nowrap;
background: var(--youth-bg-glass);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
padding: 2px 6px;
border-radius: 6px;
border: 1px solid var(--youth-glass-border);
pointer-events: none;
}
/* 信息气泡 */
.info-bubble {
position: absolute;
min-width: 140px;
background: var(--youth-bg-glass-strong);
backdrop-filter: var(--youth-glass-blur) var(--youth-glass-saturate);
-webkit-backdrop-filter: var(--youth-glass-blur) var(--youth-glass-saturate);
border: 1px solid var(--youth-glass-border-strong);
border-radius: 12px;
padding: 12px;
box-shadow: var(--youth-shadow-lg);
z-index: 20;
transform: translate(-50%, calc(-100% - 16px));
display: none;
animation: bubble-pop 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.info-bubble.show {
display: block;
}
@keyframes bubble-pop {
0% {
opacity: 0;
transform: translate(-50%, calc(-100% - 16px)) scale(0.8);
}
100% {
opacity: 1;
transform: translate(-50%, calc(-100% - 16px)) scale(1);
}
}
.info-bubble::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 8px solid var(--youth-glass-border-strong);
}
.bubble-school {
font-size: 14px;
font-weight: 600;
color: var(--youth-text-primary);
margin-bottom: 4px;
}
.bubble-count {
font-size: 12px;
color: var(--youth-text-secondary);
margin-bottom: 8px;
}
.bubble-count span {
color: var(--youth-primary);
font-weight: 600;
}
.bubble-btn {
width: 100%;
padding: 6px 0;
background: var(--youth-gradient-primary);
color: white;
font-size: 12px;
font-weight: 500;
border-radius: 8px;
border: none;
cursor: pointer;
box-shadow: var(--youth-shadow-btn);
transition: all 0.2s ease;
}
.bubble-btn:active {
transform: scale(0.96);
}
/* ===== 地图控件 ===== */
.map-controls {
position: absolute;
top: 12px;
right: 12px;
display: flex;
flex-direction: column;
gap: 8px;
z-index: 10;
}
.control-btn {
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--youth-gradient-matte-card);
border: 1px solid var(--youth-border-light);
box-shadow:
var(--shadow-card),
var(--youth-shadow-inset-light),
0 2px 4px rgba(0, 0, 0, 0.06);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s ease;
color: var(--youth-text-primary);
}
.control-btn:active {
transform: scale(0.92);
box-shadow: var(--youth-shadow-inset-deep);
}
.control-btn svg {
width: 18px;
height: 18px;
}
.zoom-group {
display: flex;
flex-direction: column;
gap: 1px;
background: var(--youth-border-light);
border-radius: 18px;
padding: 1px;
}
.zoom-group .control-btn {
border-radius: 50%;
box-shadow: none;
border: none;
background: var(--youth-gradient-matte-card);
}
/* ===== 图层筛选浮层 ===== */
.layer-panel {
position: absolute;
top: 50px;
right: 12px;
background: var(--youth-bg-glass-strong);
backdrop-filter: var(--youth-glass-blur) var(--youth-glass-saturate);
-webkit-backdrop-filter: var(--youth-glass-blur) var(--youth-glass-saturate);
border: 1px solid var(--youth-glass-border);
border-radius: 12px;
padding: 8px;
box-shadow: var(--youth-shadow-lg);
z-index: 15;
display: none;
animation: panel-slide 0.2s ease;
}
.layer-panel.show {
display: block;
}
@keyframes panel-slide {
0% {
opacity: 0;
transform: translateY(-8px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.layer-item {
padding: 8px 16px;
font-size: 13px;
color: var(--youth-text-secondary);
border-radius: 8px;
cursor: pointer;
transition: all 0.2s ease;
white-space: nowrap;
text-align: center;
}
.layer-item:hover {
background: var(--youth-bg-hover);
}
.layer-item.active {
background: var(--youth-gradient-primary);
color: white;
font-weight: 500;
}
/* ===== 排行榜区域 ===== */
.ranking-section {
margin-top: 14px;
padding: 0 0 0 16px;
}
.ranking-header {
display: flex;
align-items: center;
justify-content: space-between;
padding-right: 16px;
margin-bottom: 10px;
}
.ranking-title {
font-size: 15px;
font-weight: 600;
color: var(--youth-text-primary);
display: flex;
align-items: center;
gap: 6px;
}
.ranking-title-icon {
width: 18px;
height: 18px;
display: flex;
align-items: center;
justify-content: center;
}
.ranking-view-all {
font-size: 12px;
color: var(--youth-primary);
font-weight: 500;
cursor: pointer;
}
.ranking-scroll {
display: flex;
gap: 10px;
overflow-x: auto;
padding-right: 16px;
padding-bottom: 4px;
-ms-overflow-style: none;
scrollbar-width: none;
scroll-snap-type: x mandatory;
}
.ranking-scroll::-webkit-scrollbar {
display: none;
}
.rank-card {
flex-shrink: 0;
width: 130px;
background: var(--youth-gradient-matte-card);
border-radius: 14px;
padding: 12px;
border: 1px solid var(--youth-border-light);
box-shadow: var(--youth-shadow-card), var(--youth-shadow-inset-light);
cursor: pointer;
transition: all 0.2s ease;
scroll-snap-align: start;
position: relative;
}
.rank-card:active {
transform: scale(0.97);
}
.rank-top {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
.rank-number {
font-size: 24px;
font-weight: 700;
line-height: 1;
color: var(--youth-text-tertiary);
}
.rank-card.top1 .rank-number { color: #D4A853; }
.rank-card.top2 .rank-number { color: #A8B0B8; }
.rank-card.top3 .rank-number { color: #C48B63; }
.medal-icon {
width: 24px;
height: 24px;
}
.rank-school {
font-size: 13px;
font-weight: 600;
color: var(--youth-text-primary);
margin-bottom: 4px;
line-height: 1.3;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.rank-count {
font-size: 12px;
color: var(--youth-text-secondary);
margin-bottom: 10px;
}
.rank-count span {
color: var(--youth-primary);
font-weight: 600;
}
.rank-view-btn {
width: 100%;
padding: 6px 0;
font-size: 11px;
font-weight: 500;
color: var(--youth-primary);
background: var(--youth-primary-bg);
border: 1px solid var(--youth-primary-border);
border-radius: 8px;
cursor: pointer;
transition: all 0.2s ease;
}
.rank-view-btn:active {
background: var(--youth-primary-border);
}
/* 前三名卡片装饰 */
.rank-card.top1 {
border-color: rgba(212, 168, 83, 0.3);
box-shadow:
0 4px 16px rgba(212, 168, 83, 0.1),
var(--youth-shadow-inset-light);
}
.rank-card.top2 {
border-color: rgba(168, 176, 184, 0.3);
box-shadow:
0 4px 16px rgba(168, 176, 184, 0.1),
var(--youth-shadow-inset-light);
}
.rank-card.top3 {
border-color: rgba(196, 139, 99, 0.3);
box-shadow:
0 4px 16px rgba(196, 139, 99, 0.1),
var(--youth-shadow-inset-light);
}
/* ===== 底部Tab导航 ===== */
.bottom-tab-nav {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 58px;
background: var(--youth-bg-glass-strong);
backdrop-filter: var(--youth-glass-blur) var(--youth-glass-saturate);
-webkit-backdrop-filter: var(--youth-glass-blur) var(--youth-glass-saturate);
border-top: 1px solid var(--youth-border-light);
display: flex;
align-items: flex-start;
justify-content: space-around;
padding-top: 6px;
padding-bottom: 10px;
z-index: 50;
}
.tab-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 3px;
cursor: pointer;
padding: 2px 12px;
transition: all 0.2s ease;
}
.tab-item svg {
width: 22px;
height: 22px;
color: var(--youth-gray-400);
transition: all 0.2s ease;
stroke-width: 2;
}
.tab-item span {
font-size: 10px;
color: var(--youth-gray-400);
transition: all 0.2s ease;
}
.tab-item.active svg {
color: var(--youth-primary);
}
.tab-item.active span {
color: var(--youth-primary);
font-weight: 500;
}
.tab-item:active {
transform: scale(0.92);
}
/* ===== Toast 提示 ===== */
.toast {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0.8);
padding: 14px 22px;
background: rgba(0, 0, 0, 0.75);
color: white;
border-radius: 12px;
font-size: 14px;
opacity: 0;
pointer-events: none;
transition: all 0.3s ease;
z-index: 999;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.toast.show {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
/* ===== 深色模式调整 ===== */
/* 地图浅色轮廓线 */
.map-outline {
fill: var(--youth-gray-200);
stroke: var(--youth-gray-300);
stroke-width: 1.5;
transition: all 0.3s ease;
}
.map-province {
fill: var(--youth-gray-100);
stroke: var(--youth-gray-200);
stroke-width: 0.8;
transition: all 0.3s ease;
}
/* SVG 图标统一尺寸 */
.icon-svg {
display: inline-flex;
align-items: center;
justify-content: center;
width: 1em;
height: 1em;
vertical-align: middle;
line-height: 1;
}
.icon-svg svg {
width: 100%;
height: 100%;
stroke: currentColor;
}
/* 侧栏图标 */
.sidebar-icon .icon-svg { width: 22px; height: 22px; font-size: 22px; }
/* 社团logo图标 */
.club-logo .icon-svg { width: 28px; height: 28px; font-size: 28px; color: #fff; }
/* 头图大图标 */
.hero-icon .icon-svg { width: 56px; height: 56px; font-size: 56px; opacity: 0.3; }
/* meta 小图标 */
.club-meta .icon-svg { width: 12px; height: 12px; font-size: 12px; }
/* 分类选择网格图标 */
.cat-option .icon-svg { width: 26px; height: 26px; font-size: 26px; }
/* logo预览图标 */
.logo-preview .icon-svg { width: 40px; height: 40px; font-size: 40px; color: #fff; }
/* 提示图标 */
.notice-icon .icon-svg { width: 18px; height: 18px; font-size: 18px; }
</style>
</head>
<body>
<div class="app-container">
<!-- iOS 状态栏 -->
<div class="status-bar">
<span>9:41</span>
<div class="right-icons">
<svg width="18" height="12" viewBox="0 0 18 12" fill="currentColor">
<rect x="0" y="8" width="3" height="4" rx="1"></rect>
<rect x="5" y="5" width="3" height="7" rx="1"></rect>
<rect x="10" y="2" width="3" height="10" rx="1"></rect>
<rect x="15" y="0" width="3" height="12" rx="1"></rect>
</svg>
<svg width="16" height="12" viewBox="0 0 16 12" fill="currentColor">
<path d="M8 10.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm0-4.5c1.5 0 2.9.5 4 1.4l1.4-1.4C11.7 4.5 9.9 3.5 8 3.5S4.3 4.5 2.6 6L4 7.4C5.1 6.5 6.5 6 8 6zm0-4c2.5 0 4.8.9 6.5 2.4l1.4-1.4C13.9 1 11.1 0 8 0S2.1 1 .1 3L1.5 4.4C3.2 2.9 5.5 2 8 2z"></path>
</svg>
<svg width="25" height="12" viewBox="0 0 25 12" fill="none">
<rect x="0.5" y="0.5" width="21" height="11" rx="2.5" stroke="currentColor" stroke-opacity="0.5"></rect>
<rect x="2" y="2" width="17" height="8" rx="1.5" fill="currentColor"></rect>
<rect x="22.5" y="4" width="1.5" height="4" rx="0.75" fill="currentColor" fill-opacity="0.5"></rect>
</svg>
</div>
</div>
<!-- 顶部导航 -->
<div class="top-nav">
<button class="nav-btn" data-dom-id="btn-back" onclick="goBack()">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<polyline points="15 18 9 12 15 6"></polyline>
</svg>
</button>
<span class="nav-title">认证校友地图</span>
<button class="nav-btn" data-dom-id="btn-filter" onclick="toggleLayerPanel()">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon>
</svg>
</button>
</div>
<!-- 数据统计条 -->
<div class="stats-bar">
<div class="stat-item">
<span class="stat-label">已认证校友</span>
<span class="stat-value-primary" data-dom-id="stat-total">12,856人</span>
</div>
<div class="stat-divider"></div>
<div class="stat-item" style="text-align: right;">
<span class="stat-label">覆盖高校</span>
<span class="stat-value-secondary" data-dom-id="stat-schools">326所</span>
</div>
</div>
<!-- 地图区域 -->
<div class="map-container" data-dom-id="map-area" id="mapArea">
<!-- 地图网格 -->
<div class="map-grid"></div>
<!-- 地图背景 SVG -->
<div class="map-bg" id="mapBg">
<svg class="map-svg" viewBox="0 0 340 360" preserveAspectRatio="xMidYMid meet">
<!-- 简化中国地图轮廓 -->
<path class="map-outline" d="M60,80 L80,60 L120,50 L160,45 L200,50 L240,60 L270,80 L290,110 L300,140 L295,180 L280,210 L260,240 L240,270 L210,290 L180,300 L150,305 L120,295 L90,275 L70,250 L55,220 L45,180 L40,140 L45,100 Z"></path>
<!-- 省份分割线(简化示意) -->
<path class="map-province" d="M100,70 L130,80 L150,70 L145,100 L120,110 L95,100 Z"></path>
<path class="map-province" d="M150,70 L180,65 L210,75 L205,105 L175,115 L145,100 Z"></path>
<path class="map-province" d="M210,75 L245,85 L265,110 L260,140 L230,150 L205,130 L205,105 Z"></path>
<path class="map-province" d="M95,100 L120,110 L130,140 L115,170 L85,165 L70,135 L75,105 Z"></path>
<path class="map-province" d="M145,100 L175,115 L190,145 L175,180 L140,185 L115,170 L130,140 Z"></path>
<path class="map-province" d="M205,130 L230,150 L240,185 L220,220 L185,225 L160,200 L175,180 L190,145 Z"></path>
<path class="map-province" d="M260,140 L280,150 L290,185 L280,220 L260,240 L240,225 L240,185 Z"></path>
<path class="map-province" d="M70,165 L85,165 L100,195 L85,230 L60,225 L50,195 Z"></path>
<path class="map-province" d="M115,170 L140,185 L150,220 L130,255 L100,250 L85,230 L100,195 Z"></path>
<path class="map-province" d="M160,200 L185,225 L195,260 L170,290 L140,285 L130,255 L150,220 Z"></path>
<path class="map-province" d="M220,220 L240,225 L250,255 L230,280 L200,280 L195,260 Z"></path>
<path class="map-province" d="M100,250 L130,255 L140,285 L120,300 L95,285 Z"></path>
<path class="map-province" d="M170,290 L195,285 L210,295 L190,305 L170,300 Z"></path>
<!-- 河流示意 -->
<path d="M60,150 Q100,160 140,145 T220,130 T280,140" fill="none" stroke="var(--youth-gray-300)" stroke-width="1.5" opacity="0.5"></path>
<path d="M120,60 Q130,120 110,180 T100,260" fill="none" stroke="var(--youth-gray-300)" stroke-width="1.2" opacity="0.4"></path>
</svg>
</div>
<!-- 地图点位 -->
<!-- 大点位:清华大学 -->
<div class="map-point map-point-large" data-dom-id="point-1" style="top: 30%; left: 58%;" onclick="showBubble(event, '清华大学', '856', 'point-1')">
<div class="map-point-label">清华</div>
</div>
<!-- 大点位:北京大学 -->
<div class="map-point map-point-large" data-dom-id="point-2" style="top: 31%; left: 54%;" onclick="showBubble(event, '北京大学', '723', 'point-2')">
<div class="map-point-label">北大</div>
</div>
<!-- 中点位:北航 -->
<div class="map-point map-point-medium" style="top: 28%; left: 56%;" onclick="showBubble(event, '北京航空航天大学', '445', 'point-buaa')">
</div>
<!-- 中点位:北邮 -->
<div class="map-point map-point-medium" style="top: 33%; left: 55%;" onclick="showBubble(event, '北京邮电大学', '389', 'point-bupt')">
</div>
<!-- 中点位:复旦大学 -->
<div class="map-point map-point-medium" data-dom-id="point-3" style="top: 52%; left: 75%;" onclick="showBubble(event, '复旦大学', '589', 'point-3')">
<div class="map-point-label">复旦</div>
</div>
<!-- 中点位:上海交大 -->
<div class="map-point map-point-medium" style="top: 55%; left: 77%;" onclick="showBubble(event, '上海交通大学', '478', 'point-sjtu')">
</div>
<!-- 中点位:浙江大学 -->
<div class="map-point map-point-medium" style="top: 58%; left: 70%;" onclick="showBubble(event, '浙江大学', '512', 'point-zju')">
<div class="map-point-label">浙大</div>
</div>
<!-- 小点位:更多学校 -->
<div class="map-point map-point-small" style="top: 35%; left: 45%;" onclick="showBubble(event, '西安交通大学', '234', 'point-xjtu')"></div>
<div class="map-point map-point-small" style="top: 45%; left: 62%;" onclick="showBubble(event, '武汉大学', '312', 'point-whu')"></div>
<div class="map-point map-point-small" style="top: 50%; left: 40%;" onclick="showBubble(event, '四川大学', '278', 'point-scu')"></div>
<div class="map-point map-point-small" style="top: 60%; left: 55%;" onclick="showBubble(event, '中山大学', '256', 'point-sysu')"></div>
<div class="map-point map-point-small" style="top: 65%; left: 60%;" onclick="showBubble(event, '华南理工', '198', 'point-scut')"></div>
<div class="map-point map-point-small" style="top: 25%; left: 65%;" onclick="showBubble(event, '哈尔滨工业大学', '287', 'point-hit')"></div>
<div class="map-point map-point-small" style="top: 32%; left: 70%;" onclick="showBubble(event, '吉林大学', '215', 'point-jlu')"></div>
<div class="map-point map-point-small" style="top: 48%; left: 75%;" onclick="showBubble(event, '同济大学', '334', 'point-tongji')"></div>
<div class="map-point map-point-small" style="top: 40%; left: 72%;" onclick="showBubble(event, '南京大学', '298', 'point-nju')"></div>
<div class="map-point map-point-small" style="top: 42%; left: 35%;" onclick="showBubble(event, '重庆大学', '187', 'point-cqu')"></div>
<div class="map-point map-point-small" style="top: 55%; left: 48%;" onclick="showBubble(event, '中南大学', '223', 'point-csu')"></div>
<div class="map-point map-point-small" style="top: 38%; left: 50%;" onclick="showBubble(event, '天津大学', '267', 'point-tju')"></div>
<!-- 信息气泡 -->
<div class="info-bubble" id="infoBubble">
<div class="bubble-school" id="bubbleSchool">学校名称</div>
<div class="bubble-count">认证校友 <span id="bubbleCount">0</span> 人</div>
<button class="bubble-btn" onclick="viewSchoolAlumni()">查看</button>
</div>
<!-- 地图控件 -->
<div class="map-controls">
<div class="zoom-group">
<button class="control-btn" data-dom-id="btn-zoom-in" onclick="zoomIn()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
</button>
<button class="control-btn" data-dom-id="btn-zoom-out" onclick="zoomOut()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
</button>
</div>
<button class="control-btn" data-dom-id="btn-locate" onclick="locateMe()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"></circle>
<path d="M12 2v2"></path>
<path d="M12 20v2"></path>
<path d="M2 12h2"></path>
<path d="M20 12h2"></path>
<path d="m4.93 4.93 1.41 1.41"></path>
<path d="m17.66 17.66 1.41 1.41"></path>
<path d="m4.93 19.07 1.41-1.41"></path>
<path d="m17.66 6.34 1.41-1.41"></path>
</svg>
</button>
</div>
<!-- 图层筛选浮层 -->
<div class="layer-panel" id="layerPanel">
<div class="layer-item active" onclick="setLayer(this, 'all')">全部</div>
<div class="layer-item" onclick="setLayer(this, 'beijing')">北京</div>
<div class="layer-item" onclick="setLayer(this, 'shanghai')">上海</div>
<div class="layer-item" onclick="setLayer(this, 'guangzhou')">广州</div>
</div>
</div>
<!-- 排行榜区域 -->
<div class="ranking-section">
<div class="ranking-header">
<div class="ranking-title">
<div class="ranking-title-icon">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--youth-primary)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"></path>
<path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"></path>
<path d="M4 22h16"></path>
<path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"></path>
<path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"></path>
<path d="M18 2H6v7a6 6 0 0 0 12 0V2Z"></path>
</svg>
</div>
认证人数排行榜
</div>
<span class="ranking-view-all">查看全部</span>
</div>
<div class="ranking-scroll">
<!-- TOP1 清华大学 -->
<div class="rank-card top1" data-dom-id="rank-1" onclick="viewSchool('清华大学')">
<div class="rank-top">
<span class="rank-number">01</span>
<svg class="medal-icon" viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="15" r="6" fill="#D4A853" stroke="#B8923F" stroke-width="1.5"></circle>
<text x="12" y="18" text-anchor="middle" fill="white" font-size="8" font-weight="bold">1</text>
<path d="M8 9L9 3h6l1 6" stroke="#D4A853" stroke-width="1.5" fill="none"></path>
<path d="M12 9l-2-6h4l-2 6z" fill="#E8C878"></path>
</svg>
</div>
<div class="rank-school">清华大学</div>
<div class="rank-count"><span>856</span>人</div>
<button class="rank-view-btn">查看</button>
</div>
<!-- TOP2 北京大学 -->
<div class="rank-card top2" data-dom-id="rank-2" onclick="viewSchool('北京大学')">
<div class="rank-top">
<span class="rank-number">02</span>
<svg class="medal-icon" viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="15" r="6" fill="#A8B0B8" stroke="#8A94A0" stroke-width="1.5"></circle>
<text x="12" y="18" text-anchor="middle" fill="white" font-size="8" font-weight="bold">2</text>
<path d="M8 9L9 3h6l1 6" stroke="#A8B0B8" stroke-width="1.5" fill="none"></path>
<path d="M12 9l-2-6h4l-2 6z" fill="#C0C8D0"></path>
</svg>
</div>
<div class="rank-school">北京大学</div>
<div class="rank-count"><span>723</span>人</div>
<button class="rank-view-btn">查看</button>
</div>
<!-- TOP3 复旦大学 -->
<div class="rank-card top3" data-dom-id="rank-3" onclick="viewSchool('复旦大学')">
<div class="rank-top">
<span class="rank-number">03</span>
<svg class="medal-icon" viewBox="0 0 24 24" fill="none">
<circle cx="12" cy="15" r="6" fill="#C48B63" stroke="#A8724F" stroke-width="1.5"></circle>
<text x="12" y="18" text-anchor="middle" fill="white" font-size="8" font-weight="bold">3</text>
<path d="M8 9L9 3h6l1 6" stroke="#C48B63" stroke-width="1.5" fill="none"></path>
<path d="M12 9l-2-6h4l-2 6z" fill="#D8A883"></path>
</svg>
</div>
<div class="rank-school">复旦大学</div>
<div class="rank-count"><span>589</span>人</div>
<button class="rank-view-btn">查看</button>
</div>
<!-- TOP4 浙江大学 -->
<div class="rank-card" data-dom-id="rank-4" onclick="viewSchool('浙江大学')">
<div class="rank-top">
<span class="rank-number">04</span>
</div>
<div class="rank-school">浙江大学</div>
<div class="rank-count"><span>512</span>人</div>
<button class="rank-view-btn">查看</button>
</div>
<!-- TOP5 上海交大 -->
<div class="rank-card" data-dom-id="rank-5" onclick="viewSchool('上海交通大学')">
<div class="rank-top">
<span class="rank-number">05</span>
</div>
<div class="rank-school">上海交大</div>
<div class="rank-count"><span>478</span>人</div>
<button class="rank-view-btn">查看</button>
</div>
</div>
</div>
<!-- 底部Tab导航 -->
</div>
<!-- Toast 提示 -->
<div class="toast" id="toast"></div>
<script>// ===== 主题切换 =====
sunIcon.style.display = 'none';
moonIcon.style.display = 'block';
}
}
// 初始化主题
}
})();
// ===== 返回按钮 =====
function goBack() {
window.location.href = 'profile-home.html';
}
// ===== 地图缩放 =====
let currentZoom = 1;
const zoomSteps = [0.8, 1, 1.2, 1.4, 1.6];
let zoomIndex = 1;
function zoomIn() {
if (zoomIndex < zoomSteps.length - 1) {
zoomIndex++;
applyZoom();
showToast('放大地图');
}
}
function zoomOut() {
if (zoomIndex > 0) {
zoomIndex--;
applyZoom();
showToast('缩小地图');
}
}
function applyZoom() {
const mapBg = document.getElementById('mapBg');
const scale = zoomSteps[zoomIndex];
mapBg.style.transform = `scale(${scale})`;
}
// ===== 定位按钮 =====
function locateMe() {
const mapBg = document.getElementById('mapBg');
zoomIndex = 1;
mapBg.style.transform = 'scale(1)';
mapBg.style.transition = 'transform 0.3s ease';
showToast('已定位到全国视图');
setTimeout(() => {
mapBg.style.transition = '';
}, 300);
}
// ===== 图层筛选 =====
function toggleLayerPanel() {
const panel = document.getElementById('layerPanel');
panel.classList.toggle('show');
}
function setLayer(el, region) {
const items = document.querySelectorAll('.layer-item');
items.forEach(item => item.classList.remove('active'));
el.classList.add('active');
const regionNames = {
'all': '全部地区',
'beijing': '北京地区',
'shanghai': '上海地区',
'guangzhou': '广州地区'
};
showToast('切换至' + regionNames[region]);
document.getElementById('layerPanel').classList.remove('show');
// 模拟筛选效果
const points = document.querySelectorAll('.map-point');
points.forEach(point => {
point.style.opacity = '1';
point.style.pointerEvents = 'auto';
});
}
// 点击地图其他位置关闭图层面板
document.addEventListener('click', function(e) {
const panel = document.getElementById('layerPanel');
const filterBtn = document.querySelector('[data-dom-id="btn-filter"]');
if (!panel.contains(e.target) && !filterBtn.contains(e.target)) {
panel.classList.remove('show');
}
});
// ===== 信息气泡 =====
let currentBubblePoint = null;
function showBubble(event, schoolName, count, pointId) {
event.stopPropagation();
const bubble = document.getElementById('infoBubble');
const point = event.currentTarget;
const mapArea = document.getElementById('mapArea');
document.getElementById('bubbleSchool').textContent = schoolName;
document.getElementById('bubbleCount').textContent = count;
// 获取点位相对于地图容器的位置
const pointRect = point.getBoundingClientRect();
const mapRect = mapArea.getBoundingClientRect();
const left = pointRect.left - mapRect.left + pointRect.width / 2;
const top = pointRect.top - mapRect.top + pointRect.height / 2;
bubble.style.left = left + 'px';
bubble.style.top = top + 'px';
// 如果之前点击同一个点,则关闭气泡
if (currentBubblePoint === pointId && bubble.classList.contains('show')) {
bubble.classList.remove('show');
currentBubblePoint = null;
return;
}
bubble.classList.add('show');
currentBubblePoint = pointId;
}
// 点击地图空白处关闭气泡
document.getElementById('mapArea').addEventListener('click', function(e) {
if (!e.target.closest('.map-point') && !e.target.closest('.info-bubble') && !e.target.closest('.map-controls') && !e.target.closest('.layer-panel')) {
document.getElementById('infoBubble').classList.remove('show');
currentBubblePoint = null;
}
});
// ===== 查看学校校友 =====
function viewSchoolAlumni() {
const school = document.getElementById('bubbleSchool').textContent;
showToast('查看' + school + '校友列表');
}
function viewSchool(schoolName) {
showToast('查看' + schoolName + '校友列表');
}
// ===== 底部Tab切换 =====
function switchTab(el, tab) {
const tabs = document.querySelectorAll('.tab-item');
tabs.forEach(t => t.classList.remove('active'));
el.classList.add('active');
const tabNames = {
'home': '首页',
'activity': '组局',
'message': '消息',
'discover': '发现',
'profile': '我的'
};
showToast('切换到' + tabNames[tab]);
}
// ===== Toast 提示 =====
let toastTimer = null;
function showToast(message) {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.classList.add('show');
if (toastTimer) clearTimeout(toastTimer);
toastTimer = setTimeout(() => {
toast.classList.remove('show');
}, 1800);
}
// ===== 排行榜横向滚动支持 =====
const rankingScroll = document.querySelector('.ranking-scroll');
let isScrolling = false;
let startX = 0;
let scrollLeft = 0;
rankingScroll.addEventListener('touchstart', (e) => {
isScrolling = true;
startX = e.touches[0].pageX - rankingScroll.offsetLeft;
scrollLeft = rankingScroll.scrollLeft;
});
rankingScroll.addEventListener('touchmove', (e) => {
if (!isScrolling) return;
e.preventDefault();
const x = e.touches[0].pageX - rankingScroll.offsetLeft;
const walk = (x - startX) * 1.5;
rankingScroll.scrollLeft = scrollLeft - walk;
});
rankingScroll.addEventListener('touchend', () => {
isScrolling = false;
});</script>
</body>
</html>