Files
all-in-one-sys/high.html
KQL 61698639ef feat: 完成多多畅职就业服务平台核心功能开发
主要更新:
-  完成主题配色从暗色到亮蓝白配色的全面转换
-  实现高薪岗位页面及后端API集成
-  完成登录注册页面及认证系统
-  实现预招录确认功能
-  添加数据库管理和维护工具脚本
-  优化错误处理和用户体验

核心功能:
1. 首页 (index.html) - 3D地球、专业分类、过渡岗位
2. 高薪岗位页面 (high.html) - 岗位详情、预招录确认、成功案例
3. 登录注册 (auth.html) - 用户认证、专业分类选择
4. 后端API - RESTful接口,JWT认证,MySQL数据库

技术栈:
- 前端:Three.js, GSAP, 原生JavaScript
- 后端:Node.js, Express, MySQL
- 认证:JWT, bcrypt
- 样式:自定义CSS,响应式设计

数据库工具:
- kill-by-ids.js - 批量终止MySQL进程
- unlock-all-tables.js - 解锁数据库表
- init-db.js - 初始化数据库
- 其他管理脚本

🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 15:40:55 +08:00

1080 lines
51 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>高薪岗位直通车 - 旗舰指挥舱</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<style>
/* --- 基础变量 --- */
:root {
--bg-color: #f8fafc;
--card-bg: rgba(255, 255, 255, 0.8);
--accent-cyan: #2563eb;
--accent-blue: #2563eb;
--success-green: #10b981;
--text-main: #0f172a;
--text-sub: #64748b;
--border-color: rgba(226, 232, 240, 0.5);
}
body {
background-color: var(--bg-color);
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
color: var(--text-main);
min-height: 100vh;
overflow-x: hidden;
position: relative;
-webkit-tap-highlight-color: transparent;
}
/* 背景光影 */
body::before {
content: ''; position: fixed; top: -50%; left: -50%; width: 150%; height: 150%; z-index: -2;
background: radial-gradient(circle at center, rgba(191, 219, 254, 0.4) 0%, transparent 60%);
filter: blur(100px); pointer-events: none; opacity: 0.8;
}
body::after {
content: ''; position: fixed; bottom: -30%; right: -30%; width: 120%; height: 120%; z-index: -2;
background: radial-gradient(circle at center, rgba(147, 197, 253, 0.3) 0%, transparent 50%);
filter: blur(120px); pointer-events: none; opacity: 0.6;
}
/* 滚动条美化 */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(148, 163, 184, 0.3); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: rgba(148, 163, 184, 0.5); }
.commander-layout {
max-width: 1440px; margin: 0 auto; padding: 30px 40px;
display: flex; flex-direction: column; gap: 30px;
}
/* 通用 HUD 容器 */
.hud-section {
background: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(25px);
border-radius: 16px;
padding: 24px 30px;
border: 1px solid rgba(226, 232, 240, 0.8);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
}
.section-header {
display: flex; align-items: center; gap: 12px; margin-bottom: 20px;
border-left: 4px solid var(--accent-cyan); padding-left: 15px;
}
.section-title { font-size: 1.2rem; font-weight: bold; letter-spacing: 1px; color: #2563eb; text-shadow: 0 0 10px rgba(37, 99, 235, 0.2); }
/* ========================================= */
/* === 1. 顶部状态仪表盘 (Dashboard) === */
/* ========================================= */
.status-container { display: flex; gap: 20px; flex-wrap: wrap; align-items: stretch; }
.left-panel-wrapper { flex: 0 0 450px; display: flex; flex-direction: column; gap: 20px; }
/* --- 修改项 1Cert Card 交互样式 --- */
.cert-card {
background: linear-gradient(145deg, rgba(255, 255, 255, 0.9), rgba(248, 250, 252, 0.8));
border: 1px solid var(--border-color); border-radius: 12px; padding: 25px 30px;
display: flex; align-items: center; justify-content: space-between;
position: relative; overflow: hidden; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); min-height: 120px;
/* 新增:手势和过渡动画 */
cursor: pointer;
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
/* 新增Hover 效果 */
.cert-card:hover {
border-color: var(--accent-cyan);
box-shadow: 0 0 25px rgba(37, 99, 235, 0.15);
transform: translateY(-2px);
}
/* 新增:点击按压效果 */
.cert-card:active {
transform: scale(0.98);
box-shadow: 0 0 10px rgba(37, 99, 235, 0.1);
}
.cert-info, .status-badge { position: relative; z-index: 10; }
.cert-info h3 { font-size: 1rem; color: var(--text-sub); margin-bottom: 8px; font-weight: 500; }
.cert-info h2 { font-size: 1.6rem; font-weight: bold; color: #0f172a; white-space: nowrap; letter-spacing: 1px; }
.cert-card::before {
content: ''; position: absolute; left: 0; bottom: 0; width: 100%; height: 3px;
background: var(--success-green); box-shadow: 0 0 15px var(--success-green); z-index: 5;
}
.cert-card::after {
content: "\f013"; font-family: "Font Awesome 6 Free"; font-weight: 900;
position: absolute; right: -20px; bottom: -35px; font-size: 9rem; color: #0f172a; opacity: 0.05;
z-index: 1; transform: rotate(15deg); pointer-events: none;
}
.status-badge {
background: rgba(16, 185, 129, 0.15); border: 1px solid rgba(16, 185, 129, 0.4);
color: var(--success-green); padding: 8px 20px; border-radius: 6px; font-weight: bold; font-size: 1rem;
box-shadow: 0 0 20px rgba(16, 185, 129, 0.15); text-shadow: 0 0 8px rgba(16, 185, 129, 0.4);
display: flex; align-items: center; gap: 8px; flex-shrink: 0; margin-left: 20px;
}
.class-card {
flex: 1; background: linear-gradient(145deg, rgba(255, 255, 255, 0.9), rgba(248, 250, 252, 0.8));
border: 1px solid var(--border-color); border-radius: 12px; padding: 25px 30px;
display: flex; align-items: center; gap: 20px; position: relative; overflow: hidden; box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
.class-card::before {
content: ''; position: absolute; left: 0; bottom: 0; width: 100%; height: 3px;
background: var(--accent-blue); box-shadow: 0 0 15px var(--accent-blue);
}
.class-icon-box {
width: 50px; height: 50px; border-radius: 10px;
background: rgba(37, 99, 235, 0.15); border: 1px solid rgba(37, 99, 235, 0.3);
display: flex; align-items: center; justify-content: center; font-size: 1.4rem; color: #60a5fa;
}
.class-info label { display: block; font-size: 0.9rem; color: var(--text-sub); margin-bottom: 4px; }
.class-info .value { font-size: 1.2rem; font-weight: bold; color: #0f172a; }
.interview-pool {
flex: 1; min-width: 400px; background: rgba(255,255,255,0.6); border-radius: 12px; border: 1px solid rgba(226,232,240,0.6);
padding: 20px; display: flex; flex-direction: column; max-height: 280px; overflow-y: auto;
}
.interview-cards-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 15px; }
.interview-card {
background: rgba(255,255,255,0.8); border: 1px solid rgba(226,232,240,0.8);
border-radius: 8px; padding: 15px; transition: all 0.3s; cursor: pointer; position: relative; overflow: hidden;
}
.interview-card:hover {
background: rgba(37, 99, 235, 0.05); border-color: rgba(37, 99, 235, 0.3); transform: translateY(-2px);
}
.interview-card::before {
content: ''; position: absolute; top: 0; left: 0; width: 3px; height: 100%; background: var(--accent-blue);
}
.interview-card.status-offer::before { background: var(--success-green); box-shadow: 0 0 8px var(--success-green); }
.interview-card.status-hr::before { background: #a855f7; box-shadow: 0 0 8px #a855f7; }
.interview-card.status-ing::before { background: var(--accent-cyan); box-shadow: 0 0 8px var(--accent-cyan); }
.int-company { font-size: 1rem; font-weight: bold; color: #0f172a; margin-bottom: 4px; }
.int-job { font-size: 0.8rem; color: var(--text-sub); margin-bottom: 8px; }
.int-badge {
display: inline-block; font-size: 0.75rem; padding: 3px 8px; border-radius: 4px;
font-weight: bold; background: rgba(226,232,240,0.5); color: #64748b;
}
.status-offer .int-badge { color: var(--success-green); background: rgba(16, 185, 129, 0.1); }
.status-ing .int-badge { color: var(--accent-cyan); background: rgba(59, 130, 246, 0.1); }
/* ========================================= */
/* === 2. 核心模块 (Table) === */
/* ========================================= */
.data-list { display: flex; flex-direction: column; gap: 24px; }
.data-row {
display: flex; align-items: stretch;
background: rgba(255,255,255,0.9);
border: 1px solid rgba(226,232,240,0.9); border-radius: 12px;
transition: all 0.5s ease; box-shadow: 0 4px 20px rgba(0,0,0,0.2);
}
.data-row.status-locked { opacity: 0.6; filter: grayscale(0.8); border-color: rgba(255,255,255,0.05); }
.data-row.status-locked:hover { opacity: 0.8; border-color: rgba(255,255,255,0.2); }
.data-row.status-active {
opacity: 1; filter: grayscale(0); border-color: var(--accent-cyan);
box-shadow: 0 0 25px rgba(37, 99, 235, 0.15); background: rgba(37, 99, 235, 0.02);
}
.row-cell { padding: 25px; display: flex; flex-direction: column; justify-content: center; }
.cell-info { flex: 0 0 260px; border-right: 1px solid rgba(226,232,240,0.6); background: rgba(255,255,255,0.6); }
.course-title { font-size: 1.15rem; font-weight: bold; color: #0f172a; margin-bottom: 8px; }
.course-time { font-family: monospace; color: var(--accent-cyan); font-size: 0.9rem; }
.cell-content { flex: 1; padding: 20px 30px; display: flex; flex-direction: column; gap: 20px; }
.content-group { display: flex; flex-direction: column; gap: 8px; }
.group-label { font-size: 0.8rem; color: var(--text-sub); font-weight: bold; letter-spacing: 1px; }
.text-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px 15px; width: 100%; }
.grid-item {
background: rgba(226,232,240,0.5); border: 1px solid rgba(226,232,240,0.6);
border-radius: 6px; padding: 8px 12px; font-size: 0.9rem; color: #1e293b;
text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: all 0.2s;
}
.grid-item:hover { background: rgba(37, 99, 235, 0.1); color: #2563eb; border-color: rgba(37, 99, 235, 0.3); }
.recruit-btn {
margin-top: 15px; width: 100%; padding: 8px 0;
background: transparent; border: 1px dashed var(--accent-cyan);
color: var(--accent-cyan); font-size: 0.85rem; border-radius: 4px;
cursor: pointer; transition: all 0.3s;
display: flex; align-items: center; justify-content: center; gap: 6px;
}
.recruit-btn:hover { background: rgba(37, 99, 235, 0.1); box-shadow: 0 0 10px rgba(37, 99, 235, 0.2); }
.recruit-btn.disabled {
border-style: solid; border-color: var(--success-green); color: var(--success-green);
background: rgba(16, 185, 129, 0.1); cursor: default; box-shadow: none;
}
/* ========================================= */
/* === 3. 弹幕滚动样式 (修改项 2密集优化版) === */
/* ========================================= */
.barrage-wrapper {
width: 100%;
height: auto;
min-height: 200px;
padding: 10px 0;
overflow: hidden;
position: relative;
/* 遮罩效果 */
-webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
display: flex;
flex-direction: column;
justify-content: center;
gap: 12px;
}
.barrage-track {
display: flex;
gap: 12px;
width: max-content;
align-items: center;
animation: scroll-left linear infinite;
}
.barrage-track:hover { animation-play-state: paused; }
/* 三条轨道差速配置 */
.track-fast { animation-duration: 35s; }
.track-slow { animation-duration: 55s; }
.track-medium { animation-duration: 45s; }
@keyframes scroll-left { 0% { transform: translateX(0); } 100% { transform: translateX(-50%); } }
.barrage-card {
background: rgba(255, 255, 255, 0.95);
border: 1px solid rgba(37, 99, 235, 0.2);
backdrop-filter: blur(5px);
border-radius: 40px;
padding: 6px 16px;
display: flex; align-items: center; gap: 10px;
white-space: nowrap;
box-shadow: 0 4px 10px rgba(0,0,0,0.2);
transition: all 0.2s;
user-select: none;
}
.barrage-card:hover {
background: rgba(37, 99, 235, 0.15); border-color: var(--accent-cyan);
transform: scale(1.05); box-shadow: 0 0 15px rgba(37, 99, 235, 0.3); z-index: 10;
}
.b-avatar {
width: 26px; height: 26px;
color: #0f172a; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: 0.7rem; font-weight: bold; border: 1px solid rgba(255,255,255,0.2);
}
.b-info { display: flex; align-items: center; gap: 8px; font-size: 0.85rem; }
.b-name { color: #0f172a; font-weight: bold; }
.b-job { color: var(--accent-cyan); }
.b-company { color: var(--text-sub); font-size: 0.75rem; }
.b-salary { color: #fbbf24; font-weight: bold; font-family: monospace; background: rgba(251, 191, 36, 0.1); padding: 1px 6px; border-radius: 4px; font-size: 0.8rem; }
/* ========================================= */
/* === 4. 高薪岗位卡片样式 === */
/* ========================================= */
.grid-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 20px; }
.cyber-card {
background: var(--card-bg); backdrop-filter: blur(15px); border: 1px solid var(--border-color);
border-radius: 12px; padding: 24px; position: relative; cursor: default;
transition: all 0.25s cubic-bezier(0.25, 0.8, 0.25, 1); overflow: hidden;
display: flex; flex-direction: column; justify-content: space-between;
}
.cyber-card:hover {
border-color: rgba(37, 99, 235, 0.5); background: rgba(255, 255, 255, 0.95);
transform: translateY(-5px) scale(1.01); box-shadow: 0 15px 35px rgba(0,0,0,0.4), 0 0 15px rgba(37,99,235,0.1);
}
.job-card-top { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 15px; }
.job-icon {
width: 44px; height: 44px; border-radius: 8px;
background: rgba(255,255,255,0.8); border: 1px solid rgba(226,232,240,0.9);
display: flex; align-items: center; justify-content: center; font-size: 1.2rem; color: var(--text-sub); transition: all 0.3s;
}
.cyber-card:hover .job-icon { color: var(--accent-cyan); border-color: var(--accent-cyan); background: rgba(37,99,235,0.05); }
.salary-tag { color: var(--accent-cyan); font-weight: bold; font-family: 'Arial', sans-serif; font-size: 1.1rem; text-shadow: 0 0 10px rgba(37,99,235,0.3); }
.job-meta-row { display: flex; align-items: center; gap: 15px; margin-top: 8px; color: var(--text-sub); font-size: 0.85rem; }
.meta-item { display: flex; align-items: center; gap: 6px; }
.cyber-btn {
width: 100%; margin-top: 20px; padding: 10px 0;
background: rgba(37, 99, 235, 0.05); border: 1px solid rgba(37, 99, 235, 0.3);
color: var(--accent-cyan); font-size: 0.9rem; font-weight: bold;
border-radius: 6px; cursor: pointer; transition: all 0.3s;
position: relative; overflow: hidden; letter-spacing: 1px;
}
.cyber-btn::before {
content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
background: linear-gradient(90deg, transparent, rgba(37, 99, 235, 0.2), transparent);
transition: 0.5s;
}
.cyber-btn:hover { background: rgba(37, 99, 235, 0.2); box-shadow: 0 0 20px rgba(37, 99, 235, 0.3); color: #0f172a; border-color: var(--accent-cyan); }
.cyber-btn:hover::before { left: 100%; }
/* ========================================= */
/* === 5. 模态框 (通用 & 确认框) === */
/* ========================================= */
.modal-overlay {
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(15, 23, 42, 0.6); backdrop-filter: blur(8px);
z-index: 1000; display: none; align-items: center; justify-content: center;
opacity: 0; transition: opacity 0.3s;
}
.modal-overlay.active { display: flex; opacity: 1; }
.modal-window {
width: 800px; max-width: 90%; max-height: 85vh;
background: rgba(255, 255, 255, 0.98); border: 1px solid var(--accent-cyan);
border-radius: 16px; box-shadow: 0 0 50px rgba(37, 99, 235, 0.15), inset 0 0 20px rgba(37, 99, 235, 0.05);
display: flex; flex-direction: column; overflow: hidden;
transform: scale(0.9); transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
position: relative;
}
.modal-overlay.active .modal-window { transform: scale(1); }
.confirm-modal-window {
width: 400px; background: rgba(255, 255, 255, 0.98); border: 1px solid #f87171;
border-radius: 12px; padding: 25px; text-align: center;
box-shadow: 0 0 40px rgba(248, 113, 113, 0.2);
transform: scale(0.9); transition: transform 0.3s;
}
.modal-overlay.active .confirm-modal-window { transform: scale(1); }
.confirm-icon { font-size: 3rem; color: #f87171; margin-bottom: 15px; }
.confirm-text { color: #0f172a; font-size: 1.1rem; margin-bottom: 8px; font-weight: bold; }
.confirm-sub { color: #94a3b8; font-size: 0.9rem; margin-bottom: 25px; line-height: 1.5; }
.confirm-actions { display: flex; gap: 10px; justify-content: center; }
.btn-confirm-yes {
background: #f87171; color: #0f172a; border: none; padding: 8px 24px; border-radius: 6px; cursor: pointer; font-weight: bold;
}
.btn-confirm-yes:hover { background: #ef4444; box-shadow: 0 0 15px rgba(239, 68, 68, 0.4); }
.corner-decor { position: absolute; width: 20px; height: 20px; border: 2px solid var(--accent-cyan); pointer-events: none; }
.corner-tl { top: 0; left: 0; border-bottom: none; border-right: none; border-top-left-radius: 12px; }
.corner-tr { top: 0; right: 0; border-bottom: none; border-left: none; border-top-right-radius: 12px; }
.corner-bl { bottom: 0; left: 0; border-top: none; border-right: none; border-bottom-left-radius: 12px; }
.corner-br { bottom: 0; right: 0; border-top: none; border-left: none; border-bottom-right-radius: 12px; }
.modal-header {
padding: 25px 30px; border-bottom: 1px solid rgba(226,232,240,0.8);
display: flex; justify-content: space-between; align-items: flex-start;
background: linear-gradient(90deg, rgba(37,99,235,0.05), transparent);
}
.modal-title-group h2 { font-size: 1.8rem; color: #0f172a; margin-bottom: 5px; text-shadow: 0 0 10px rgba(0,0,0,0.5); }
.modal-salary { font-size: 1.5rem; color: #fbbf24; font-family: 'Arial', sans-serif; font-weight: bold; text-shadow: 0 0 10px rgba(251, 191, 36, 0.3); }
.close-btn { background: transparent; border: none; color: var(--text-sub); font-size: 1.5rem; cursor: pointer; transition: color 0.3s; }
.close-btn:hover { color: #0f172a; }
.modal-body { padding: 30px; overflow-y: auto; flex: 1; }
.modal-tags { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 25px; }
.modal-tag {
background: rgba(37, 99, 235, 0.1); border: 1px solid rgba(37, 99, 235, 0.3);
color: #60a5fa; padding: 4px 12px; border-radius: 20px; font-size: 0.85rem;
}
.info-grid {
display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;
margin-bottom: 30px; padding: 20px;
background: rgba(255,255,255,0.9); border-radius: 10px; border: 1px solid rgba(226,232,240,0.6);
}
.info-item label { display: block; color: var(--text-sub); font-size: 0.85rem; margin-bottom: 5px; }
.info-item div { color: #0f172a; font-size: 1.1rem; font-weight: 500; display: flex; align-items: center; gap: 8px; }
.content-section { margin-bottom: 25px; }
.section-head {
font-size: 1.1rem; color: var(--accent-cyan); margin-bottom: 12px;
display: flex; align-items: center; gap: 8px;
border-left: 3px solid var(--accent-cyan); padding-left: 10px;
}
.text-content { color: #0f172a; line-height: 1.6; font-size: 0.95rem; white-space: pre-line; }
.modal-footer {
padding: 20px 30px; border-top: 1px solid rgba(226,232,240,0.8);
display: flex; justify-content: flex-end; gap: 15px; background: rgba(248,250,252,0.8);
}
.btn-cancel {
padding: 10px 25px; border-radius: 6px; cursor: pointer;
background: transparent; border: 1px solid rgba(255,255,255,0.2); color: #64748b; transition: all 0.3s;
}
.btn-cancel:hover { border-color: #0f172a; color: #0f172a; }
.btn-apply {
padding: 10px 35px; border-radius: 6px; cursor: pointer;
background: var(--accent-blue); border: none; color: #0f172a; font-weight: bold;
box-shadow: 0 0 15px rgba(37, 99, 235, 0.4); transition: all 0.3s;
}
.btn-apply:hover { background: #3b82f6; box-shadow: 0 0 25px rgba(37, 99, 235, 0.6); transform: translateY(-1px); }
/* ========================================= */
/* === 6. 移动端适配 (Media Queries) === */
/* ========================================= */
/* 返回首页按钮 - 移动端调整 */
#back-home-btn {
top: 20px; left: 20px;
}
@media (max-width: 768px) {
/* 返回按钮缩小 */
#back-home-btn {
top: 15px; left: 15px;
padding: 8px 16px !important;
font-size: 12px !important;
}
#back-home-btn svg { width: 16px; height: 16px; }
/* 整体布局 */
.commander-layout {
padding: 15px;
gap: 20px;
padding-top: 80px;
}
.hud-section { padding: 20px 15px; }
/* 顶部面板 */
.status-container { flex-direction: column; }
.left-panel-wrapper { flex: auto; width: 100%; }
.interview-pool { min-width: auto; width: 100%; max-height: 350px; }
/* 资质 & 班级卡片 */
.cert-card, .class-card {
padding: 20px; flex-direction: column; align-items: flex-start; gap: 15px; min-height: auto;
}
.cert-info h2 { font-size: 1.3rem; white-space: normal; line-height: 1.4; }
.status-badge { margin-left: 0; align-self: flex-start; }
/* 课程推送单元 (时间线) */
.data-row { flex-direction: column; }
.cell-info {
flex: auto; width: 100%;
border-right: none;
border-bottom: 1px solid rgba(255,255,255,0.05);
padding: 20px;
}
.course-title { margin-bottom: 5px; }
.cell-content { padding: 20px; }
.text-grid { grid-template-columns: repeat(2, 1fr); }
/* 弹幕区域 - 移动端调整 */
.barrage-wrapper { height: 180px; gap: 8px; }
.barrage-card { padding: 5px 12px; }
.b-avatar { width: 22px; height: 22px; font-size: 0.6rem; }
.b-info { font-size: 0.75rem; }
/* 岗位详情弹窗 */
.modal-window { width: 95%; max-height: 90vh; }
.modal-header { padding: 15px 20px; }
.modal-title-group h2 { font-size: 1.3rem; line-height: 1.3; }
.modal-salary { font-size: 1.3rem; }
.modal-body { padding: 20px; }
.info-grid { grid-template-columns: 1fr; gap: 12px; }
/* 确认弹窗 */
.confirm-modal-window { width: 90%; padding: 20px; }
.confirm-text { font-size: 1rem; }
}
/* 动画关键帧:进度条扫光 */
@keyframes shine {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
</style>
</head>
<body>
<button id="back-home-btn" onclick="window.location.href='index.html'" style="
position: fixed; top: 20px; left: 20px; z-index: 101;
display: flex; align-items: center; gap: 8px; padding: 12px 24px;
background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(12px);
border: 1px solid rgba(37, 99, 235, 0.3); border-radius: 50px;
color: #2563eb; font-size: 14px; cursor: pointer; transition: all 0.3s ease;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
" onmouseover="this.style.background='rgba(37, 99, 235, 0.1)'; this.style.borderColor='#2563eb'; this.style.boxShadow='0 0 30px rgba(37, 99, 235, 0.3)'; this.style.transform='translateX(-5px)';"
onmouseout="this.style.background='rgba(255, 255, 255, 0.95)'; this.style.borderColor='rgba(37, 99, 235, 0.3)'; this.style.transform='translateX(0)';">
<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
</svg>
<span>返回首页</span>
</button>
<div class="commander-layout">
<section class="hud-section">
<div class="section-header">
<i class="fa-solid fa-user-astronaut text-blue-600"></i>
<div class="section-title">我的状态</div>
</div>
<div class="status-container">
<div class="left-panel-wrapper">
<div class="cert-card" onclick="openCertModal()">
<div class="cert-info">
<h3>必要资质要求</h3>
<h2>过渡岗位工作经历证明</h2>
</div>
<div class="status-badge">
<i class="fa-solid fa-certificate"></i> 已获得
</div>
</div>
<div class="class-card">
<div class="class-icon-box">
<i class="fa-solid fa-graduation-cap"></i>
</div>
<div class="class-info">
<label>当前所属就业班</label>
<div class="value">智能制造班</div>
</div>
</div>
</div>
<div class="interview-pool">
<div class="flex justify-between items-center mb-3 text-slate-600 text-sm">
<span>我的高薪岗位面试</span>
<i class="fa-solid fa-list-check"></i>
</div>
<div class="interview-cards-container">
<div class="interview-card status-offer">
<div class="int-company">字节跳动</div>
<div class="int-job">后端开发工程师</div>
<div class="int-badge">Offer发放</div>
</div>
<div class="interview-card status-hr">
<div class="int-company">蔚来汽车</div>
<div class="int-job">自动驾驶算法助理</div>
<div class="int-badge">HR复试</div>
</div>
<div class="interview-card status-ing">
<div class="int-company">哔哩哔哩</div>
<div class="int-job">前端开发 (React)</div>
<div class="int-badge">二面考核</div>
</div>
<div class="interview-card status-ing">
<div class="int-company">京东商城</div>
<div class="int-job">物流数据分析</div>
<div class="int-badge">初试邀请</div>
</div>
<div class="interview-card status-ing">
<div class="int-company">米哈游</div>
<div class="int-job">游戏客户端开发</div>
<div class="int-badge">笔试通过</div>
</div>
<div class="interview-card status-ing">
<div class="int-company">腾讯游戏</div>
<div class="int-job">关卡策划</div>
<div class="int-badge">简历评估</div>
</div>
</div>
</div>
</div>
</section>
<section class="hud-section">
<div class="section-header">
<i class="fa-solid fa-database text-blue-600"></i>
<div class="section-title">高薪岗位预招录确认</div>
</div>
<div class="data-list">
</div>
</section>
<section class="hud-section">
<div class="section-header">
<i class="fa-solid fa-medal text-blue-600"></i>
<div class="section-title">恭喜以下学员成功入职高薪岗位</div>
</div>
<div class="barrage-wrapper">
<div class="barrage-track track-fast"></div>
<div class="barrage-track track-slow"></div>
<div class="barrage-track track-medium"></div>
</div>
</section>
<section class="hud-section" style="margin-bottom: 0;">
<div class="section-header">
<i class="fa-solid fa-rocket text-blue-600"></i>
<div class="section-title">当日高薪岗位信息</div>
</div>
<div class="grid-container">
</div>
</section>
</div>
<div class="modal-overlay" id="recruitConfirmModal">
<div class="confirm-modal-window">
<div class="confirm-icon"><i class="fa-solid fa-triangle-exclamation"></i></div>
<div class="confirm-text">确认进入预招录名单?</div>
<div class="confirm-sub">一旦确认后将无法自行修改。<br>如需更改,请联系人工客服进行人工审核。</div>
<div class="confirm-actions">
<button class="btn-cancel" onclick="closeConfirmModal()">取消</button>
<button class="btn-confirm-yes" onclick="confirmRecruitment()">确认锁定</button>
</div>
</div>
</div>
<div class="modal-overlay" id="certModal">
<div class="confirm-modal-window" style="width: 450px; text-align: left; border-color: var(--accent-cyan); box-shadow: 0 0 40px rgba(37, 99, 235, 0.2);">
<div class="flex items-center gap-3 mb-6 border-b border-slate-200 pb-3">
<i class="fa-solid fa-hourglass-half text-blue-600 text-xl"></i>
<h3 class="text-slate-900 text-lg font-bold">工作经历证明获取进度</h3>
</div>
<div class="mb-4 text-slate-700 font-medium">
到岗时间:<span id="displayStartDate" class="text-blue-600 font-mono font-bold text-lg"></span>
</div>
<div class="mb-2 flex justify-between text-xs text-slate-600">
<span>当前进度</span>
<span id="progressText" class="text-blue-600 font-bold">0%</span>
</div>
<div class="w-full bg-slate-100 rounded-full h-3 border border-slate-300 overflow-hidden relative shadow-inner">
<div id="progressBar" class="h-full bg-gradient-to-r from-blue-500 to-cyan-400 rounded-full relative transition-all duration-1000 ease-out" style="width: 0%">
<div class="absolute top-0 left-0 w-full h-full bg-white opacity-20" style="animation: shine 2s infinite;"></div>
</div>
</div>
<div class="mt-2 text-right text-xs text-gray-500">
周期目标90天
</div>
<div class="mt-8 flex justify-end">
<button class="btn-cancel w-full" onclick="closeCertModal()">关闭面板</button>
</div>
</div>
</div>
<div class="modal-overlay" id="jobModal">
<div class="modal-window">
<div class="corner-decor corner-tl"></div><div class="corner-decor corner-tr"></div><div class="corner-decor corner-bl"></div><div class="corner-decor corner-br"></div>
<div class="modal-header">
<div class="modal-title-group">
<h2 id="modalJobTitle">加载中...</h2><div class="modal-salary" id="modalSalary">--</div>
</div>
<button class="close-btn" onclick="closeModal()"><i class="fa-solid fa-xmark"></i></button>
</div>
<div class="modal-body">
<div class="modal-tags" id="modalTags"></div>
<div class="info-grid">
<div class="info-item"><label>所属企业</label><div id="modalCompany"><i class="fa-regular fa-building"></i> --</div></div>
<div class="info-item"><label>工作地点</label><div id="modalLocation"><i class="fa-solid fa-location-dot"></i> --</div></div>
<div class="info-item"><label>招聘名额</label><div class="text-green-400" id="modalQuota"><i class="fa-solid fa-users"></i> --</div></div>
</div>
<div class="content-section"><div class="section-head"><i class="fa-solid fa-clipboard-check"></i> 岗位要求</div><div class="text-content" id="modalRequirements"></div></div>
<div class="content-section"><div class="section-head"><i class="fa-solid fa-briefcase"></i> 企业介绍</div><div class="text-content" id="modalCompanyDesc"></div></div>
</div>
</div>
</div>
<script>
// ==========================================
// === API配置和工具函数 ===
// ==========================================
// API配置
const API_BASE_URL = window.location.origin; // 使用当前域名
// 全局变量
let jobsList = []; // 从常量改为变量
let trainingUnitsData = [];
let successStoriesData = {};
// 工具函数发送API请求
async function fetchAPI(endpoint) {
try {
const response = await fetch(`${API_BASE_URL}${endpoint}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
if (!result.success) {
throw new Error(result.message || 'API返回失败');
}
return result.data;
} catch (error) {
console.error(`获取数据失败 (${endpoint}):`, error);
return null;
}
}
// 页面初始化函数
async function initPage() {
await Promise.all([
loadJobsList(),
loadTrainingUnits(),
loadSuccessStories()
]);
}
// 页面加载完成后执行
document.addEventListener('DOMContentLoaded', initPage);
// ==========================================
// === 加载和渲染高薪岗位数据 ===
// ==========================================
// 加载高薪岗位数据
async function loadJobsList() {
const data = await fetchAPI('/api/high-salary-jobs?limit=100');
if (data && data.jobs) {
jobsList = data.jobs;
renderJobCards();
}
}
// 渲染岗位卡片到页面
function renderJobCards() {
const container = document.querySelector('.grid-container');
if (!container) return;
container.innerHTML = ''; // 清空现有内容
jobsList.forEach((job, index) => {
const card = createJobCard(job, index);
container.appendChild(card);
});
}
// 创建单个岗位卡片
function createJobCard(job, index) {
const card = document.createElement('div');
card.className = 'cyber-card';
const icon = job.icon || 'fa-microchip';
card.innerHTML = `
<div class="job-card-top">
<div class="job-icon"><i class="fa-solid ${icon}"></i></div>
<div class="salary-tag">${job.salary}</div>
</div>
<div>
<div class="text-slate-900 font-bold text-lg mb-1">${job.title}</div>
<div class="job-meta-row">
<div class="meta-item">
<i class="fa-regular fa-building"></i> ${job.company}
</div>
<div class="meta-item">
<i class="fa-solid fa-location-dot"></i> ${job.location}
</div>
</div>
<button class="cyber-btn" onclick="openModal(${index})">
查看详情 <i class="fa-solid fa-angle-right ml-1"></i>
</button>
</div>
`;
return card;
}
// ==========================================
// === 2. 交互逻辑:打开详情弹窗 ===
// ==========================================
/**
* 打开详情弹窗
* @param {number} index - 岗位在数组中的索引 (0-19)
* 对应 HTML 中的 onclick="openModal(0)", onclick="openModal(1)" ...
*/
function openModal(index) {
console.log("正在打开第 " + index + " 个岗位的详情");
// 0. 检查数据是否已加载
if (!jobsList || jobsList.length === 0) {
alert('数据加载中,请稍候...');
return;
}
// 1. 获取数据
const data = jobsList[index];
if (!data) {
console.error("未找到索引为 " + index + " 的数据");
return;
}
// 2. 填充弹窗基础信息
document.getElementById('modalJobTitle').innerText = data.title;
document.getElementById('modalSalary').innerText = data.salary;
document.getElementById('modalCompany').innerHTML = `<i class="fa-regular fa-building"></i> ${data.company}`;
document.getElementById('modalLocation').innerHTML = `<i class="fa-solid fa-location-dot"></i> ${data.location}`;
document.getElementById('modalQuota').innerHTML = `<i class="fa-solid fa-users"></i> ${data.quota}`;
// 3. 填充福利标签 (先清空旧的)
const tagContainer = document.getElementById('modalTags');
tagContainer.innerHTML = '';
if (data.tags && data.tags.length > 0) {
data.tags.forEach(tag => {
const span = document.createElement('span');
span.className = 'modal-tag';
span.innerText = tag;
tagContainer.appendChild(span);
});
}
// 4. 填充详细文本 (支持换行显示)
document.getElementById('modalRequirements').innerText = data.requirements;
document.getElementById('modalCompanyDesc').innerText = data.description;
// 5. 显示弹窗并禁止背景滚动
document.getElementById('jobModal').classList.add('active');
document.body.style.overflow = 'hidden';
}
// ==========================================
// === 3. 交互逻辑:关闭详情弹窗 ===
// ==========================================
function closeModal() {
document.getElementById('jobModal').classList.remove('active');
document.body.style.overflow = 'auto';
}
// 点击遮罩层也可以关闭
document.getElementById('jobModal').addEventListener('click', function(e) {
if (e.target === this) closeModal();
});
// ==========================================
// === 加载和渲染培训单元数据 ===
// ==========================================
// 加载培训单元数据
async function loadTrainingUnits() {
trainingUnitsData = await fetchAPI('/api/training-units');
if (trainingUnitsData) {
renderTrainingUnits();
}
}
// 渲染培训单元
function renderTrainingUnits() {
const container = document.querySelector('.data-list');
if (!container) return;
container.innerHTML = '';
trainingUnitsData.forEach((unit, index) => {
const row = createTrainingUnitRow(unit, index);
container.appendChild(row);
});
}
// 创建单个培训单元行
function createTrainingUnitRow(unit, index) {
const row = document.createElement('div');
row.className = `data-row ${unit.is_confirmed ? 'status-active' : 'status-locked'}`;
row.id = `row-unit-${index}`;
// 格式化日期
const date = new Date(unit.start_date);
const dateStr = `${date.getFullYear()}/${(date.getMonth()+1).toString().padStart(2,'0')}/${date.getDate().toString().padStart(2,'0')}`;
row.innerHTML = `
<div class="row-cell cell-info">
<div class="course-title">${unit.title}</div>
<div class="course-time">
<i class="fa-regular fa-clock mr-1"></i> ${dateStr} 开课
</div>
<button class="recruit-btn ${unit.is_confirmed ? 'disabled' : ''}"
${unit.is_confirmed ? '' : `onclick="openConfirmModal('row-unit-${index}', ${unit.id})"`}>
<i class="fa-solid ${unit.is_confirmed ? 'fa-check-circle' : 'fa-user-plus'}"></i>
${unit.is_confirmed ? '已确认进入名单' : '预招录确认'}
</button>
</div>
<div class="row-cell cell-content">
<div class="content-group">
<div class="group-label text-blue-600">对应岗位</div>
<div class="text-grid">
${unit.related_positions.map(pos => `<div class="grid-item">${pos}</div>`).join('')}
</div>
</div>
<div class="content-group">
<div class="group-label text-blue-400">相关企业</div>
<div class="text-grid">
${unit.related_companies.map(comp => `<div class="grid-item">${comp}</div>`).join('')}
</div>
</div>
</div>
`;
return row;
}
// ==========================================
// === 加载和渲染成功案例弹幕数据 ===
// ==========================================
// 加载成功案例弹幕数据
async function loadSuccessStories() {
successStoriesData = await fetchAPI('/api/success-stories');
if (successStoriesData) {
renderSuccessStories();
}
}
// 渲染成功案例弹幕
function renderSuccessStories() {
renderTrack('fast', successStoriesData.fast);
renderTrack('slow', successStoriesData.slow);
renderTrack('medium', successStoriesData.medium);
}
// 渲染单条轨道
function renderTrack(trackType, stories) {
const track = document.querySelector(`.track-${trackType}`);
if (!track || !stories || stories.length === 0) return;
track.innerHTML = '';
// 生成弹幕卡片重复2次以实现无缝循环
const cardsHTML = stories.map(story => createStoryCard(story)).join('');
track.innerHTML = cardsHTML + cardsHTML; // 重复一次
}
// 创建单个弹幕卡片
function createStoryCard(story) {
return `
<div class="barrage-card">
<div class="b-avatar" style="background:${story.avatar_color};">
${story.name.charAt(0)}
</div>
<div class="b-info">
<span class="b-name">${story.name}</span>
<span class="b-job">${story.job}</span>
<span class="b-company">@${story.company}</span>
<span class="b-salary">${story.salary}</span>
</div>
</div>
`;
}
// ==========================================
// === 4. 其他板块逻辑 (保留原有逻辑) ===
// ==========================================
// --- 预招录确认逻辑 ---
let currentTargetRowId = null;
let currentUnitId = null;
function openConfirmModal(rowId, unitId) {
currentTargetRowId = rowId;
currentUnitId = unitId;
document.getElementById('recruitConfirmModal').classList.add('active');
}
function closeConfirmModal() {
document.getElementById('recruitConfirmModal').classList.remove('active');
currentTargetRowId = null;
currentUnitId = null;
}
async function confirmRecruitment() {
if (!currentTargetRowId || !currentUnitId) return;
// 调用API确认预招录
const result = await confirmTrainingUnit(currentUnitId);
if (result.success) {
const row = document.getElementById(currentTargetRowId);
const btn = row.querySelector('.recruit-btn');
row.classList.remove('status-locked');
row.classList.add('status-active');
btn.classList.add('disabled');
btn.innerHTML = '<i class="fa-solid fa-check-circle"></i> 已确认进入名单';
btn.removeAttribute('onclick');
closeConfirmModal();
setTimeout(() => { alert("操作成功!您已进入该单元的企业预招录序列。"); }, 300);
} else {
// 显示详细的错误消息
alert(result.message || '确认失败,请稍后重试');
}
}
// API调用确认培训单元
async function confirmTrainingUnit(unitId) {
try {
const token = localStorage.getItem('duoduo_auth_token');
if (!token) {
return {
success: false,
message: '请先登录'
};
}
const response = await fetch(`${API_BASE_URL}/api/training-units/${unitId}/confirm`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
const result = await response.json();
// 返回详细的结果信息
return {
success: result.success,
message: result.message || (result.success ? '确认成功' : '操作失败')
};
} catch (error) {
console.error('确认预招录失败:', error);
return {
success: false,
message: '网络错误,请稍后重试'
};
}
}
document.getElementById('recruitConfirmModal').addEventListener('click', function(e) { if (e.target === this) closeConfirmModal(); });
// --- 资质进度弹窗逻辑 (保留) ---
function openCertModal() {
const modal = document.getElementById('certModal');
// 设定到岗时间 (示例2025-12-03)
const today = new Date();
const startDate = new Date("2025-12-03");
// 格式化日期显示
const dateStr = startDate.getFullYear() + '/' +
(startDate.getMonth() + 1).toString().padStart(2, '0') + '/' +
startDate.getDate().toString().padStart(2, '0');
// 计算天数差
const diffTime = Math.abs(today - startDate);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
// 计算百分比 (90天周期)
const totalDuration = 90;
let percentage = (diffDays / totalDuration) * 100;
if (percentage > 100) percentage = 100;
if (percentage < 0) percentage = 0;
document.getElementById('displayStartDate').innerText = dateStr;
document.getElementById('progressText').innerText = percentage.toFixed(1) + "%";
modal.classList.add('active');
const bar = document.getElementById('progressBar');
bar.style.width = '0%';
setTimeout(() => { bar.style.width = percentage + '%'; }, 50);
}
function closeCertModal() {
document.getElementById('certModal').classList.remove('active');
}
document.getElementById('certModal').addEventListener('click', function(e) {
if (e.target === this) closeCertModal();
});
</script>
</body>
</html>