从零到一开发电子病历编辑器(源码+教程)

最近一直在研发AI+数字化办公产品,对文档编辑器的底层实现做了大量的研究,所以最近抽空花时间写了一款轻量级的电子病历编辑器:

技术栈我采用目前目前比较就行的Vite + Vue3实现,帮助大家用一杯咖啡的钱(19.9元)解锁新技能。文末我会提供完整的教程和源码,如果大家有需求可以参考一下。

项目介绍

电子病历编辑器是一个基于Vue 3的富文本编辑器,专为医疗行业设计,用于创建、编辑和管理电子病历文档。本项目采用组件化设计,实现了文本编辑、表格操作、图片插入、模板管理等功能,并支持导出为PDF和图片格式。

主要功能

  • 富文本编辑(加粗、斜体、下划线等)

  • 表格创建与编辑

  • 图片插入与管理

  • 医疗模板管理

  • 文档导出(PDF、图片)

  • 自动保存

技术栈

  • 前端框架 Vue3 + Composition API
  • 构建工具 Vite
  • 数据存储 IndexedDB (通用idb库)
  • 文档导出 jsPDF、html2canvas
  • 文件处理 file-saver

项目结构

核心功能实现

3.1 富文本编辑器实现

电子病历编辑器的核心是基于浏览器原生的 contenteditable 属性和 document.execCommand API 实现的。

基本原理

typescript 复制代码
// 设置内容可编辑<div   class="editor-content"   contenteditable="true"  ref="editorContent"  @input="updateContent"  @click="checkTableFocus"></div>
// 执行编辑命令const execCommand = (command, value = null) => {  try {    document.execCommand(command, false, value);  } catch (error) {    console.error(`执行命令 ${command} 时出错:`, error);  }};

编辑器接口

为了方便子组件调用编辑器功能,我创建了一个统一的编辑器接口:

javascript 复制代码
const editorInterface = {  execCommand: (command, showUI, value) => {    saveSelection();    document.execCommand(command, showUI, value);    restoreSelection();    updateContent();  },  getContent: () => {    return editorContent.value ? editorContent.value.innerHTML : '';  },  setContent: (content) => {    if (editorContent.value) {      editorContent.value.innerHTML = content;      updateContent();    }  },  focus: () => {    if (editorContent.value) {      editorContent.value.focus();    }  },  isActive: (command) => {    try {      return document.queryCommandState(command);    } catch (error) {      console.error(`检查命令状态 ${command} 时出错:`, error);      return false;    }  }};

选区管理

在富文本编辑中,正确管理选区是确保编辑操作准确执行的关键。接下来分享一下我设计的选取管理功能:

javascript 复制代码
// 保存当前选区const saveSelection = () => {  const selection = window.getSelection();  if (selection.rangeCount > 0) {    savedSelection.value = selection.getRangeAt(0).cloneRange();  }};
// 恢复保存的选区const restoreSelection = () => {  if (savedSelection.value) {    const selection = window.getSelection();    selection.removeAllRanges();    selection.addRange(savedSelection.value);    return true;  }  return false;};

表格操作功能

表格操作是电子病历编辑器的重要功能,包括创建表格、插入/删除行列、合并/拆分单元格等。表格实现的核心代码介绍:

