2026-03-17 12:09:43 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="join-us-page">
|
|
|
|
|
|
<div class="page-container">
|
|
|
|
|
|
<div class="page-header">
|
|
|
|
|
|
<h1 class="page-title">加入我们</h1>
|
|
|
|
|
|
<p class="page-desc">成为Skill开发者,开启自由职业新篇章</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="hero-section">
|
|
|
|
|
|
<div class="hero-content">
|
|
|
|
|
|
<h2>招募Skill开发者</h2>
|
|
|
|
|
|
<p>移动办公 · 时间自由 · 收入可观</p>
|
|
|
|
|
|
<div class="hero-tags">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<a-tag color="blue">远程办公</a-tag>
|
|
|
|
|
|
<a-tag color="green">时间自由</a-tag>
|
|
|
|
|
|
<a-tag color="orange">收入可观</a-tag>
|
|
|
|
|
|
<a-tag color="red">技术成长</a-tag>
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="benefits-section">
|
|
|
|
|
|
<h2 class="section-title">开发者权益</h2>
|
|
|
|
|
|
<div class="benefits-grid">
|
|
|
|
|
|
<div class="benefit-card">
|
|
|
|
|
|
<div class="benefit-icon">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<wallet-outlined :style="{ fontSize: '36px', color: '#409eff' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<h3>丰厚收益</h3>
|
|
|
|
|
|
<p>每次下载获得收益分成<br/>优秀开发者月入过万</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="benefit-card">
|
|
|
|
|
|
<div class="benefit-icon">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<environment-outlined :style="{ fontSize: '36px', color: '#67c23a' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<h3>移动办公</h3>
|
|
|
|
|
|
<p>无需坐班,随时随地<br/>在家也能轻松赚钱</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="benefit-card">
|
|
|
|
|
|
<div class="benefit-icon">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<clock-circle-outlined :style="{ fontSize: '36px', color: '#e6a23c' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<h3>时间自由</h3>
|
|
|
|
|
|
<p>自己安排开发时间<br/>工作生活完美平衡</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="benefit-card">
|
|
|
|
|
|
<div class="benefit-icon">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<rise-outlined :style="{ fontSize: '36px', color: '#f56c6c' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<h3>技术成长</h3>
|
|
|
|
|
|
<p>实战项目经验积累<br/>提升技术能力</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="benefit-card">
|
|
|
|
|
|
<div class="benefit-icon">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<trophy-outlined :style="{ fontSize: '36px', color: '#909399' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<h3>官方认证</h3>
|
|
|
|
|
|
<p>获得平台官方认证<br/>提升个人品牌影响力</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="benefit-card">
|
|
|
|
|
|
<div class="benefit-icon">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<team-outlined :style="{ fontSize: '36px', color: '#9b59b6' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<h3>社区资源</h3>
|
|
|
|
|
|
<p>加入开发者社区<br/>与同行交流学习</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="requirements-section">
|
|
|
|
|
|
<h2 class="section-title">申请要求</h2>
|
|
|
|
|
|
<div class="requirements-list">
|
|
|
|
|
|
<div class="requirement-item">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<check-circle-outlined :style="{ fontSize: '24px', color: '#67c23a' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
<div class="requirement-content">
|
|
|
|
|
|
<h4>技术能力</h4>
|
|
|
|
|
|
<p>熟练掌握至少一门编程语言,有实际项目开发经验</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="requirement-item">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<check-circle-outlined :style="{ fontSize: '24px', color: '#67c23a' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
<div class="requirement-content">
|
|
|
|
|
|
<h4>作品展示</h4>
|
|
|
|
|
|
<p>需提供至少一个可演示的Skill作品或相关项目经验</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="requirement-item">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<check-circle-outlined :style="{ fontSize: '24px', color: '#67c23a' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
<div class="requirement-content">
|
|
|
|
|
|
<h4>责任心</h4>
|
|
|
|
|
|
<p>对产品质量负责,能够及时响应和修复问题</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="requirement-item">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<check-circle-outlined :style="{ fontSize: '24px', color: '#67c23a' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
<div class="requirement-content">
|
|
|
|
|
|
<h4>持续维护</h4>
|
|
|
|
|
|
<p>愿意持续维护和更新已发布的Skill产品</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="form-section">
|
|
|
|
|
|
<h2 class="section-title">申请成为开发者</h2>
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<a-form
|
2026-03-17 12:09:43 +08:00
|
|
|
|
ref="formRef"
|
|
|
|
|
|
:model="form"
|
|
|
|
|
|
:rules="rules"
|
2026-03-21 18:35:41 +08:00
|
|
|
|
layout="horizontal"
|
|
|
|
|
|
:label-col="{ span: 5 }"
|
|
|
|
|
|
:wrapper-col="{ span: 19 }"
|
2026-03-17 12:09:43 +08:00
|
|
|
|
class="apply-form"
|
|
|
|
|
|
>
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<a-divider orientation="left">基本信息</a-divider>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="真实姓名" name="realName">
|
|
|
|
|
|
<a-input v-model:value="form.realName" placeholder="请输入真实姓名" />
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
<a-form-item label="手机号码" name="phone">
|
|
|
|
|
|
<a-input v-model:value="form.phone" placeholder="请输入手机号码" />
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
<a-form-item label="电子邮箱" name="email">
|
|
|
|
|
|
<a-input v-model:value="form.email" placeholder="请输入电子邮箱" />
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
<a-form-item label="所在城市" name="city">
|
|
|
|
|
|
<a-input v-model:value="form.city" placeholder="请输入所在城市" />
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-divider orientation="left">专业信息</a-divider>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="技术栈" name="techStack">
|
|
|
|
|
|
<a-checkbox-group v-model:value="form.techStack" :options="techStackOptions" />
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
<a-form-item label="工作年限" name="experience">
|
|
|
|
|
|
<a-select v-model:value="form.experience" placeholder="请选择工作年限" :options="experienceOptions" />
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
<a-form-item label="擅长领域" name="expertise">
|
|
|
|
|
|
<a-select v-model:value="form.expertise" mode="multiple" placeholder="请选择擅长领域" :options="expertiseOptions" />
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-divider orientation="left">简历与作品</a-divider>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="个人简介" name="bio">
|
|
|
|
|
|
<a-textarea
|
|
|
|
|
|
v-model:value="form.bio"
|
2026-03-17 12:09:43 +08:00
|
|
|
|
:rows="4"
|
|
|
|
|
|
placeholder="请简单介绍一下自己,包括教育背景、工作经历等"
|
|
|
|
|
|
/>
|
2026-03-21 18:35:41 +08:00
|
|
|
|
</a-form-item>
|
|
|
|
|
|
<a-form-item label="简历上传" name="resumeUrl">
|
|
|
|
|
|
<div class="upload-area">
|
|
|
|
|
|
<a-upload
|
|
|
|
|
|
:file-list="resumeFileList"
|
|
|
|
|
|
:before-upload="beforeResumeUpload"
|
|
|
|
|
|
:custom-request="handleResumeUpload"
|
|
|
|
|
|
:max-count="1"
|
|
|
|
|
|
accept=".pdf,.doc,.docx"
|
|
|
|
|
|
@remove="handleResumeRemove"
|
|
|
|
|
|
>
|
|
|
|
|
|
<a-button :loading="resumeUploading">
|
|
|
|
|
|
<template #icon><upload-outlined /></template>
|
|
|
|
|
|
{{ resumeUploading ? '上传中...' : '选择简历文件' }}
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</a-upload>
|
|
|
|
|
|
<div class="upload-or">或</div>
|
|
|
|
|
|
<a-input
|
|
|
|
|
|
v-model:value="form.resumeUrl"
|
|
|
|
|
|
placeholder="粘贴简历网盘链接(百度网盘、腾讯微云等)"
|
|
|
|
|
|
:disabled="!!resumeFileList.length"
|
|
|
|
|
|
style="flex: 1"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #prefix><link-outlined /></template>
|
|
|
|
|
|
</a-input>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-tip">支持 PDF/DOC/DOCX 格式,最大 5MB;也可粘贴网盘链接</div>
|
|
|
|
|
|
<a-progress v-if="resumeUploading" :percent="resumeProgress" size="small" style="margin-top: 4px" />
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
<a-form-item label="Skill演示视频" name="demoVideoUrl">
|
|
|
|
|
|
<div class="upload-area">
|
|
|
|
|
|
<a-upload
|
|
|
|
|
|
:file-list="videoFileList"
|
|
|
|
|
|
:before-upload="beforeVideoUpload"
|
|
|
|
|
|
:custom-request="handleVideoUpload"
|
|
|
|
|
|
:max-count="1"
|
|
|
|
|
|
accept=".mp4,.mov,.avi,.webm,.mkv"
|
|
|
|
|
|
@remove="handleVideoRemove"
|
|
|
|
|
|
>
|
|
|
|
|
|
<a-button :loading="videoUploading">
|
|
|
|
|
|
<template #icon><upload-outlined /></template>
|
|
|
|
|
|
{{ videoUploading ? '上传中...' : '选择视频文件' }}
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</a-upload>
|
|
|
|
|
|
<div class="upload-or">或</div>
|
|
|
|
|
|
<a-input
|
|
|
|
|
|
v-model:value="form.demoVideoUrl"
|
|
|
|
|
|
placeholder="粘贴视频网盘链接"
|
|
|
|
|
|
:disabled="!!videoFileList.length"
|
|
|
|
|
|
style="flex: 1"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #prefix><video-camera-outlined /></template>
|
|
|
|
|
|
</a-input>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-tip">支持 MP4/MOV/AVI/WEBM 格式,最大 100MB;也可粘贴网盘链接</div>
|
|
|
|
|
|
<a-progress v-if="videoUploading" :percent="videoProgress" size="small" style="margin-top: 4px" />
|
|
|
|
|
|
</a-form-item>
|
2026-03-23 16:38:13 +08:00
|
|
|
|
<a-form-item label="作品集" name="portfolioUrl">
|
|
|
|
|
|
<div class="upload-area">
|
|
|
|
|
|
<a-upload
|
|
|
|
|
|
:file-list="portfolioFileList"
|
|
|
|
|
|
:before-upload="beforePortfolioUpload"
|
|
|
|
|
|
:custom-request="handlePortfolioUpload"
|
|
|
|
|
|
:max-count="5"
|
|
|
|
|
|
multiple
|
|
|
|
|
|
accept=".zip,.rar,.7z,.tar.gz,.pdf,.doc,.docx,.ppt,.pptx,.png,.jpg,.jpeg,.gif"
|
|
|
|
|
|
@remove="handlePortfolioRemove"
|
|
|
|
|
|
>
|
|
|
|
|
|
<a-button :loading="portfolioUploading">
|
|
|
|
|
|
<template #icon><upload-outlined /></template>
|
|
|
|
|
|
{{ portfolioUploading ? '上传中...' : '选择作品文件' }}
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</a-upload>
|
|
|
|
|
|
<div class="upload-or">或</div>
|
|
|
|
|
|
<a-input
|
|
|
|
|
|
v-model:value="form.portfolioUrl"
|
|
|
|
|
|
placeholder="粘贴作品集链接(GitHub、网盘等)"
|
|
|
|
|
|
:disabled="!!portfolioFileList.length"
|
|
|
|
|
|
style="flex: 1"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #prefix><link-outlined /></template>
|
|
|
|
|
|
</a-input>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="form-tip">支持 ZIP/RAR/PDF/图片等格式,单文件最大 50MB,最多 5 个;也可粘贴链接</div>
|
|
|
|
|
|
<a-progress v-if="portfolioUploading" :percent="portfolioProgress" size="small" style="margin-top: 4px" />
|
2026-03-21 18:35:41 +08:00
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="期望收益" name="expectedIncome">
|
|
|
|
|
|
<a-radio-group v-model:value="form.expectedIncome">
|
|
|
|
|
|
<a-radio value="1000-3000">1,000-3,000元/月</a-radio>
|
|
|
|
|
|
<a-radio value="3000-5000">3,000-5,000元/月</a-radio>
|
|
|
|
|
|
<a-radio value="5000-10000">5,000-10,000元/月</a-radio>
|
|
|
|
|
|
<a-radio value="10000+">10,000元以上/月</a-radio>
|
|
|
|
|
|
</a-radio-group>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item :wrapper-col="{ offset: 5, span: 19 }">
|
|
|
|
|
|
<a-checkbox v-model:checked="form.agreement">
|
2026-03-17 12:09:43 +08:00
|
|
|
|
我已阅读并同意
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<a-button type="link">《开发者协议》</a-button>
|
|
|
|
|
|
</a-checkbox>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item :wrapper-col="{ offset: 5, span: 19 }">
|
|
|
|
|
|
<a-space>
|
|
|
|
|
|
<a-button type="primary" size="large" :loading="submitting" @click="handleSubmit">
|
|
|
|
|
|
提交申请
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
<a-button size="large" @click="resetForm">重置</a-button>
|
|
|
|
|
|
</a-space>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
</a-form>
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="process-section">
|
|
|
|
|
|
<h2 class="section-title">申请流程</h2>
|
|
|
|
|
|
<div class="process-steps">
|
|
|
|
|
|
<div class="process-step">
|
|
|
|
|
|
<div class="step-number">1</div>
|
|
|
|
|
|
<div class="step-content">
|
|
|
|
|
|
<h4>提交申请</h4>
|
|
|
|
|
|
<p>填写申请表单<br/>上传简历和作品</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="step-arrow">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<right-outlined :style="{ fontSize: '24px' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="process-step">
|
|
|
|
|
|
<div class="step-number">2</div>
|
|
|
|
|
|
<div class="step-content">
|
|
|
|
|
|
<h4>资质审核</h4>
|
|
|
|
|
|
<p>平台审核团队<br/>评估技术能力</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="step-arrow">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<right-outlined :style="{ fontSize: '24px' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="process-step">
|
|
|
|
|
|
<div class="step-number">3</div>
|
|
|
|
|
|
<div class="step-content">
|
|
|
|
|
|
<h4>技能测试</h4>
|
|
|
|
|
|
<p>完成测试任务<br/>展示开发能力</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="step-arrow">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<right-outlined :style="{ fontSize: '24px' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="process-step">
|
|
|
|
|
|
<div class="step-number">4</div>
|
|
|
|
|
|
<div class="step-content">
|
|
|
|
|
|
<h4>正式入驻</h4>
|
|
|
|
|
|
<p>签署合作协议<br/>开始发布Skill</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<a-modal
|
|
|
|
|
|
v-model:open="successDialogVisible"
|
2026-03-17 12:09:43 +08:00
|
|
|
|
title="申请提交成功"
|
2026-03-21 18:35:41 +08:00
|
|
|
|
:width="500"
|
|
|
|
|
|
:closable="true"
|
|
|
|
|
|
:mask-closable="false"
|
2026-03-17 12:09:43 +08:00
|
|
|
|
>
|
|
|
|
|
|
<div class="success-content">
|
|
|
|
|
|
<div class="success-icon">
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<check-circle-outlined :style="{ fontSize: '64px', color: '#67c23a' }" />
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<h3>您的申请已提交成功!</h3>
|
|
|
|
|
|
<p class="success-desc">我们将在3-5个工作日内完成审核,审核结果将通过邮件通知您</p>
|
|
|
|
|
|
<div class="contact-info">
|
|
|
|
|
|
<p>如有疑问,请联系:</p>
|
|
|
|
|
|
<p>邮箱:developer@openclaw.com</p>
|
|
|
|
|
|
<p>微信:OpenClawDev</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<template #footer>
|
2026-03-21 18:35:41 +08:00
|
|
|
|
<a-button type="primary" @click="successDialogVisible = false">我知道了</a-button>
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</template>
|
2026-03-21 18:35:41 +08:00
|
|
|
|
</a-modal>
|
2026-03-17 12:09:43 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { ref, reactive } from 'vue'
|
2026-03-21 18:35:41 +08:00
|
|
|
|
import { message } from 'ant-design-vue'
|
|
|
|
|
|
import { developerApi, uploadApi } from '@/service/apiService'
|
|
|
|
|
|
import {
|
|
|
|
|
|
UserOutlined,
|
|
|
|
|
|
LockOutlined,
|
|
|
|
|
|
MailOutlined,
|
|
|
|
|
|
EnvironmentOutlined,
|
|
|
|
|
|
CodeOutlined,
|
|
|
|
|
|
ClockCircleOutlined,
|
|
|
|
|
|
FileTextOutlined,
|
|
|
|
|
|
PlayCircleOutlined,
|
|
|
|
|
|
ProjectOutlined,
|
|
|
|
|
|
DollarCircleOutlined,
|
|
|
|
|
|
CheckCircleFilled,
|
2026-03-23 16:38:13 +08:00
|
|
|
|
CheckCircleOutlined,
|
2026-03-21 18:35:41 +08:00
|
|
|
|
TrophyOutlined,
|
|
|
|
|
|
StarOutlined,
|
|
|
|
|
|
UploadOutlined,
|
|
|
|
|
|
VideoCameraOutlined,
|
|
|
|
|
|
LinkOutlined,
|
2026-03-23 16:38:13 +08:00
|
|
|
|
DesktopOutlined,
|
|
|
|
|
|
WalletOutlined,
|
|
|
|
|
|
RiseOutlined,
|
|
|
|
|
|
TeamOutlined,
|
|
|
|
|
|
RightOutlined
|
2026-03-21 18:35:41 +08:00
|
|
|
|
} from '@ant-design/icons-vue'
|
2026-03-17 12:09:43 +08:00
|
|
|
|
|
|
|
|
|
|
const formRef = ref(null)
|
|
|
|
|
|
const submitting = ref(false)
|
|
|
|
|
|
const successDialogVisible = ref(false)
|
|
|
|
|
|
|
2026-03-21 18:35:41 +08:00
|
|
|
|
// 简历上传状态
|
|
|
|
|
|
const resumeFileList = ref([])
|
|
|
|
|
|
const resumeUploading = ref(false)
|
|
|
|
|
|
const resumeProgress = ref(0)
|
|
|
|
|
|
|
|
|
|
|
|
// 视频上传状态
|
|
|
|
|
|
const videoFileList = ref([])
|
|
|
|
|
|
const videoUploading = ref(false)
|
|
|
|
|
|
const videoProgress = ref(0)
|
|
|
|
|
|
|
2026-03-23 16:38:13 +08:00
|
|
|
|
// 作品集上传状态
|
|
|
|
|
|
const portfolioFileList = ref([])
|
|
|
|
|
|
const portfolioUploading = ref(false)
|
|
|
|
|
|
const portfolioProgress = ref(0)
|
|
|
|
|
|
|
2026-03-17 12:09:43 +08:00
|
|
|
|
const form = reactive({
|
|
|
|
|
|
realName: '',
|
|
|
|
|
|
phone: '',
|
|
|
|
|
|
email: '',
|
|
|
|
|
|
city: '',
|
|
|
|
|
|
techStack: [],
|
2026-03-21 18:35:41 +08:00
|
|
|
|
experience: undefined,
|
2026-03-17 12:09:43 +08:00
|
|
|
|
expertise: [],
|
|
|
|
|
|
bio: '',
|
|
|
|
|
|
resumeUrl: '',
|
|
|
|
|
|
demoVideoUrl: '',
|
|
|
|
|
|
portfolioUrl: '',
|
|
|
|
|
|
expectedIncome: '',
|
|
|
|
|
|
agreement: false
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2026-03-21 18:35:41 +08:00
|
|
|
|
const techStackOptions = [
|
|
|
|
|
|
{ label: 'Python', value: 'Python' },
|
|
|
|
|
|
{ label: 'JavaScript', value: 'JavaScript' },
|
|
|
|
|
|
{ label: 'Java', value: 'Java' },
|
|
|
|
|
|
{ label: 'Go', value: 'Go' },
|
|
|
|
|
|
{ label: 'C/C++', value: 'C/C++' },
|
|
|
|
|
|
{ label: 'Rust', value: 'Rust' },
|
|
|
|
|
|
{ label: 'TypeScript', value: 'TypeScript' },
|
|
|
|
|
|
{ label: '其他', value: '其他' }
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
const experienceOptions = [
|
|
|
|
|
|
{ label: '1年以下', value: '0-1' },
|
|
|
|
|
|
{ label: '1-3年', value: '1-3' },
|
|
|
|
|
|
{ label: '3-5年', value: '3-5' },
|
|
|
|
|
|
{ label: '5-10年', value: '5-10' },
|
|
|
|
|
|
{ label: '10年以上', value: '10+' }
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
const expertiseOptions = [
|
|
|
|
|
|
{ label: '办公自动化', value: 'office' },
|
|
|
|
|
|
{ label: '数据处理', value: 'data' },
|
|
|
|
|
|
{ label: 'AI/机器学习', value: 'ai' },
|
|
|
|
|
|
{ label: 'Web开发', value: 'web' },
|
|
|
|
|
|
{ label: '移动端开发', value: 'mobile' },
|
|
|
|
|
|
{ label: '爬虫/采集', value: 'crawler' },
|
|
|
|
|
|
{ label: '自动化测试', value: 'testing' },
|
|
|
|
|
|
{ label: '其他', value: 'other' }
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// 简历上传前校验
|
|
|
|
|
|
const beforeResumeUpload = (file) => {
|
|
|
|
|
|
const allowedExts = ['.pdf', '.doc', '.docx']
|
|
|
|
|
|
const ext = file.name.substring(file.name.lastIndexOf('.')).toLowerCase()
|
|
|
|
|
|
if (!allowedExts.includes(ext)) {
|
|
|
|
|
|
message.error('简历仅支持 PDF/DOC/DOCX 格式')
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
if (file.size > 5 * 1024 * 1024) {
|
|
|
|
|
|
message.error('简历文件大小不能超过 5MB')
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 简历上传处理
|
|
|
|
|
|
const handleResumeUpload = async ({ file, onSuccess, onError }) => {
|
|
|
|
|
|
resumeUploading.value = true
|
|
|
|
|
|
resumeProgress.value = 0
|
|
|
|
|
|
// 模拟进度
|
|
|
|
|
|
const progressTimer = setInterval(() => {
|
|
|
|
|
|
if (resumeProgress.value < 90) resumeProgress.value += 10
|
|
|
|
|
|
}, 200)
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await uploadApi.uploadFile('resume', file)
|
|
|
|
|
|
clearInterval(progressTimer)
|
|
|
|
|
|
resumeProgress.value = 100
|
|
|
|
|
|
const url = res.data?.url || res.data?.fileUrl
|
|
|
|
|
|
form.resumeUrl = url
|
|
|
|
|
|
resumeFileList.value = [{ uid: file.uid, name: file.name, status: 'done', url }]
|
|
|
|
|
|
onSuccess(res, file)
|
|
|
|
|
|
message.success('简历上传成功')
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
clearInterval(progressTimer)
|
|
|
|
|
|
onError(err)
|
|
|
|
|
|
message.error('简历上传失败:' + (err.response?.data?.message || err.message))
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
resumeUploading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 简历删除
|
|
|
|
|
|
const handleResumeRemove = () => {
|
|
|
|
|
|
resumeFileList.value = []
|
|
|
|
|
|
form.resumeUrl = ''
|
|
|
|
|
|
resumeProgress.value = 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 视频上传前校验
|
|
|
|
|
|
const beforeVideoUpload = (file) => {
|
|
|
|
|
|
const allowedExts = ['.mp4', '.mov', '.avi', '.webm', '.mkv']
|
|
|
|
|
|
const ext = file.name.substring(file.name.lastIndexOf('.')).toLowerCase()
|
|
|
|
|
|
if (!allowedExts.includes(ext)) {
|
|
|
|
|
|
message.error('视频仅支持 MP4/MOV/AVI/WEBM/MKV 格式')
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
if (file.size > 100 * 1024 * 1024) {
|
|
|
|
|
|
message.error('视频文件大小不能超过 100MB')
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 视频上传处理
|
|
|
|
|
|
const handleVideoUpload = async ({ file, onSuccess, onError }) => {
|
|
|
|
|
|
videoUploading.value = true
|
|
|
|
|
|
videoProgress.value = 0
|
|
|
|
|
|
const progressTimer = setInterval(() => {
|
|
|
|
|
|
if (videoProgress.value < 90) videoProgress.value += 5
|
|
|
|
|
|
}, 500)
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await uploadApi.uploadFile('video', file)
|
|
|
|
|
|
clearInterval(progressTimer)
|
|
|
|
|
|
videoProgress.value = 100
|
|
|
|
|
|
const url = res.data?.url || res.data?.fileUrl
|
|
|
|
|
|
form.demoVideoUrl = url
|
|
|
|
|
|
videoFileList.value = [{ uid: file.uid, name: file.name, status: 'done', url }]
|
|
|
|
|
|
onSuccess(res, file)
|
|
|
|
|
|
message.success('视频上传成功')
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
clearInterval(progressTimer)
|
|
|
|
|
|
onError(err)
|
|
|
|
|
|
message.error('视频上传失败:' + (err.response?.data?.message || err.message))
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
videoUploading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 视频删除
|
|
|
|
|
|
const handleVideoRemove = () => {
|
|
|
|
|
|
videoFileList.value = []
|
|
|
|
|
|
form.demoVideoUrl = ''
|
|
|
|
|
|
videoProgress.value = 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-23 16:38:13 +08:00
|
|
|
|
// 作品集上传前校验
|
|
|
|
|
|
const beforePortfolioUpload = (file) => {
|
|
|
|
|
|
if (file.size > 50 * 1024 * 1024) {
|
|
|
|
|
|
message.error('单个文件大小不能超过 50MB')
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 作品集上传处理
|
|
|
|
|
|
const handlePortfolioUpload = async ({ file, onSuccess, onError }) => {
|
|
|
|
|
|
portfolioUploading.value = true
|
|
|
|
|
|
portfolioProgress.value = 0
|
|
|
|
|
|
const progressTimer = setInterval(() => {
|
|
|
|
|
|
if (portfolioProgress.value < 90) portfolioProgress.value += 10
|
|
|
|
|
|
}, 200)
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await uploadApi.uploadFile('portfolio', file)
|
|
|
|
|
|
clearInterval(progressTimer)
|
|
|
|
|
|
portfolioProgress.value = 100
|
|
|
|
|
|
const url = res.data?.url || res.data?.fileUrl
|
|
|
|
|
|
portfolioFileList.value = [...portfolioFileList.value, { uid: file.uid, name: file.name, status: 'done', url }]
|
|
|
|
|
|
// 将所有已上传文件URL用逗号拼接存入portfolioUrl
|
|
|
|
|
|
form.portfolioUrl = portfolioFileList.value.map(f => f.url).join(',')
|
|
|
|
|
|
onSuccess(res, file)
|
|
|
|
|
|
message.success('文件上传成功')
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
clearInterval(progressTimer)
|
|
|
|
|
|
onError(err)
|
|
|
|
|
|
message.error('文件上传失败:' + (err.response?.data?.message || err.message))
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
portfolioUploading.value = false
|
|
|
|
|
|
portfolioProgress.value = 0
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 作品集文件删除
|
|
|
|
|
|
const handlePortfolioRemove = (file) => {
|
|
|
|
|
|
portfolioFileList.value = portfolioFileList.value.filter(f => f.uid !== file.uid)
|
|
|
|
|
|
form.portfolioUrl = portfolioFileList.value.length
|
|
|
|
|
|
? portfolioFileList.value.map(f => f.url).join(',')
|
|
|
|
|
|
: ''
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 12:09:43 +08:00
|
|
|
|
const rules = {
|
|
|
|
|
|
realName: [{ required: true, message: '请输入真实姓名', trigger: 'blur' }],
|
|
|
|
|
|
phone: [
|
|
|
|
|
|
{ required: true, message: '请输入手机号码', trigger: 'blur' },
|
|
|
|
|
|
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
|
|
|
|
|
|
],
|
|
|
|
|
|
email: [
|
|
|
|
|
|
{ required: true, message: '请输入电子邮箱', trigger: 'blur' },
|
|
|
|
|
|
{ type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
|
|
|
|
|
|
],
|
|
|
|
|
|
city: [{ required: true, message: '请输入所在城市', trigger: 'blur' }],
|
|
|
|
|
|
techStack: [{ required: true, message: '请选择技术栈', trigger: 'change' }],
|
|
|
|
|
|
experience: [{ required: true, message: '请选择工作年限', trigger: 'change' }],
|
|
|
|
|
|
expertise: [{ required: true, message: '请选择擅长领域', trigger: 'change' }],
|
|
|
|
|
|
bio: [
|
|
|
|
|
|
{ required: true, message: '请输入个人简介', trigger: 'blur' },
|
|
|
|
|
|
{ min: 50, message: '个人简介至少50个字符', trigger: 'blur' }
|
|
|
|
|
|
],
|
2026-03-21 18:35:41 +08:00
|
|
|
|
resumeUrl: [{ required: true, message: '请上传简历或粘贴网盘链接', trigger: 'blur' }],
|
|
|
|
|
|
demoVideoUrl: [{ required: true, message: '请上传视频或粘贴网盘链接', trigger: 'blur' }],
|
2026-03-17 12:09:43 +08:00
|
|
|
|
expectedIncome: [{ required: true, message: '请选择期望收益', trigger: 'change' }]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
|
|
if (!formRef.value) return
|
|
|
|
|
|
|
2026-03-21 18:35:41 +08:00
|
|
|
|
try {
|
|
|
|
|
|
await formRef.value.validate()
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!form.agreement) {
|
|
|
|
|
|
message.warning('请阅读并同意开发者协议')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
submitting.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
await developerApi.submitApplication(form)
|
|
|
|
|
|
message.success('申请提交成功')
|
|
|
|
|
|
successDialogVisible.value = true
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('提交失败:', error)
|
|
|
|
|
|
message.error(error.response?.data?.message || '提交失败,请稍后重试')
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
submitting.value = false
|
|
|
|
|
|
}
|
2026-03-17 12:09:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const resetForm = () => {
|
|
|
|
|
|
formRef.value?.resetFields()
|
2026-03-21 18:35:41 +08:00
|
|
|
|
resumeFileList.value = []
|
|
|
|
|
|
resumeProgress.value = 0
|
|
|
|
|
|
videoFileList.value = []
|
|
|
|
|
|
videoProgress.value = 0
|
2026-03-23 16:38:13 +08:00
|
|
|
|
portfolioFileList.value = []
|
|
|
|
|
|
portfolioProgress.value = 0
|
2026-03-17 12:09:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.join-us-page {
|
|
|
|
|
|
padding: 20px 0 60px;
|
|
|
|
|
|
|
|
|
|
|
|
.page-header {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
margin-bottom: 30px;
|
|
|
|
|
|
|
|
|
|
|
|
.page-title {
|
|
|
|
|
|
font-size: 32px;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.page-desc {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.hero-section {
|
|
|
|
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
|
|
|
border-radius: 16px;
|
|
|
|
|
|
padding: 50px 40px;
|
|
|
|
|
|
margin-bottom: 40px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
|
|
|
|
|
|
h2 {
|
|
|
|
|
|
font-size: 28px;
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
p {
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
opacity: 0.9;
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.hero-tags {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.section-title {
|
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
margin-bottom: 30px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.benefits-section {
|
|
|
|
|
|
margin-bottom: 50px;
|
|
|
|
|
|
|
|
|
|
|
|
.benefits-grid {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(3, 1fr);
|
|
|
|
|
|
gap: 20px;
|
|
|
|
|
|
|
|
|
|
|
|
.benefit-card {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
padding: 30px 20px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
transform: translateY(-4px);
|
|
|
|
|
|
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.benefit-icon {
|
|
|
|
|
|
width: 64px;
|
|
|
|
|
|
height: 64px;
|
|
|
|
|
|
background: #f5f7fa;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
margin: 0 auto 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
h3 {
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
p {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.requirements-section {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
padding: 40px;
|
|
|
|
|
|
margin-bottom: 50px;
|
|
|
|
|
|
|
|
|
|
|
|
.requirements-list {
|
|
|
|
|
|
max-width: 700px;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
|
|
|
|
|
|
.requirement-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
padding: 20px 0;
|
|
|
|
|
|
border-bottom: 1px solid #ebeef5;
|
|
|
|
|
|
|
|
|
|
|
|
&:last-child {
|
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.requirement-content {
|
|
|
|
|
|
h4 {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
p {
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-section {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
padding: 40px;
|
|
|
|
|
|
margin-bottom: 50px;
|
|
|
|
|
|
|
|
|
|
|
|
.apply-form {
|
|
|
|
|
|
max-width: 700px;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
|
2026-03-21 18:35:41 +08:00
|
|
|
|
.form-tip {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
margin-top: 4px;
|
2026-03-17 12:09:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-21 18:35:41 +08:00
|
|
|
|
.upload-area {
|
2026-03-17 12:09:43 +08:00
|
|
|
|
display: flex;
|
2026-03-21 18:35:41 +08:00
|
|
|
|
align-items: flex-start;
|
2026-03-17 12:09:43 +08:00
|
|
|
|
gap: 12px;
|
2026-03-21 18:35:41 +08:00
|
|
|
|
flex-wrap: wrap;
|
2026-03-17 12:09:43 +08:00
|
|
|
|
|
2026-03-21 18:35:41 +08:00
|
|
|
|
.upload-or {
|
|
|
|
|
|
color: #c0c4cc;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
line-height: 32px;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
2026-03-17 12:09:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.process-section {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
padding: 40px;
|
|
|
|
|
|
|
|
|
|
|
|
.process-steps {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
|
|
|
|
|
|
.process-step {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
max-width: 180px;
|
|
|
|
|
|
|
|
|
|
|
|
.step-number {
|
|
|
|
|
|
width: 48px;
|
|
|
|
|
|
height: 48px;
|
|
|
|
|
|
background: linear-gradient(135deg, #409eff, #67c23a);
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
margin: 0 auto 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.step-content {
|
|
|
|
|
|
h4 {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
p {
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.step-arrow {
|
|
|
|
|
|
padding-top: 12px;
|
|
|
|
|
|
color: #c0c4cc;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.success-content {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
|
|
|
|
|
|
.success-icon {
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
h3 {
|
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.success-desc {
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.contact-info {
|
|
|
|
|
|
background: #f5f7fa;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
|
|
|
|
|
|
p {
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
line-height: 1.8;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 992px) {
|
|
|
|
|
|
.join-us-page {
|
|
|
|
|
|
.benefits-grid {
|
|
|
|
|
|
grid-template-columns: repeat(2, 1fr) !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.process-steps {
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
|
|
|
|
|
|
.step-arrow {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.process-step {
|
|
|
|
|
|
flex-basis: calc(50% - 12px);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 576px) {
|
|
|
|
|
|
.join-us-page {
|
|
|
|
|
|
.benefits-grid {
|
|
|
|
|
|
grid-template-columns: 1fr !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.process-steps {
|
|
|
|
|
|
.process-step {
|
|
|
|
|
|
flex-basis: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-section,
|
|
|
|
|
|
.requirements-section,
|
|
|
|
|
|
.process-section {
|
|
|
|
|
|
padding: 24px 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|