鸿蒙electron跨端框架PC课业板实战:课程、截止时间、提交物和风险都放到桌面上

前言

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

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

我做 课业板 时最先确认的,不是颜色和布局,而是它到底帮谁省了哪一步。

课程作业的麻烦不只是任务多,而是课程、老师、截止时间、提交物、进度和风险同时压过来。

它面向的是同时处理多门课程作业、实验报告和小组任务的学生。

课业板这一篇更像是给学期任务做一个桌面看板。

我关心的不是把作业记下来就结束,而是让"哪门课、什么时候交、还差什么、风险在哪"同时可见。

一、先确认作业管理的压力点

1.1 课业板真正要解决什么

课程作业的麻烦不只是任务多,而是课程、老师、截止时间、提交物、进度和风险同时压过来。

学生真正焦虑的通常不是任务本身,而是不确定自己有没有漏掉关键要求。

所以第一版我先抓住这些信息:

  1. 课程、老师、截止时间必须清楚
  2. 提交物和进度要能单独维护
  3. 风险提示要靠前,不要等到导出时才看见

1.2 为什么不做成大而全

课业工具如果一开始就做成绩统计、课程表同步、小组协作,会迅速变重。

这一版先服务"把当前作业推进到可提交"的主线。

范围 第一版做法 原因
截止时间 放到核心字段 决定优先级
提交物 单独记录 作业完成不等于材料齐
风险 明确写出来 方便提前补救
课程表同步 暂不做 第一版不依赖外部系统

这样它更像作业风险台,而不是普通待办列表。

二、文件分工对应课程任务

2.1 主要文件职责

文件 职责 这篇关注点
Home.vue 搭课程任务台 组织课程分组、详情和风险预览
NoteSidebar.vue 列出课程作业 方便按课程或状态定位任务
NoteEditor.vue 编辑提交要求 截止时间、提交物、风险都在这里写清
NoteToolbar.vue 放推进动作 新建作业、复制清单、导出
useNotes.ts 管理作业状态 保存、筛选、排序和当前选择
useNativeBridge.ts 处理复制提醒 把作业清单带到聊天或文档里

同样是通用组件,但在课业板里它们服务的是"别漏交"。

这比组件名本身更重要。

三、整体结构围绕截止时间

3.1 页面结构图

课业板结构图展示课程面板、作业目录和风险预览的组织方式。

3.2 布局为什么这样分

课业板采用的是 课程分组 + 作业目录 + 任务详情和风险预览

我希望用户打开后先看到临近截止的任务,而不是被一堆漂亮卡片分散注意力。

区域 承担的任务 设计注意点
课程分组 看任务属于哪门课 课程名和老师信息要稳定
作业目录 找到当前要推进的作业 截止日期和状态要醒目
任务详情 写提交物和进度 避免只剩一句待办
风险预览 提醒卡点 放到右侧,随时能扫到

课业板的布局要降低焦虑,关键信息比装饰更重要。

四、字段设计要覆盖课程和提交物

4.1 课业板的核心字段

字段要覆盖一次真实作业推进。

只存课程名和标题,会让后面的风险判断没依据。

字段 含义 页面位置
id 作业标识 状态层
course 课程名称 列表/编辑区
teacher 任课老师或助教 编辑区
dueDate 截止时间 列表/侧栏
deliverables 需要提交的材料 编辑区
progress 当前完成度 编辑区/侧栏
risk 可能卡住的地方 侧栏/导出

4.2 TypeScript 类型

ts 复制代码
export interface AppItem {
  id: string;
  course: string;
  teacher: string;
  dueDate: number | string;
  deliverables: string;
  progress: string;
  risk: number | string;
}

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

这段类型的重点是把"提交要求"和"风险"分开。

前者回答要交什么,后者回答为什么可能交不上。

五、默认作业要像真实学期

5.1 为什么要写种子数据

默认作业要像一个真实学期里的任务。

