前言

欢迎加入鸿蒙PC开发者社区,共同打造开发者工具生态:鸿蒙PC开发者社区 :https://harmonypc.csdn.net/

项目开源地址:https://AtomGit.com/lqjmac/ele-yishizhuizong

议事追踪这个小工具看起来轻,但真正落地时要先把主路径想清楚。
很多会议不是没有讨论,而是结论、行动项和风险在会后散掉了。会议纪要要能被继续跟进。
它面向的是需要把同步会、评审会、客户会议整理成可执行纪要的人。

议事追踪这一篇不把会议纪要当成长文本来写。
我更关心会后能不能继续执行:结论是什么、谁来做、风险在哪里、什么时候再跟进。

一、先把会后执行对象找出来

1.1 议事追踪真正要解决什么

很多会议不是没有讨论,而是结论、行动项和风险在会后散掉了。会议纪要要能被继续跟进。
如果纪要只是一大段文字,会后真正需要执行的人还要重新翻一遍,效率很低。

第一版我先把纪要拆成可执行对象:

  1. 议题和议程用于还原背景
  2. 结论、行动项和风险必须分开
  3. 跟进动作要能复制给团队成员

1.2 为什么不做成大而全

会议工具很容易继续做日程、录音转写、多人协同。
这些能力都大,但这一版先做“会后执行面板”,保证结果能落地。

会议信息 当前处理 原因
议程 保留 让结论有上下文
结论 单独字段 避免埋在长文本里
行动项 单独字段 会后执行最依赖它
录音转写 暂不做 第一版先处理结构化纪要

这样它不是会议记录本,而是一个会后跟进台。

二、文件分工对应纪要整理

2.1 主要文件职责

文件 职责 这篇关注点
Home.vue 组织会后执行面板 会议列表、纪要区和行动项侧栏在这里组合
NoteSidebar.vue 管会议入口 按议题、时间或状态找会议
NoteEditor.vue 写结论和行动项 不让纪要退化成长文本
NoteToolbar.vue 放流转动作 新建纪要、复制行动项、导出
useNotes.ts 管纪要状态 保存、筛选、排序和当前会议
useNativeBridge.ts 衔接通知和剪贴板 方便把行动项发到外部协作工具

这里的关键不是把组件名改成 MeetingEditor,而是让每个组件围绕“会后还能执行”来分工。

三、整体结构围绕行动项

3.1 页面结构图

在这里插入图片描述

议事追踪结构图展示会议时间轴、纪要工作台和行动项摘要区。

3.2 布局为什么这样分

议事追踪采用的是 会议分类 + 会议时间轴 + 结论和行动项侧栏
左边找会议,中间整理纪要,右边盯行动项和风险,路径很直。

区域 承担的任务 设计注意点
会议分类 找到某次同步或评审 议题和时间要清楚
时间轴 查看会议推进 最近会议和未关闭事项靠前
纪要工作台 写议程、结论、行动项 字段分开,减少二次整理
行动项侧栏 看风险和跟进 让会后执行不沉底

会议纪要的价值在会后,所以右侧行动项不能只是装饰。

四、字段设计要覆盖结论和责任人

4.1 议事追踪的核心字段

字段要把会议从“聊过”变成“能推进”。
这也是议事追踪和普通笔记的区别。

字段 含义 页面位置
id 纪要标识 状态层
topic 会议主题 列表/编辑区
agenda 讨论议程 编辑区
decisions 已确认结论 编辑区/导出
actions 行动项和责任人 编辑区/侧栏
risks 风险或阻塞 侧栏/导出
followUp 后续跟进时间或方式 侧栏/导出

4.2 TypeScript 类型

export interface AppItem {
  id: string;
  topic: string;
  agenda: string;
  decisions: number | string;
  actions: string;
  risks: string;
  followUp: number | string;
}

export type AppFilter = 'all' | 'active' | 'archived';

这套类型把结论、行动项、风险拆开。
后续无论复制还是导出,都不用再从长段落里手工挑。

五、默认纪要要像真实同步会

5.1 为什么要写种子数据

默认纪要要像真实同步会。
用户第一次打开时应该能看懂行动项怎么写,而不是看到一堆字段名。

我写种子纪要时会检查:

  • 议题具体
  • 结论能直接复述
  • 行动项有下一步

5.2 示例数据

export const seedAppItems: AppItem[] = [
  {
    id: 'yishi_zhuizong-001',
    topic: '鸿蒙 PC 适配问题同步',
    agenda: '确认白屏原因、分配 HAP 重建和验证任务',
    decisions: '协作沉淀',
    actions: '前端确认 dist;打包同学重建 11-20;测试同学复跑白屏日志。',
    risks: '旧 HAP 可能仍被误安装,需要明确新包路径。',
    followUp: '今晚 20:00 前回收验证结果',
  },
];

真实纪要能测试长行动项、风险侧栏和导出 Markdown 的层级。