javascript 复制代码
const handleCreateTable = ({ rows, cols, style, hasHeader }) => {  try {    // 创建表格HTML    let tableHTML = '<table border="1" style="width: 100%; border-collapse: collapse;">';
    // 添加表头    if (hasHeader) {      tableHTML += '<thead><tr>';      for (let j = 0; j < cols; j++) {        tableHTML += '<th style="background-color: #f5f5f5; font-weight: bold; padding: 8px;">表头</th>';      }      tableHTML += '</tr></thead>';    }
    // 添加表格内容    tableHTML += '<tbody>';    for (let i = 0; i < (hasHeader ? rows - 1 : rows); i++) {      tableHTML += '<tr>';      for (let j = 0; j < cols; j++) {        tableHTML += '<td style="padding: 8px;">单元格</td>';      }      tableHTML += '</tr>';    }    tableHTML += '</tbody></table><p><br></p>';
    // 插入表格    document.execCommand('insertHTML', false, tableHTML);  } catch (error) {    console.error('插入表格时出错:', error);  }};

表格行列操作:

javascript 复制代码
// 插入行const insertRow = (table, rowIndex) => {  try {    // 确定要插入行的位置    let tbody = table.querySelector('tbody');    if (!tbody) {      tbody = table;    }
    // 创建新行    const newRow = document.createElement('tr');
    // 获取列数    const columnCount = table.rows[0].cells.length;
    // 添加单元格    for (let i = 0; i < columnCount; i++) {      const newCell = document.createElement('td');      newCell.innerHTML = '单元格';      newCell.style.padding = '8px';      newRow.appendChild(newCell);    }
    // 插入新行    if (rowIndex < tbody.rows.length) {      tbody.insertBefore(newRow, tbody.rows[rowIndex]);    } else {      tbody.appendChild(newRow);    }  } catch (error) {    console.error('插入行失败:', error);    throw error;  }};
// 插入列const insertColumn = (table, columnIndex) => {  try {    for (let i = 0; i < table.rows.length; i++) {      const row = table.rows[i];      const newCell = document.createElement(row.cells[0].nodeName);      newCell.innerHTML = '单元格';      newCell.style.padding = '8px';
      if (columnIndex < row.cells.length) {        row.insertBefore(newCell, row.cells[columnIndex]);      } else {        row.appendChild(newCell);      }    }  } catch (error) {    console.error('插入列失败:', error);    throw error;  }};

图片插入功能

图片插入功能支持从URL插入和本地上传两种方式。具体实现如下:

kotlin 复制代码
const handleInsertImage = (imgSrc) => {  try {    if (!imgSrc) return;
    // 创建图片HTML    const imgHtml = `<div style="text-align: center; margin: 10px 0;"><img src="${imgSrc}" alt="插入的图片" style="max-width: 100%; height: auto;"></div><p><br></p>`;
    // 确保编辑器有焦点并恢复选区    editorContent.value.focus();    restoreSelection();
    // 使用document.execCommand插入HTML    document.execCommand('insertHTML', false, imgHtml);  } catch (error) {    console.error('插入图片时出错:', error);  }};

自动保存功能

自动保存功能使用IndexedDB存储编辑器内容,确保用户不会丢失工作。我实现了一个自动保存管理器来管理:

javascript 复制代码
// 创建自动保存管理器const autoSaveManager = createAutoSaveManager(saveCurrentContent, 30000);
// 自动保存当前内容const saveCurrentContent = async () => {  try {    if (!editorContent.value) return;
    const content = editorContent.value.innerHTML;    currentRecordId.value = await saveRecord(content, currentRecordId.value || 'current-record');    autoSaveStatus.value = `已保存 (${new Date().toLocaleTimeString()})`;  } catch (error) {    console.error('自动保存失败:', error);    autoSaveStatus.value = '保存失败';  }};

文档导出功能

编辑器支持将文档导出为PDF和图片格式。这个功能是我设计的核心功能之一,也涉及到一些解析方案,并支持不同分辨率图片的导出。代码实现框架如下:

相关推荐
烬头88211 小时前
React Native鸿蒙跨平台实现二维码联系人APP(QRCodeContactApp)
javascript·react native·react.js·ecmascript·harmonyos
pas1361 小时前
40-mini-vue 实现三种联合类型
前端·javascript·vue.js
摇滚侠1 小时前
2 小时快速入门 ES6 基础视频教程
前端·ecmascript·es6
2601_949833391 小时前
flutter_for_openharmony口腔护理app实战+预约管理实现
android·javascript·flutter
珑墨2 小时前
【Turbo】使用介绍
前端
军军君013 小时前
Three.js基础功能学习十三:太阳系实例上
前端·javascript·vue.js·学习·3d·前端框架·three
xiaoqi9223 小时前
React Native鸿蒙跨平台如何实现分类页面组件通过searchQuery状态变量管理搜索输入,实现了分类的实时过滤功能
javascript·react native·react.js·ecmascript·harmonyos
打小就很皮...4 小时前
Tesseract.js OCR 中文识别
前端·react.js·ocr
qq_177767374 小时前
React Native鸿蒙跨平台实现应用介绍页,实现了应用信息卡片展示、特色功能网格布局、权限/联系信息陈列、评分展示、模态框详情交互等通用场景
javascript·react native·react.js·ecmascript·交互·harmonyos
2603_949462104 小时前
Flutter for OpenHarmony社团管理App实战:预算管理实现
android·javascript·flutter