change to next
This commit is contained in:
174
backup/web/src/apps/cv/index.tsx
Normal file
174
backup/web/src/apps/cv/index.tsx
Normal file
@@ -0,0 +1,174 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import MDEditor from '@uiw/react-md-editor'
|
||||
import { ToastContainer, Slide } from 'react-toastify'
|
||||
import { Save, Download, Printer, Eye, Edit, RotateCcw } from 'lucide-react'
|
||||
import 'github-markdown-css/github-markdown-light.css'
|
||||
import './index.css'
|
||||
|
||||
const defaultResume = `# 张三
|
||||
|
||||
**前端开发工程师** | 北京 | zhangsan@example.com | 138-0000-0000
|
||||
|
||||
## 个人简介
|
||||
|
||||
热爱前端开发,拥有5年React和Vue开发经验。专注于构建高性能、可维护的Web应用。
|
||||
|
||||
## 工作经历
|
||||
|
||||
### 高级前端工程师 | ABC科技有限公司
|
||||
*2021年6月 - 至今*
|
||||
|
||||
- 负责公司核心产品的前端架构设计和开发
|
||||
- 使用React和TypeScript构建企业级管理系统
|
||||
- 优化前端性能,页面加载速度提升40%
|
||||
- 带领5人前端团队,制定代码规范和最佳实践
|
||||
|
||||
### 前端开发工程师 | XYZ互联网公司
|
||||
*2019年3月 - 2021年5月*
|
||||
|
||||
- 参与电商平台的前端开发
|
||||
- 使用Vue.js开发响应式Web应用
|
||||
- 与后端团队协作,实现RESTful API对接
|
||||
|
||||
## 技能
|
||||
|
||||
- **前端框架**: React, Vue.js, Next.js, Astro
|
||||
- **编程语言**: TypeScript, JavaScript, HTML5, CSS3
|
||||
- **工具**: Git, Webpack, Vite, Docker
|
||||
- **其他**: Node.js, GraphQL, Tailwind CSS
|
||||
|
||||
## 教育背景
|
||||
|
||||
### 计算机科学与技术 | 本科
|
||||
*北京某大学 | 2015年9月 - 2019年6月*
|
||||
|
||||
- 主修课程:数据结构、算法、计算机网络、数据库原理
|
||||
- 优秀毕业生,GPA 3.8/4.0
|
||||
|
||||
## 项目经验
|
||||
|
||||
### 企业级管理系统
|
||||
*技术栈: React, TypeScript, Ant Design*
|
||||
|
||||
- 设计并实现模块化权限管理系统
|
||||
- 开发数据可视化大屏,支持实时数据展示
|
||||
- 编写单元测试,代码覆盖率达到85%
|
||||
|
||||
### 电商平台前端
|
||||
*技术栈: Vue.js, Vuex, Element UI*
|
||||
|
||||
- 实现购物车、订单管理等核心功能
|
||||
- 优化首屏加载时间,LCP从2.5s降至1.2s
|
||||
- 响应式设计,完美支持移动端访问
|
||||
|
||||
## 语言能力
|
||||
|
||||
- 英语:CET-6,能够阅读英文技术文档
|
||||
- 普通话:母语
|
||||
`
|
||||
|
||||
export const AppProvider = () => {
|
||||
return (
|
||||
<div>
|
||||
<App />
|
||||
<ToastContainer transition={Slide} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const App = () => {
|
||||
const [markdown, setMarkdown] = useState<string | undefined>(defaultResume)
|
||||
const [isPreviewMode, setIsPreviewMode] = useState(false)
|
||||
|
||||
// 从 localStorage 加载保存的简历
|
||||
useEffect(() => {
|
||||
const saved = localStorage.getItem('cv-content')
|
||||
if (saved) {
|
||||
setMarkdown(saved)
|
||||
}
|
||||
}, [])
|
||||
|
||||
// 保存到 localStorage
|
||||
const handleSave = () => {
|
||||
if (markdown) {
|
||||
localStorage.setItem('cv-content', markdown)
|
||||
alert('简历已保存!')
|
||||
}
|
||||
}
|
||||
|
||||
// 导出为 Markdown 文件
|
||||
const handleExport = () => {
|
||||
if (markdown) {
|
||||
const blob = new Blob([markdown], { type: 'text/markdown' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = 'resume.md'
|
||||
a.click()
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
}
|
||||
|
||||
// 打印简历
|
||||
const handlePrint = () => {
|
||||
window.print()
|
||||
}
|
||||
|
||||
// 重置为默认模板
|
||||
const handleReset = () => {
|
||||
if (confirm('确定要重置为默认模板吗?当前内容将丢失。')) {
|
||||
setMarkdown(defaultResume)
|
||||
localStorage.removeItem('cv-content')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="cv-app">
|
||||
<header className="cv-header">
|
||||
<h1>📄 简历编辑器</h1>
|
||||
<div className="cv-actions">
|
||||
<button onClick={handleSave} className="cv-btn cv-btn-primary">
|
||||
<Save size={16} />
|
||||
<span>保存</span>
|
||||
</button>
|
||||
<button onClick={handleExport} className="cv-btn cv-btn-secondary">
|
||||
<Download size={16} />
|
||||
<span>导出 MD</span>
|
||||
</button>
|
||||
<button onClick={handlePrint} className="cv-btn cv-btn-secondary">
|
||||
<Printer size={16} />
|
||||
<span>打印</span>
|
||||
</button>
|
||||
<button onClick={() => setIsPreviewMode(!isPreviewMode)} className="cv-btn cv-btn-secondary">
|
||||
{isPreviewMode ? <Edit size={16} /> : <Eye size={16} />}
|
||||
<span>{isPreviewMode ? '编辑' : '预览'}</span>
|
||||
</button>
|
||||
<button onClick={handleReset} className="cv-btn cv-btn-danger">
|
||||
<RotateCcw size={16} />
|
||||
<span>重置</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{isPreviewMode ? (
|
||||
<div className="cv-preview-container">
|
||||
<div className="cv-preview markdown-body">
|
||||
<MDEditor.Markdown source={markdown} />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="cv-editor-container" data-color-mode="light">
|
||||
<MDEditor
|
||||
value={markdown}
|
||||
onChange={setMarkdown}
|
||||
height={800}
|
||||
preview="edit"
|
||||
textareaProps={{
|
||||
placeholder: '在这里输入你的简历内容(支持 Markdown 格式)...'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user