六、状态层处理跟进和关闭

6.1 composable 的职责

useNotes.ts 这层我更愿意把它理解成“当前工具的数据服务”。
页面不应该直接处理太多 localStorage、排序和导出拼接。

const STORAGE_KEY = 'yishi-zhuizong';

const items = ref<AppItem[]>(loadItems());
const activeId = ref(items.value[0]?.id ?? '');

function persist() {
  localStorage.setItem(STORAGE_KEY, JSON.stringify(items.value));
}

function loadItems() {
  const raw = localStorage.getItem(STORAGE_KEY);
  return raw ? JSON.parse(raw) : seedAppItems;
}

6.2 本地存储 key 一定要独立

这里的 key 我会明确写成 yishi-zhuizong
这样做可以避免不同工具之间互相读到旧数据。

本地数据一旦串了,页面看起来像小问题,实际会让调试和截图都变得很难判断。

七、筛选排序突出未完成事项

7.1 computed 更适合承接派生视图

筛选、搜索、排序这些逻辑如果直接写在模板里,很快会让页面变得难读。
我更倾向于让状态层先准备好可展示列表。

const keyword = ref('');
const filter = ref<'all' | 'topic'>('all');

const visibleItems = computed(() => {
  const text = keyword.value.trim().toLowerCase();
  return items.value
    .filter(item => JSON.stringify(item).toLowerCase().includes(text))
    .sort((a, b) => String(b.id).localeCompare(String(a.id)));
});

7.2 排序服务于场景

会议纪要整理工具里,排序不是“哪个字段容易写就按哪个排”。
它应该服务用户打开应用时最想看到的那批内容。

  1. 未处理内容优先出现
  2. 置顶或高优先级内容靠前
  3. 最近更新内容不要沉底

八、Vue 页面承接执行面板

8.1 Home.vue 只做编排

我不希望 Home.vue 变成所有逻辑的大杂烩。
它更适合负责页面骨架和组件之间的数据传递。

<template>
  <main class="yishi_zhuizong-page">
    <NoteToolbar
      @create="createItem"
      @copy="copyCurrent"
      @export="exportCurrent"
    />
    <section class="workspace">
      <NoteSidebar :items="visibleItems" @select="selectItem" />
      <NoteEditor :item="currentItem" @update="updateItem" />
    </section>
  </main>
</template>

8.2 组件之间的边界

组件 应该知道什么 不应该知道什么
NoteToolbar 当前能触发哪些动作 具体字段如何存储
NoteSidebar 列表、筛选、选中项 导出 Markdown 细节
NoteEditor 当前对象字段 全局搜索逻辑

边界清楚以后,后续改样式和改字段都会轻很多。

九、编辑器要把结论写实

9.1 不要只留下标题和正文

议事追踪如果只保留标题和正文,就会退回普通记事本。
所以编辑器必须把核心字段摆出来。

<script setup lang="ts">
defineProps<{ item: AppItem | null }>();
const emit = defineEmits<{ update: [item: AppItem] }>();
</script>

<template>
  <form v-if="item" class="editor-form">
    <input v-model="item.topic" />
    <textarea v-model="item.actions" />
  </form>
</template>

9.2 表单不是越多越好

我会优先放能影响用户判断的字段。
辅助字段可以放到右侧信息区,或者只在导出时使用。

十、工具栏围绕复制和导出

10.1 工具栏放哪些按钮

工具栏最容易变成按钮仓库。
议事追踪里我只保留和主流程强相关的动作。

  • 整理会议
  • 提炼结论
  • 拆行动项
  • 标记风险
  • 复制摘要
  • 导出纪要

10.2 复制摘要

function buildAppSummary(item: AppItem) {
  return [
    '# 议事追踪摘要',
    '- topic: ' + item.topic,
    '- agenda: ' + item.agenda,
    '- decisions: ' + item.decisions,
    '- actions: ' + item.actions,
  ].join('\n');
}

复制摘要的好处是很实际的。
用户不一定每次都要导出文件,有时只是想把当前内容发到聊天窗口或文档里。

十一、桥接层处理通知和剪贴板

11.1 桥接层只暴露稳定动作

页面不应该知道底层是 Electron clipboard,还是 OpenHarmony 侧的能力。
它只需要知道“复制”“导出”“通知”这些动作。

export function useNativeBridge() {
  const api = window.ohosBridge ?? window.electronAPI;

  async function copyText(text: string) {
    if (api?.copyText) return api.copyText(text);
    return navigator.clipboard.writeText(text);
  }

  async function notify(message: string) {
    if (api?.notify) return api.notify(message);
  }

  return { copyText, notify };
}

11.2 为什么要有浏览器兜底

开发阶段经常会直接跑 Vite。
如果没有浏览器兜底,页面调试会被原生环境绑得太死。

十二、导出 Markdown 要能直接流转

