跳过正文

WPS二次开发接口(JS-API)实战:开发一个会议纪要自动生成插件

在高效办公的时代,自动化是提升生产力的核心。你是否厌倦了每次会议后手动整理杂乱无章的讨论要点、行动项和待办清单?对于WPS Office的高级用户和开发者而言,其强大的二次开发能力——特别是基于JavaScript的JS-API——为我们打开了定制化、自动化办公解决方案的大门。本文将以一个极具实用价值的“会议纪要自动生成插件”为例,带你从零开始,深入实战,完整掌握利用WPS JS-API开发自定义插件的全流程。无论你是希望下载WPS并探索其高级功能的用户,还是寻求将 WPS Office 集成到特定工作流中的开发者,本篇指南都将提供清晰的路径。

wps WPS二次开发接口(JS-API)实战:开发一个会议纪要自动生成插件

引言:为什么选择WPS JS-API进行办公自动化?
#

WPS Office不仅是一款功能全面的办公套件,更是一个开放的开发平台。其提供的JavaScript API(JS-API)允许开发者使用熟悉的Web技术(HTML, CSS, JavaScript)来扩展WPS的功能,创建自定义任务窗格、功能区按钮和自动化脚本。相较于传统的VBA宏,JS-API具有跨平台潜力(尤其在云端和移动端愿景中)、与现代Web技术栈无缝集成安全性更高以及能够创建更丰富的用户界面等优势。

本实战项目旨在开发一个插件,它能自动分析一份记录了原始讨论内容的WPS文字文档,智能提取关键信息(如会议主题、时间、参会人、决议、行动项等),并按照标准的企业会议纪要格式,生成一份结构清晰、可直接分发的正式文档。这个过程将涉及文档内容读取、文本模式识别、新文档创建与格式化等核心操作,充分展示JS-API的核心能力。

第一部分:开发环境搭建与项目初始化
#

wps 第一部分:开发环境搭建与项目初始化

在开始编码之前,我们需要准备好正确的开发环境。WPS JS-API插件的开发主要依赖WPS Office桌面版(开发者模式)和一个代码编辑器。

1.1 环境准备与工具清单
#

  • WPS Office 版本要求:请确保安装的是WPS Office 2019专业版或以上版本,或者WPS Office 开发者版。个人版可能对插件加载有一定限制。你可以访问我们的指南《 如何免费下载正版WPS Office个人版:官方安全指南》了解官方下载渠道,但为了开发,建议获取专业版或启用开发者模式。
  • 代码编辑器:任何你熟悉的编辑器均可,如VS Code、WebStorm、Sublime Text等。VS Code因其强大的JavaScript和调试支持而广受推荐。
  • 基础知识:需要具备基本的HTML、CSS和JavaScript(ES6+)知识。无需提前精通WPS API。

1.2 创建你的第一个WPS JS-API插件项目
#

WPS JS-API插件本质上是一个包含特定配置文件的网页应用。我们手动创建项目结构以理解其构成。

  1. 创建项目文件夹:在本地创建一个新文件夹,例如 WPS-Meeting-Minutes-Generator
  2. 初始化核心文件:在该文件夹内,创建以下文件:
    • manifest.xml: 插件的“身份证”,用于向WPS声明插件信息。
    • ribbon.xml: 定义在WPS功能区显示的按钮和控件。
    • index.html: 插件任务窗格的主界面。
    • main.js: 主要的JavaScript逻辑代码。
    • style.css: 插件界面的样式文件。

1.3 详解配置文件:Manifest与Ribbon
#

manifest.xml 示例

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Manifest xmlns="http://schemas.microsoft.com/office/taskpaneappversion-1.0">
    <OfficeApp>
        <Id>your-unique-plugin-id</Id> <!-- 建议使用GUID生成器生成唯一ID -->
        <Version>1.0.0.0</Version>
        <ProviderName>WPSWM.COM</ProviderName>
        <DisplayName DefaultValue="会议纪要生成器" />
        <Description DefaultValue="自动从原始记录生成标准会议纪要。"/>
        <IconUrl DefaultValue="https://wpswm.com/icon-32.png"/> <!-- 可选 -->
        <Hosts>
            <Host Name="Document" />
        </Hosts>
        <DefaultSettings>
            <SourceLocation DefaultValue="index.html" />
        </DefaultSettings>
        <Permissions>ReadWriteDocument</Permissions>
    </OfficeApp>
</Manifest>

关键点<Id> 必须唯一,<Host Name="Document"> 表示此插件寄宿于WPS文字组件。

ribbon.xml 示例

