# softresume
**Repository Path**: csxlin/softresume
## Basic Information
- **Project Name**: softresume
- **Description**: 免费开源的在线简历制作工具 | Vue 3 + Vite 单文件应用 | 19 套模板 · 7 种主题色 · 富文本编辑 · 一键导出 A4 PDF | 无需注册,数据本地存储
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: main
- **Homepage**: https://qing-resume-builder.app.workbuddy.host
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2026-11-03
- **Last Updated**: 2026-11-05
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 轻简历 SoftResume
[](https://qing-resume-builder.app.workbuddy.host/?sharecode=2PFJEBOAWE)
[](./LICENSE)
[](https://v3.vuejs.org/)

免费、开源、无需注册的在线简历制作工具。打开即用,数据只存在浏览器本地,一键导出 A4 PDF。
## ✨ 在线体验
**[👉 https://qing-resume-builder.app.workbuddy.host](https://qing-resume-builder.app.workbuddy.host/?sharecode=2PFJEBOAWE)**
无需注册、无需安装,打开即写;也支持下载仓库中的 `index.html` 直接双击离线使用。
## 📋 功能特性
- **19 套模板**:经典专业 / 时间轴 / 商务横幅 / 现代侧栏 / 极简大字 / 雅致衬线 / 深色侧栏 / 右侧栏 / 双栏紧凑 / 卡片板块 / 瑞士网格 / 渐变横幅 / 日期左列 / 序号章节 / 照片头版 / 杂志衬线 / 极简ATS / 色块头版 / 清新圆角(版式家族参考 Awesome-CV、moderncv、AltaCV、Jake's Resume 等开源模板)
- **主题随心配**:7 种精选主题色 + 自定义取色盘;19 种中英文字体;三档字号、三档行距
- **一个模块 = 一个富文本框**:加粗、斜体、下划线、删除线、圆点 / 编号 / 普通段落、Tab 缩进、局部换字体,都是 Word 式的段落编辑
- **智能一页**:内容超出一页时自动缩小字号压到一页,导出 PDF 不用手动调
- **头像处理**:上传后可裁剪、可切方形 / 圆形
- **多简历管理**:多份简历分别保存,支持导入 / 导出 JSON 备份
- **打印预览**:直接调起浏览器打印界面,导出 A4 PDF
## 技术栈
Vue 3 + Vite + Pinia,零后端、零外部请求。构建产物是**单个 index.html**([vite-plugin-singlefile](https://github.com/richardtallent/vite-plugin-singlefile) 把 JS/CSS 全部内联),所以既可以直接双击打开,也可以丢到任意静态托管。
## 开发
```bash
npm install
npm run dev # http://localhost:5178(开发入口 src/index.html)
npm run build # 产出 dist/index.html,并同步一份到根目录 index.html
npm run preview # 本地预览构建产物
```
> 根目录的 `index.html` 是构建产物(文件头有标注),不要手改;开发用的模板是 `src/index.html`。
## 目录结构
```
index.html ★ 构建产物(单文件成品),已可双击打开 / 直接发布
vite.config.js Vite root 指向 src,构建后自动把成品同步到根目录
src/
├── index.html 开发入口模板
├── main.js 入口:注册 Pinia + 引入分层样式
├── App.vue 三段式布局:顶栏 / 编辑面板 / 预览
├── constants/ 纯数据:板块元信息、字体表、模板与配色、图标
│ ├── sections.js 新增一个板块,只需在这里加一项
│ ├── fonts.js 字体清单 + 分组 + fontStackOf()
│ ├── templates.js 模板 / 配色 / 字号 / 间距 / A4 常量
│ └── icons.js 联系方式图标与字段顺序
├── lib/ 与框架无关的纯逻辑,可单独复用、单测
│ ├── utils.js esc / debounce / parseDate / 颜色混合 …
│ ├── bind.js 短路径绑定(work.items.0.company → sections.…)
│ ├── richtext.js 富文本白名单清洗、结构规整、纯文本镜像
│ ├── caret.js 光标 / 段落级操作(缩进、选区套格式)
│ ├── listOps.js 圆点 / 编号 / 普通段落三态互转
│ ├── image.js 图片压缩、裁剪导出
│ └── print.js 打印:临时改文档标题
├── model/
│ ├── resume.js 数据模型 + 深合并 + 老数据迁移
│ └── sample.js 示例简历
├── stores/
│ ├── resume.js Pinia:多简历、字段写入、自动保存、导入导出
│ └── ui.js 折叠状态、预览↔编辑器定位联动
├── composables/
│ ├── useRteToolbar.js 浮动工具栏(单例,含定位与格式命令)
│ └── useCropper.js 头像裁剪(单例)
├── components/
│ ├── AppTopBar.vue 顶栏
│ ├── DocSwitcher.vue 多简历切换面板
│ ├── EditorPanel.vue 左侧面板 + 拖拽排序
│ ├── cards/ 样式设置 / 基本信息 / 求职意向 / 板块卡片 / 条目表单
│ ├── preview/ A4 纸面、头部、板块、条目、单行字段、富文本区
│ ├── RteToolbar.vue 富文本工具栏
│ ├── CropperDialog.vue 裁剪弹窗
│ └── ui/ 分段选择器、模板缩略图
└── styles/ 按区域拆分的 CSS(base / topbar / layout / editor / resume / templates / toolbar / cropper / print)
```
## 几个关键设计
**数据模型**:一份简历 = `docs[i].data`,结构见 `model/resume.js` 的 `defaultState()`。每个富文本块存两份:`descHtml`(结构)+ `desc`(纯文本镜像,供左侧 textarea 与搜索使用),老数据的 `descRich` / `rich` 由 `legacyToHtml()` 惰性迁移。
**可编辑字段不参与 diff**:预览里的可编辑元素(`InlineField` / `RichArea`)内部自己维护 DOM,只在「值变化且未聚焦」时重绘。否则每次 keystroke 回写状态都会重建文本节点,光标就跳了。这是把 contenteditable 放进响应式框架里最容易踩的坑。
**一个模块 = 一个 contenteditable**:段落、列表由浏览器原生行为产生(Enter 新建 li 并继承缩进),我们只补浏览器做不好的部分:Tab 整块缩进、列表类型互转、空列表项退格兜底。所有 HTML 落库前都过 `sanitizeRichHtml()` 白名单。
**自动保存**:Pinia 的 `$subscribe` 深度监听 + 400ms 防抖写 localStorage,切换简历 / 导入前会 `flushNow()` 立即落盘。
**打印**:`@page A4` + 打印时隐藏顶栏 / 编辑面板 / 辅助线与占位提示,纸面宽度改 210mm,页数由真实内容高度决定;「一页」开关会在超页时按 4.5% 步进缩小字号。
## 部署
构建产物是单文件,丢哪儿都能跑:
```bash
npm run build
# 根目录 index.html(与 dist/index.html 同内容)上传到任意静态托管均可
# Gitee Pages / Nginx / OSS / Vercel / Cloudflare Pages 都只是「放一个 html 文件」
```
静态托管方(含 workbuddy 应用发布)直接把项目根目录当站点根即可,因为根目录的 `index.html` 就是成品;不需要在服务器上 `npm install`。
## 数据与隐私
所有内容都在 `localStorage`(键名 `qingresume_docs_v1`),不上传任何服务器。换设备/换浏览器请用「导出JSON」备份再「导入」。
## 版本说明
`v1.0-single-file` 标签是重构前的单文件版本(一个 2700 行的 index.html),保留在 git 历史里便于对照:
```bash
git show v1.0-single-file:index.html > legacy.html
```
## License
MIT