12.1 导出内容要能独立阅读

导出的 Markdown 不能只是把字段拼起来。
它最好离开应用以后也能被看懂。

function exportAppMarkdown(item: AppItem) {
  return [
    '# 议事追踪',
    '',
    '> 由 议事追踪 导出。',
    '## topic', String(item.topic ?? ''),
    '## agenda', String(item.agenda ?? ''),
    '## decisions', String(item.decisions ?? ''),
    '## actions', String(item.actions ?? ''),
    '## risks', String(item.risks ?? ''),
    '## followUp', String(item.followUp ?? ''),
  ].join('\n');
}

12.2 导出动作和通知联动

async function exportCurrent() {
  if (!currentItem.value) return;
  const markdown = exportAppMarkdown(currentItem.value);
  await bridge.copyText(markdown);
  await bridge.notify('议事追踪内容已复制为 Markdown');
}

这样用户完成导出以后能马上得到反馈。

十三、主进程加载保证会后可查

13.1 开发环境和生产环境分开

桌面应用最常见的白屏问题之一,是生产环境还在访问开发服务器。
所以主进程里一定要把加载逻辑分清楚。

const path = require('path');

function resolveRendererUrl() {
  if (process.env.VITE_DEV_SERVER_URL) {
    return process.env.VITE_DEV_SERVER_URL;
  }
  return `file://${path.join(__dirname, '../dist/index.html')}`;
}

mainWindow.loadURL(resolveRendererUrl());

13.2 preload 只注入必要接口

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
  copyText: text => ipcRenderer.invoke('copy-text', text),
  notify: message => ipcRenderer.invoke('notify', message),
});

接口少一点,维护起来更安心。

十四、纪要样式要方便追踪

14.1 视觉气质服务使用场景

议事追踪的视觉方向是:蓝灰协作感、执行面板、结构清楚
这个判断会影响间距、字号、卡片密度和按钮重量。

.yishi_zhuizong-page {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: #f7f8fb;
  color: #1f2937;
}

.workspace {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: 16px;
  min-height: 0;
}

14.2 滚动区要提前处理

桌面应用窗口经常被用户缩小。
如果滚动区没有处理好,内容一多就会挤成一团。

  • 左侧列表要能独立滚动
  • 编辑区不能把工具栏挤出屏幕
  • 右侧信息区要允许内容截断和换行

十五、构建后检查会后主题

15.1 先确认前端产物能生成

写文章之前,我会先跑一次构建。
这一步很朴素,但能挡住不少低级问题。

cd ../../electron_for_harmony/electron-openharmony-vue3-19/ohos_hap/web_engine/src/main/resources/resfile/resources/app/vue-app
npm install
npm run build

15.2 再确认关键文件没有串主题

rg "yishi-zhuizong|/meeting-digest|议事追踪" src package.json
rg "TODO|旧标题|测试数据" src

构建通过不代表体验完美,但至少说明当前页面和依赖关系是站得住的。

十六、这版议事追踪的经验

16.1 先换问题,再换界面

议事追踪最重要的不是页面长什么样,而是它先回答了一个明确问题:很多会议不是没有讨论,而是结论、行动项和风险在会后散掉了。会议纪要要能被继续跟进。
问题清楚以后,字段、布局和按钮才知道往哪里收。

16.2 哪些东西可以复用

  • 清晰的页面、状态层、桥接层分工
  • 状态层和本地存储节奏
  • 复制、导出、通知这组桌面动作
  • 开发环境与生产环境分开的加载逻辑

16.3 哪些东西不要硬套

  • 旧的数据字段
  • 旧的默认文案
  • 旧的视觉重心
  • 旧的排序规则

十七、后续可以补的跟进能力

议事追踪目前已经能把会议内容拆成结论、行动项和跟进风险。
真要继续加功能,我会优先从这些方向补:

  1. 增加行动项负责人字段
  2. 支持按未关闭事项筛选会议
  3. 给风险增加处理状态
  4. 导出适合群里发送的行动项摘要
  5. 增加下次跟进时间提醒

议事追踪后续要盯住会后执行,不要退回长篇纪要编辑器。

十八、发布前做一次执行检查

发布前我会按下面这张表再扫一遍,尤其确认 主题一致性 和可发布性。

检查项 结果 说明
标题和主题一致 通过 议事追踪实战:把结论、行动项和风险整理成会后执行面板
图片存在 通过 保留项目结构图或运行效果图
代码块数量 通过 覆盖类型、状态、组件、桥接、导出、构建
资源链接 通过 保留社区和官方文档入口

总结

议事追踪这一版把会议后的执行面板做出来了。结论、行动项、风险和责任人不再散在长文本里,团队回看时更容易知道下一步是谁来做。
议事追踪要避免会议纪要再次变成长文档。
把结论、行动项、风险和跟进时间拆开以后,会后执行才有抓手,团队也更容易同步下一步。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