Files
all-in-one-sys/3.html

842 lines
51 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<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: #05070a;
--card-bg: #11141a;
--accent-cyan: #00f0ff;
--accent-blue: #2563eb;
--accent-green: #00ff9d;
--accent-orange: #ff9d00;
--text-main: #ffffff;
--text-sub: #94a3b8;
--border-color: rgba(255,255,255,0.08);
--modal-bg: rgba(15, 19, 26, 0.98);
}
body {
background-color: var(--bg-color);
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
color: var(--text-main);
height: 100vh; overflow: hidden; position: relative;
}
/* 背景光影 */
body::before {
content: ''; position: fixed; top: -50%; left: -50%; width: 150%; height: 150%; z-index: -2;
background: radial-gradient(circle at center, rgba(0, 240, 255, 0.1) 0%, transparent 60%);
filter: blur(100px); opacity: 0.8; pointer-events: none;
}
body::after {
content: ''; position: fixed; bottom: -30%; right: -30%; width: 120%; height: 120%; z-index: -2;
background: radial-gradient(circle at center, rgba(25, 50, 150, 0.2) 0%, transparent 50%);
filter: blur(120px); opacity: 0.6; pointer-events: none;
}
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #333; border-radius: 3px; }
.commander-layout {
display: flex; flex-direction: column; height: 100vh;
max-width: 1440px; margin: 0 auto; padding: 20px 40px; box-sizing: border-box;
position: relative; z-index: 1;
}
/* --- 1. 顶部 HUD 分栏 --- */
.hud-split-wrapper {
display: flex; gap: 20px; margin-bottom: 25px; flex-shrink: 0;
}
.hud-panel {
background: rgba(17, 20, 26, 0.7); backdrop-filter: blur(20px);
border-radius: 16px; padding: 20px;
border: 1px solid var(--border-color);
box-shadow: 0 20px 40px -10px rgba(0,0,0,0.5);
display: flex; flex-direction: column;
}
.hud-left { flex: 3; }
.hud-right { flex: 1; border-color: rgba(255, 157, 0, 0.3); background: rgba(20, 15, 10, 0.7); }
.hud-header {
display: flex; justify-content: space-between; align-items: center;
margin-bottom: 15px; border-bottom: 1px solid var(--border-color); padding-bottom: 10px;
}
.hud-title-group { display: flex; align-items: center; gap: 10px; }
.hud-icon { font-size: 1.2rem; text-shadow: 0 0 10px rgba(255,255,255,0.3); }
.hud-left .hud-icon { color: var(--accent-cyan); }
.hud-right .hud-icon { color: var(--accent-orange); }
.hud-title { font-size: 1rem; font-weight: bold; letter-spacing: 1px; color: #fff; }
.hud-subtitle { font-size: 0.7rem; color: #666; margin-left: 6px; font-weight: normal; }
.slots-container { display: grid; gap: 15px; flex: 1; }
.slots-left { grid-template-columns: repeat(3, 1fr); }
.slots-right { grid-template-columns: 1fr; }
.slot-module {
height: 120px; background: rgba(0,0,0,0.3); border: 1px dashed #333; border-radius: 8px;
display: flex; flex-direction: column; justify-content: center; align-items: center;
transition: all 0.3s; position: relative; overflow: hidden;
}
.slot-module.empty:hover { border-color: #555; background: rgba(255,255,255,0.02); }
.hud-left .slot-module.filled {
background: linear-gradient(160deg, #1e232e, #13161c); border: 1px solid var(--accent-cyan);
box-shadow: 0 0 15px rgba(0, 240, 255, 0.1); cursor: pointer;
}
.hud-right .slot-module.filled {
background: linear-gradient(160deg, #2e251e, #1c1613); border: 1px solid var(--accent-orange);
box-shadow: 0 0 15px rgba(255, 157, 0, 0.2); cursor: pointer;
}
.slot-module.filled:hover { transform: translateY(-3px); }
.slot-remove-mask {
position: absolute; inset: 0; background: rgba(0,0,0,0.85); display: flex; flex-direction: column; align-items: center; justify-content: center;
opacity: 0; transition: opacity 0.2s; color: #ff4d4d;
}
.slot-module.filled:hover .slot-remove-mask { opacity: 1; }
.slot-content-title { font-size: 0.9rem; font-weight: bold; color: white; margin-bottom: 2px; text-align: center; width: 90%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.slot-content-salary { font-weight: bold; font-size: 0.85rem; font-family: 'Arial', sans-serif; }
.hud-left .slot-content-salary { color: var(--accent-cyan); }
.hud-right .slot-content-salary { color: var(--accent-orange); }
.slot-content-company { font-size: 0.7rem; color: var(--text-sub); }
.slot-index { position: absolute; top: 5px; left: 8px; font-size: 1.2rem; font-weight: 900; color: rgba(255,255,255,0.05); pointer-events: none; }
.action-btn {
width: 100%; margin-top: 15px; padding: 10px; border-radius: 6px;
font-weight: 800; font-size: 0.9rem; letter-spacing: 1px;
border: none; cursor: pointer; transition: all 0.3s;
display: flex; justify-content: center; align-items: center; gap: 8px;
opacity: 0.5; pointer-events: none; filter: grayscale(100%);
}
.action-btn.active { opacity: 1; pointer-events: auto; filter: grayscale(0%); }
.action-btn:hover { transform: scale(1.02); }
.btn-submit { background: linear-gradient(90deg, var(--accent-blue), var(--accent-cyan)); color: #000; box-shadow: 0 0 15px rgba(0, 240, 255, 0.2); }
.btn-submit.active:hover { box-shadow: 0 0 25px rgba(0, 240, 255, 0.5); color: white; }
.btn-confirm { background: linear-gradient(90deg, #d97706, var(--accent-orange)); color: #000; box-shadow: 0 0 15px rgba(255, 157, 0, 0.2); }
.btn-confirm.active:hover { box-shadow: 0 0 25px rgba(255, 157, 0, 0.5); color: white; }
/* --- 2. 列表与筛选 --- */
.list-section { flex: 1; overflow-y: auto; padding-right: 5px; }
.list-header {
display: flex; align-items: center; justify-content: space-between; margin-bottom: 15px;
border-left: 4px solid var(--accent-cyan); padding-left: 12px;
}
.list-title { font-size: 1.1rem; font-weight: bold; color: #fff; letter-spacing: 1px; }
.filter-bar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px; gap: 15px; position: relative; z-index: 40; }
.city-quick-select { display: flex; gap: 10px; align-items: center; }
.city-btn { padding: 6px 16px; border-radius: 4px; font-size: 0.85rem; color: var(--text-sub); background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.1); cursor: pointer; transition: all 0.3s; }
.city-btn:hover { background: rgba(255,255,255,0.08); color: #fff; }
.city-btn.active { background: rgba(0, 240, 255, 0.1); border-color: var(--accent-cyan); color: var(--accent-cyan); font-weight: bold; }
.more-city-btn { display: flex; align-items: center; gap: 6px; padding: 6px 16px; background: linear-gradient(145deg, #2a2e3a, #20232c); border: 1px solid var(--accent-cyan); color: var(--accent-cyan); border-radius: 4px; cursor: pointer; font-size: 0.85rem; font-weight: bold; transition: all 0.3s; }
.more-city-btn:hover { transform: translateY(-2px); box-shadow: 0 0 20px rgba(0,240,255,0.3); color: white; }
.type-selector { position: relative; min-width: 140px; }
.type-btn { width: 100%; background: linear-gradient(145deg, #1e232e, #13161c); border: 1px solid rgba(255,255,255,0.1); color: #fff; padding: 8px 15px; border-radius: 8px; font-size: 0.85rem; display: flex; justify-content: space-between; align-items: center; cursor: pointer; transition: all 0.3s; }
.type-btn:hover { border-color: var(--accent-blue); box-shadow: 0 0 15px rgba(37, 99, 235, 0.3); }
.type-dropdown { position: absolute; top: 110%; right: 0; width: 160px; z-index: 50; background: #151820; border: 1px solid var(--border-color); border-radius: 6px; box-shadow: 0 10px 30px rgba(0,0,0,0.8); padding: 5px; display: none; }
.type-dropdown.show { display: block; }
.type-option { padding: 8px 12px; font-size: 0.85rem; color: #999; cursor: pointer; border-radius: 4px; }
.type-option:hover { background: rgba(255,255,255,0.05); color: white; }
.type-option.selected { color: var(--accent-blue); background: rgba(37, 99, 235, 0.1); font-weight: bold; }
.job-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; padding-bottom: 40px; }
.job-card {
background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 12px;
padding: 24px; position: relative; cursor: pointer; transition: all 0.25s ease-out;
display: flex; flex-direction: column; justify-content: space-between; min-height: 190px; /* 增加高度以容纳按钮 */
}
.job-card:hover { border-color: rgba(0, 240, 255, 0.5); background: rgba(26, 30, 38, 0.8); transform: translateY(-5px) scale(1.01); box-shadow: 0 15px 35px rgba(0,0,0,0.4), 0 0 15px rgba(0,240,255,0.1); }
.job-card.disabled { opacity: 0.4; filter: grayscale(100%); background: #0a0c10; border-color: #333; pointer-events: none; cursor: default; transform: none !important; box-shadow: none !important; }
.card-top { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px; }
.card-icon { width: 44px; height: 44px; border-radius: 8px; background: rgba(255,255,255,0.03); display: flex; align-items: center; justify-content: center; font-size: 1.2rem; color: var(--text-sub); transition: color 0.3s; }
.job-card:hover .card-icon { color: var(--accent-cyan); background: rgba(0, 240, 255, 0.05); }
.card-salary { color: var(--accent-cyan); font-weight: bold; font-size: 1rem; }
.card-title { font-size: 1.1rem; font-weight: bold; color: #fff; margin-bottom: 6px; }
.card-company { font-size: 0.85rem; color: var(--text-sub); display: flex; align-items: center; gap: 6px; }
.card-tags { margin-top: 12px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
.tag { font-size: 0.75rem; padding: 3px 8px; border-radius: 4px; background: rgba(255,255,255,0.03); color: #888; border: 1px solid rgba(255,255,255,0.02); }
.type-badge {
display: inline-block; font-size: 0.75rem; padding: 3px 8px; border-radius: 4px;
margin-right: 6px; font-weight: bold; letter-spacing: 0.5px;
}
.type-produce { background: rgba(37, 99, 235, 0.15); color: #60a5fa; border: 1px solid rgba(37, 99, 235, 0.3); }
.type-service { background: rgba(0, 255, 157, 0.1); color: #34d399; border: 1px solid rgba(0, 255, 157, 0.3); }
.check-mark { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: rgba(0,0,0,0.6); color: var(--accent-cyan); font-size: 2rem; opacity: 0; transition: all 0.3s; pointer-events: none; z-index: 10; }
.job-card.disabled .check-mark { opacity: 1; }
/* 名额角标 */
.quota-badge {
position: absolute; top: 0; right: 0;
background: rgba(255, 157, 0, 0.15); border-bottom-left-radius: 12px;
padding: 4px 10px; border-left: 1px solid rgba(255, 157, 0, 0.3); border-bottom: 1px solid rgba(255, 157, 0, 0.3);
font-size: 0.75rem; color: var(--accent-orange); font-weight: bold; letter-spacing: 0.5px;
}
/* --- 新增:详情按钮 --- */
.btn-detail {
width: 100%;
padding: 8px 0;
border: 1px solid rgba(255,255,255,0.1);
background: rgba(255,255,255,0.03);
color: var(--text-sub);
font-size: 0.8rem;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s;
margin-top: auto; /* 推到底部 */
display: flex; align-items: center; justify-content: center; gap: 6px;
}
.btn-detail:hover {
border-color: var(--accent-cyan);
color: var(--accent-cyan);
background: rgba(0, 240, 255, 0.05);
}
/* --- 模态框通用 --- */
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.85); backdrop-filter: blur(8px); z-index: 100; display: flex; align-items: center; justify-content: center; opacity: 0; pointer-events: none; transition: opacity 0.3s; }
.modal-overlay.show { opacity: 1; pointer-events: auto; }
/* 城市选择模态框 */
.city-modal { width: 900px; max-width: 90vw; height: 600px; background: #1a1e26; border: 1px solid var(--border-color); border-radius: 12px; box-shadow: 0 20px 60px rgba(0,0,0,0.8); display: flex; flex-direction: column; }
/* --- 新增:岗位详情模态框 --- */
.detail-modal {
width: 1000px; max-width: 95vw; height: 80vh;
background: #11141a; border: 1px solid var(--border-color); border-radius: 16px;
box-shadow: 0 0 50px rgba(0,0,0,0.9), 0 0 0 1px rgba(0, 240, 255, 0.1);
display: flex; flex-direction: column; overflow: hidden;
position: relative;
}
.detail-header {
padding: 24px 30px;
background: linear-gradient(90deg, rgba(0, 240, 255, 0.05), transparent);
border-bottom: 1px solid var(--border-color);
display: flex; justify-content: space-between; align-items: flex-start;
}
.detail-title-area { flex: 1; }
.detail-job-title { font-size: 1.8rem; font-weight: bold; color: white; margin-bottom: 8px; display: flex; align-items: center; gap: 15px; }
.detail-salary-tag { font-size: 1.2rem; color: var(--accent-cyan); font-family: 'Arial', sans-serif; background: rgba(0, 240, 255, 0.1); padding: 2px 12px; border-radius: 4px; border: 1px solid rgba(0, 240, 255, 0.3); }
.detail-company-name { font-size: 1rem; color: var(--text-sub); display: flex; align-items: center; gap: 8px; }
.detail-body { display: flex; flex: 1; overflow: hidden; }
/* 左侧:核心参数栏 */
.detail-sidebar {
width: 320px; background: rgba(0,0,0,0.2); border-right: 1px solid var(--border-color);
padding: 25px; overflow-y: auto; display: flex; flex-direction: column; gap: 20px;
}
.param-group { background: rgba(255,255,255,0.03); padding: 15px; border-radius: 8px; border: 1px solid rgba(255,255,255,0.05); }
.param-label { color: #666; font-size: 0.8rem; margin-bottom: 5px; text-transform: uppercase; letter-spacing: 1px; }
.param-value { color: white; font-weight: bold; font-size: 0.95rem; display: flex; align-items: center; gap: 8px; }
.param-icon { width: 24px; text-align: center; color: var(--accent-blue); }
/* 右侧:详细描述 */
.detail-content { flex: 1; padding: 30px; overflow-y: auto; }
.section-title { font-size: 1.1rem; font-weight: bold; color: white; margin-bottom: 15px; padding-left: 10px; border-left: 3px solid var(--accent-cyan); display: flex; align-items: center; gap: 10px; }
.req-list { list-style: none; padding: 0; margin-bottom: 30px; }
.req-item { position: relative; padding-left: 20px; margin-bottom: 10px; color: #ccc; line-height: 1.6; font-size: 0.95rem; }
.req-item::before { content: '▹'; position: absolute; left: 0; color: var(--accent-cyan); }
.welfare-grid { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 30px; }
.welfare-tag { background: rgba(37, 99, 235, 0.1); border: 1px solid rgba(37, 99, 235, 0.3); color: #93c5fd; padding: 6px 12px; border-radius: 20px; font-size: 0.85rem; }
.company-intro { color: #999; line-height: 1.7; font-size: 0.9rem; text-align: justify; }
.modal-close-btn {
width: 36px; height: 36px; display: flex; align-items: center; justify-content: center;
border-radius: 50%; background: rgba(255,255,255,0.1); color: white; cursor: pointer; transition: all 0.2s;
}
.modal-close-btn:hover { background: #ff4d4d; transform: rotate(90deg); }
/* Modal 内部滚动条 */
.detail-sidebar::-webkit-scrollbar, .detail-content::-webkit-scrollbar { width: 5px; }
.detail-sidebar::-webkit-scrollbar-thumb, .detail-content::-webkit-scrollbar-thumb { background: #333; border-radius: 3px; }
/* Modal 通用样式补丁 */
.modal-header { padding: 15px 25px; border-bottom: 1px solid #333; display: flex; justify-content: space-between; align-items: center; background: #151820; }
.modal-title { font-size: 1.1rem; font-weight: bold; color: white; letter-spacing: 1px; }
.modal-body { display: flex; flex: 1; overflow: hidden; }
.region-sidebar { width: 160px; background: #111; border-right: 1px solid #333; overflow-y: auto; }
.region-item { padding: 15px 20px; color: #888; cursor: pointer; border-left: 3px solid transparent; transition: all 0.2s; }
.region-item:hover { color: white; background: #222; }
.region-item.active { background: #222; color: var(--accent-cyan); border-left-color: var(--accent-cyan); font-weight: bold; }
.city-grid-area { flex: 1; padding: 25px; overflow-y: auto; background: #1a1e26; }
.city-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); gap: 12px; }
.city-option { padding: 8px; text-align: center; border-radius: 4px; background: #252a33; cursor: pointer; color: #ccc; font-size: 0.9rem; transition: all 0.2s; }
.city-option:hover { background: #333; color: white; transform: translateY(-2px); border: 1px solid var(--accent-cyan); }
</style>
</head>
<body>
<div class="commander-layout">
<div class="hud-split-wrapper">
<div class="hud-panel hud-left">
<div class="hud-header">
<div class="hud-title-group">
<i class="fa-solid fa-cube hud-icon"></i>
<div>
<div class="hud-title">我的意向过渡岗位</div>
<span class="hud-subtitle">INTENDED POSITIONS</span>
</div>
</div>
<div class="text-gray-500 font-mono text-sm">
已选: <span id="count-left" class="text-cyan-400 font-bold text-lg">0</span> / 3
</div>
</div>
<div class="slots-container slots-left" id="slots-left"></div>
<button id="btn-submit-intent" class="action-btn btn-submit">
提交意向清单 <i class="fa-solid fa-cloud-arrow-up"></i>
</button>
</div>
<div class="hud-panel hud-right">
<div class="hud-header">
<div class="hud-title-group">
<i class="fa-solid fa-star hud-icon"></i>
<div>
<div class="hud-title">过渡岗位确认</div>
<span class="hud-subtitle">FINAL LOCK</span>
</div>
</div>
</div>
<div class="slots-container slots-right" id="slots-right"></div>
<button id="btn-confirm-final" class="action-btn btn-confirm">
确认锁定 <i class="fa-solid fa-lock"></i>
</button>
</div>
</div>
<section class="list-section custom-scrollbar">
<div class="list-header">
<div class="list-title">岗位资源库</div>
</div>
<div class="filter-bar">
<div class="city-quick-select" id="city-quick-select"></div>
<div class="type-selector" id="type-selector">
<button class="type-btn" onclick="toggleTypeDropdown()">
<span id="current-type">全部类型</span>
<i class="fa-solid fa-chevron-down text-xs text-gray-500"></i>
</button>
<div class="type-dropdown" id="type-dropdown"></div>
</div>
</div>
<div class="job-grid" id="job-grid"></div>
</section>
</div>
<div class="modal-overlay" id="city-modal-overlay">
<div class="city-modal">
<div class="modal-header">
<div class="modal-title">选择城市</div>
<div class="modal-close-btn" onclick="closeCityModal()"><i class="fa-solid fa-xmark"></i></div>
</div>
<div class="modal-body">
<ul class="region-sidebar" id="region-sidebar"></ul>
<div class="city-grid-area">
<div class="city-grid" id="city-grid"></div>
</div>
</div>
</div>
</div>
<div class="modal-overlay" id="detail-modal-overlay">
<div class="detail-modal">
<div class="detail-header">
<div class="detail-title-area">
<div class="detail-job-title">
<span id="detail-title">岗位名称</span>
<span id="detail-salary" class="detail-salary-tag">4K-6K</span>
</div>
<div class="detail-company-name">
<i class="fa-regular fa-building"></i> <span id="detail-company">公司名称</span>
<span class="text-gray-600 mx-2">|</span>
<span id="detail-type" class="text-blue-400">岗位类型</span>
</div>
</div>
<div class="modal-close-btn" onclick="closeDetailModal()"><i class="fa-solid fa-xmark"></i></div>
</div>
<div class="detail-body">
<div class="detail-sidebar">
<div class="param-group">
<div class="param-label">到岗时间</div>
<div class="param-value"><i class="fa-regular fa-calendar param-icon"></i> <span id="detail-start-date">--</span></div>
</div>
<div class="param-group">
<div class="param-label">工作周期</div>
<div class="param-value"><i class="fa-solid fa-rotate param-icon"></i> <span id="detail-duration">--</span></div>
</div>
<div class="param-group">
<div class="param-label">报道地点</div>
<div class="param-value"><i class="fa-solid fa-location-dot param-icon"></i> <span id="detail-location">--</span></div>
</div>
<div class="param-group">
<div class="param-label">吃住情况</div>
<div class="param-value"><i class="fa-solid fa-utensils param-icon"></i> <span id="detail-roomboard">--</span></div>
</div>
<div class="param-group">
<div class="param-label">剩余名额</div>
<div class="param-value text-orange-500"><i class="fa-solid fa-users param-icon text-orange-500"></i> <span id="detail-quota">--</span></div>
</div>
</div>
<div class="detail-content">
<div class="section-title"><i class="fa-solid fa-list-check"></i> 岗位要求</div>
<ul class="req-list" id="detail-requirements">
</ul>
<div class="section-title"><i class="fa-solid fa-gift"></i> 福利待遇</div>
<div class="welfare-grid" id="detail-benefits">
</div>
<div class="section-title"><i class="fa-regular fa-building"></i> 企业介绍</div>
<div class="company-intro" id="detail-company-intro">
</div>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script>
// --- 1. 全量城市数据 ---
const regionData = {
"热门城市": ["全部", "北京市", "上海市", "广州市", "深圳市", "成都市", "杭州市", "武汉市", "苏州市", "南京市", "重庆市", "天津市", "西安市"],
"直辖市": ["北京市", "上海市", "天津市", "重庆市"],
"广东省": ["广州市", "深圳市", "珠海市", "汕头市", "佛山市", "韶关市", "湛江市", "肇庆市", "江门市", "茂名市", "惠州市", "梅州市", "汕尾市", "河源市", "阳江市", "清远市", "东莞市", "中山市", "潮州市", "揭阳市", "云浮市"],
"江苏省": ["南京市", "无锡市", "徐州市", "常州市", "苏州市", "南通市", "连云港市", "淮安市", "盐城市", "扬州市", "镇江市", "泰州市", "宿迁市"],
"浙江省": ["杭州市", "宁波市", "温州市", "嘉兴市", "湖州市", "绍兴市", "金华市", "衢州市", "舟山市", "台州市", "丽水市"],
"山东省": ["济南市", "青岛市", "淄博市", "枣庄市", "东营市", "烟台市", "潍坊市", "济宁市", "泰安市", "威海市", "日照市", "临沂市", "德州市", "聊城市", "滨州市", "菏泽市"],
"四川省": ["成都市", "自贡市", "攀枝花市", "泸州市", "德阳市", "绵阳市", "广元市", "遂宁市", "内江市", "乐山市", "南充市", "眉山市", "宜宾市", "广安市", "达州市", "雅安市", "巴中市", "资阳市"],
"河南省": ["郑州市", "开封市", "洛阳市", "平顶山市", "安阳市", "鹤壁市", "新乡市", "焦作市", "濮阳市", "许昌市", "漯河市", "三门峡市", "南阳市", "商丘市", "信阳市", "周口市", "驻马店市"],
"湖北省": ["武汉市", "黄石市", "十堰市", "宜昌市", "襄阳市", "鄂州市", "荆门市", "孝感市", "荆州市", "黄冈市", "咸宁市", "随州市", "恩施州"],
"湖南省": ["长沙市", "株洲市", "湘潭市", "衡阳市", "邵阳市", "岳阳市", "常德市", "张家界市", "益阳市", "郴州市", "永州市", "怀化市", "娄底市"],
"福建省": ["福州市", "厦门市", "莆田市", "三明市", "泉州市", "漳州市", "南平市", "龙岩市", "宁德市"],
"安徽省": ["合肥市", "芜湖市", "蚌埠市", "淮南市", "马鞍山市", "淮北市", "铜陵市", "安庆市", "黄山市", "滁州市", "阜阳市", "宿州市", "六安市", "亳州市", "池州市", "宣城市"],
"河北省": ["石家庄市", "唐山市", "秦皇岛市", "邯郸市", "邢台市", "保定市", "张家口市", "承德市", "沧州市", "廊坊市", "衡水市"],
"陕西省": ["西安市", "铜川市", "宝鸡市", "咸阳市", "渭南市", "延安市", "汉中市", "榆林市", "安康市", "商洛市"],
"辽宁省": ["沈阳市", "大连市", "鞍山市", "抚顺市", "本溪市", "丹东市", "锦州市", "营口市", "阜新市", "辽阳市", "盘锦市", "铁岭市", "朝阳市", "葫芦岛市"]
};
// --- 2. 岗位数据 (已扩展详情字段) ---
// 使用 CSV 中的第一条真实数据演示,其他为模拟数据
const allJobs = [
{
id: 1,
title: "自动化技术员",
company: "恒力集团",
salary: "4K-6K",
icon: "fa-microchip",
tags: ["苏州", "包吃住"],
type: "生产类岗位",
city: "苏州市",
quota: 150,
occupied: 45,
// --- 详情字段 ---
startDate: "2026/3/5",
reportLocation: "江苏省苏州市吴江区盛泽镇南麻恒力路1号",
duration: "3个月",
roomBoard: "包吃包住",
requirements: "电气、自动化或相关专业,大专及以上学历;\n熟悉 PLC继电器电气控制原理能独立完成设备电气线路安装与调试\n有自动化设备维护、故障分析经验者优先\n工作认真负责有团队协作精神。",
benefits: ["五险一金", "年终奖", "项目奖金", "单休", "员工宿舍", "绩效奖金"],
companyIntro: "恒力集团有限公司成立于1994年总部位于江苏省苏州市吴江区是立足实业发展的全球化民营企业。集团注册资产达520亿元人民币全球员工总数超12万人2022年实现营业收入6117亿元连续七年跻身世界500强企业榜单。公司以石化、聚酯新材料、纺织为主业构建形成“原油-芳烃-乙烯-精对苯二甲酸PTA-聚酯-纺织”全产业链布局。"
},
{
id: 2, title: "跨境电商运营总监", company: "SHEIN", salary: "40-70k", icon: "fa-globe", tags: ["广州", "欧美"], type: "服务类岗位", city: "广州市", quota: 2, occupied: 1,
startDate: "2025/12/1", reportLocation: "广州市番禺区万博商务区", duration: "长期", roomBoard: "提供餐补", requirements: "5年以上跨境电商运营经验\n英语流利可作为工作语言\n具备优秀的团队管理能力。", benefits: ["股票期权", "带薪年假", "年度旅游"], companyIntro: "SHEIN是一家全球领先的时尚和生活方式在线零售商致力于让“人人尽享时尚之美”。"
},
{
id: 3, title: "AI 大模型算法专家", company: "未来智能", salary: "50-80k", icon: "fa-brain", tags: ["北京", "NLP"], type: "生产类岗位", city: "北京市", quota: 3, occupied: 3,
startDate: "2025/11/15", reportLocation: "北京市海淀区中关村软件园", duration: "长期", roomBoard: "不包吃住", requirements: "计算机相关专业博士学历;\n在NLP领域有顶级会议论文发表\n熟悉PyTorch/TensorFlow。", benefits: ["补充医疗保险", "弹性工作", "定期体检"], companyIntro: "未来智能致力于构建通用人工智能,为人类社会带来变革性的技术进步。"
},
{
id: 4, title: "资深产品经理", company: "字节跳动", salary: "30-55k", icon: "fa-cube", tags: ["上海", "SaaS"], type: "生产类岗位", city: "上海市", quota: 4, occupied: 2,
startDate: "尽快", reportLocation: "上海市闵行区宜山路", duration: "长期", roomBoard: "免费三餐", requirements: "3年以上B端产品经验\n逻辑思维清晰具备优秀的数据分析能力。", benefits: ["房补", "免费健身房", "下午茶"], companyIntro: "字节跳动是最早将人工智能应用于移动互联网场景的科技企业之一。"
},
{
id: 5, title: "供应链数据分析师", company: "恒力集团", salary: "18-30k", icon: "fa-chart-pie", tags: ["大连", "SQL"], type: "服务类岗位", city: "大连市", quota: 8, occupied: 5,
startDate: "2026/1/10", reportLocation: "大连市长兴岛经济区", duration: "1年", roomBoard: "提供宿舍", requirements: "统计学或数学相关专业;\n精通SQL/Python\n对数字敏感。", benefits: ["五险一金", "班车接送"], companyIntro: "恒力石化(大连)有限公司是恒力集团在东北地区的重要产业基地。"
},
{ id: 6, title: "嵌入式系统架构师", company: "科沃斯", salary: "35-60k", icon: "fa-microchip", tags: ["苏州", "ROS"], type: "生产类岗位", city: "苏州市", quota: 1, occupied: 0, startDate: "2025/12/20", reportLocation: "苏州市吴中区石湖西路", duration: "长期", roomBoard: "餐补", requirements: "熟悉嵌入式Linux开发\n精通C/C++。", benefits: ["年终奖", "股票期权"], companyIntro: "科沃斯机器人是全球最早的服务机器人研发与生产商之一。" },
{ id: 7, title: "HRBP (研发向)", company: "阿里巴巴", salary: "25-40k", icon: "fa-users", tags: ["杭州", "OD"], type: "服务类岗位", city: "杭州市", quota: 2, occupied: 1, startDate: "2025/11/30", reportLocation: "杭州市余杭区文一西路", duration: "长期", roomBoard: "餐补", requirements: "5年以上HR经验\n熟悉互联网研发团队特点。", benefits: ["主要看阿里福报"], companyIntro: "阿里巴巴集团旨在构建未来的商业基础设施。" },
{ id: 8, title: "高级前端工程师", company: "微软", salary: "30-50k", icon: "fa-code", tags: ["苏州", "React"], type: "生产类岗位", city: "苏州市", quota: 6, occupied: 4, startDate: "2026/2/1", reportLocation: "苏州市工业园区星湖街", duration: "长期", roomBoard: "不包", requirements: "精通React/Vue\n英语读写流利。", benefits: ["15天年假", "补充医疗"], companyIntro: "微软(中国)有限公司是微软公司在中国设立的子公司。" },
{ id: 9, title: "品牌视觉设计专家", company: "腾讯", salary: "25-45k", icon: "fa-pen-nib", tags: ["深圳", "C4D"], type: "生产类岗位", city: "深圳市", quota: 3, occupied: 2, startDate: "2025/12/15", reportLocation: "深圳市南山区深南大道", duration: "长期", roomBoard: "班车", requirements: "美术类专业;\n精通C4D/PS/AI。", benefits: ["Q币", "公仔"], companyIntro: "腾讯是一家世界领先的互联网科技公司。" },
{ id: 10, title: "财务主管", company: "美团", salary: "20-35k", icon: "fa-calculator", tags: ["北京", "CPA"], type: "服务类岗位", city: "北京市", quota: 2, occupied: 0, startDate: "2026/1/5", reportLocation: "北京市朝阳区望京东路", duration: "长期", roomBoard: "餐补", requirements: "持有CPA证书\n3年以上财务主管经验。", benefits: ["六险一金"], companyIntro: "美团的使命是“帮大家吃得更好,生活更好”。" },
{ id: 11, title: "新媒体运营", company: "小红书", salary: "15-25k", icon: "fa-hashtag", tags: ["上海", "营销"], type: "服务类岗位", city: "上海市", quota: 10, occupied: 8, startDate: "2025/11/25", reportLocation: "上海市黄浦区马当路", duration: "长期", roomBoard: "下午茶", requirements: "网感好;\n熟悉小红书平台规则。", benefits: ["宠物友好"], companyIntro: "小红书是年轻人的生活方式平台。" },
{ id: 12, title: "游戏客户端开发", company: "米哈游", salary: "30-60k", icon: "fa-gamepad", tags: ["上海", "Unity"], type: "生产类岗位", city: "上海市", quota: 5, occupied: 1, startDate: "2025/12/10", reportLocation: "上海市徐汇区宜山路", duration: "长期", roomBoard: "免费晚餐", requirements: "热爱二次元;\n精通Unity3D。", benefits: ["免费咖啡", "年会大奖"], companyIntro: "技术宅拯救世界。" }
];
// --- 状态管理 ---
let selectedJobs = [];
let filterState = { city: "全部", type: "全部" };
let currentRegion = "热门城市";
const MAX_SELECTION = 4;
// --- DOM ---
const slotsLeft = document.getElementById('slots-left');
const slotsRight = document.getElementById('slots-right');
const jobGrid = document.getElementById('job-grid');
const countLeft = document.getElementById('count-left');
const btnSubmit = document.getElementById('btn-submit-intent');
const btnConfirm = document.getElementById('btn-confirm-final');
const cityModalOverlay = document.getElementById('city-modal-overlay');
const detailModalOverlay = document.getElementById('detail-modal-overlay');
// 1. 初始化槽位
function initSlots() {
slotsLeft.innerHTML = '';
slotsRight.innerHTML = '';
for (let i = 0; i < 3; i++) createSlot(i, slotsLeft);
createSlot(3, slotsRight);
}
function createSlot(index, container) {
const slot = document.createElement('div');
slot.className = 'slot-module empty';
slot.id = `slot-${index}`;
slot.onclick = () => removeJobByIndex(index);
const iconClass = index === 3 ? "fa-star text-yellow-500 opacity-30" : "fa-plus text-gray-500 opacity-20";
const text = index === 3 ? "最终确认位" : "意向岗位";
slot.innerHTML = `
<div class="slot-index">0${index+1}</div>
<i class="fa-solid ${iconClass} text-2xl mb-2"></i>
<div class="text-xs text-gray-600 font-bold tracking-widest">${text}</div>
`;
container.appendChild(slot);
}
// 2. 初始化筛选器
function initFilters() {
const types = ["全部", "生产类岗位", "服务类岗位"];
const quickCities = regionData["热门城市"].slice(0, 5);
const cityQuickContainer = document.getElementById('city-quick-select');
const renderQuickCities = () => {
cityQuickContainer.innerHTML = '';
quickCities.forEach(city => {
const btn = document.createElement('div');
btn.className = `city-btn ${filterState.city === city ? 'active' : ''}`;
btn.innerText = city;
btn.onclick = () => {
filterState.city = city;
renderQuickCities();
renderJobGrid();
};
cityQuickContainer.appendChild(btn);
});
const moreBtn = document.createElement('div');
moreBtn.className = 'more-city-btn';
moreBtn.innerHTML = `<span>${filterState.city === '全部' || quickCities.includes(filterState.city) ? '切换城市' : filterState.city}</span> <i class="fa-solid fa-location-crosshairs"></i>`;
moreBtn.onclick = openCityModal;
cityQuickContainer.appendChild(moreBtn);
};
renderQuickCities();
const typeContainer = document.getElementById('type-dropdown');
typeContainer.innerHTML = '';
types.forEach(type => {
const option = document.createElement('div');
option.className = `type-option ${type === '全部' ? 'selected' : ''}`;
option.innerHTML = `<span>${type}</span>`;
option.onclick = () => {
document.getElementById('current-type').innerText = type === '全部' ? '全部类型' : type;
document.querySelectorAll('.type-option').forEach(el => el.classList.remove('selected'));
option.classList.add('selected');
toggleTypeDropdown();
filterState.type = type;
renderJobGrid();
};
typeContainer.appendChild(option);
});
document.addEventListener('click', (e) => {
if (!document.getElementById('type-selector').contains(e.target)) {
document.getElementById('type-dropdown').classList.remove('show');
document.querySelector('.type-btn').classList.remove('active');
}
if (e.target === cityModalOverlay) closeCityModal();
if (e.target === detailModalOverlay) closeDetailModal();
});
}
function toggleTypeDropdown() {
document.getElementById('type-dropdown').classList.toggle('show');
document.querySelector('.type-btn').classList.toggle('active');
}
// --- 城市模态框 ---
function openCityModal() {
cityModalOverlay.classList.add('show');
renderRegionSidebar();
renderCityGrid(currentRegion);
}
function closeCityModal() { cityModalOverlay.classList.remove('show'); }
function renderRegionSidebar() {
const sidebar = document.getElementById('region-sidebar');
sidebar.innerHTML = '';
Object.keys(regionData).forEach(region => {
const item = document.createElement('li');
item.className = `region-item ${currentRegion === region ? 'active' : ''}`;
let icon = '';
if (region === '热门城市') icon = '<i class="fa-solid fa-fire text-red-500 mr-2"></i>';
else if (region === '直辖市') icon = '<i class="fa-solid fa-star text-yellow-500 mr-2"></i>';
item.innerHTML = `${icon}${region}`;
item.onclick = () => {
currentRegion = region;
renderRegionSidebar();
renderCityGrid(region);
document.querySelector('.city-grid-area').scrollTop = 0;
};
sidebar.appendChild(item);
});
}
function renderCityGrid(region) {
const grid = document.getElementById('city-grid');
grid.innerHTML = '';
const cities = regionData[region] || [];
cities.forEach(city => {
const item = document.createElement('div');
item.className = `city-option ${filterState.city === city ? 'selected' : ''}`;
item.innerText = city;
item.onclick = () => {
filterState.city = city;
closeCityModal();
initFilters();
renderJobGrid();
};
grid.appendChild(item);
});
}
// --- 详情模态框逻辑 (新增) ---
function openJobDetail(event, id) {
event.stopPropagation(); // 阻止冒泡,避免触发选卡
const job = allJobs.find(j => j.id === id);
if(!job) return;
// 填充数据
document.getElementById('detail-title').innerText = job.title;
document.getElementById('detail-salary').innerText = job.salary;
document.getElementById('detail-company').innerText = job.company;
document.getElementById('detail-type').innerText = job.type;
// 左侧参数
document.getElementById('detail-start-date').innerText = job.startDate || "待定";
document.getElementById('detail-duration').innerText = job.duration || "长期";
document.getElementById('detail-location').innerText = job.reportLocation || job.city;
document.getElementById('detail-roomboard').innerText = job.roomBoard || "不提供";
document.getElementById('detail-quota').innerText = `已招 ${job.occupied} / 共 ${job.quota} 人`;
// 右侧列表:岗位要求 (处理换行符)
const reqList = document.getElementById('detail-requirements');
reqList.innerHTML = '';
if(job.requirements) {
const reqs = job.requirements.split('\n');
reqs.forEach(req => {
if(req.trim()){
const li = document.createElement('li');
li.className = 'req-item';
li.innerText = req.trim();
reqList.appendChild(li);
}
});
} else {
reqList.innerHTML = '<li class="req-item">暂无详细要求</li>';
}
// 右侧列表:福利待遇
const benefitsContainer = document.getElementById('detail-benefits');
benefitsContainer.innerHTML = '';
if(job.benefits && job.benefits.length > 0) {
job.benefits.forEach(b => {
const tag = document.createElement('span');
tag.className = 'welfare-tag';
tag.innerText = b;
benefitsContainer.appendChild(tag);
});
} else {
benefitsContainer.innerHTML = '<span class="text-gray-500 text-sm">暂无福利信息</span>';
}
// 企业介绍
document.getElementById('detail-company-intro').innerText = job.companyIntro || "暂无企业介绍。";
// 显示
detailModalOverlay.classList.add('show');
}
function closeDetailModal() {
detailModalOverlay.classList.remove('show');
}
// 3. 渲染岗位网格 (包含详情按钮)
function renderJobGrid() {
jobGrid.innerHTML = '';
const filteredJobs = allJobs.filter(job => {
const matchCity = filterState.city === "全部" || job.city === filterState.city;
const matchType = filterState.type === "全部" || job.type === filterState.type;
return matchCity && matchType;
});
if (filteredJobs.length === 0) {
jobGrid.innerHTML = `<div class="col-span-3 text-center py-10 text-gray-600"><p>暂无匹配岗位</p></div>`;
return;
}
filteredJobs.forEach(job => {
const isSelected = selectedJobs.includes(job.id);
const card = document.createElement('div');
card.className = `job-card ${isSelected ? 'disabled' : ''}`;
card.id = `job-card-${job.id}`;
// 点击卡片本体还是选人
card.onclick = () => selectJob(job.id);
const typeClass = job.type === "生产类岗位" ? "type-produce" : "type-service";
const typeLabelHtml = `<span class="type-badge ${typeClass}">${job.type}</span>`;
const tagsHtml = job.tags.map(t => `<span class="tag">${t}</span>`).join('');
card.innerHTML = `
<div class="quota-badge">已选 ${job.occupied} / ${job.quota}</div>
<div class="card-top">
<div class="card-icon"><i class="fa-solid ${job.icon}"></i></div>
<div class="card-salary">${job.salary}</div>
</div>
<div>
<div class="card-title">${job.title}</div>
<div class="card-company"><i class="fa-regular fa-building"></i> ${job.company}</div>
<div class="card-tags">
${typeLabelHtml}
${tagsHtml}
</div>
</div>
<button class="btn-detail" onclick="openJobDetail(event, ${job.id})">
<i class="fa-regular fa-eye"></i> 查看详情
</button>
<div class="check-mark"><i class="fa-solid fa-circle-check"></i></div>
`;
jobGrid.appendChild(card);
});
}
// --- 核心交互逻辑 ---
function selectJob(id) {
if (selectedJobs.includes(id)) return;
if (selectedJobs.length >= MAX_SELECTION) {
gsap.fromTo([slotsLeft, slotsRight], { x: -5 }, { x: 0, duration: 0.4, ease: "elastic.out(1, 0.3)" });
return;
}
selectedJobs.push(id);
updateUI(true, id);
}
function removeJobByIndex(index) {
if (index >= selectedJobs.length) return;
const removedId = selectedJobs[index];
selectedJobs.splice(index, 1);
updateUI(false, removedId);
}
function updateUI(isAdding, targetId) {
for (let i = 0; i < MAX_SELECTION; i++) {
const slot = document.getElementById(`slot-${i}`);
const jobId = selectedJobs[i];
if (jobId) {
const job = allJobs.find(j => j.id === jobId);
if (slot.classList.contains('empty') || slot.dataset.lastId != jobId) {
slot.className = 'slot-module filled';
slot.dataset.lastId = jobId;
const isFinal = (i === 3);
const removeText = isFinal ? "撤销确认" : "移除意向";
slot.innerHTML = `
<div class="slot-index">0${i+1}</div>
<div class="slot-content-title">${job.title}</div>
<div class="slot-content-salary">${job.salary}</div>
<div class="slot-content-company">${job.company}</div>
<div class="slot-remove-mask">
<i class="fa-solid fa-xmark text-2xl mb-2"></i>
<span class="text-xs font-bold tracking-widest">${removeText}</span>
</div>
`;
if(isAdding && i === selectedJobs.length - 1) {
gsap.fromTo(slot, { y: -30, opacity: 0, scale: 0.8 }, { y: 0, opacity: 1, scale: 1, duration: 0.5, ease: "back.out(1.5)" });
}
}
} else {
if (!slot.classList.contains('empty')) {
slot.className = 'slot-module empty';
delete slot.dataset.lastId;
const isFinal = (i === 3);
const iconClass = isFinal ? "fa-star text-yellow-500 opacity-30" : "fa-plus text-gray-500 opacity-20";
const text = isFinal ? "最终确认位" : "意向岗位";
slot.innerHTML = `<div class="slot-index">0${i+1}</div><i class="fa-solid ${iconClass} text-2xl mb-2"></i><div class="text-xs text-gray-600 font-bold tracking-widest">${text}</div>`;
}
}
}
if (targetId) {
const card = document.getElementById(`job-card-${targetId}`);
if (card) {
if (isAdding) {
card.classList.add('disabled');
gsap.to(card, { scale: 0.92, opacity: 0.3, duration: 0.3, ease: "power2.out" });
} else {
card.classList.remove('disabled');
gsap.to(card, { scale: 1, opacity: 1, duration: 0.4, ease: "back.out(1.2)", clearProps: "all" });
}
}
}
const hasIntent = selectedJobs.length > 0;
countLeft.innerText = Math.min(selectedJobs.length, 3);
if (hasIntent) btnSubmit.classList.add('active');
else btnSubmit.classList.remove('active');
const hasFinal = selectedJobs.length === 4;
if (hasFinal) btnConfirm.classList.add('active');
else btnConfirm.classList.remove('active');
}
initSlots();
initFilters();
renderJobGrid();
</script>
</body>
</html>