<?xml version="1.0" encoding="utf-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
    <ribbon>
        <tabs>
            <tab id="TabWPSWM" label="WPS智能工具">
                <group id="GroupMeeting" label="会议纪要">
                    <button id="ButtonGenerate" label="生成纪要" size="large" 
                            onAction="ButtonGenerate_Click" 
                            imageMso="ContentControlRichText" />
                </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>

关键点:此文件在WPS功能区创建了一个名为“WPS智能工具”的新标签页,并放置了一个“生成纪要”的按钮。onAction 属性指定的 ButtonGenerate_Click 是一个回调函数,需要在JS中实现。

1.4 加载插件到WPS Office
#

  1. 将整个项目文件夹复制到WPS的插件目录。通常路径为:C:\Users\[你的用户名]\Documents\Kingsoft\wps\addons\(Windows)。如果目录不存在,可手动创建 addons 文件夹。
  2. 启动或重启WPS文字。
  3. 点击“开发工具”选项卡(如果未显示,需要在“文件”->“选项”->“自定义功能区”中勾选),你应该能看到“WPS智能工具”标签页和我们的按钮。首次加载可能会提示启用插件,请选择允许。

至此,开发环境与项目骨架已搭建完毕。接下来,我们将进入核心逻辑的编写。

第二部分:插件核心逻辑设计与实现
#

wps 第二部分:插件核心逻辑设计与实现

我们的插件核心功能是:解析当前活动文档 -> 提取结构化信息 -> 生成新文档。我们将分步实现。

2.1 理解WPS JS-API对象模型
#

WPS JS-API的对象模型与Microsoft Office JS API高度兼容,核心对象包括:

  • Application: 代表整个WPS应用程序。
  • Document: 代表一个文档,我们可以通过 Application.ActiveDocument 获取当前文档。
  • Range: 代表文档中的一个连续区域,是进行文本操作的主要对象。
  • Paragraphs, Tables, Styles 等集合与对象,用于访问特定元素。

2.2 实现Ribbon按钮回调与任务窗格通信
#

首先,在 index.html 中创建简单的任务窗格界面,并在 main.js 中实现按钮回调。

index.html (精简版):

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>会议纪要生成器</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id="app">
        <h3>会议纪要智能生成</h3>
        <p>请确保当前文档为原始的会议讨论记录。</p>
        <div class="control-group">
            <label for="theme">会议主题关键词:</label>
            <input type="text" id="theme" placeholder="例如:Q3产品规划会">
        </div>
        <button id="btnStart">开始分析与生成</button>
        <div id="status"></div>
    </div>
    <script src="main.js"></script>
</body>
</html>

main.js - 按钮回调与初始化:

// 全局变量,用于与WPS API交互
let Wps = window.Wps || window.Application;

// Ribbon按钮点击事件的全局回调函数(必须暴露给全局作用域)
function ButtonGenerate_Click() {
    // 此函数的作用是显示我们的任务窗格。
    // 在真实的开发中,可能需要调用WPS API来确保任务窗格可见。
    // 为了简化,我们假设插件加载后任务窗格已自动显示。
    console.log("Ribbon按钮被点击");
    document.getElementById('status').innerText = '请点击下方的“开始分析与生成”按钮。';
}

// 页面加载完成后,绑定任务窗格内按钮的事件
document.addEventListener('DOMContentLoaded', function() {
    document.getElementById('btnStart').addEventListener('click', generateMinutes);
});

// 核心生成函数
async function generateMinutes() {
    const statusDiv = document.getElementById('status');
    statusDiv.innerHTML = '<em>正在分析当前文档...</em>';
    
    try {
        // 确保WPS API已就绪
        await Wps.run(async context => {
            const document = context.application.activeDocument;
            context.load(document, 'paragraphs');
            await context.sync();
            
            // 1. 获取全文内容
            const fullTextRange = document.getRange();
            fullTextRange.load('text');
            await context.sync();
            const rawText = fullTextRange.text;
            
            statusDiv.innerHTML = '<em>正在提取关键信息...</em>';
            
            // 2. 调用信息提取逻辑(下一节实现)
            const meetingInfo = extractMeetingInfo(rawText);
            
            statusDiv.innerHTML = '<em>正在生成标准纪要文档...</em>';
            
            // 3. 创建新文档并格式化(下一节实现)
            await createFormattedMinutes(context, meetingInfo);
            
            statusDiv.innerHTML = '<strong style=\"color:green;\">✅ 会议纪要生成成功!已在新文档中打开。</strong>';
        });
    } catch (error) {
        console.error('生成失败:', error);
        statusDiv.innerHTML = `<strong style=\"color:red;\">❌ 生成失败: ${error.message}</strong>`;
    }
}

