Files
TermiNexus 14902a404d chore(ccgo): 以 Vue3 做题站替换 TempLate/CCGO 原生页面并清理 www 残留
CCGO 构建产物部署至 TempLate/CCGO(旧文件移至 backup/ccgo);GVSite 已迁移残留的 Invite/Errors 旧页移至 backup/www;.gitignore 排除新工程
2026-08-11 01:41:39 +08:00

1107 lines
50 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.
<style>
/* ==================== 1. 变量定义 ==================== */
:root {
--primary-color: #1e3a8a; /* 深蓝 */
--primary-light: #3b82f6; /* 亮蓝 */
--accent-color: #d4af37; /* 金色 */
--bg-color: #f0f4f8; /* 背景灰蓝 */
--card-bg: #ffffff;
--text-main: #1e293b;
--text-sub: #64748b;
--border-color: #e2e8f0;
--shadow-soft: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);
--shadow-hover: 0 10px 15px -3px rgba(0, 0, 0, 0.08), 0 4px 6px -2px rgba(0, 0, 0, 0.04);
--transition: all 0.2s ease-out;
--error: #ef4444;
--radius: 0.75rem;
}
/* ==================== 2. 布局容器 ==================== */
.container-galaxy {
max-width: 1400px;
margin: 0 auto;
padding: 1rem;
width: 100%;
}
.glass-card {
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: var(--radius);
padding: 1.5rem;
margin-bottom: 1.5rem;
box-shadow: var(--shadow-soft);
transition: var(--transition);
}
.glass-card:hover {
box-shadow: var(--shadow-hover);
}
.grid-layout {
display: grid;
gap: 1.25rem;
grid-template-columns: 1fr;
}
/* 响应式断点 */
@media (min-width: 640px) {
.grid-layout { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
.grid-layout { grid-template-columns: repeat(4, 1fr); }
}
/* ==================== 3. 排版与标题 ==================== */
.section-title {
font-size: 1.1rem;
font-weight: 700;
color: var(--primary-color);
margin-bottom: 1.25rem;
display: flex;
align-items: center;
gap: 0.5rem;
padding-bottom: 0.75rem;
border-bottom: 1px dashed var(--border-color);
}
.svg-icon {
width: 1.2em;
height: 1.2em;
fill: currentColor;
color: var(--primary-light);
}
.header-box { text-align: center; justify-items: center; margin-bottom: 2rem; padding-top: 1rem; }
h1 {
font-size: 2rem;
background: linear-gradient(to right, var(--primary-color), var(--accent-color));
-webkit-background-clip: text;
color: transparent;
margin: 0.5rem 0;
}
.subtitle { color: var(--text-sub); font-size: 0.9rem; margin-top: 0.25rem; }
/* ==================== 4. 表单控件 ==================== */
.input-group { margin-bottom: 0.5rem; }
.label-text {
display: block;
font-size: 0.85rem;
font-weight: 600;
color: var(--text-sub);
margin-bottom: 0.4rem;
}
.required-mark { color: var(--error); margin-left: 2px; }
.custom-input {
width: 100%;
padding: 0.6rem 0.8rem;
border: 1px solid var(--border-color);
border-radius: 0.5rem;
font-size: 0.95rem;
color: var(--text-main);
transition: var(--transition);
background: #fafafa;
}
.custom-input:focus {
outline: none;
border-color: var(--primary-light);
background: #fff;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
textarea.custom-input { resize: vertical; min-height: 80px; }
/* === 高性能滑块 === */
.slider-tabs {
display: flex;
position: relative;
background: #f1f5f9;
padding: 4px;
border-radius: 8px;
user-select: none;
}
.slider-bg {
position: absolute;
top: 4px; bottom: 4px; left: 4px;
background: #fff;
border-radius: 6px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
z-index: 1;
will-change: left;
transition: left 0.25s cubic-bezier(0.4, 0.0, 0.2, 1);
width: calc(33.333% - 4px);
}
.slider-tabs[data-count="2"] .slider-bg { width: calc(48% - 4px); }
.slider-option {
flex: 1;
text-align: center;
padding: 6px 4px;
cursor: pointer;
z-index: 2;
color: var(--text-sub);
font-size: 0.9rem;
font-weight: 500;
position: relative;
transition: color 0.2s;
}
.slider-option.active { color: var(--primary-color); }
/* === 协议盒子与自定义复选框 (重点更新) === */
.agreement-box {
margin-top: 0.5rem;
padding: 0.5rem;
background: #eff6ff;
border-radius: 0.5rem;
font-size: 0.8rem;
color: #475569;
display: flex;
align-items: flex-start;
gap: 0.5rem;
opacity: 1;
max-height: 100px;
transform: translateY(0);
transition: all 0.25s ease;
overflow: hidden;
}
.agreement-box.hidden-state {
opacity: 0;
max-height: 0;
margin-top: 0;
padding-top: 0;
padding-bottom: 0;
transform: translateY(-5px);
pointer-events: none;
}
.agreement-link {
color: var(--primary-light);
text-decoration: none;
font-weight: 600;
cursor: pointer;
border-bottom: 1px dashed transparent;
white-space: nowrap;
}
.agreement-link:hover { border-bottom-color: var(--primary-light); }
/* 自定义 Checkbox 样式 */
.custom-checkbox {
appearance: none;
-webkit-appearance: none;
width: 16px;
height: 16px;
min-width: 16px;
border: 2px solid #cbd5e1;
border-radius: 4px;
background: #fff;
cursor: pointer;
position: relative;
margin-top: 2px; /* 对齐文字微调 */
transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.custom-checkbox:checked {
background-color: var(--primary-color);
border-color: var(--primary-color);
transform: scale(1.1);
}
/* 勾选动画 */
.custom-checkbox::after {
content: '';
position: absolute;
top: 2px; left: 4px;
width: 3px; height: 7px;
border: solid white;
border-width: 0 2px 2px 0;
transform: rotate(45deg) scale(0);
opacity: 0;
transition: all 0.2s ease;
}
.custom-checkbox:checked::after {
transform: rotate(45deg) scale(1);
opacity: 1;
}
/* Flex 对齐辅助 */
.align-center { display: flex; align-items: center; }
/* === 联系方式多选 === */
.contact-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
gap: 0.5rem;
}
.contact-checkbox { display: none; }
.contact-label {
display: flex;
align-items: center;
justify-content: center;
padding: 0.4rem;
border: 1px solid var(--border-color);
border-radius: 0.4rem;
background: #fff;
cursor: pointer;
font-size: 0.85rem;
color: var(--text-sub);
transition: all 0.15s;
}
.contact-checkbox:checked + .contact-label {
background: #eff6ff;
border-color: var(--primary-light);
color: var(--primary-color);
font-weight: 600;
box-shadow: 0 2px 4px rgba(59, 130, 246, 0.1);
}
/* ==================== 5. 模态框 ==================== */
.modal-overlay {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(2px);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s;
padding: 1rem;
}
.modal-overlay.open {
opacity: 1;
visibility: visible;
}
.modal-content {
background: #fff;
width: 100%;
max-width: 500px;
border-radius: 1rem;
padding: 1.5rem;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
transform: scale(0.95);
transition: transform 0.2s;
max-height: 80vh;
overflow-y: auto;
}
.modal-overlay.open .modal-content { transform: scale(1); }
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--border-color);
}
.modal-title { font-weight: 700; color: var(--primary-color); font-size: 1.1rem; }
.close-btn { background: none; border: none; font-size: 1.5rem; cursor: pointer; color: #94a3b8; }
.close-btn:hover { color: var(--text-main); }
/* ==================== 6. 按钮与Toast ==================== */
.submit-btn {
width: 100%;
padding: 0.8rem;
background: linear-gradient(135deg, var(--primary-color), var(--primary-light));
color: white;
border: none;
border-radius: 2rem;
font-weight: 700;
font-size: 1rem;
cursor: pointer;
box-shadow: 0 4px 6px rgba(37, 99, 235, 0.2);
transition: var(--transition);
position: relative;
overflow: hidden;
}
.submit-btn:hover { transform: translateY(-1px); box-shadow: 0 6px 8px rgba(37, 99, 235, 0.3); }
.submit-btn:active { transform: translateY(1px); }
/* 入职协议特别按钮样式 */
.agreement-btn {
display: inline-block;
background-color: #fff;
color: var(--primary-color);
border: 2px solid var(--primary-color);
padding: 0.5rem 1rem;
border-radius: 0.5rem;
text-decoration: none;
font-weight: 600;
font-size: 0.9rem;
transition: var(--transition);
}
.agreement-btn:hover {
background-color: var(--primary-color);
color: white;
box-shadow: 0 4px 6px rgba(30, 58, 138, 0.2);
}
.toast {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%) translateY(-20px);
background: #1e293b;
color: white;
padding: 0.75rem 1.5rem;
border-radius: 2rem;
font-size: 0.9rem;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
opacity: 0;
pointer-events: none;
transition: all 0.3s;
z-index: 2000;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
/* 错误提示 */
.error-msg { color: var(--error); font-size: 0.75rem; margin-top: 0.25rem; display: none; }
</style>
<div class="container-galaxy">
<div class="header-box">
<div class=" w-48 h-48 rounded-lg overflow-hidden flex items-center justify-center bg-white shadow-sm">
<img src="https://www.gvsds.com/assets/hlogos/logo.jpg" alt="GVSADS Logo" class="w-full h-full object-contain">
</div>
<h1>银河锋锐 入职 网络申请表单</h1>
<p class="subtitle">Galaxy Universal Software Development Studio</p>
<p style="font-size: 0.8rem; letter-spacing: 2px; color: #94a3b8; margin-top: 0.5rem;">JOIN US · CREATE THE FUTURE</p>
</div>
<!-- 新增JSON填充测试按钮
<div style="text-align: center; margin-bottom: 1rem;">
<button onclick="testFillForm()" style="padding: 0.5rem 1rem; background: #3b82f6; color: white; border: none; border-radius: 0.5rem; cursor: pointer;">
测试JSON填充表单
</button>
</div> -->
<form id="appForm" onsubmit="handleSubmit(event)">
<!-- 第一部分 -->
<section class="glass-card">
<div class="section-title">
<svg class="svg-icon" viewBox="0 0 448 512"><path d="M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512H418.3c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304H178.3z"/></svg>
基础档案
</div>
<div class="grid-layout">
<div class="input-group">
<label class="label-text">网名 <span class="required-mark">*</span></label>
<input type="text" id="netName" name="netName" class="custom-input" placeholder="您的常用网名" required>
</div>
<div class="input-group">
<label class="label-text">真实姓名 (可选)</label>
<input type="text" id="realName" name="realName" class="custom-input" placeholder="选填">
</div>
<div class="input-group">
<label class="label-text">性别 <span class="required-mark">*</span></label>
<div class="slider-tabs" id="genderSlider" data-count="3">
<div class="slider-bg" id="genderBg"></div>
<div class="slider-option active" onclick="updateSlider('gender', 0)">男</div>
<div class="slider-option" onclick="updateSlider('gender', 1)">女</div>
<div class="slider-option" onclick="updateSlider('gender', 2)">不公开</div>
</div>
<input type="hidden" id="gender" name="gender" value="male">
<div id="genderAgreement" class="agreement-box hidden-state">
<input type="checkbox" id="agreeGender" class="custom-checkbox">
<label for="agreeGender" class="cursor-pointer align-center" style="flex:1; cursor:pointer;">
我已阅读并同意 <a class="agreement-link" onclick="openModal('genderSecret')">《性别不公开声明》</a>
</label>
</div>
</div>
<div class="input-group">
<label class="label-text">民族 <span class="required-mark">*</span></label>
<div class="slider-tabs" id="nationSlider" data-count="3">
<div class="slider-bg" id="nationBg"></div>
<div class="slider-option active" onclick="updateSlider('nation', 0)">汉族</div>
<div class="slider-option" onclick="updateSlider('nation', 1)">少数民族</div>
<div class="slider-option" onclick="updateSlider('nation', 2)">不公开</div>
</div>
<input type="hidden" id="nation" name="nation" value="han">
<div id="nationAgreement" class="agreement-box hidden-state">
<input type="checkbox" id="agreeNation" class="custom-checkbox">
<label for="agreeNation" class="cursor-pointer align-center" style="flex:1; cursor:pointer;">
我已阅读并同意 <a class="agreement-link" id="nationAgreementLink" onclick="openModal('nationAuth')">《民族真实性声明》</a>
</label>
</div>
</div>
</div>
</section>
<!-- 第二部分 -->
<section class="glass-card">
<div class="section-title">
<svg class="svg-icon" viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/></svg>
政治面貌与联络
</div>
<div class="grid-layout">
<div class="input-group">
<label class="label-text">政治面貌 <span class="required-mark">*</span></label>
<input type="text" id="politics" name="politics" class="custom-input" placeholder="如:群众、党员..." oninput="checkPolitics(this)">
<div id="politicsAgreement" class="agreement-box hidden-state">
<input type="checkbox" id="agreePolitics" class="custom-checkbox">
<label for="agreePolitics" class="cursor-pointer align-center" style="flex:1; cursor:pointer;">
我确认并签署 <a class="agreement-link" onclick="openModal('minorParty')">《少数党派声明》</a>
</label>
</div>
</div>
<div class="input-group">
<label class="label-text">年龄 (可选)</label>
<input type="number" id="age" name="age" class="custom-input" placeholder="例如:18" min="10" max="99">
</div>
<div class="input-group">
<label class="label-text">生日 (可选)</label>
<input type="date" id="birthday" name="birthday" class="custom-input">
</div>
<div class="input-group">
<label class="label-text">居住地 (可选)</label>
<input type="text" id="location" name="location" class="custom-input" placeholder="省/市/区" oninput="checkLocation(this)">
<div id="locationAgreement" class="agreement-box hidden-state">
<div style="display:flex; flex-direction:column; gap:6px;">
<label class="align-center gap-2 cursor-pointer" style="display:flex; gap:0.5rem;">
<input type="checkbox" id="agreeLocInfo" class="custom-checkbox">
<span><a class="agreement-link" onclick="openModal('infoSecret')">《工作室成员信息不公开协议》</a></span>
</label>
<label class="align-center gap-2 cursor-pointer" style="display:flex; gap:0.5rem;">
<input type="checkbox" id="agreeLocReal" class="custom-checkbox">
<span><a class="agreement-link" onclick="openModal('realLoc')">《居住地真实声明》</a></span>
</label>
</div>
</div>
</div>
</div>
</section>
<!-- 第三部分 -->
<section class="glass-card">
<div class="section-title">
<svg class="svg-icon" viewBox="0 0 640 512"><path d="M579.8 267.7c56.5-56.5 56.5-148 0-204.5c-50-50-127.5-56.5-184.8-19.9L226.5 84.5C185.3 53.3 132.1 53.3 91 84.5L42.6 132.9C13.4 162.1 3.4 207.6 22.4 247.5c13.1 27.3 39.4 45.8 69.7 48.2l10.7 1c9.3 .8 18.2 4 25.9 9.1l47.4 31.6c-4.7-12.9-7.2-26.8-7.2-41.2c0-53 43-96 96-96s96 43 96 96c0 14.4-2.5 28.3-7.2 41.2l47.4-31.6c7.7-5.1 16.6-8.3 25.9-9.1l10.7-1c30.3-2.4 56.6-20.9 69.7-48.2c19-39.9 9-85.4-20.2-114.6l-48.4-48.4c-41.1-41.1-94.3-41.1-135.5 0L251 160.8c-25.6 25.6-29 65.3-10.3 94.8c5.9 9.2 16.1 14.8 27.1 14.8h4.4c14.5 0 27.6-8.5 33.5-21.7c4.7-10.6 14.8-17.4 26.3-17.4s21.6 6.8 26.3 17.4c5.9 13.2 19 21.7 33.5 21.7h4.4c11 0 21.2-5.6 27.1-14.8c18.7-29.5 15.3-69.2-10.3-94.8z"/></svg>
联系方式矩阵
</div>
<div class="mb-4">
<p style="font-size:0.85rem; color:var(--text-sub); margin-bottom:0.5rem;">请选择您常用的联系方式 (微信、QQ二选一或全选,其余可选):</p>
<div class="contact-grid" id="contactTypes"></div>
<div id="contactError" class="error-msg">请至少选择微信或QQ中的一种联系方式!</div>
</div>
<div id="contactInputsContainer" class="grid-layout" style="grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));"></div>
</section>
<!-- 第四部分 -->
<section class="glass-card">
<div class="section-title">
<svg class="svg-icon" viewBox="0 0 576 512"><path d="M384 480h48c11.4 0 21.9-6.1 27.6-16.1l56-96c6.4-11 4.8-25-3.9-34.3s-22.2-12.1-33.5-6.6L416 368.2V128c0-17.7-14.3-32-32-32s-32 14.3-32 32v178.7l-27.5-20.6c-10.3-7.7-24.6-6.5-33.5 2.8s-10.3 23.2-3.9 34.3l56 96c5.7 10 16.2 16.1 27.6 16.1H384zM192 480h48c11.4 0 21.9-6.1 27.6-16.1l56-96c6.4-11 4.8-25-3.9-34.3s-22.2-12.1-33.5-6.6L224 368.2V128c0-17.7-14.3-32-32-32s-32 14.3-32 32v178.7l-27.5-20.6c-10.3-7.7-24.6-6.5-33.5 2.8s-10.3 23.2-3.9 34.3l56 96c5.7 10 16.2 16.1 27.6 16.1z"/></svg>
履历与愿景
</div>
<div style="display:flex; flex-direction:column; gap:1.25rem;">
<div class="input-group">
<label class="label-text">教育背景 <span class="required-mark">*</span></label>
<textarea id="education" name="education" rows="3" class="custom-input" placeholder="请详细描述您的学历、毕业院校及专业,若您年龄过小可选择如实填写或不公开,留空表明您不公开..."></textarea>
<div class="agreement-box">
<input type="checkbox" id="agreeEdu" class="custom-checkbox" required>
<label for="agreeEdu" class="cursor-pointer align-center" style="flex:1; cursor:pointer;">
我保证以上信息真实有效,即 <a class="agreement-link" onclick="openModal('eduReal')">签署《学历真实声明》</a>
</label>
</div>
</div>
<div class="input-group">
<label class="label-text">求职/工作经历 (选填)</label>
<textarea id="experience" name="experience" rows="3" class="custom-input" placeholder="请简述您过往的工作或项目经验..."></textarea>
</div>
<div class="input-group">
<label class="label-text">求职意向 <span class="required-mark">*</span></label>
<textarea id="intention" name="intention" rows="3" class="custom-input" placeholder="您为什么想来本工作室?期望的职位是什么?" required></textarea>
</div>
<div class="input-group">
<label class="label-text">个人自述 <span class="required-mark">*</span></label>
<textarea id="selfIntro" name="selfIntro" rows="4" class="custom-input" placeholder="请自由发挥:优缺点、自我介绍、心理素质展示等..." required></textarea>
</div>
</div>
</section>
<section class="glass-card" style="border-left: 5px solid var(--accent-color);">
<div class="section-title">
<svg class="svg-icon" style="color: var(--accent-color);" viewBox="0 0 448 512"><path d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V173.3c0-17-6.7-33.3-18.7-45.3L352 50.7C340 38.7 323.7 32 306.7 32H64zm0 96c0-17.7 14.3-32 32-32H288c17.7 0 32 14.3 32 32v64c0 17.7-14.3 32-32 32H96c-17.7 0-32-14.3-32-32V128zM224 288a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"/></svg>
入职必读协议
</div>
<div style="background: #fffbeb; padding: 1rem; border-radius: 0.5rem; border: 1px solid #fcd34d;">
<p style="margin:0 0 0.5rem 0; font-weight:600; color: #92400e;">请务必在提交前签署《工作室成员入职协议》</p>
<div style="display:flex; justify-content:space-between; align-items:center; gap:1rem;">
<a href="https://doc.gvsds.com/D9F9194A243D3A499108A7CA082373A7" target="_blank" class="agreement-btn">
点击阅读并签署 &rarr;
</a>
<label class="align-center cursor-pointer" style="font-size: 0.9rem; color: #78350f; white-space: nowrap;">
<input type="checkbox" id="agreeJoin" class="custom-checkbox" required>
<span style="margin-left:0.5rem;">我已阅读并签署</span>
</label>
</div>
</div>
</section>
<section class="glass-card">
<div class="section-title">
<svg class="svg-icon" viewBox="0 0 512 512"><path d="M448 256c0-106-86-192-192-192S64 150 64 256c0 84.6 54.5 156.3 130.6 181.7c-2.6-8.4-4-17.3-4-26.5c0-41.2 22.1-79.2 57.9-99.3c-5.8-4.7-9.5-11.9-9.5-19.9c0-14.1 11.4-25.5 25.5-25.5s25.5 11.4 25.5 25.5c0 8-3.7 15.2-9.5 19.9c35.8 20.2 57.9 58.1 57.9 99.3c0 9.2-1.4 18.2-4 26.5C353.5 412.3 408 340.6 408 256z"/></svg>
最终确认
</div>
<div class="input-group">
<label class="label-text">联系邮箱 <span class="required-mark">*</span></label>
<input type="email" id="email" name="email" class="custom-input" placeholder="我们将发送Offer至此邮箱" required>
</div>
<div style="display:flex; align-items:flex-end;">
<button type="submit" class="submit-btn">
提交申请
</button>
</div>
</section>
</form>
<footer style="text-align:center; color:#94a3b8; font-size:0.8rem; padding-top:2rem;">
&copy; 2023 银河锋锐软件开发工作室. All Rights Reserved.
</footer>
</div>
<!-- Toast -->
<div id="toast" class="toast">提示信息</div>
<script>
// === 数据与配置 ===
const agreements = {
genderSecret: {
title: '《性别不公开声明》',
content: `
<p>鉴于申请人在本申请表中选择“性别:不公开”(以下简称“保密选择”),银河锋锐软件开发工作室(以下简称“工作室”)与申请人就性别信息保密事宜达成如下声明:</p>
<p>一、工作室承诺:</p>
<p>1. 严格保护申请人的性别隐私权,仅在法律法规强制性要求(如社保、税务登记等)的必要场景下留存真实性别信息,且该信息仅限指定行政人员查阅,严禁外泄。</p>
<p>2. 在招聘评估、团队协作、对外公示等所有非必要场景中,均不披露、不询问申请人的性别信息,完全遵循性别中立原则。</p>
<p>二、申请人确认:</p>
<p>1. 知悉保密选择仅适用于非法定场景,理解并配合工作室在法定必要环节提供真实性别信息的要求。</p>
<p>2. 不因性别信息保密要求向工作室提出超出合理范围的特殊待遇诉求。</p>
`
},
nationAuth: {
title: '《少数民族真实性声明》',
content: `
<p>本人(申请人)郑重作出如下声明:</p>
<p>1. 本人在本申请表中填报的民族信息为【少数民族】,该信息完全基于本人的户籍登记及真实民族归属,无任何虚构、篡改行为。</p>
<p>2. 本人知晓工作室尊重各民族文化习俗,承诺在合作/工作期间遵守国家民族政策,维护民族团结,不利用少数民族身份谋取不正当利益。</p>
<p>3. 若本人填报的民族信息存在虚假,自愿接受以下后果:</p>
<p>(1)工作室有权立即撤销录用/合作资格;</p>
<p>(2)若已建立合作关系,工作室可无条件解除协议,且本人需承担因此给工作室造成的全部损失。</p>
`
},
nationReal: {
title: '《民族真实性声明》',
content: `
<p>本人(申请人)郑重作出如下声明:</p>
<p>1. 本人在本申请表中填报的民族信息为【汉族】,该信息完全基于本人的户籍登记及真实民族归属,无任何虚构、篡改行为。</p>
<p>2. 本人知晓工作室尊重各民族文化习俗,承诺在合作/工作期间遵守国家民族政策,维护民族团结。</p>
<p>3. 若本人填报的民族信息存在虚假,自愿接受以下后果:</p>
<p>(1)工作室有权立即撤销录用/合作资格;</p>
<p>(2)若已建立合作关系,工作室可无条件解除协议,且本人需承担因此给工作室造成的全部损失。</p>
`
},
nationSecret: {
title: '《民族不公开协议》',
content: `
<p>鉴于申请人在本申请表中选择“民族:不公开”(以下简称“保密选择”),银河锋锐软件开发工作室(以下简称“工作室”)与申请人就民族信息保密事宜达成如下协议:</p>
<p>一、工作室承诺:</p>
<p>1. 严格保护申请人的民族隐私权,仅在法律法规强制性要求的必要场景下留存真实民族信息,且该信息仅限指定行政人员查阅,严禁外泄。</p>
<p>2. 在招聘评估、团队协作、对外公示等所有非必要场景中,均不披露、不询问申请人的民族信息,完全遵循民族中立原则。</p>
<p>二、申请人确认:</p>
<p>1. 知悉保密选择仅适用于非法定场景,理解并配合工作室在法定必要环节提供真实民族信息的要求。</p>
<p>2. 不因民族信息保密要求向工作室提出超出合理范围的特殊待遇诉求。</p>
`
},
minorParty: {
title: '《少数党派声明》',
content: `
<p>本人(申请人)就政治面貌相关事宜声明如下:</p>
<p>1. 本人填报的政治面貌为【非主流党派】(非群众、中共党员、共青团员、无党派人士),该信息真实有效。</p>
<p>2. 本人承诺所归属的党派/团体均为合法登记的组织,本人的政治信仰及活动均遵守中华人民共和国宪法及相关法律法规。</p>
<p>3. 工作室确认:</p>
<p>(1)尊重申请人的政治信仰自由,不因申请人的政治面貌差异实施任何形式的歧视;</p>
<p>(2)在招聘评估、岗位安排、福利待遇等方面,对申请人与其他政治面貌的应聘者/员工一视同仁。</p>
`
},
infoSecret: {
title: '《工作室成员信息不公开协议》',
content: `
<p>甲方:银河锋锐软件开发工作室 乙方:申请人</p>
<p>为保障乙方个人信息安全,甲乙双方就居住地信息保密事宜达成如下协议:</p>
<p>一、信息使用范围:</p>
<p>1. 甲方收集乙方的居住地信息,仅用于建立员工/合作成员基础档案及紧急联络。</p>
<p>二、甲方保密义务:</p>
<p>1. 严禁将乙方居住地信息出售、出租、转让给任何第三方。</p>
<p>2. 严禁在公开渠道披露乙方居住地信息。</p>
<p>3. 若因甲方原因导致信息泄露,甲方需承担相应赔偿责任。</p>
`
},
realLoc: {
title: '《居住地真实声明》',
content: `
<p>本人(申请人)郑重声明:</p>
<p>1. 本人在本申请表中填报的居住地信息(省/市/区/街道等)真实、准确、完整。</p>
<p>2. 本人知晓该信息用于物料发放、会议协调等。</p>
<p>3. 若本人填报的居住地信息虚假,自愿承担后果:</p>
<p>(1)因地址错误导致的物料无法送达等损失,由本人自行承担;</p>
<p>(2)工作室有权撤销录用资格。</p>
`
},
eduReal: {
title: '《学历真实声明》',
content: `
<p>本人(申请人)就教育背景信息的真实性作出如下不可撤销的声明:</p>
<p>1. 本人在“教育背景”栏填报的所有信息均为真实、完整。</p>
<p>2. 本人同意工作室通过学信网等方式进行核验。</p>
<p>3. 若经核实发现本人信息存在虚假,本人自愿接受:</p>
<p>(1)无论是否已录用,工作室均有权立即终止流程;</p>
<p>(2)若已入职,工作室可无条件解除劳动合同且无需支付补偿;</p>
<p>(3)本人赔偿工作室因虚假信息导致的全部损失。</p>
<p>您可以留空来声明不公开学历。</p>
`
}
};
const contactOptions = [
{ id: 'wechat', label: '微信' },
{ id: 'qq', label: 'QQ' },
{ id: 'phone', label: '电话号' },
{ id: 'kuaishou', label: '快手' },
{ id: 'douyin', label: '抖音' },
{ id: 'bilibili', label: 'B站' },
{ id: 'email_alt', label: '邮箱' },
{ id: 'weibo', label: '微博' },
{ id: 'youtube', label: 'YouTube' },
{ id: 'tiktok', label: 'TikTok' },
{ id: 'google', label: 'Google' },
{ id: 'x_twitter', label: 'X' },
{ id: 'discord', label: 'Discord' },
{ id: 'facebook', label: 'Facebook' },
{ id: 'instagram', label: 'Instagram' },
{ id: 'github', label: 'Github' },
{ id: 'csdn', label: 'CSDN' },
];
// === 核心逻辑:滑块与协议 ===
function updateSlider(group, index) {
const slider = document.getElementById(group + 'Slider');
const bg = document.getElementById(group + 'Bg');
const options = slider.querySelectorAll('.slider-option');
const values = {
'gender': ['male', 'female', 'secret'],
'nation': ['han', 'other', 'secret']
};
const val = values[group][index];
document.getElementById(group).value = val;
options.forEach(opt => opt.classList.remove('active'));
options[index].classList.add('active');
const count = options.length;
bg.style.left = `calc(${index * (100 / count) - 1}% + 4px)`;
// 协议逻辑
if (group === 'nation') {
const agreementDiv = document.getElementById('nationAgreement');
const chk = document.getElementById('agreeNation');
const link = document.getElementById('nationAgreementLink');
if (val === 'han') {
// 汉族:显示民族真实性声明
agreementDiv.classList.remove('hidden-state');
chk.setAttribute('required', 'true');
link.textContent = '《民族真实性声明》';
link.setAttribute('onclick', "openModal('nationReal')");
} else if (val === 'other') {
// 少数民族:显示少数民族真实性声明
agreementDiv.classList.remove('hidden-state');
chk.setAttribute('required', 'true');
link.textContent = '《少数民族真实性声明》';
link.setAttribute('onclick', "openModal('nationAuth')");
} else if (val === 'secret') {
// 不公开:显示民族不公开协议
agreementDiv.classList.remove('hidden-state');
chk.setAttribute('required', 'true');
link.textContent = '《民族不公开协议》';
link.setAttribute('onclick', "openModal('nationSecret')");
} else {
agreementDiv.classList.add('hidden-state');
chk.removeAttribute('required');
chk.checked = false;
}
} else {
const agreementMap = {
'gender': { id: 'genderAgreement', chk: 'agreeGender', triggerVal: 'secret' }
};
const config = agreementMap[group];
const agreementDiv = document.getElementById(config.id);
const chk = document.getElementById(config.chk);
if (val === config.triggerVal) {
agreementDiv.classList.remove('hidden-state');
chk.setAttribute('required', 'true');
} else {
agreementDiv.classList.add('hidden-state');
chk.removeAttribute('required');
chk.checked = false;
}
}
}
// === 联系方式逻辑 ===
function initContactTypes() {
const container = document.getElementById('contactTypes');
contactOptions.forEach(opt => {
const div = document.createElement('div');
div.innerHTML = `
<input type="checkbox" id="chk_${opt.id}" value="${opt.id}" class="contact-checkbox" onchange="renderContactInputs()">
<label for="chk_${opt.id}" class="contact-label">${opt.label}</label>
`;
container.appendChild(div);
});
}
function renderContactInputs() {
const container = document.getElementById('contactInputsContainer');
const checkedIds = Array.from(document.querySelectorAll('.contact-checkbox:checked')).map(cb => cb.value);
Array.from(container.children).forEach(child => {
if (!checkedIds.includes(child.dataset.type)) child.remove();
});
checkedIds.forEach(id => {
if (container.querySelector(`[data-type="${id}"]`)) return;
const option = contactOptions.find(o => o.id === id);
const div = document.createElement('div');
div.className = 'input-group contact-input-item';
div.dataset.type = id;
div.innerHTML = `
<label class="label-text">${option.label}账号/ID</label>
<input type="text" name="contact_${id}" class="custom-input" placeholder="请输入${option.label}">
`;
container.appendChild(div);
});
}
// === 监听与校验 ===
function checkPolitics(input) {
const val = input.value.trim();
const div = document.getElementById('politicsAgreement');
const chk = document.getElementById('agreePolitics');
const valid = ['群众', '党员', '团员', '中共党员', '中共团员', '共青团员', '无党派', '无党派人士'].includes(val);
if (val && !valid) {
div.classList.remove('hidden-state');
chk.setAttribute('required', 'true');
} else {
div.classList.add('hidden-state');
chk.removeAttribute('required');
chk.checked = false;
}
}
function checkLocation(input) {
const val = input.value.trim();
const div = document.getElementById('locationAgreement');
const chk1 = document.getElementById('agreeLocInfo');
const chk2 = document.getElementById('agreeLocReal');
if (val) {
div.classList.remove('hidden-state');
chk1.setAttribute('required', 'true');
chk2.setAttribute('required', 'true');
} else {
div.classList.add('hidden-state');
chk1.removeAttribute('required');
chk2.removeAttribute('required');
chk1.checked = false;
chk2.checked = false;
}
}
// === 模态框逻辑 ===
function openModal(key) {
const data = agreements[key];
if (!data) return;
const oldModal = document.getElementById('dynamicModal');
if (oldModal) oldModal.remove();
const overlay = document.createElement('div');
overlay.id = 'dynamicModal';
overlay.className = 'modal-overlay';
overlay.innerHTML = `
<div class="modal-content" onclick="event.stopPropagation()">
<div class="modal-header">
<span class="modal-title">${data.title}</span>
<button class="close-btn" onclick="closeModal()">&times;</button>
</div>
<div class="modal-body" style="font-size:0.9rem; color:#475569;">${data.content}</div>
<div style="text-align:right; margin-top:1.5rem;">
<button onclick="closeModal()" style="background:var(--primary-color); color:white; border:none; padding:0.5rem 1.5rem; border-radius:0.5rem; cursor:pointer;">我已阅读并关闭</button>
</div>
</div>
`;
document.body.appendChild(overlay);
requestAnimationFrame(() => {
overlay.classList.add('open');
});
overlay.onclick = (e) => {
if (e.target === overlay) closeModal();
};
}
function closeModal() {
const overlay = document.getElementById('dynamicModal');
if (overlay) {
overlay.classList.remove('open');
setTimeout(() => overlay.remove(), 200);
}
}
// === 提交与提示 ===
function showToast(msg) {
const toast = document.getElementById('toast');
toast.textContent = msg;
toast.classList.add('show');
setTimeout(() => toast.classList.remove('show'), 3000);
}
// 【核心修改】获取整个表单数据的函数
function getFormData(formElement) {
const formData = new FormData(formElement);
const result = {};
// 1. 处理普通字段(text, hidden, textarea, select)
// 这一步会自动把 netName, realName, gender, nation, education 等放入 result
for (let [key, value] of formData.entries()) {
// 过滤掉空的联系方式占位符(虽然这里我们主要处理动态数据,但保持整洁)
if (key.startsWith('contact_')) continue;
result[key] = value;
}
// 2. 处理动态联系方式
result.contacts = {};
const contactInputs = document.querySelectorAll('.contact-input-item');
contactInputs.forEach(item => {
const type = item.dataset.type; // 'wechat', 'qq' 等
const input = item.querySelector('input');
if (input && input.value.trim() !== "") {
// 查找对应的 Label 文本
const label = contactOptions.find(o => o.id === type)?.label || type;
result.contacts[type] = {
label: label,
value: input.value.trim()
};
}
});
// 3. 处理协议勾选状态
result.agreements = {
genderSecret: document.getElementById('agreeGender').checked,
nationAuth: document.getElementById('agreeNation').checked,
minorParty: document.getElementById('agreePolitics').checked,
infoSecret: document.getElementById('agreeLocInfo').checked,
realLoc: document.getElementById('agreeLocReal').checked,
eduReal: document.getElementById('agreeEdu').checked,
joinAgreement: document.getElementById('agreeJoin').checked
};
return result;
}
function handleSubmit(e) {
e.preventDefault();
const form = document.getElementById('appForm');
// 校验联系方式(必须有微信或QQ)
const wechat = document.getElementById('chk_wechat').checked;
const qq = document.getElementById('chk_qq').checked;
const err = document.getElementById('contactError');
if (!wechat && !qq) {
err.style.display = 'block';
showToast('请至少选择微信或QQ');
document.getElementById('contactTypes').scrollIntoView({ behavior: 'smooth', block: 'center' });
return;
}
err.style.display = 'none';
// 校验入职协议
const joinAgree = document.getElementById('agreeJoin').checked;
if (!joinAgree) {
showToast('请先签署《工作室成员入职协议》');
document.getElementById('agreeJoin').scrollIntoView({ behavior: 'smooth', block: 'center' });
return;
}
// --- 获取 JSON 数据 ---
const jsonData = getFormData(form);
// 在控制台查看结果,或者发送给后端
console.log('提交的 JSON 数据:', jsonData);
console.log('JSON 字符串:', JSON.stringify(jsonData, null, 2));
// 模拟提交成功
showToast('申请提交成功!数据已生成 JSON。');
}
// ========== 新增:JSON逆向填充函数 ==========
/**
* 将JSON数据逆向填充到表单中
* @param {Object} jsonData - 要填充的JSON数据对象
*/
function fillFormFromJSON(jsonData) {
if (!jsonData || typeof jsonData !== 'object') {
showToast('无效的JSON数据!');
return;
}
// ========== 1. 填充普通表单字段 ==========
const basicFields = [
'netName', 'realName', 'politics', 'age', 'birthday',
'location', 'education', 'experience', 'intention',
'selfIntro', 'email'
];
basicFields.forEach(field => {
const element = document.getElementById(field);
if (element && jsonData[field] !== undefined) {
element.value = jsonData[field];
// 触发相关的协议显示逻辑(如政治面貌、居住地)
if (field === 'politics') checkPolitics(element);
if (field === 'location') checkLocation(element);
}
});
// ========== 2. 填充滑块选择器(性别、民族) ==========
// 性别映射:male→0, female→1, secret→2
const genderIndexMap = { 'male': 0, 'female': 1, 'secret': 2 };
if (jsonData.gender && genderIndexMap[jsonData.gender] !== undefined) {
updateSlider('gender', genderIndexMap[jsonData.gender]);
}
// 民族映射:han→0, other→1, secret→2
const nationIndexMap = { 'han': 0, 'other': 1, 'secret': 2 };
if (jsonData.nation && nationIndexMap[jsonData.nation] !== undefined) {
updateSlider('nation', nationIndexMap[jsonData.nation]);
}
// ========== 3. 填充协议勾选状态 ==========
if (jsonData.agreements && typeof jsonData.agreements === 'object') {
const agreementCheckboxes = {
genderSecret: 'agreeGender',
nationAuth: 'agreeNation',
minorParty: 'agreePolitics',
infoSecret: 'agreeLocInfo',
realLoc: 'agreeLocReal',
eduReal: 'agreeEdu',
joinAgreement: 'agreeJoin'
};
Object.entries(agreementCheckboxes).forEach(([agreementKey, checkboxId]) => {
const checkbox = document.getElementById(checkboxId);
if (checkbox && jsonData.agreements[agreementKey] !== undefined) {
checkbox.checked = jsonData.agreements[agreementKey];
}
});
}
// ========== 4. 填充动态联系方式 ==========
// 先清空所有已选的联系方式
document.querySelectorAll('.contact-checkbox').forEach(cb => {
cb.checked = false;
});
// 清空已渲染的联系方式输入框
document.getElementById('contactInputsContainer').innerHTML = '';
// 填充选中的联系方式并输入值
if (jsonData.contacts && typeof jsonData.contacts === 'object') {
Object.entries(jsonData.contacts).forEach(([type, contactInfo]) => {
const checkbox = document.getElementById(`chk_${type}`);
if (checkbox) {
// 勾选联系方式类型
checkbox.checked = true;
// 触发输入框渲染
renderContactInputs();
// 填充联系方式值
const inputItem = document.querySelector(`.contact-input-item[data-type="${type}"]`);
if (inputItem) {
const input = inputItem.querySelector('input');
if (input) input.value = contactInfo.value || contactInfo;
}
}
});
}
showToast('表单数据填充成功!');
}
// ========== 新增:测试填充函数 ==========
function testFillForm() {
const sampleJSON = {
"netName": "银河开发者",
"realName": "张三",
"gender": "secret",
"nation": "other",
"politics": "民盟",
"age": "28",
"birthday": "1996-01-15",
"location": "北京市朝阳区",
"education": "本科,XX大学计算机科学与技术专业",
"experience": "5年前端开发经验,参与过多个企业级项目",
"intention": "期望加入工作室担任前端开发工程师,共同打造优质产品",
"selfIntro": "熟练掌握HTML/CSS/JS,熟悉Vue/React框架,具备良好的团队协作能力",
"email": "zhangsan@example.com",
"contacts": {
"wechat": {
"label": "微信",
"value": "zhangsan123456"
},
"qq": {
"label": "QQ",
"value": "123456789"
},
"github": {
"label": "Github",
"value": "github.com/zhangsan"
}
},
"agreements": {
"genderSecret": true,
"nationAuth": true,
"minorParty": true,
"infoSecret": true,
"realLoc": true,
"eduReal": true,
"joinAgreement": true
}
};
// 调用填充函数
fillFormFromJSON(sampleJSON);
}
// 初始化
initContactTypes();
</script>