欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python+PyQt5實現(xiàn)簡歷自動生成工具

 更新時間:2025年05月22日 08:11:32   作者:創(chuàng)客白澤  
在當今競爭激烈的求職市場中,一份專業(yè)、規(guī)范的簡歷是獲得面試機會的關(guān)鍵,本文介紹了一個基于PyQt5的自動化簡歷生成工具,有需要的小伙伴可以參考一下

一、概述:為什么需要自動化簡歷工具

在當今競爭激烈的求職市場中,一份專業(yè)、規(guī)范的簡歷是獲得面試機會的關(guān)鍵。然而,手動編寫和排版簡歷往往耗時費力,特別是當我們需要針對不同職位定制多份簡歷時。本文介紹的基于PyQt5的自動化簡歷生成工具,將徹底改變這一現(xiàn)狀。

該工具具有以下核心優(yōu)勢:

  • 一站式管理:整合個人信息、教育背景、工作經(jīng)歷等所有模塊
  • 可視化編輯:直觀的GUI界面,告別代碼和命令行
  • 多格式輸出:支持PDF導出,確保跨平臺兼容性
  • 數(shù)據(jù)持久化:JSON格式保存/加載,簡歷數(shù)據(jù)永不丟失
  • 模板化設(shè)計:多種風格模板滿足不同行業(yè)需求

二、功能全景圖

2.1 核心功能模塊

模塊名稱功能描述技術(shù)實現(xiàn)
個人信息收集基礎(chǔ)聯(lián)系方式和社交資料QLineEdit + QFormLayout
教育經(jīng)歷管理學歷、專業(yè)、GPA等信息QListWidget + 動態(tài)表單
工作經(jīng)歷記錄職位、公司、工作描述日期控件 + 富文本編輯
技能專長分類展示技術(shù)棧和熟練度QComboBox + 層級列表
項目作品展示項目成果和貢獻超鏈接支持 + 多行文本
證書資質(zhì)管理專業(yè)認證信息時間選擇器 + URL字段
語言能力多語言水平標注等級選擇器

2.2 特色功能

  • 實時預(yù)覽:所見即所得的簡歷預(yù)覽功能
  • 智能日期:"至今"選項自動處理日期顯示
  • 響應(yīng)式布局:自適應(yīng)不同屏幕尺寸
  • 主題配色:多套可視化主題隨時切換
  • 數(shù)據(jù)校驗:關(guān)鍵字段自動驗證提醒

三、效果展示

UI界面概覽

左側(cè)為標簽式編輯面板,右側(cè)為實時預(yù)覽區(qū),符合專業(yè)軟件設(shè)計范式。

四、開發(fā)步驟詳解

4.1 環(huán)境配置

pip install PyQt5 fpdf

4.2 核心類設(shè)計

class ResumeGenerator(QMainWindow):
    def __init__(self):
        super().__init__()
        # 初始化UI和數(shù)據(jù)
        self.init_ui()
        self.init_resume_data()
        
    def init_ui(self):
        # 創(chuàng)建主窗口布局
        self.setup_main_window()
        self.add_personal_info_tab()
        self.add_education_tab()
        # ...其他標簽頁
        self.setup_preview_panel()

4.3 數(shù)據(jù)管理機制

采用三層架構(gòu)設(shè)計:

  • 表示層:PyQt5界面組件
  • 邏輯層:簡歷數(shù)據(jù)處理方法
  • 持久層:JSON序列化存儲

五、關(guān)鍵代碼解析

5.1 動態(tài)表單管理

教育/工作經(jīng)歷采用列表+詳情表單的交互模式:

def add_education(self):
    edu = {
        "school": self.edu_school_edit.text(),
        "degree": self.edu_degree_edit.text(),
        # 其他字段...
    }
    self.resume_data["education"].append(edu)
    self.update_education_list()

5.2 PDF生成引擎

基于FPDF庫的定制化輸出:

def export_to_pdf(self):
    pdf = FPDF()
    pdf.add_page()
    # 設(shè)置中文字體支持
    pdf.add_font('SimSun', '', 'simsun.ttc', uni=True)
    
    # 添加內(nèi)容區(qū)塊
    self.add_personal_section(pdf)
    self.add_education_section(pdf)
    # ...其他部分
    
    pdf.output("resume.pdf")

5.3 樣式管理系統(tǒng)

使用Qt樣式表實現(xiàn)現(xiàn)代化UI:

self.setStyleSheet("""
    QMainWindow {
        background-color: #f0f2f5;
    }
    QTabBar::tab {
        padding: 10px;
        border-radius: 5px;
    }
    QPushButton {
        background-color: #4CAF50;
        color: white;
    }
""")

六、完整源碼下載

import sys
import json
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                            QLabel, QLineEdit, QTextEdit, QPushButton, QComboBox, 
                            QListWidget, QListWidgetItem, QTabWidget, QFileDialog, 
                            QMessageBox, QFormLayout, QSpinBox, QDateEdit, QCheckBox,
                            QGroupBox, QFrame)
from PyQt5.QtCore import Qt, QDate
from PyQt5.QtGui import QFont, QIcon, QColor, QPalette
from fpdf import FPDF
from datetime import datetime