说明:我们使用了 Wps.run 这个批处理模式来执行所有API调用,这是JS-API推荐的最佳实践,能提升性能并减少与客户端同步的次数。

2.3 实现文本分析与信息提取引擎
#

这是本插件的“大脑”。我们需要编写 extractMeetingInfo 函数。这里采用基于规则的模式匹配,这是一个务实且有效的起点。

function extractMeetingInfo(rawText) {
    const info = {
        theme: document.getElementById('theme').value || '临时会议',
        date: null,
        time: null,
        attendees: [],
        resolutions: [],
        actionItems: [] // 包含负责人和截止日期
    };
    
    const lines = rawText.split(/\r?\n/).filter(line => line.trim());
    
    // 规则1:提取日期(简单正则匹配)
    const datePattern = /\d{4}[-年]\d{1,2}[-月]\d{1,2}[日]?|\d{1,2}[-/]\d{1,2}[-/]\d{2,4}/;
    for (let line of lines) {
        const match = line.match(datePattern);
        if (match && !info.date) {
            info.date = match[0];
            break;
        }
    }
    
    // 规则2:提取参会人(寻找包含“参会”、“出席”、“人员”等关键词的行)
    const attendeeKeywords = ['参会', '出席', '人员', '参加', '与会'];
    for (let line of lines) {
        if (attendeeKeywords.some(keyword => line.includes(keyword))) {
            // 简单分割,实际应用可能需要更复杂的解析(如“张三、李四、王五”)
            const parts = line.split(/[::]/);
            if (parts.length > 1) {
                info.attendees = parts[1].split(/[,,、\s]+/).map(name => name.trim()).filter(name => name);
            }
            break;
        }
    }
    
    // 规则3:提取决议(寻找包含“决议”、“决定”、“同意”等关键词的段落)
    const resolutionKeywords = ['决议', '决定', '同意', '通过', '确认'];
    info.resolutions = lines.filter(line => 
        resolutionKeywords.some(keyword => line.includes(keyword))
    ).slice(0, 5); // 最多取5条
    
    // 规则4:提取行动项(寻找包含“负责”、“截止”、“完成”等任务性词汇的句子)
    const actionPattern = /(.+?)\s+(?:由|负责)?\s*([\u4e00-\u9fa5]{2,4})\s*(?:在|于|截止)?\s*(\d{1,2}[-月]\d{1,2}[日]?|\d{4}-\d{1,2}-\d{1,2})/;
    for (let line of lines) {
        const match = line.match(actionPattern);
        if (match) {
            info.actionItems.push({
                task: match[1].trim(),
                owner: match[2].trim(),
                deadline: match[3].trim()
            });
        }
    }
    
    // 如果没有匹配到行动项,尝试更简单的模式
    if (info.actionItems.length === 0) {
        const simpleActionLines = lines.filter(line => line.includes('TODO') || line.includes('Action') || line.includes('下一步'));
        info.actionItems = simpleActionLines.map(line => ({ task: line, owner: '待定', deadline: '待定' }));
    }
    
    return info;
}

提示:此提取引擎较为基础。在实际产品中,你可以集成更复杂的NLP库(需考虑插件体积),或允许用户通过交互式界面进行修正,如高亮文本后指定其类型。这展示了《 WPS Office AI功能体验测评:智能写作、排版与数据分析实战》中提到的AI能力与自动化结合的潜力方向。

2.4 实现新文档创建与自动化排版
#

现在,我们将提取的信息填充到一个格式规范的新文档中。这充分运用了WPS文字通过JS-API进行格式控制的能力。