否则风险侧栏、截止时间和提交物字段都测不出效果。

我给种子作业定了三个条件:

  • 课程和老师要具体
  • 截止时间要形成压力
  • 风险要能提醒下一步

5.2 示例数据

ts 复制代码
export const seedAppItems: AppItem[] = [
  {
    id: 'keye_ban-001',
    course: '软件工程实践',
    teacher: '周老师',
    dueDate: '2026-05-30 18:00',
    deliverables: '需求说明书、演示录屏、源码压缩包',
    progress: '需求说明完成 70%,演示录屏未开始',
    risk: '小组接口还没有最终确认,可能影响录屏。',
  },
];

这类数据能帮助检查日期展示、长提交物换行和风险提示样式。

六、状态层处理进度和风险

6.1 composable 的职责

useNotes.ts 这层我更愿意把它理解成"当前工具的数据服务"。

页面不应该直接处理太多 localStorage、排序和导出拼接。

ts 复制代码
const STORAGE_KEY = 'keye-ban';

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 我会明确写成 keye-ban

这样做可以避免不同工具之间互相读到旧数据。

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

七、筛选排序突出临近截止项

7.1 computed 更适合承接派生视图

筛选、搜索、排序这些逻辑如果直接写在模板里,很快会让页面变得难读。

我更倾向于让状态层先准备好可展示列表。