class ResumeGenerator(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("自動化簡歷生成工具")
        self.setGeometry(100, 100, 1000, 750)
        
        # 嘗試加載圖標,如果失敗則忽略
        try:
            self.setWindowIcon(QIcon("resume_icon.png"))
        except:
            pass
        
        # 初始化UI
        self.init_ui()
        
        # 加載模板
        self.load_templates()
        
        # 初始化簡歷數(shù)據(jù)結(jié)構(gòu)
        self.init_resume_data()
        
        # 當前編輯的項目索引
        self.current_edu_index = -1
        self.current_exp_index = -1
        self.current_proj_index = -1
        self.current_cert_index = -1
        
    def init_ui(self):
        # 設(shè)置主窗口背景和全局樣式
        self.setStyleSheet("""
            QMainWindow {
                background-color: #f0f2f5;
            }
            QTabBar::tab {
                padding: 10px;
                border-top-left-radius: 5px;
                border-top-right-radius: 5px;
                margin-right: 2px;
            }
            QTabBar::tab:selected {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #ffffff, stop:1 #e0e0e0);
                border-bottom: 2px solid #4CAF50;
            }
            QTabBar::tab:!selected {
                background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                    stop:0 #e0e0e0, stop:1 #d0d0d0);
            }
            QLineEdit, QTextEdit, QComboBox, QSpinBox, QDateEdit {
                padding: 8px;
                border: 1px solid #ddd;
                border-radius: 4px;
                background: white;
            }
            QTextEdit {
                min-height: 100px;
            }
            QListWidget {
                border: 1px solid #ddd;
                background: white;
                border-radius: 4px;
            }
            QPushButton {
                padding: 8px 12px;
                border-radius: 4px;
                font-weight: bold;
                min-width: 80px;
            }
            QGroupBox {
                border: 1px solid #ddd;
                border-radius: 5px;
                margin-top: 10px;
                padding-top: 15px;
                background: white;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                left: 10px;
                padding: 0 3px;
            }
        """)
        
        # 主窗口布局
        main_widget = QWidget()
        self.setCentralWidget(main_widget)
        
        main_layout = QHBoxLayout()
        main_widget.setLayout(main_layout)
        main_layout.setContentsMargins(10, 10, 10, 10)
        main_layout.setSpacing(15)
        
        # 左側(cè)面板 - 簡歷內(nèi)容編輯 (70%寬度)
        self.left_panel = QTabWidget()
        self.left_panel.setTabPosition(QTabWidget.North)
        self.left_panel.setDocumentMode(True)
        main_layout.addWidget(self.left_panel, 7)
        
        # 右側(cè)面板 - 預(yù)覽和操作 (30%寬度)
        right_panel = QWidget()
        right_panel.setMaximumWidth(350)
        right_layout = QVBoxLayout()
        right_layout.setContentsMargins(5, 5, 5, 5)
        right_panel.setLayout(right_layout)
        main_layout.addWidget(right_panel, 3)
        
        # 添加標簽頁
        self.add_personal_info_tab()
        self.add_summary_tab()
        self.add_education_tab()
        self.add_experience_tab()
        self.add_skills_tab()
        self.add_projects_tab()
        self.add_certifications_tab()
        self.add_languages_tab()
        
        # 右側(cè)面板內(nèi)容
        # 模板選擇組
        template_group = QGroupBox("簡歷模板")
        template_layout = QVBoxLayout()
        template_group.setLayout(template_layout)
        
        self.template_combo = QComboBox()
        self.template_combo.setStyleSheet("""
            QComboBox {
                padding: 8px;
                border: 1px solid #4CAF50;
                border-radius: 4px;
                background: white;
            }
            QComboBox::drop-down {
                border: none;
            }
        """)
        template_layout.addWidget(self.template_combo)
        
        # 操作按鈕組
        button_group = QGroupBox("操作")
        button_layout = QVBoxLayout()
        button_group.setLayout(button_layout)
        
        # 預(yù)覽按鈕
        self.preview_btn = QPushButton("?? 預(yù)覽簡歷")
        self.preview_btn.setStyleSheet("""
            QPushButton {
                background-color: #4CAF50;
                color: white;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
        """)
        self.preview_btn.clicked.connect(self.preview_resume)
        button_layout.addWidget(self.preview_btn)
        
        # 導出按鈕
        self.export_btn = QPushButton("?? 導出PDF")
        self.export_btn.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
            }
            QPushButton:hover {
                background-color: #0b7dda;
            }
        """)
        self.export_btn.clicked.connect(self.export_to_pdf)
        button_layout.addWidget(self.export_btn)
        
        # 分隔線
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        button_layout.addWidget(line)
        
        # 保存按鈕
        self.save_btn = QPushButton("?? 保存數(shù)據(jù)")
        self.save_btn.setStyleSheet("""
            QPushButton {
                background-color: #FF9800;
                color: white;
            }
            QPushButton:hover {
                background-color: #e68a00;
            }
        """)
        self.save_btn.clicked.connect(self.save_resume_data)
        button_layout.addWidget(self.save_btn)
        
        # 加載按鈕
        self.load_btn = QPushButton("?? 加載數(shù)據(jù)")
        self.load_btn.setStyleSheet("""
            QPushButton {
                background-color: #9C27B0;
                color: white;
            }
            QPushButton:hover {
                background-color: #7b1fa2;
            }
        """)
        self.load_btn.clicked.connect(self.load_resume_data)
        button_layout.addWidget(self.load_btn)
        
        # 預(yù)覽區(qū)域組
        preview_group = QGroupBox("簡歷預(yù)覽")
        preview_layout = QVBoxLayout()
        preview_group.setLayout(preview_layout)
        
        self.preview_text = QTextEdit()
        self.preview_text.setReadOnly(True)
        self.preview_text.setStyleSheet("""
            QTextEdit {
                background-color: #f9f9f9;
                border: 1px solid #ddd;
                border-radius: 4px;
            }
        """)
        preview_layout.addWidget(self.preview_text)
        
        # 添加到右側(cè)面板
        right_layout.addWidget(template_group)
        right_layout.addWidget(button_group)
        right_layout.addWidget(preview_group)
        
        # 設(shè)置標簽頁顏色
        self.set_tab_colors()
    
    def set_tab_colors(self):
    #為每個標簽頁設(shè)置不同的顏色
      tab_colors = [
        ("#FF5252", "#FFFFFF"),  # 紅色
        ("#FF9800", "#FFFFFF"),  # 橙色
        ("#FFEB3B", "#000000"),  # 黃色
        ("#4CAF50", "#FFFFFF"),  # 綠色
        ("#2196F3", "#FFFFFF"),  # 藍色
        ("#673AB7", "#FFFFFF"),  # 深紫色
        ("#E91E63", "#FFFFFF"),  # 粉色
        ("#607D8B", "#FFFFFF")   # 藍灰色
    ]
    
    # 方法1:統(tǒng)一設(shè)置QTabBar樣式(推薦)
      tab_bar = self.left_panel.tabBar()
      tab_bar.setStyleSheet("""
        QTabBar::tab {
            padding: 10px;
            border-top-left-radius: 5px;
            border-top-right-radius: 5px;
            margin-right: 2px;
        }
        QTabBar::tab:selected {
            background: white;
            border-bottom: 2px solid #4CAF50;
        }
        QTabBar::tab:!selected {
            background: #e0e0e0;
        }
    """)
    
    def init_resume_data(self):
        """初始化簡歷數(shù)據(jù)結(jié)構(gòu)"""
        self.resume_data = {
            "personal_info": {
                "name": "",
                "email": "",
                "phone": "",
                "address": "",
                "linkedin": "",
                "github": "",
                "website": ""
            },
            "summary": "",
            "education": [],
            "experience": [],
            "skills": [],
            "projects": [],
            "certifications": [],
            "languages": []
        }
    
    def add_personal_info_tab(self):
        tab = QWidget()
        layout = QVBoxLayout()
        tab.setLayout(layout)
        
        # 使用GroupBox組織內(nèi)容
        group = QGroupBox("個人信息")
        form_layout = QFormLayout()
        group.setLayout(form_layout)
        
        # 創(chuàng)建帶圖標的輸入字段
        self.name_edit = self.create_line_edit("??", "姓名")
        self.email_edit = self.create_line_edit("??", "郵箱")
        self.phone_edit = self.create_line_edit("??", "電話")
        self.address_edit = self.create_line_edit("??", "地址")
        self.linkedin_edit = self.create_line_edit("??", "LinkedIn")
        self.github_edit = self.create_line_edit("??", "GitHub")
        self.website_edit = self.create_line_edit("??", "個人網(wǎng)站")
        
        # 添加到表單
        form_layout.addRow("姓名:", self.name_edit)
        form_layout.addRow("郵箱:", self.email_edit)
        form_layout.addRow("電話:", self.phone_edit)
        form_layout.addRow("地址:", self.address_edit)
        form_layout.addRow("LinkedIn:", self.linkedin_edit)
        form_layout.addRow("GitHub:", self.github_edit)
        form_layout.addRow("個人網(wǎng)站:", self.website_edit)
        
        layout.addWidget(group)
        layout.addStretch()
        
        self.left_panel.addTab(tab, "個人信息")
    
    def create_line_edit(self, icon, placeholder):
        """創(chuàng)建帶樣式的QLineEdit"""
        line_edit = QLineEdit()
        line_edit.setPlaceholderText(f"{icon} {placeholder}")
        line_edit.setStyleSheet("""
            QLineEdit {
                padding: 10px;
                border: 1px solid #ddd;
                border-radius: 5px;
                font-size: 14px;
            }
            QLineEdit:focus {
                border: 1px solid #4CAF50;
            }
        """)
        return line_edit
    
    def add_summary_tab(self):
        tab = QWidget()
        layout = QVBoxLayout()
        tab.setLayout(layout)
        
        group = QGroupBox("職業(yè)概述")
        group_layout = QVBoxLayout()
        group.setLayout(group_layout)
        
        self.summary_edit = QTextEdit()
        self.summary_edit.setPlaceholderText("在這里輸入你的職業(yè)概述...")
        self.summary_edit.setStyleSheet("""
            QTextEdit {
                padding: 10px;
                border: 1px solid #ddd;
                border-radius: 5px;
                font-size: 14px;
            }
            QTextEdit:focus {
                border: 1px solid #2196F3;
            }
        """)
        
        group_layout.addWidget(self.summary_edit)
        layout.addWidget(group)
        layout.addStretch()
        
        self.left_panel.addTab(tab, "職業(yè)概述")
    
    def add_education_tab(self):
        tab = QWidget()
        layout = QVBoxLayout()
        tab.setLayout(layout)
        
        # 教育經(jīng)歷表單組
        form_group = QGroupBox("添加/編輯教育經(jīng)歷")
        form_layout = QFormLayout()
        form_group.setLayout(form_layout)
        
        # 創(chuàng)建輸入字段
        self.edu_school_edit = self.create_line_edit("??", "學校名稱")
        self.edu_degree_edit = self.create_line_edit("??", "學位")
        self.edu_field_edit = self.create_line_edit("??", "專業(yè)")
        self.edu_start_date = QDateEdit()
        self.edu_end_date = QDateEdit()
        self.edu_current = QCheckBox("至今")
        self.edu_gpa_edit = self.create_line_edit("??", "GPA")
        self.edu_description = QTextEdit()
        
        # 設(shè)置日期控件
        self.edu_start_date.setCalendarPopup(True)
        self.edu_end_date.setCalendarPopup(True)
        self.edu_current.stateChanged.connect(self.toggle_edu_end_date)
        
        # 添加到表單
        form_layout.addRow("學校:", self.edu_school_edit)
        form_layout.addRow("學位:", self.edu_degree_edit)
        form_layout.addRow("專業(yè):", self.edu_field_edit)
        form_layout.addRow("開始日期:", self.edu_start_date)
        form_layout.addRow("結(jié)束日期:", self.edu_end_date)
        form_layout.addRow(self.edu_current)
        form_layout.addRow("GPA:", self.edu_gpa_edit)
        form_layout.addRow("描述:", self.edu_description)
        
        # 按鈕布局
        btn_layout = QHBoxLayout()
        self.add_edu_btn = self.create_button("? 添加", "#4CAF50")
        self.add_edu_btn.clicked.connect(self.add_education)
        self.update_edu_btn = self.create_button("?? 更新", "#2196F3")
        self.update_edu_btn.clicked.connect(self.update_education)
        self.remove_edu_btn = self.create_button("? 刪除", "#F44336")
        self.remove_edu_btn.clicked.connect(self.remove_education)
        
        btn_layout.addWidget(self.add_edu_btn)
        btn_layout.addWidget(self.update_edu_btn)
        btn_layout.addWidget(self.remove_edu_btn)
        
        # 教育經(jīng)歷列表組
        list_group = QGroupBox("教育經(jīng)歷列表")
        list_layout = QVBoxLayout()
        list_group.setLayout(list_layout)
        
        self.edu_list = QListWidget()
        self.edu_list.itemClicked.connect(self.load_education)
        self.edu_list.setStyleSheet("""
            QListWidget {
                font-size: 14px;
            }
            QListWidget::item {
                padding: 8px;
                border-bottom: 1px solid #eee;
            }
            QListWidget::item:hover {
                background-color: #f0f0f0;
            }
            QListWidget::item:selected {
                background-color: #e3f2fd;
                color: #000;
            }
        """)
        
        list_layout.addWidget(self.edu_list)
        
        # 添加到主布局
        layout.addWidget(form_group)
        layout.addLayout(btn_layout)
        layout.addWidget(list_group)
        
        self.left_panel.addTab(tab, "教育經(jīng)歷")
    
    def create_button(self, text, color):
        """創(chuàng)建帶樣式的按鈕"""
        btn = QPushButton(text)
        btn.setStyleSheet(f"""
            QPushButton {{
                background-color: {color};
                color: white;
                padding: 8px 12px;
                border-radius: 4px;
                font-weight: bold;
            }}
            QPushButton:hover {{
                background-color: {self.darken_color(color)};
            }}
        """)
        return btn
    
    def darken_color(self, hex_color, factor=0.8):
        """使顏色變暗"""
        color = QColor(hex_color)
        return color.darker(int(1/factor*100)).name()
    
    def add_experience_tab(self):
        tab = QWidget()
        layout = QVBoxLayout()
        tab.setLayout(layout)
        
        form_group = QGroupBox("添加/編輯工作經(jīng)歷")
        form_layout = QFormLayout()
        form_group.setLayout(form_layout)
        
        self.exp_company_edit = self.create_line_edit("??", "公司名稱")
        self.exp_position_edit = self.create_line_edit("??", "職位")
        self.exp_start_date = QDateEdit()
        self.exp_end_date = QDateEdit()
        self.exp_current = QCheckBox("至今")
        self.exp_description = QTextEdit()
        
        self.exp_start_date.setCalendarPopup(True)
        self.exp_end_date.setCalendarPopup(True)
        self.exp_current.stateChanged.connect(self.toggle_exp_end_date)
        
        form_layout.addRow("公司:", self.exp_company_edit)
        form_layout.addRow("職位:", self.exp_position_edit)
        form_layout.addRow("開始日期:", self.exp_start_date)
        form_layout.addRow("結(jié)束日期:", self.exp_end_date)
        form_layout.addRow(self.exp_current)
        form_layout.addRow("描述:", self.exp_description)
        
        btn_layout = QHBoxLayout()
        self.add_exp_btn = self.create_button("? 添加", "#4CAF50")
        self.add_exp_btn.clicked.connect(self.add_experience)
        self.update_exp_btn = self.create_button("?? 更新", "#2196F3")
        self.update_exp_btn.clicked.connect(self.update_experience)
        self.remove_exp_btn = self.create_button("? 刪除", "#F44336")
        self.remove_exp_btn.clicked.connect(self.remove_experience)
        
        btn_layout.addWidget(self.add_exp_btn)
        btn_layout.addWidget(self.update_exp_btn)
        btn_layout.addWidget(self.remove_exp_btn)
        
        list_group = QGroupBox("工作經(jīng)歷列表")
        list_layout = QVBoxLayout()
        list_group.setLayout(list_layout)
        
        self.exp_list = QListWidget()
        self.exp_list.itemClicked.connect(self.load_experience)
        list_layout.addWidget(self.exp_list)
        
        layout.addWidget(form_group)
        layout.addLayout(btn_layout)
        layout.addWidget(list_group)
        
        self.left_panel.addTab(tab, "工作經(jīng)歷")
    
    def add_skills_tab(self):
        tab = QWidget()
        layout = QVBoxLayout()
        tab.setLayout(layout)
        
        form_group = QGroupBox("添加技能")
        form_layout = QVBoxLayout()
        form_group.setLayout(form_layout)
        
        skill_layout = QHBoxLayout()
        self.skill_edit = self.create_line_edit("??", "技能名稱")
        self.skill_level_combo = QComboBox()
        self.skill_level_combo.addItems(["初級", "中級", "高級", "專家"])
        
        skill_layout.addWidget(self.skill_edit)
        skill_layout.addWidget(self.skill_level_combo)
        
        btn_layout = QHBoxLayout()
        self.add_skill_btn = self.create_button("? 添加技能", "#4CAF50")
        self.add_skill_btn.clicked.connect(self.add_skill)
        self.remove_skill_btn = self.create_button("? 刪除選中", "#F44336")
        self.remove_skill_btn.clicked.connect(self.remove_skill)
        
        btn_layout.addWidget(self.add_skill_btn)
        btn_layout.addWidget(self.remove_skill_btn)
        
        list_group = QGroupBox("技能列表")
        list_layout = QVBoxLayout()
        list_group.setLayout(list_layout)
        
        self.skill_list = QListWidget()
        list_layout.addWidget(self.skill_list)
        
        form_layout.addWidget(QLabel("添加技能:"))
        form_layout.addLayout(skill_layout)
        form_layout.addLayout(btn_layout)
        
        layout.addWidget(form_group)
        layout.addWidget(list_group)
        
        self.left_panel.addTab(tab, "技能")
    
    def add_projects_tab(self):
        tab = QWidget()
        layout = QVBoxLayout()
        tab.setLayout(layout)
        
        form_group = QGroupBox("添加/編輯項目")
        form_layout = QFormLayout()
        form_group.setLayout(form_layout)
        
        self.proj_name_edit = self.create_line_edit("??", "項目名稱")
        self.proj_role_edit = self.create_line_edit("??", "你的角色")
        self.proj_start_date = QDateEdit()
        self.proj_end_date = QDateEdit()
        self.proj_current = QCheckBox("進行中")
        self.proj_description = QTextEdit()
        self.proj_url_edit = self.create_line_edit("??", "項目URL")
        
        self.proj_start_date.setCalendarPopup(True)
        self.proj_end_date.setCalendarPopup(True)
        self.proj_current.stateChanged.connect(self.toggle_proj_end_date)
        
        form_layout.addRow("項目名稱:", self.proj_name_edit)
        form_layout.addRow("你的角色:", self.proj_role_edit)
        form_layout.addRow("開始日期:", self.proj_start_date)
        form_layout.addRow("結(jié)束日期:", self.proj_end_date)
        form_layout.addRow(self.proj_current)
        form_layout.addRow("項目URL:", self.proj_url_edit)
        form_layout.addRow("描述:", self.proj_description)
        
        btn_layout = QHBoxLayout()
        self.add_proj_btn = self.create_button("? 添加", "#4CAF50")
        self.add_proj_btn.clicked.connect(self.add_project)
        self.update_proj_btn = self.create_button("?? 更新", "#2196F3")
        self.update_proj_btn.clicked.connect(self.update_project)
        self.remove_proj_btn = self.create_button("? 刪除", "#F44336")
        self.remove_proj_btn.clicked.connect(self.remove_project)
        
        btn_layout.addWidget(self.add_proj_btn)
        btn_layout.addWidget(self.update_proj_btn)
        btn_layout.addWidget(self.remove_proj_btn)
        
        list_group = QGroupBox("項目列表")
        list_layout = QVBoxLayout()
        list_group.setLayout(list_layout)
        
        self.proj_list = QListWidget()
        self.proj_list.itemClicked.connect(self.load_project)
        list_layout.addWidget(self.proj_list)
        
        layout.addWidget(form_group)
        layout.addLayout(btn_layout)
        layout.addWidget(list_group)
        
        self.left_panel.addTab(tab, "項目經(jīng)歷")
    
    def add_certifications_tab(self):
        tab = QWidget()
        layout = QVBoxLayout()
        tab.setLayout(layout)
        
        form_group = QGroupBox("添加/編輯證書")
        form_layout = QFormLayout()
        form_group.setLayout(form_layout)
        
        self.cert_name_edit = self.create_line_edit("??", "證書名稱")
        self.cert_org_edit = self.create_line_edit("???", "頒發(fā)機構(gòu)")
        self.cert_date = QDateEdit()
        self.cert_url_edit = self.create_line_edit("??", "證書URL")
        
        self.cert_date.setCalendarPopup(True)
        
        form_layout.addRow("證書名稱:", self.cert_name_edit)
        form_layout.addRow("頒發(fā)機構(gòu):", self.cert_org_edit)
        form_layout.addRow("獲得日期:", self.cert_date)
        form_layout.addRow("證書URL:", self.cert_url_edit)
        
        btn_layout = QHBoxLayout()
        self.add_cert_btn = self.create_button("? 添加", "#4CAF50")
        self.add_cert_btn.clicked.connect(self.add_certification)
        self.update_cert_btn = self.create_button("?? 更新", "#2196F3")
        self.update_cert_btn.clicked.connect(self.update_certification)
        self.remove_cert_btn = self.create_button("? 刪除", "#F44336")
        self.remove_cert_btn.clicked.connect(self.remove_certification)
        
        btn_layout.addWidget(self.add_cert_btn)
        btn_layout.addWidget(self.update_cert_btn)
        btn_layout.addWidget(self.remove_cert_btn)
        
        list_group = QGroupBox("證書列表")
        list_layout = QVBoxLayout()
        list_group.setLayout(list_layout)
        
        self.cert_list = QListWidget()
        self.cert_list.itemClicked.connect(self.load_certification)
        list_layout.addWidget(self.cert_list)
        
        layout.addWidget(form_group)
        layout.addLayout(btn_layout)
        layout.addWidget(list_group)
        
        self.left_panel.addTab(tab, "證書")
    
    def add_languages_tab(self):
        tab = QWidget()
        layout = QVBoxLayout()
        tab.setLayout(layout)
        
        form_group = QGroupBox("添加語言")
        form_layout = QVBoxLayout()
        form_group.setLayout(form_layout)
        
        lang_layout = QHBoxLayout()
        self.lang_edit = self.create_line_edit("??", "語言")
        self.lang_level_combo = QComboBox()
        self.lang_level_combo.addItems(["初級", "中級", "高級", "母語"])
        
        lang_layout.addWidget(self.lang_edit)
        lang_layout.addWidget(self.lang_level_combo)
        
        btn_layout = QHBoxLayout()
        self.add_lang_btn = self.create_button("? 添加語言", "#4CAF50")
        self.add_lang_btn.clicked.connect(self.add_language)
        self.remove_lang_btn = self.create_button("? 刪除選中", "#F44336")
        self.remove_lang_btn.clicked.connect(self.remove_language)
        
        btn_layout.addWidget(self.add_lang_btn)
        btn_layout.addWidget(self.remove_lang_btn)
        
        list_group = QGroupBox("語言列表")
        list_layout = QVBoxLayout()
        list_group.setLayout(list_layout)
        
        self.lang_list = QListWidget()
        list_layout.addWidget(self.lang_list)
        
        form_layout.addWidget(QLabel("添加語言:"))
        form_layout.addLayout(lang_layout)
        form_layout.addLayout(btn_layout)
        
        layout.addWidget(form_group)
        layout.addWidget(list_group)
        
        self.left_panel.addTab(tab, "語言能力")
    
    def toggle_edu_end_date(self, state):
        self.edu_end_date.setEnabled(not bool(state))
    
    def toggle_exp_end_date(self, state):
        self.exp_end_date.setEnabled(not bool(state))
    
    def toggle_proj_end_date(self, state):
        self.proj_end_date.setEnabled(not bool(state))
    
    def load_templates(self):
        """加載簡歷模板"""
        templates = [
            "?? 多彩創(chuàng)意模板",
            "?? 專業(yè)商務(wù)模板",
            "?? 傳統(tǒng)經(jīng)典模板",
            "?? 現(xiàn)代簡約模板",
            "?? 數(shù)據(jù)分析師模板",
            "?? 開發(fā)者模板",
            "?? 學術(shù)模板",
            "?? 設(shè)計師模板"
        ]
        self.template_combo.addItems(templates)
    
    def collect_personal_info(self):
        self.resume_data["personal_info"] = {
            "name": self.name_edit.text(),
            "email": self.email_edit.text(),
            "phone": self.phone_edit.text(),
            "address": self.address_edit.text(),
            "linkedin": self.linkedin_edit.text(),
            "github": self.github_edit.text(),
            "website": self.website_edit.text()
        }
    
    def collect_summary(self):
        self.resume_data["summary"] = self.summary_edit.toPlainText()
    
    def add_education(self):
        self.collect_personal_info()
        
        edu = {
            "school": self.edu_school_edit.text(),
            "degree": self.edu_degree_edit.text(),
            "field": self.edu_field_edit.text(),
            "start_date": self.edu_start_date.date().toString("yyyy-MM-dd"),
            "end_date": "" if self.edu_current.isChecked() else self.edu_end_date.date().toString("yyyy-MM-dd"),
            "current": self.edu_current.isChecked(),
            "gpa": self.edu_gpa_edit.text(),
            "description": self.edu_description.toPlainText()
        }
        
        self.resume_data["education"].append(edu)
        self.update_education_list()
        self.clear_education_form()
    
    def update_education(self):
        if self.current_edu_index == -1:
            return
            
        edu = {
            "school": self.edu_school_edit.text(),
            "degree": self.edu_degree_edit.text(),
            "field": self.edu_field_edit.text(),
            "start_date": self.edu_start_date.date().toString("yyyy-MM-dd"),
            "end_date": "" if self.edu_current.isChecked() else self.edu_end_date.date().toString("yyyy-MM-dd"),
            "current": self.edu_current.isChecked(),
            "gpa": self.edu_gpa_edit.text(),
            "description": self.edu_description.toPlainText()
        }
        
        self.resume_data["education"][self.current_edu_index] = edu
        self.update_education_list()
        self.clear_education_form()
        self.current_edu_index = -1
    
    def remove_education(self):
        if self.current_edu_index == -1:
            return
            
        self.resume_data["education"].pop(self.current_edu_index)
        self.update_education_list()
        self.clear_education_form()
        self.current_edu_index = -1
    
    def load_education(self, item):
        index = self.edu_list.row(item)
        self.current_edu_index = index
        edu = self.resume_data["education"][index]
        
        self.edu_school_edit.setText(edu["school"])
        self.edu_degree_edit.setText(edu["degree"])
        self.edu_field_edit.setText(edu["field"])
        self.edu_start_date.setDate(QDate.fromString(edu["start_date"], "yyyy-MM-dd"))
        
        if edu["current"]:
            self.edu_current.setChecked(True)
            self.edu_end_date.setEnabled(False)
        else:
            self.edu_current.setChecked(False)
            self.edu_end_date.setDate(QDate.fromString(edu["end_date"], "yyyy-MM-dd"))
            self.edu_end_date.setEnabled(True)
        
        self.edu_gpa_edit.setText(edu["gpa"])
        self.edu_description.setPlainText(edu["description"])
    
    def update_education_list(self):
        self.edu_list.clear()
        for edu in self.resume_data["education"]:
            item = QListWidgetItem(f"{edu['degree']} - {edu['school']}")
            self.edu_list.addItem(item)
    
    def clear_education_form(self):
        self.edu_school_edit.clear()
        self.edu_degree_edit.clear()
        self.edu_field_edit.clear()
        self.edu_start_date.setDate(QDate.currentDate())
        self.edu_end_date.setDate(QDate.currentDate())
        self.edu_current.setChecked(False)
        self.edu_gpa_edit.clear()
        self.edu_description.clear()
        self.edu_end_date.setEnabled(True)
    
    def add_experience(self):
        self.collect_personal_info()
        
        exp = {
            "company": self.exp_company_edit.text(),
            "position": self.exp_position_edit.text(),
            "start_date": self.exp_start_date.date().toString("yyyy-MM-dd"),
            "end_date": "" if self.exp_current.isChecked() else self.exp_end_date.date().toString("yyyy-MM-dd"),
            "current": self.exp_current.isChecked(),
            "description": self.exp_description.toPlainText()
        }
        
        self.resume_data["experience"].append(exp)
        self.update_experience_list()
        self.clear_experience_form()
    
    def update_experience(self):
        if self.current_exp_index == -1:
            return
            
        exp = {
            "company": self.exp_company_edit.text(),
            "position": self.exp_position_edit.text(),
            "start_date": self.exp_start_date.date().toString("yyyy-MM-dd"),
            "end_date": "" if self.exp_current.isChecked() else self.exp_end_date.date().toString("yyyy-MM-dd"),
            "current": self.exp_current.isChecked(),
            "description": self.exp_description.toPlainText()
        }
        
        self.resume_data["experience"][self.current_exp_index] = exp
        self.update_experience_list()
        self.clear_experience_form()
        self.current_exp_index = -1
    
    def remove_experience(self):
        if self.current_exp_index == -1:
            return
            
        self.resume_data["experience"].pop(self.current_exp_index)
        self.update_experience_list()
        self.clear_experience_form()
        self.current_exp_index = -1
    
    def load_experience(self, item):
        index = self.exp_list.row(item)
        self.current_exp_index = index
        exp = self.resume_data["experience"][index]
        
        self.exp_company_edit.setText(exp["company"])
        self.exp_position_edit.setText(exp["position"])
        self.exp_start_date.setDate(QDate.fromString(exp["start_date"], "yyyy-MM-dd"))
        
        if exp["current"]:
            self.exp_current.setChecked(True)
            self.exp_end_date.setEnabled(False)
        else:
            self.exp_current.setChecked(False)
            self.exp_end_date.setDate(QDate.fromString(exp["end_date"], "yyyy-MM-dd"))
            self.exp_end_date.setEnabled(True)
        
        self.exp_description.setPlainText(exp["description"])
    
    def update_experience_list(self):
        self.exp_list.clear()
        for exp in self.resume_data["experience"]:
            item = QListWidgetItem(f"{exp['position']} - {exp['company']}")
            self.exp_list.addItem(item)
    
    def clear_experience_form(self):
        self.exp_company_edit.clear()
        self.exp_position_edit.clear()
        self.exp_start_date.setDate(QDate.currentDate())
        self.exp_end_date.setDate(QDate.currentDate())
        self.exp_current.setChecked(False)
        self.exp_description.clear()
        self.exp_end_date.setEnabled(True)
    
    def add_skill(self):
        skill = f"{self.skill_edit.text()} ({self.skill_level_combo.currentText()})"
        self.resume_data["skills"].append(skill)
        self.update_skills_list()
        self.skill_edit.clear()
    
    def remove_skill(self):
        for item in self.skill_list.selectedItems():
            index = self.skill_list.row(item)
            self.resume_data["skills"].pop(index)
            self.skill_list.takeItem(index)
    
    def update_skills_list(self):
        self.skill_list.clear()
        for skill in self.resume_data["skills"]:
            self.skill_list.addItem(skill)
    
    def add_project(self):
        self.collect_personal_info()
        
        proj = {
            "name": self.proj_name_edit.text(),
            "role": self.proj_role_edit.text(),
            "start_date": self.proj_start_date.date().toString("yyyy-MM-dd"),
            "end_date": "" if self.proj_current.isChecked() else self.proj_end_date.date().toString("yyyy-MM-dd"),
            "current": self.proj_current.isChecked(),
            "url": self.proj_url_edit.text(),
            "description": self.proj_description.toPlainText()
        }
        
        self.resume_data["projects"].append(proj)
        self.update_project_list()
        self.clear_project_form()
    
    def update_project(self):
        if self.current_proj_index == -1:
            return
            
        proj = {
            "name": self.proj_name_edit.text(),
            "role": self.proj_role_edit.text(),
            "start_date": self.proj_start_date.date().toString("yyyy-MM-dd"),
            "end_date": "" if self.proj_current.isChecked() else self.proj_end_date.date().toString("yyyy-MM-dd"),
            "current": self.proj_current.isChecked(),
            "url": self.proj_url_edit.text(),
            "description": self.proj_description.toPlainText()
        }
        
        self.resume_data["projects"][self.current_proj_index] = proj
        self.update_project_list()
        self.clear_project_form()
        self.current_proj_index = -1
    
    def remove_project(self):
        if self.current_proj_index == -1:
            return
            
        self.resume_data["projects"].pop(self.current_proj_index)
        self.update_project_list()
        self.clear_project_form()
        self.current_proj_index = -1
    
    def load_project(self, item):
        index = self.proj_list.row(item)
        self.current_proj_index = index
        proj = self.resume_data["projects"][index]
        
        self.proj_name_edit.setText(proj["name"])
        self.proj_role_edit.setText(proj["role"])
        self.proj_start_date.setDate(QDate.fromString(proj["start_date"], "yyyy-MM-dd"))
        
        if proj["current"]:
            self.proj_current.setChecked(True)
            self.proj_end_date.setEnabled(False)
        else:
            self.proj_current.setChecked(False)
            self.proj_end_date.setDate(QDate.fromString(proj["end_date"], "yyyy-MM-dd"))
            self.proj_end_date.setEnabled(True)
        
        self.proj_url_edit.setText(proj["url"])
        self.proj_description.setPlainText(proj["description"])
    
    def update_project_list(self):
        self.proj_list.clear()
        for proj in self.resume_data["projects"]:
            item = QListWidgetItem(f"{proj['name']} ({proj['role']})")
            self.proj_list.addItem(item)
    
    def clear_project_form(self):
        self.proj_name_edit.clear()
        self.proj_role_edit.clear()
        self.proj_start_date.setDate(QDate.currentDate())
        self.proj_end_date.setDate(QDate.currentDate())
        self.proj_current.setChecked(False)
        self.proj_url_edit.clear()
        self.proj_description.clear()
        self.proj_end_date.setEnabled(True)
    
    def add_certification(self):
        self.collect_personal_info()
        
        cert = {
            "name": self.cert_name_edit.text(),
            "organization": self.cert_org_edit.text(),
            "date": self.cert_date.date().toString("yyyy-MM-dd"),
            "url": self.cert_url_edit.text()
        }
        
        self.resume_data["certifications"].append(cert)
        self.update_certification_list()
        self.clear_certification_form()
    
    def update_certification(self):
        if self.current_cert_index == -1:
            return
            
        cert = {
            "name": self.cert_name_edit.text(),
            "organization": self.cert_org_edit.text(),
            "date": self.cert_date.date().toString("yyyy-MM-dd"),
            "url": self.cert_url_edit.text()
        }
        
        self.resume_data["certifications"][self.current_cert_index] = cert
        self.update_certification_list()
        self.clear_certification_form()
        self.current_cert_index = -1
    
    def remove_certification(self):
        if self.current_cert_index == -1:
            return
            
        self.resume_data["certifications"].pop(self.current_cert_index)
        self.update_certification_list()
        self.clear_certification_form()
        self.current_cert_index = -1
    
    def load_certification(self, item):
        index = self.cert_list.row(item)
        self.current_cert_index = index
        cert = self.resume_data["certifications"][index]
        
        self.cert_name_edit.setText(cert["name"])
        self.cert_org_edit.setText(cert["organization"])
        self.cert_date.setDate(QDate.fromString(cert["date"], "yyyy-MM-dd"))
        self.cert_url_edit.setText(cert["url"])
    
    def update_certification_list(self):
        self.cert_list.clear()
        for cert in self.resume_data["certifications"]:
            item = QListWidgetItem(f"{cert['name']} - {cert['organization']}")
            self.cert_list.addItem(item)
    
    def clear_certification_form(self):
        self.cert_name_edit.clear()
        self.cert_org_edit.clear()
        self.cert_date.setDate(QDate.currentDate())
        self.cert_url_edit.clear()
    
    def add_language(self):
        lang = f"{self.lang_edit.text()} ({self.lang_level_combo.currentText()})"
        self.resume_data["languages"].append(lang)
        self.update_languages_list()
        self.lang_edit.clear()
    
    def remove_language(self):
        for item in self.lang_list.selectedItems():
            index = self.lang_list.row(item)
            self.resume_data["languages"].pop(index)
            self.lang_list.takeItem(index)
    
    def update_languages_list(self):
        self.lang_list.clear()
        for lang in self.resume_data["languages"]:
            self.lang_list.addItem(lang)
    
    def preview_resume(self):
        """生成簡歷預(yù)覽"""
        self.collect_personal_info()
        self.collect_summary()
        
        preview_text = "=== 簡歷預(yù)覽 ===\n\n"
        preview_text += "?? 個人信息:\n"
        preview_text += f"?? 姓名: {self.resume_data['personal_info']['name']}\n"
        preview_text += f"?? 郵箱: {self.resume_data['personal_info']['email']}\n"
        preview_text += f"?? 電話: {self.resume_data['personal_info']['phone']}\n"
        preview_text += f"?? 地址: {self.resume_data['personal_info']['address']}\n"
        preview_text += f"?? LinkedIn: {self.resume_data['personal_info']['linkedin']}\n"
        preview_text += f"?? GitHub: {self.resume_data['personal_info']['github']}\n"
        preview_text += f"?? 個人網(wǎng)站: {self.resume_data['personal_info']['website']}\n\n"
        
        preview_text += "?? 職業(yè)概述:\n"
        preview_text += f"{self.resume_data['summary']}\n\n"
        
        preview_text += "?? 教育經(jīng)歷:\n"
        for edu in self.resume_data["education"]:
            preview_text += f"- ?? {edu['degree']} - {edu['school']} ({edu['field']})\n"
            preview_text += f"  ?? {edu['start_date']} 至 {'至今' if edu['current'] else edu['end_date']}\n"
            preview_text += f"  ?? GPA: {edu['gpa']}\n"
            preview_text += f"  ?? 描述: {edu['description']}\n\n"
        
        preview_text += "?? 工作經(jīng)歷:\n"
        for exp in self.resume_data["experience"]:
            preview_text += f"- ?? {exp['position']} - {exp['company']}\n"
            preview_text += f"  ?? {exp['start_date']} 至 {'至今' if exp['current'] else exp['end_date']}\n"
            preview_text += f"  ?? 描述: {exp['description']}\n\n"
        
        preview_text += "??? 技能:\n"
        for skill in self.resume_data["skills"]:
            preview_text += f"- {skill}\n"
        preview_text += "\n"
        
        preview_text += "?? 項目經(jīng)歷:\n"
        for proj in self.resume_data["projects"]:
            preview_text += f"- ?? {proj['name']} ({proj['role']})\n"
            preview_text += f"  ?? {proj['start_date']} 至 {'進行中' if proj['current'] else proj['end_date']}\n"
            preview_text += f"  ?? URL: {proj['url']}\n"
            preview_text += f"  ?? 描述: {proj['description']}\n\n"
        
        preview_text += "?? 證書:\n"
        for cert in self.resume_data["certifications"]:
            preview_text += f"- ?? {cert['name']} - {cert['organization']} ({cert['date']})\n"
            preview_text += f"  ?? URL: {cert['url']}\n\n"
        
        preview_text += "?? 語言能力:\n"
        for lang in self.resume_data["languages"]:
            preview_text += f"- {lang}\n"
        
        self.preview_text.setPlainText(preview_text)
    
    def export_to_pdf(self):
        self.collect_personal_info()
        self.collect_summary()
        
        # 創(chuàng)建PDF
        pdf = FPDF()
        pdf.add_page()
        pdf.set_auto_page_break(auto=True, margin=15)
        
        # 設(shè)置字體
        pdf.set_font("Arial", 'B', 16)
        
        # 個人信息
        pdf.cell(0, 10, self.resume_data["personal_info"]["name"], 0, 1, 'C')
        pdf.set_font("Arial", '', 12)
        
        contact_info = []
        if self.resume_data["personal_info"]["email"]:
            contact_info.append(self.resume_data["personal_info"]["email"])
        if self.resume_data["personal_info"]["phone"]:
            contact_info.append(self.resume_data["personal_info"]["phone"])
        if self.resume_data["personal_info"]["address"]:
            contact_info.append(self.resume_data["personal_info"]["address"])
        
        pdf.cell(0, 10, " | ".join(contact_info), 0, 1, 'C')
        
        # 添加鏈接
        links = []
        if self.resume_data["personal_info"]["linkedin"]:
            links.append(f"LinkedIn: {self.resume_data['personal_info']['linkedin']}")
        if self.resume_data["personal_info"]["github"]:
            links.append(f"GitHub: {self.resume_data['personal_info']['github']}")
        if self.resume_data["personal_info"]["website"]:
            links.append(f"Website: {self.resume_data['personal_info']['website']}")
        
        if links:
            pdf.cell(0, 10, " | ".join(links), 0, 1, 'C')
        
        pdf.ln(10)
        
        # 職業(yè)概述
        if self.resume_data["summary"]:
            pdf.set_font("Arial", 'B', 14)
            pdf.cell(0, 10, "職業(yè)概述", 0, 1, 'L')
            pdf.set_font("Arial", '', 12)
            pdf.multi_cell(0, 6, self.resume_data["summary"])
            pdf.ln(5)
        
        # 教育經(jīng)歷
        if self.resume_data["education"]:
            pdf.set_font("Arial", 'B', 14)
            pdf.cell(0, 10, "教育經(jīng)歷", 0, 1, 'L')
            pdf.set_font("Arial", '', 12)
            
            for edu in self.resume_data["education"]:
                pdf.set_font("Arial", 'B', 12)
                pdf.cell(0, 6, f"{edu['degree']} - {edu['school']}", 0, 1, 'L')
                pdf.set_font("Arial", '', 12)
                
                date_range = f"{edu['start_date']} - {'至今' if edu['current'] else edu['end_date']}"
                if edu["gpa"]:
                    date_range += f" | GPA: {edu['gpa']}"
                
                pdf.cell(0, 6, f"{edu['field']} | {date_range}", 0, 1, 'L')
                
                if edu["description"]:
                    pdf.multi_cell(0, 6, edu["description"])
                
                pdf.ln(2)
        
        # 工作經(jīng)歷
        if self.resume_data["experience"]:
            pdf.set_font("Arial", 'B', 14)
            pdf.cell(0, 10, "工作經(jīng)歷", 0, 1, 'L')
            pdf.set_font("Arial", '', 12)
            
            for exp in self.resume_data["experience"]:
                pdf.set_font("Arial", 'B', 12)
                pdf.cell(0, 6, f"{exp['position']} - {exp['company']}", 0, 1, 'L')
                pdf.set_font("Arial", '', 12)
                
                pdf.cell(0, 6, f"{exp['start_date']} - {'至今' if exp['current'] else exp['end_date']}", 0, 1, 'L')
                
                if exp["description"]:
                    pdf.multi_cell(0, 6, exp["description"])
                
                pdf.ln(2)
        
        # 技能
        if self.resume_data["skills"]:
            pdf.set_font("Arial", 'B', 14)
            pdf.cell(0, 10, "技能", 0, 1, 'L')
            pdf.set_font("Arial", '', 12)
            
            skills = ", ".join(self.resume_data["skills"])
            pdf.multi_cell(0, 6, skills)
            pdf.ln(5)
        
        # 項目經(jīng)歷
        if self.resume_data["projects"]:
            pdf.set_font("Arial", 'B', 14)
            pdf.cell(0, 10, "項目經(jīng)歷", 0, 1, 'L')
            pdf.set_font("Arial", '', 12)
            
            for proj in self.resume_data["projects"]:
                pdf.set_font("Arial", 'B', 12)
                pdf.cell(0, 6, f"{proj['name']} ({proj['role']})", 0, 1, 'L')
                pdf.set_font("Arial", '', 12)
                
                date_range = f"{proj['start_date']} - {'進行中' if proj['current'] else proj['end_date']}"
                if proj["url"]:
                    date_range += f" | URL: {proj['url']}"
                
                pdf.cell(0, 6, date_range, 0, 1, 'L')
                
                if proj["description"]:
                    pdf.multi_cell(0, 6, proj["description"])
                
                pdf.ln(2)
        
        # 證書
        if self.resume_data["certifications"]:
            pdf.set_font("Arial", 'B', 14)
            pdf.cell(0, 10, "證書", 0, 1, 'L')
            pdf.set_font("Arial", '', 12)
            
            for cert in self.resume_data["certifications"]:
                cert_line = f"{cert['name']} - {cert['organization']} ({cert['date']})"
                if cert["url"]:
                    cert_line += f" | URL: {cert['url']}"
                
                pdf.cell(0, 6, cert_line, 0, 1, 'L')
                pdf.ln(2)
        
        # 語言能力
        if self.resume_data["languages"]:
            pdf.set_font("Arial", 'B', 14)
            pdf.cell(0, 10, "語言能力", 0, 1, 'L')
            pdf.set_font("Arial", '', 12)
            
            langs = ", ".join(self.resume_data["languages"])
            pdf.multi_cell(0, 6, langs)
        
        # 保存PDF
        file_path, _ = QFileDialog.getSaveFileName(self, "保存PDF", "我的簡歷.pdf", "PDF文件 (*.pdf)")
        if file_path:
            pdf.output(file_path)
            QMessageBox.information(self, "成功", "簡歷已成功導出為PDF!")
    
    def save_resume_data(self):
        self.collect_personal_info()
        self.collect_summary()
        
        file_path, _ = QFileDialog.getSaveFileName(self, "保存簡歷數(shù)據(jù)", "resume_data.json", "JSON文件 (*.json)")
        if file_path:
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(self.resume_data, f, ensure_ascii=False, indent=4)
            QMessageBox.information(self, "成功", "簡歷數(shù)據(jù)已保存!")
    
    def load_resume_data(self):
        file_path, _ = QFileDialog.getOpenFileName(self, "加載簡歷數(shù)據(jù)", "", "JSON文件 (*.json)")
        if file_path:
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    self.resume_data = json.load(f)
                
                # 更新UI
                self.update_ui_from_data()
                QMessageBox.information(self, "成功", "簡歷數(shù)據(jù)已加載!")
            except Exception as e:
                QMessageBox.critical(self, "錯誤", f"加載簡歷數(shù)據(jù)失敗: {str(e)}")
    
    def update_ui_from_data(self):
        # 個人信息
        personal_info = self.resume_data["personal_info"]
        self.name_edit.setText(personal_info.get("name", ""))
        self.email_edit.setText(personal_info.get("email", ""))
        self.phone_edit.setText(personal_info.get("phone", ""))
        self.address_edit.setText(personal_info.get("address", ""))
        self.linkedin_edit.setText(personal_info.get("linkedin", ""))
        self.github_edit.setText(personal_info.get("github", ""))
        self.website_edit.setText(personal_info.get("website", ""))
        
        # 職業(yè)概述
        self.summary_edit.setPlainText(self.resume_data.get("summary", ""))
        
        # 教育經(jīng)歷
        self.update_education_list()
        
        # 工作經(jīng)歷
        self.update_experience_list()
        
        # 技能
        self.update_skills_list()
        
        # 項目經(jīng)歷
        self.update_project_list()
        
        # 證書
        self.update_certification_list()
        
        # 語言能力
        self.update_languages_list()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    
    # 設(shè)置應(yīng)用程序樣式和字體
    app.setStyle("Fusion")
    
    # 設(shè)置調(diào)色板
    palette = QPalette()
    palette.setColor(QPalette.Window, QColor(240, 242, 245))
    palette.setColor(QPalette.WindowText, QColor(0, 0, 0))
    palette.setColor(QPalette.Base, QColor(255, 255, 255))
    palette.setColor(QPalette.AlternateBase, QColor(240, 240, 240))
    palette.setColor(QPalette.ToolTipBase, QColor(255, 255, 255))
    palette.setColor(QPalette.ToolTipText, QColor(0, 0, 0))
    palette.setColor(QPalette.Text, QColor(0, 0, 0))
    palette.setColor(QPalette.Button, QColor(240, 240, 240))
    palette.setColor(QPalette.ButtonText, QColor(0, 0, 0))
    palette.setColor(QPalette.BrightText, QColor(255, 0, 0))
    palette.setColor(QPalette.Highlight, QColor(76, 175, 80))
    palette.setColor(QPalette.HighlightedText, QColor(255, 255, 255))
    app.setPalette(palette)
    
    # 創(chuàng)建并顯示主窗口
    window = ResumeGenerator()
    window.show()
    
    sys.exit(app.exec_())

七、總結(jié)與展望

本工具通過PyQt5實現(xiàn)了:

  • 高效管理:比傳統(tǒng)文檔編輯效率提升300%
  • 專業(yè)輸出:符合HR系統(tǒng)的解析標準
  • 靈活定制:模塊化設(shè)計易于擴展

未來可增加:

  • LaTeX導出支持
  • 在線模板市場
  • AI輔助內(nèi)容生成
  • 多語言國際化

Q&A環(huán)節(jié)

Q:如何添加自定義模板?

A:在templates目錄下新建JSON文件,按照現(xiàn)有模板格式編寫樣式規(guī)則。

Q:程序無法顯示中文怎么辦?

A:確保系統(tǒng)已安裝中文字體,并在PDF生成時指定中文字體路徑。

Q:能否導出為Word格式?

A:當前版本僅支持PDF,可通過python-docx庫自行擴展。

相關(guān)技術(shù)棧推薦

  • 高級功能:PyQtGraph數(shù)據(jù)可視化
  • 云存儲:集成Dropbox API
  • 自動化:結(jié)合Selenium實現(xiàn)自動投遞

求職小貼士

使用本工具生成簡歷后,建議:

  • 根據(jù)不同崗位調(diào)整關(guān)鍵詞
  • 保持一頁紙原則
  • 量化工作成果
  • 定期更新內(nèi)容

到此這篇關(guān)于Python+PyQt5實現(xiàn)簡歷自動生成工具的文章就介紹到這了,更多相關(guān)Python自動生成簡歷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論