async function createFormattedMinutes(context, meetingInfo) {
    // 创建一个新的WPS文字文档
    const newDocument = context.application.documents.add();
    
    // 获取新文档的起始Range
    let range = newDocument.getRange();
    
    // 1. 写入标题
    range.insertText(`会议纪要:${meetingInfo.theme}\n`, 'After');
    range = range.expandTo(newDocument.body.paragraphs.last); // 移动range到最后一段
    range.font.bold = true;
    range.font.size = 16;
    range.paragraphFormat.alignment = 'Center'; // 居中
    
    // 2. 写入基本信息表格
    range.insertText('\n'); // 换行
    range = range.expandTo(newDocument.body.paragraphs.last);
    
    // 创建一个2x4的表格
    const table = newDocument.body.tables.add(range, 4, 2); // 4行2列
    table.borders.enable = true;
    
    // 填充表格内容
    table.rows.getItem(0).cells.getItem(0).range.text = '会议日期';
    table.rows.getItem(0).cells.getItem(1).range.text = meetingInfo.date || '待补充';
    table.rows.getItem(1).cells.getItem(0).range.text = '会议时间';
    table.rows.getItem(1).cells.getItem(1).range.text = meetingInfo.time || '待补充';
    table.rows.getItem(2).cells.getItem(0).range.text = '会议地点';
    table.rows.getItem(2).cells.getItem(1).range.text = '待补充';
    table.rows.getItem(3).cells.getItem(0).range.text = '参会人员';
    table.rows.getItem(3).cells.getItem(1).range.text = meetingInfo.attendees.join('、 ') || '待补充';
    
    // 3. 写入决议部分
    range = newDocument.body.paragraphs.last.getRange('End');
    range.insertText('\n\n二、会议决议\n', 'After');
    range = range.expandTo(newDocument.body.paragraphs.last);
    range.font.bold = true; // 小标题加粗
    
    if (meetingInfo.resolutions.length > 0) {
        for (let res of meetingInfo.resolutions) {
            range = newDocument.body.paragraphs.last.getRange('End');
            range.insertText(`• ${res}\n`, 'After');
        }
    } else {
        range = newDocument.body.paragraphs.last.getRange('End');
        range.insertText('(本次会议未形成明确决议)\n', 'After');
    }
    
    // 4. 写入行动项部分(使用更清晰的表格)
    range = newDocument.body.paragraphs.last.getRange('End');
    range.insertText('\n\n三、行动项(Action Items)\n', 'After');
    range = range.expandTo(newDocument.body.paragraphs.last);
    range.font.bold = true;
    
    if (meetingInfo.actionItems.length > 0) {
        // 创建行动项表格,4列:序号、工作内容、负责人、截止日期
        const actionTableRange = newDocument.body.paragraphs.last.getRange('End');
        const actionTable = newDocument.body.tables.add(actionTableRange, meetingInfo.actionItems.length + 1, 4); // 表头+数据行
        actionTable.borders.enable = true;
        actionTable.rows.getItem(0).shading.backgroundPatternColor = '#E6E6E6'; // 表头背景色
        
        // 设置表头
        const headers = ['序号', '工作内容', '负责人', '截止日期'];
        for (let i = 0; i < headers.length; i++) {
            const cell = actionTable.rows.getItem(0).cells.getItem(i);
            cell.range.text = headers[i];
            cell.range.font.bold = true;
            cell.range.paragraphFormat.alignment = 'Center';
        }
        
        // 填充数据
        for (let i = 0; i < meetingInfo.actionItems.length; i++) {
            const item = meetingInfo.actionItems[i];
            const row = actionTable.rows.getItem(i + 1);
            row.cells.getItem(0).range.text = (i + 1).toString();
            row.cells.getItem(1).range.text = item.task;
            row.cells.getItem(2).range.text = item.owner;
            row.cells.getItem(3).range.text = item.deadline;
        }
    }
    
    // 5. 应用文档样式(可选)
    // 可以尝试应用WPS内置的“标题1”、“标题2”等样式,使文档更专业
    // 关于样式管理,可参考《WPS文字样式管理与格式刷高级用法:快速统一企业文档规范》(https://wpswm.com/news/49/)
    
    // 最后,将光标移动到文档开头
    newDocument.activate(); // 激活新文档窗口
    await context.sync();
}

通过以上步骤,一个具备基础智能的会议纪要自动生成插件就实现了。它展示了从文档读取、数据处理到文档生成和格式化的完整闭环。

第三部分:插件调试、打包与发布建议
#

wps 第三部分:插件调试、打包与发布建议

3.1 调试技巧
#

  • 控制台日志:在 main.js 中广泛使用 console.log。在WPS中,你需要打开开发者工具来查看日志。在WPS文字中,按 F12 或通过“开发工具”选项卡打开“脚本编辑器”或“Web检查器”(取决于版本)。
  • 错误处理:始终用 try...catch 包裹 Wps.run 块,并在界面上友好地提示用户,如我们代码中所做。
  • API探查:使用 context.load 显式加载你需要访问的属性,并在 context.sync 后访问它们,这是避免“PropertyNotLoaded”错误的关键。

3.2 性能优化与代码组织
#

  • 批量操作:始终在单个 Wps.run 批处理中执行尽可能多的操作,减少 context.sync 的调用次数。
  • 模块化:随着功能复杂,将 extractMeetingInfocreateFormattedMinutes 等函数拆分到独立模块文件中。
  • UI反馈:在长时间操作(如处理超长文档)时,务必在任务窗格中提供清晰的进度状态,避免用户以为插件无响应。

