文章目录[隐藏]
详细指南:在WordPress中开发集成在线简历制作与智能职位匹配工具
摘要
随着就业市场竞争日益激烈,求职者和招聘方都需要更高效的工具来连接彼此。本文将详细介绍如何在WordPress平台上开发一个集在线简历制作与智能职位匹配功能于一体的工具。通过WordPress代码二次开发,我们将实现一个功能完整、用户体验优秀的职业服务平台,帮助求职者创建专业简历,同时利用智能算法匹配最适合的职位机会。
一、项目概述与规划
1.1 项目背景与市场需求
在数字化招聘时代,传统的简历投递方式已无法满足现代求职市场的需求。根据最新统计,超过70%的求职者希望通过在线平台创建和管理简历,而招聘方则期望更精准的候选人匹配机制。WordPress作为全球最流行的内容管理系统,拥有强大的扩展性和庞大的开发者社区,是构建此类工具的绝佳平台。
本项目旨在开发一个集成以下核心功能的WordPress插件:
- 可视化在线简历编辑器
- 智能职位匹配引擎
- 用户管理系统
- 数据分析与报告功能
1.2 技术架构设计
我们将采用分层架构设计:
- 表现层:使用WordPress主题模板和前端框架(如Vue.js或React)构建用户界面
- 业务逻辑层:通过自定义插件处理核心业务逻辑
- 数据层:扩展WordPress数据库结构,存储简历、职位和匹配数据
- 服务层:集成第三方API(如职位数据源、AI分析服务)
1.3 开发环境准备
在开始开发前,需要配置以下环境:
- 本地开发环境:XAMPP/MAMP或Local by Flywheel
- WordPress安装(建议最新版本)
- 代码编辑器:VS Code或PHPStorm
- 版本控制:Git
- 调试工具:Query Monitor、Debug Bar
二、数据库设计与扩展
2.1 自定义数据表设计
WordPress默认的数据表无法满足复杂应用需求,我们需要创建以下自定义表:
-- 简历表
CREATE TABLE wp_resume_builder_resumes (
resume_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
user_id BIGINT(20) UNSIGNED NOT NULL,
resume_title VARCHAR(255) NOT NULL,
resume_data LONGTEXT NOT NULL, -- JSON格式存储简历内容
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
is_public TINYINT(1) DEFAULT 1,
PRIMARY KEY (resume_id),
KEY user_id (user_id)
);
-- 职位表
CREATE TABLE wp_resume_builder_jobs (
job_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
company_id BIGINT(20) UNSIGNED NOT NULL,
job_title VARCHAR(255) NOT NULL,
job_description LONGTEXT NOT NULL,
requirements LONGTEXT NOT NULL,
location VARCHAR(255),
job_type VARCHAR(50), -- 全职、兼职等
salary_range VARCHAR(100),
posted_date DATETIME NOT NULL,
expiry_date DATETIME,
is_active TINYINT(1) DEFAULT 1,
PRIMARY KEY (job_id)
);
-- 匹配记录表
CREATE TABLE wp_resume_builder_matches (
match_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
resume_id BIGINT(20) UNSIGNED NOT NULL,
job_id BIGINT(20) UNSIGNED NOT NULL,
match_score DECIMAL(5,2) NOT NULL, -- 匹配分数0-100
match_reasons TEXT, -- 匹配原因分析
created_at DATETIME NOT NULL,
PRIMARY KEY (match_id),
KEY resume_job (resume_id, job_id)
);
2.2 数据库操作类实现
创建数据库操作类来管理自定义表:
<?php
class Resume_Builder_DB {
private static $instance = null;
private $wpdb;
private $resumes_table;
private $jobs_table;
private $matches_table;
private function __construct() {
global $wpdb;
$this->wpdb = $wpdb;
$this->resumes_table = $wpdb->prefix . 'resume_builder_resumes';
$this->jobs_table = $wpdb->prefix . 'resume_builder_jobs';
$this->matches_table = $wpdb->prefix . 'resume_builder_matches';
}
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
// 创建或更新简历
public function save_resume($user_id, $resume_data, $resume_id = null) {
$data = array(
'user_id' => $user_id,
'resume_title' => sanitize_text_field($resume_data['title']),
'resume_data' => json_encode($resume_data),
'updated_at' => current_time('mysql')
);
if ($resume_id) {
// 更新现有简历
$where = array('resume_id' => $resume_id);
return $this->wpdb->update($this->resumes_table, $data, $where);
} else {
// 创建新简历
$data['created_at'] = current_time('mysql');
return $this->wpdb->insert($this->resumes_table, $data);
}
}
// 获取用户的所有简历
public function get_user_resumes($user_id) {
$query = $this->wpdb->prepare(
"SELECT * FROM {$this->resumes_table} WHERE user_id = %d ORDER BY updated_at DESC",
$user_id
);
return $this->wpdb->get_results($query);
}
// 更多数据库操作方法...
}
?>
三、在线简历编辑器开发
3.1 前端编辑器界面
使用现代JavaScript框架构建响应式简历编辑器:
<!-- 简历编辑器主界面结构 -->
<div id="resume-builder-app">
<div class="resume-editor-container">
<!-- 左侧编辑面板 -->
<div class="editor-panel">
<div class="section-tabs">
<button class="tab active" data-section="personal">个人信息</button>
<button class="tab" data-section="experience">工作经历</button>
<button class="tab" data-section="education">教育背景</button>
<button class="tab" data-section="skills">技能专长</button>
<button class="tab" data-section="projects">项目经验</button>
</div>
<div class="section-content">
<!-- 个人信息部分 -->
<div class="section active" id="personal-section">
<div class="form-group">
<label>姓名</label>
<input type="text" v-model="resume.personal.name" class="form-control">
</div>
<div class="form-group">
<label>职业头衔</label>
<input type="text" v-model="resume.personal.title" class="form-control">
</div>
<!-- 更多字段... -->
</div>
<!-- 工作经历部分 -->
<div class="section" id="experience-section">
<div class="experience-item" v-for="(exp, index) in resume.experience">
<h4>工作经历 {{ index + 1 }}</h4>
<div class="form-group">
<label>公司名称</label>
<input type="text" v-model="exp.company" class="form-control">
</div>
<div class="form-group">
<label>职位</label>
<input type="text" v-model="exp.position" class="form-control">
</div>
<!-- 更多字段... -->
</div>
<button @click="addExperience">添加工作经历</button>
</div>
<!-- 其他部分... -->
</div>
</div>
<!-- 右侧实时预览 -->
<div class="preview-panel">
<div class="resume-preview">
<div class="resume-header">
<h1>{{ resume.personal.name }}</h1>
<h2>{{ resume.personal.title }}</h2>
</div>
<!-- 实时预览内容... -->
</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="editor-actions">
<button class="btn btn-save" @click="saveResume">保存简历</button>
<button class="btn btn-export" @click="exportPDF">导出PDF</button>
<button class="btn btn-match" @click="findMatches">智能匹配职位</button>
</div>
</div>
3.2 简历数据模型与存储
定义简历数据结构并实现保存功能:
// 简历数据模型
const resumeModel = {
personal: {
name: '',
title: '',
email: '',
phone: '',
location: '',
summary: ''
},
experience: [
{
company: '',
position: '',
startDate: '',
endDate: '',
description: '',
achievements: []
}
],
education: [],
skills: {
technical: [],
soft: [],
languages: []
},
projects: [],
settings: {
template: 'modern',
colorScheme: 'blue',
fontSize: 'medium'
}
};
// Vue.js应用实例
const app = new Vue({
el: '#resume-builder-app',
data: {
resume: JSON.parse(JSON.stringify(resumeModel)),
currentSection: 'personal',
isLoading: false
},
methods: {
// 保存简历到服务器
async saveResume() {
this.isLoading = true;
try {
const response = await fetch('/wp-json/resume-builder/v1/save', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': resumeBuilderData.nonce
},
body: JSON.stringify({
resume: this.resume,
title: this.resume.personal.name + '的简历'
})
});
const result = await response.json();
if (result.success) {
alert('简历保存成功!');
} else {
alert('保存失败:' + result.message);
}
} catch (error) {
console.error('保存错误:', error);
alert('保存过程中发生错误');
} finally {
this.isLoading = false;
}
},
// 添加工作经历
addExperience() {
this.resume.experience.push({
company: '',
position: '',
startDate: '',
endDate: '',
description: '',
achievements: []
});
},
// 导出PDF
async exportPDF() {
// 使用jsPDF或调用服务器端生成PDF
const response = await fetch('/wp-json/resume-builder/v1/export-pdf', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': resumeBuilderData.nonce
},
body: JSON.stringify({ resume: this.resume })
});
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = '我的简历.pdf';
a.click();
},
// 查找匹配职位
async findMatches() {
this.isLoading = true;
try {
const response = await fetch('/wp-json/resume-builder/v1/find-matches', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': resumeBuilderData.nonce
},
body: JSON.stringify({ resume: this.resume })
});
const matches = await response.json();
this.displayMatches(matches);
} catch (error) {
console.error('匹配错误:', error);
alert('匹配过程中发生错误');
} finally {
this.isLoading = false;
}
},
displayMatches(matches) {
// 显示匹配结果
const matchModal = new bootstrap.Modal(document.getElementById('matchModal'));
this.matchResults = matches;
matchModal.show();
}
}
});
四、智能职位匹配引擎
4.1 匹配算法设计
智能匹配引擎采用多维度评分算法:
<?php
class Job_Matching_Engine {
private $resume_data;
private $job_data;
public function __construct($resume_data, $job_data) {
$this->resume_data = $resume_data;
$this->job_data = $job_data;
}
// 计算总体匹配分数
public function calculate_match_score() {
$weights = array(
'skills' => 0.35,
'experience' => 0.25,
'education' => 0.15,
'location' => 0.10,
'job_type' => 0.10,
'salary' => 0.05
);
$scores = array(
'skills' => $this->match_skills(),
'experience' => $this->match_experience(),
'education' => $this->match_education(),
'location' => $this->match_location(),
'job_type' => $this->match_job_type(),
'salary' => $this->match_salary_expectations()
);
// 计算加权总分
$total_score = 0;
foreach ($weights as $key => $weight) {
$total_score += $scores[$key] * $weight;
}
return array(
'total_score' => round($total_score, 2),
'category_scores' => $scores,
'match_reasons' => $this->generate_match_reasons($scores)
);
}
// 技能匹配算法
private function match_skills() {
$resume_skills = $this->extract_skills_from_resume();
$job_skills = $this->extract_skills_from_job();
if (empty($job_skills)) {
return 50; // 如果没有指定技能要求,给基准分
}
$matched_skills = array_intersect($resume_skills, $job_skills);
$match_percentage = count($matched_skills) / count($job_skills) * 100;
// 确保不超过100分
return min($match_percentage, 100);
}
// 从简历中提取技能关键词
private function extract_skills_from_resume() {
$skills = array();
// 从技能部分提取
if (!empty($this->resume_data['skills']['technical'])) {
$skills = array_merge($skills, $this->resume_data['skills']['technical']);
}
// 从工作经历描述中提取技能关键词
if (!empty($this->resume_data['experience'])) {
foreach ($this->resume_data['experience'] as $experience) {
$keywords = $this->extract_keywords($experience['description']);
$skills = array_merge($skills, $keywords);
}
}
// 标准化技能名称
$skills = $this->normalize_skills($skills);
return array_unique($skills);
}
// 从职位描述中提取技能要求
private function extract_skills_from_job() {
$text = $this->job_data['job_description'] . ' ' . $this->job_data['requirements'];
// 预定义的技能词典
$skill_dictionary = array(
'PHP', 'JavaScript', 'Python', 'Java', 'WordPress', 'React', 'Vue.js',
'MySQL', 'CSS', 'HTML', 'Git', 'REST API', 'AWS', 'Docker'
);
$found_skills = array();
foreach ($skill_dictionary as $skill) {
if (stripos($text, $skill) !== false) {
$found_skills[] = $skill;
}
}
return array_unique($found_skills);
}
// 工作经历匹配
private function match_experience() {
$required_years = $this->extract_experience_requirement();
$actual_years = $this->calculate_experience_years();
if ($required_years == 0) {
return 100; // 不要求工作经验
}
if ($actual_years >= $required_years) {
return 100; // 完全满足
} else {
return ($actual_years / $required_years) * 100;
}
}
// 更多匹配算法...
// 生成匹配原因
private function generate_match_reasons($scores) {
$reasons = array();
if ($scores['skills'] >= 80) {
$reasons[] = '您的技能与职位要求高度匹配';
} elseif ($scores['skills'] >= 50) {
$reasons[] = '您具备部分所需技能';
}
if ($scores['experience'] >= 90) {
$reasons[] = '您的工作经验完全满足职位要求';
}
// 添加更多原因...
return $reasons;
}
}
?>
4.2 REST API端点实现
创建WordPress REST API端点处理匹配请求:
<?php
// 注册REST API路由
add_action('rest_api_init', function() {
// 保存简历
register_rest_route('resume-builder/v1', '/save', array(
'methods' => 'POST',
'callback' => 'resume_builder_save_resume',
'permission_callback' => function() {
return is_user_logged_in();
}
));
// 查找匹配职位
register_rest_route('resume-builder/v1', '/find-matches', array(
'methods' => 'POST',
'callback' => 'resume_builder_find_matches',
'permission_callback' => function() {
return is_user_logged_in();
}
));
// 获取推荐职位
register_rest_route('resume-builder/v1', '/recommended-jobs', array(
'methods' => 'GET',
'callback' => 'resume_builder_get_recommended_jobs',
'permission_callback' => function() {
return is_user_logged_in();
}
));
});
// 查找匹配职位回调函数
function resume_builder_find_matches($request) {
$user_id = get_current_user_id();
$resume_data = json_decode($request->get_param('resume'), true);
// 获取所有活跃职位
global $wpdb;
$jobs_table = $wpdb->prefix . 'resume_builder_jobs';
$active_jobs = $wpdb->get_results(
"SELECT * FROM {$jobs_table} WHERE is_active = 1 AND expiry_date > NOW()"
);
$matches = array();
foreach ($active_jobs as $job) {
$matching_engine = new Job_Matching_Engine($resume_data, (array)$job);
$match_result = $matching_engine->calculate_match_score();
// 只返回匹配度高于阈值的职位
if ($match_result['total_score'] >= 60) {
$matches[] = array(
'job_id' => $job->job_id,
'job_title' => $job->job_title,
'company' => get_company_name($job->company_id),
'location' => $job->location,
'job_type' => $job->job_type,
'match_score' => $match_result['total_score'],
'match_reasons' => $match_result['match_reasons'],
'job_link' => get_permalink($job->job_id)
);
}
}
// 按匹配分数排序
usort($matches, function($a, $b) {
return $b['match_score'] <=> $a['match_score'];
});
// 保存匹配记录
save_match_records($user_id, $matches);
return rest_ensure_response(array(
'success' => true,
'matches' => array_slice($matches, 0, 20), // 返回前20个匹配
'total_found' => count($matches)
));
}
// 获取推荐职位
function resume_builder_get_recommended_jobs($request) {
$user_id = get_current_user_id();
$page = $request->get_param('page') ?: 1;
$per_page = 10;
$offset = ($page - 1) * $per_page;
// 获取用户最新简历
$resumes = get_user_resumes($user_id);
if (empty($resumes)) {
return rest_ensure_response(array(
'success' => true,
'jobs' => array(),
'message' => '请先创建简历'
));
}
$latest_resume = json_decode($resumes[0]->resume_data, true);
// 从匹配记录中获取推荐职位
global $wpdb;
$matches_table = $wpdb->prefix . 'resume_builder_matches';
$jobs_table = $wpdb->prefix . 'resume_builder_jobs';
$recommended_jobs = $wpdb->get_results($wpdb->prepare(
"SELECT j.*, m.match_score
FROM {$matches_table} m
JOIN {$jobs_table} j ON m.job_id = j.job_id
WHERE m.resume_id = %d
AND j.is_active = 1
ORDER BY m.match_score DESC
LIMIT %d OFFSET %d",
$resumes[0]->resume_id,
$per_page,
$offset
));
$formatted_jobs = array_map(function($job) {
return array(
'id' => $job->job_id,
'title' => $job->job_title,
'company' => get_company_name($job->company_id),
'location' => $job->location,
'type' => $job->job_type,
'salary' => $job->salary_range,
'match_score' => $job->match_score,
'posted_date' => human_time_diff(strtotime($job->posted_date), current_time('timestamp')) . '前',
'apply_link' => home_url('/apply/?job_id=' . $job->job_id)
);
}, $recommended_jobs);
return rest_ensure_response(array(
'success' => true,
'jobs' => $formatted_jobs,
'pagination' => array(
'page' => $page,
'per_page' => $per_page,
'has_more' => count($recommended_jobs) === $per_page
)
));
}
?>
五、用户界面与体验优化
5.1 响应式仪表板设计
创建用户友好的仪表板界面:
<?php
// 短代码显示用户仪表板
add_shortcode('resume_dashboard', 'resume_builder_dashboard_shortcode');
function resume_builder_dashboard_shortcode() {
if (!is_user_logged_in()) {
return '<div class="resume-login-required">
<p>请先登录以访问简历中心</p>
<a href="' . wp_login_url(get_permalink()) . '" class="btn btn-primary">登录</a>
<a href="' . wp_registration_url() . '" class="btn btn-secondary">注册</a>
</div>';
}
ob_start();
?>
<div class="resume-dashboard">
<div class="dashboard-header">
<h1>简历中心</h1>
<div class="dashboard-stats">
<div class="stat-card">
<span class="stat-number"><?php echo count_user_resumes(); ?></span>
<span class="stat-label">份简历</span>
</div>
<div class="stat-card">
<span class="stat-number"><?php echo count_job_matches(); ?></span>
<span class="stat-label">个匹配职位</span>
</div>
<div class="stat-card">
<span class="stat-number"><?php echo count_applications(); ?></span>
<span class="stat-label">次申请</span>
</div>
</div>
</div>
<div class="dashboard-content">
<div class="dashboard-sidebar">
<nav class="dashboard-nav">
<a href="#my-resumes" class="nav-item active">
<i class="fas fa-file-alt"></i>
<span>我的简历</span>
</a>
<a href="#job-matches" class="nav-item">
<i class="fas fa-bullseye"></i>
<span>职位匹配</span>
</a>
<a href="#applications" class="nav-item">
<i class="fas fa-paper-plane"></i>
<span>我的申请</span>
</a>
<a href="#profile" class="nav-item">
<i class="fas fa-user-cog"></i>
<span>账户设置</span>
</a>
</nav>
<div class="quick-actions">
<button class="btn btn-primary btn-block" onclick="window.location.href='<?php echo home_url('/create-resume/'); ?>'">
<i class="fas fa-plus"></i> 创建新简历
</button>
<button class="btn btn-secondary btn-block" id="quick-match-btn">
<i class="fas fa-search"></i> 快速匹配职位
</button>
</div>
</div>
<div class="dashboard-main">
<div class="dashboard-section active" id="my-resumes-section">
<h2>我的简历</h2>
<div class="resumes-grid">
<?php display_user_resumes(); ?>
</div>
</div>
<div class="dashboard-section" id="job-matches-section">
<h2>推荐职位</h2>
<div class="job-filters">
<select id="match-score-filter">
<option value="all">所有匹配度</option>
<option value="90">90%以上</option>
<option value="80">80%以上</option>
<option value="70">70%以上</option>
</select>
<select id="job-type-filter">
<option value="all">所有类型</option>
<option value="full-time">全职</option>
<option value="part-time">兼职</option>
<option value="remote">远程</option>
</select>
</div>
<div id="job-matches-container">
<!-- 通过AJAX加载职位 -->
<div class="loading-spinner"></div>
</div>
</div>
<!-- 其他部分... -->
</div>
</div>
</div>
<script>
jQuery(document).ready(function($) {
// 加载推荐职位
function loadRecommendedJobs(page = 1) {
$('#job-matches-container').html('<div class="loading-spinner"></div>');
$.ajax({
url: '<?php echo rest_url('resume-builder/v1/recommended-jobs'); ?>',
method: 'GET',
data: {
page: page
},
beforeSend: function(xhr) {
xhr.setRequestHeader('X-WP-Nonce', '<?php echo wp_create_nonce('wp_rest'); ?>');
},
success: function(response) {
if (response.success) {
displayJobs(response.jobs);
setupPagination(response.pagination);
}
}
});
}
function displayJobs(jobs) {
let html = '';
if (jobs.length === 0) {
html = '<div class="no-results"><p>暂无推荐职位,请完善您的简历</p></div>';
} else {
jobs.forEach(function(job) {
html += `
<div class="job-card" data-match="${job.match_score}">
<div class="job-card-header">
<h3>${job.title}</h3>
<span class="match-badge">${job.match_score}% 匹配</span>
</div>
<div class="job-card-body">
<p><i class="fas fa-building"></i> ${job.company}</p>
<p><i class="fas fa-map-marker-alt"></i> ${job.location}</p>
<p><i class="fas fa-clock"></i> ${job.type}</p>
<p><i class="fas fa-money-bill-wave"></i> ${job.salary || '面议'}</p>
</div>
<div class="job-card-footer">
<span class="posted-date">${job.posted_date}</span>
<a href="${job.apply_link}" class="btn btn-apply">立即申请</a>
</div>
</div>
`;
});
}
$('#job-matches-container').html(html);
}
// 初始加载
loadRecommendedJobs();
// 筛选功能
$('#match-score-filter, #job-type-filter').change(function() {
applyFilters();
});
function applyFilters() {
const minScore = $('#match-score-filter').val();
const jobType = $('#job-type-filter').val();
$('.job-card').each(function() {
const matchScore = parseInt($(this).data('match'));
const cardJobType = $(this).find('.fa-clock').next().text().trim();
let show = true;
if (minScore !== 'all' && matchScore < parseInt(minScore)) {
show = false;
}
if (jobType !== 'all' && !cardJobType.includes(jobType === 'full-time' ? '全职' :
jobType === 'part-time' ? '兼职' : '远程')) {
show = false;
}
$(this).toggle(show);
});
}
});
</script>
<?php
return ob_get_clean();
}
?>
5.2 简历模板系统
实现多套简历模板供用户选择:
<?php
class Resume_Templates {
private static $templates = array(
'modern' => array(
'name' => '现代简约',
'description' => '简洁专业的现代风格',
'preview' => RESUME_BUILDER_URL . 'templates/modern/preview.jpg',
'styles' => array(
'primary_color' => '#2563eb',
'secondary_color' => '#1e40af',
'font_family' => 'Segoe UI, sans-serif',
'layout' => 'single-column'
)
),
'classic' => array(
'name' => '经典传统',
'description' => '传统保守的商务风格',
'preview' => RESUME_BUILDER_URL . 'templates/classic/preview.jpg',
'styles' => array(
'primary_color' => '#374151',
'secondary_color' => '#111827',
'font_family' => 'Times New Roman, serif',
'layout' => 'two-column'
)
),
'creative' => array(
'name' => '创意设计',
'description' => '适合创意行业的个性风格',
'preview' => RESUME_BUILDER_URL . 'templates/creative/preview.jpg',
'styles' => array(
'primary_color' => '#7c3aed',
'secondary_color' => '#5b21b6',
'font_family' => 'Inter, sans-serif',
'layout' => 'creative'
)
)
);
public static function get_all_templates() {
return apply_filters('resume_builder_templates', self::$templates);
}
public static function render_resume($resume_data, $template_name = 'modern') {
$templates = self::get_all_templates();
if (!isset($templates[$template_name])) {
$template_name = 'modern';
}
$template = $templates[$template_name];
ob_start();
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo esc_html($resume_data['personal']['name']); ?>的简历</title>
<style>
:root {
--primary-color: <?php echo $template['styles']['primary_color']; ?>;
--secondary-color: <?php echo $template['styles']['secondary_color']; ?>;
--font-family: <?php echo $template['styles']['font_family']; ?>;
}
body {
font-family: var(--font-family);
line-height: 1.6;
color: #333;
max-width: 210mm;
margin: 0 auto;
padding: 20px;
background: #fff;
}
.resume-header {
border-bottom: 3px solid var(--primary-color);
padding-bottom: 20px;
margin-bottom: 30px;
}
.resume-header h1 {
color: var(--primary-color);
margin: 0;
font-size: 32px;
}
.resume-header h2 {
color: var(--secondary-color);
margin: 5px 0 15px;
font-size: 20px;
font-weight: normal;
}
.contact-info {
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.contact-item {
display: flex;
align-items: center;
gap: 5px;
}
.section {
margin-bottom: 25px;
}
.section-title {
color: var(--primary-color);
border-bottom: 2px solid var(--secondary-color);
padding-bottom: 5px;
margin-bottom: 15px;
font-size: 18px;
}
.experience-item, .education-item {
margin-bottom: 20px;
}
.item-header {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
}
.item-title {
font-weight: bold;
font-size: 16px;
}
.item-subtitle {
color: var(--secondary-color);
font-style: italic;
}
.item-date {
color: #666;
}
.skills-list {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.skill-tag {
background: var(--primary-color);
color: white;
padding: 5px 12px;
border-radius: 20px;
font-size: 14px;
}
@media print {
body {
padding: 0;
}
.no-print {
display: none;
}
}
</style>
</head>
<body>
<div class="resume-container">
<!-- 头部信息 -->
<div class="resume-header">
<h1><?php echo esc_html($resume_data['personal']['name']); ?></h1>
<h2><?php echo esc_html($resume_data['personal']['title']); ?></h2>
<div class="contact-info">
<?php if (!empty($resume_data['personal']['email'])): ?>
<div class="contact-item">
<i class="fas fa-envelope"></i>
<span><?php echo esc_html($resume_data['personal']['email']); ?></span>
</div>
<?php endif; ?>
<?php if (!empty($resume_data['personal']['phone'])): ?>
<div class="contact-item">
<i class="fas fa-phone"></i>
<span><?php echo esc_html($resume_data['personal']['phone']); ?></span>