ts 复制代码
const keyword = ref('');
const filter = ref<'all' | 'course'>('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 变成所有逻辑的大杂烩。

它更适合负责页面骨架和组件之间的数据传递。

vue 复制代码
<template>
  <main class="keye_ban-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 不要只留下标题和正文

课业板如果只保留标题和正文,就会退回普通记事本。

所以编辑器必须把核心字段摆出来。

vue 复制代码
<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.course" />
    <textarea v-model="item.deliverables" />
  </form>
</template>

9.2 表单不是越多越好

我会优先放能影响用户判断的字段。

辅助字段可以放到右侧信息区,或者只在导出时使用。

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

10.1 工具栏放哪些按钮

工具栏最容易变成按钮仓库。

课业板里我只保留和主流程强相关的动作。

  • 新增作业
  • 拆解清单
  • 更新进度
  • 记录风险
  • 复制提交摘要
  • 导出作业计划

10.2 复制摘要

ts 复制代码
function buildAppSummary(item: AppItem) {
  return [
    '# 课业板摘要',
    '- course: ' + item.course,
    '- teacher: ' + item.teacher,
    '- dueDate: ' + item.dueDate,
    '- deliverables: ' + item.deliverables,
  ].join('\n');
}

复制摘要的好处是很实际的。

用户不一定每次都要导出文件,有时只是想把当前内容发到聊天窗口或文档里。

十一、桥接层处理提醒和反馈

11.1 桥接层只暴露稳定动作

页面不应该知道底层是 Electron clipboard,还是 OpenHarmony 侧的能力。

它只需要知道"复制""导出""通知"这些动作。

ts 复制代码
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 不能只是把字段拼起来。

它最好离开应用以后也能被看懂。

ts 复制代码
function exportAppMarkdown(item: AppItem) {
  return [
    '# 课业板',
    '',
    '> 由 课业板 导出。',
    '## course', String(item.course ?? ''),
    '## teacher', String(item.teacher ?? ''),
    '## dueDate', String(item.dueDate ?? ''),
    '## deliverables', String(item.deliverables ?? ''),
    '## progress', String(item.progress ?? ''),
    '## risk', String(item.risk ?? ''),
  ].join('\n');
}

12.2 导出动作和通知联动

ts 复制代码
async function exportCurrent() {
  if (!currentItem.value) return;
  const markdown = exportAppMarkdown(currentItem.value);
  await bridge.copyText(markdown);
  await bridge.notify('课业板内容已复制为 Markdown');
}

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

十三、主进程加载保证随时查看

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

桌面应用最常见的白屏问题之一,是生产环境还在访问开发服务器。

所以主进程里一定要把加载逻辑分清楚。

js 复制代码
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 只注入必要接口

js 复制代码
const { contextBridge, ipcRenderer } = require('electron');

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

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

十四、作业工具样式要降低焦虑

14.1 视觉气质服务使用场景

课业板的视觉方向是:清晰、学习桌面、任务台感

这个判断会影响间距、字号、卡片密度和按钮重量。

css 复制代码
.keye_ban-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 先确认前端产物能生成

写文章之前,我会先跑一次构建。

这一步很朴素,但能挡住不少低级问题。

bash 复制代码
cd ../../electron_for_harmony/electron-openharmony-vue3-16/ohos_hap/web_engine/src/main/resources/resfile/resources/app/vue-app
npm install
npm run build

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

bash 复制代码
rg "keye-ban|/coursework|课业板" src package.json
rg "TODO|旧标题|测试数据" src

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

十六、这版作业工具的经验

16.1 先换问题,再换界面

课业板最重要的不是页面长什么样,而是它先回答了一个明确问题:课程作业的麻烦不只是任务多,而是课程、老师、截止时间、提交物、进度和风险同时压过来。

问题清楚以后,字段、布局和按钮才知道往哪里收。

16.2 哪些东西可以复用

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

16.3 哪些东西不要硬套

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

十七、后续可以补的学习能力

课业板目前已经能把课程任务从零散待办整理成可追踪清单。

真要继续加功能,我会优先从这些方向补:

  1. 增加按截止时间自动排序
  2. 对高风险任务做醒目标记
  3. 支持提交物清单逐项勾选
  4. 增加课程维度的本周任务视图
  5. 导出给小组成员看的任务摘要

课业板后续要继续围绕"别漏、别拖、别交错材料"来补。

十八、发布前做一次作业检查

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

检查项 结果 说明
标题和主题一致 通过 课业板实战:课程、截止时间、提交物和风险都放到桌面上
图片存在 通过 保留项目结构图或运行效果图
代码块数量 通过 覆盖类型、状态、组件、桥接、导出、构建
资源链接 通过 保留社区和官方文档入口

总结

课业板这一版把"快到期""还差什么""风险在哪里"放到了台面上。多门课程一起压过来时,结构化任务台比单纯记忆可靠得多。

课业板的重点是把压力拆开。

课程、截止时间、提交物和风险分开以后,用户才知道今天应该先补材料、先找队友,还是先完成最终提交。

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


相关资源:

相关推荐
Bert.Cai3 小时前
Linux tee命令详解
linux·运维·服务器
楷哥爱开发3 小时前
演唱会自动化抢票如何提高成功率?票务住宅IP与配置指南
服务器·前端·php
测试员周周4 小时前
【Appium 系列】第17节-XMind用例转换 — 从思维导图到 YAML
java·服务器·人工智能·单元测试·appium·测试用例·xmind
cui_ruicheng4 小时前
Linux网络编程(七):TCP Socket编程与EchoServer
linux·服务器·网络·tcp/ip
feasibility.4 小时前
nvidia-smi 失灵,显存凭空消失?—— NVML 驱动版本错配的记录
linux·运维·服务器·经验分享·nvidia·驱动
雨的旋律20994 小时前
keepalived + LVS NAT模式
服务器·网络·lvs
NiceCloud喜云4 小时前
Claude API PDF 文档问答实战:从原生解析到分页引用的完整方案
java·服务器·前端·网络·数据库·人工智能·pdf
傅科摆 _ py4 小时前
企业 / 校园 合法远程访问工具详解
服务器·网络·数据库
小雨青年5 小时前
鸿蒙 HarmonyOS 6 | Pura X Max 鸿蒙原生适配 10:横屏下页面从上下结构改为左右结构
华为·harmonyos