3.3 插件打包与分发
#

  1. 清理与压缩:清理调试代码,压缩(Minify)你的JS和CSS文件以减小插件体积。
  2. 创建安装包:最简单的分发方式是将整个插件文件夹打包成ZIP文件,并重命名为 .wpsaddon 后缀(例如 MeetingMinutesGenerator.wpsaddon)。
  3. 用户安装:最终用户可以通过WPS文字中的“开发工具”->“插件管理”->“加载插件包”来安装此 .wpsaddon 文件。
  4. 安全考虑:由于插件具有 ReadWriteDocument 权限,务必从可信来源获取插件。对于企业部署,可以参考《 WPS Office企业部署与集中管理方案:权限控制与批量安装教程》进行集中分发和管理。

第四部分:进阶可能性与扩展思路
#

本实战项目只是一个起点,WPS JS-API的潜力远不止于此。你可以考虑以下方向进行扩展:

  • 集成云端AI服务:将文本提取引擎替换为调用云端NLP API(如百度ERNIE、腾讯NLP),实现更精准的实体识别、情感分析和摘要生成。
  • 与WPS云文档联动:将生成的会议纪要自动保存到指定的WPS云文档团队空间,并@相关责任人。这需要结合《 WPS云文档团队协作全流程:实时编辑、评论与权限管理详解》中提到的云API。
  • 生成甘特图或时间线:将行动项自动同步到WPS脑图或表格中,生成可视化的项目进度图。这可以与《 WPS脑图与甘特图联动:用可视化工具进行项目规划与管理》中的思想结合。
  • 自定义设置面板:允许用户配置提取规则、纪要模板(公司LOGO、固定抬头)、输出目录等。
  • 支持多语言:利用WPS的多语言特性,开发能生成中英文双语会议纪要的插件。

常见问题解答(FAQ)
#

Q1: 开发WPS JS-API插件需要付费吗? A1: 开发本身是免费的,只需要合法的WPS Office副本(建议使用专业版或开发者版以获取完整支持)。插件分发也不直接向金山办公付费,但若涉及商业发行,需遵循其开发者协议。

Q2: 这个插件能在WPS表格或演示中使用吗? A2: 本示例插件的 manifest.xml 中指定了 <Host Name="Document">,因此它只在WPS文字中加载。你可以修改Manifest文件,添加 <Host Name="Workbook"><Host Name="Presentation"> 来使其在表格或演示中可用,但API对象模型会有所不同,需要调整代码。

Q3: JS-API和传统的VBA宏有什么区别?哪个更好? A3: JS-API基于现代Web标准,能创建更美观的交互界面,安全性模型更好,且是WPS未来重点发展的扩展方向。VBA宏功能深厚,尤其在复杂的桌面端自动化方面经验丰富,但学习曲线较陡,界面老旧,且面临逐步淘汰的趋势。对于新项目,特别是希望有良好UI和跨平台前景的,推荐JS-API。对于维护已有的VBA项目,可参考《 WPS宏与自动化入门:用VBA简化重复性办公任务》和《 WPS宏脚本进阶:利用JavaScript API实现跨文档自动化处理》进行了解或迁移。

Q4: 我开发的插件如何让团队其他成员使用? A4: 如3.3节所述,打包成 .wpsaddon 文件分发给同事安装即可。对于企业环境,建议通过内网共享或管理系统进行统一部署,确保版本一致和安全可控。

Q5: 遇到API调用不生效或报错怎么办? A5: 首先检查控制台(F12)的错误信息。最常见的原因是: 1. 未在 context.load 中声明要访问的属性。 2. 在 context.sync 之前尝试读取属性值。 3. 对象引用已失效(例如,在多次 sync 后未重新获取Range)。 仔细阅读错误信息,并回顾WPS JS-API的“批量执行-同步”编程模型。

结语
#

通过这个“会议纪要自动生成插件”的实战,我们系统地走过了WPS JS-API插件开发的完整生命周期:从环境搭建、项目配置,到核心的文档操作、信息提取与自动化排版逻辑实现,再到调试、打包的注意事项。这不仅解决了一个具体的办公痛点,更提供了一个可复用的开发框架。

WPS Office通过JS-API将其强大的文档处理能力开放出来,使得每一位具备Web开发技能的开发者都能成为办公效率工具的创造者。你可以以此项目为蓝本,发挥想象,开发出诸如自动报告生成器、合同关键条款检查器、批量文档格式转换工具等一系列提升效能的插件。深入探索WPS二次开发的世界,你将能够打造真正贴合个人或团队需求的智能办公流程,从而在数字化转型中占据先机。

本文由 WPS官方下载 站点提供,欢迎访问 WPS Office 电脑版 页面了解更多办公软件资讯。