查看: 155|回复: 3

ArkTS离线交接台:状态推进、持久化与剪贴板摘

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
值班交接最容易丢的往往不是标题,而是“接下来谁做什么”。一条消息里可能同时包含负责人、影响范围、截止时间和上下文,过几个小时再找,信息已经被新讨论顶到后面。原文作者用ArkTS和ArkUI做了一个离线“交接台”,面向小团队值班、研发支持和个人项目管理,记录事项状态、负责人、影响范围、下一步、截止时间和处理记录。应用不依赖网络,数据留在本机;交班时把未完成事项整理成纯文本,复制到群聊或工单。

需要先明确验证边界:开发和验证都在DevEco Studio的HarmonyOS 7手机模拟器中完成,证明的是模拟器上的功能流程,不能替代真机性能、通知能力或真实团队部署验证。示例事项是脱敏测试数据,用来覆盖页面和流程,不代表已经接入某个企业的真实工单系统。

一、先把交接对象定义成RelayItem

原文把一条交接事项收敛为RelayItem,字段没有追求多,重点是回答交接时最常问的几件事。history是后来补上的字段:最初只有当前状态,页面看起来能用,但状态一推进,之前发生过什么就没有地方可追。交接场景里这会产生反效果:工具把信息收拢了,却把过程抹掉了。因此每次状态变化都会在数组头部增加一条事件记录。
  1. export interface RelayItem {
  2.   id: number;
  3.   title: string;
  4.   owner: string;
  5.   impact: string;
  6.   nextStep: string;
  7.   due: string;
  8.   status: string;
  9.   note: string;
  10.   updatedAt: string;
  11.   history: string[];
  12. }
复制代码

二、首页计数从当前数组重新计算

首页先给出未完成、阻塞、待验证和已完成四个计数,再放搜索、状态筛选和新建入口。计数不是写死在页面上的文案,而是从当前数组重新计算。
  1. private refreshCounts(source: Array<RelayItem>): void {
  2.   this.unfinishedCount = source.filter(
  3.     (item: RelayItem) => item.status !== RelayStatus.DONE
  4.   ).length;
  5.   this.blockedCount = source.filter(
  6.     (item: RelayItem) => item.status === RelayStatus.BLOCKED
  7.   ).length;
  8.   this.verifyCount = source.filter(
  9.     (item: RelayItem) => item.status === RelayStatus.VERIFY
  10.   ).length;
  11.   this.doneCount = source.filter(
  12.     (item: RelayItem) => item.status === RelayStatus.DONE
  13.   ).length;
  14. }
复制代码

首屏样例数据故意保留四种状态:支付回调阻塞、版本灰度待验证、客户字段待处理,以及已经完成的周报校对。这样打开应用就能看到筛选和状态推进的实际入口,而不是一张空白页面。搜索和筛选是两条独立条件:筛选先判断状态,搜索再在标题、负责人和影响范围中匹配。当前模拟器的输入自动化工具只接受ASCII文本,所以中文关键词搜索没有作为自动化证据写进结论,仍需要在实际设备或可输入中文的测试环境中补一轮。

三、新建事项先挡住不完整输入

新建表单只把事项、负责人和下一步设为必填。影响范围、截止时间和补充记录允许暂时留空,因为交接现场经常是先把责任和下一步记下来,再补充细节。表单收起时,页面保持在列表视图;展开后可以一次填写六个字段。表单和列表使用同一套页面状态,打开表单时原来的事项不会被清空,收起后仍然停留在原来的筛选位置。

原文特意保留了一张不完整提交的结果:点击保存时,如果三个必填字段中有一个为空,页面显示错误提示,原表单不会被关闭,也不会把半条数据写进本地存储。校验提示没有弹出需要再确认的对话框,而是直接放在保存按钮上方。操作人能看到缺的是哪组信息,补完后继续填写,不会丢掉已经输入的字段。填写完整后,应用给新事项分配时间戳,初始状态设为待处理,并在history中写入新建事项。写入成功后才收起表单,这样页面上的状态和本地数据不会出现已经消失但实际没有保存的假象。保存后的事项回到列表数据源,计数卡片也随之重新计算;页面没有另做一份“刚刚新增”的临时列表,所以刷新或重新打开时看到的内容和保存到Preferences的内容使用同一个来源。

在手机模拟器中,输入框会触发系统键盘,键盘收起后再保存的路径也单独跑过一遍。保存按钮在键盘收起后仍然保持可见,列表卡片的间距也没有被压缩。这个小检查让填写完成和回到列表之间的操作更连贯,也能避免输入法把最后一个按钮推到屏幕之外。不同设备的输入法高度仍然需要在对应设备上重新确认。

四、状态推进必须留下痕迹

列表卡片默认只显示当前状态和下一步。点开一条事项后,再展示补充说明、处理历史和推进状态按钮。这个层级让首页保持可扫读,真正需要追过程时再展开。展开之后,补充说明和历史事件按同一张卡片排列,读者不必在列表、详情页和日志页之间来回跳。当前状态仍然放在卡片右上角,历史只在需要时展开。

状态推进使用一个很短的状态机:待处理进入待验证,待验证进入已完成;阻塞事项解除后回到待处理。每次推进都会复制当前对象的字段,只替换状态、更新时间和历史数组。
  1. const next = nextStatus(item.status);
  2. const nextItems = this.items.map((current: RelayItem) => {
  3.   if (current.id !== item.id) {
  4.     return current;
  5.   }
  6.   return {
  7.     ...current,
  8.     status: next,
  9.     updatedAt: changedAt,
  10.     history: [
  11.       changedAt + ' 状态由「' + current.status + '」更新为「' + next + '」。',
  12.       ...current.history
  13.     ]
  14.   } as RelayItem;
  15. });
复制代码

原文在模拟器里先把“支付回调偶发超时”从阻塞中推进到待处理,再展开记录确认新事件排在最前面。列表上的状态和历史文本同时变化,证明这里不是只改了一个临时的页面变量。状态事件文本包含旧状态和新状态,时间戳使用应用当前时间生成。它不是完整审计日志,但对于交接来说,至少能回答这条事项什么时候从阻塞恢复,也能避免下一位处理人把已经做过的动作再做一遍。状态变化后,筛选栏也会跟着重新计算。点击待处理只保留两条事项,刚刚解除阻塞的回调问题和原来的客户字段事项都能被找到;已完成的周报校对不会混进结果里。筛选结果中的两条事项来自同一个本地数组,计数卡片和列表条数保持一致,说明离线模式下页面的基本筛选链路可以独立运行。

五、Preferences解决交班后别丢

数据层使用Preferences保存序列化后的事项数组。应用启动时由EntryAbility初始化存储,页面出现后异步加载;每次新建和状态推进都调用save,写入后执行flush。
  1. static async save(items: Array<RelayItem>): Promise<void> {
  2.   if (RelayStore.store === undefined) {
  3.     return;
  4.   }
  5.   await RelayStore.store.put('items', JSON.stringify(items));
  6.   await RelayStore.store.flush();
  7. }
复制代码

华为文档将Preferences定义为应用侧的持久化键值存储,并说明getPreferences返回的实例会被缓存。这里保存的是一个小型事项列表,使用JSON字符串比为每个字段拆很多key更容易迁移。旧数据没有history字段时,加载过程会补一条“已导入历史事项”的记录,避免升级后页面直接报错。

验证持久化时,原文作者先推进状态并关闭应用,再重新启动。重新进入首页后,回调事项仍是待处理,更新时间也保持为刚才的16:35;重新展开后还能看到原来的状态变化记录。这一步只验证了模拟器里的应用重启和本地数据保留,没有做清除应用数据后的恢复,也没有把数据同步到其他设备。离线交接台的边界很明确:它适合单设备上的小团队值班记录和个人项目跟进,跨设备协作需要再接入分布式数据或服务端同步。

六、交接摘要要能离开应用

如果事项只能留在页面里,交班时还是要重新描述一次。因此原文把未完成事项转换成一段纯文本,格式保持简单:状态、标题、负责人、下一步和截止时间。已完成事项不进入摘要,避免把已经结束的工作带进新的交班消息。
  1. export function formatHandoffSummary(items: Array<RelayItem>): string {
  2.   const unfinished = items.filter(
  3.     (item: RelayItem) => item.status !== RelayStatus.DONE
  4.   );
  5.   if (unfinished.length === 0) {
  6.     return '当前没有未完成事项。';
  7.   }
  8.   return unfinished.map((item: RelayItem) => {
  9.     return `${item.status}|${item.title}\n` +
  10.       `负责人:${item.owner} 下一步:${item.nextStep} 截止:${item.due}`;
  11.   }).join('\n\n');
  12. }
复制代码

摘要面板先让人确认内容,再点击复制。复制实现使用@kit.BasicServicesKit中的系统剪贴板,把文本写入text/plain。
  1. private async copySummary(): Promise<void> {
  2.   const board = pasteboard.getSystemPasteboard();
  3.   await board.setData(
  4.     pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, this.summaryText)
  5.   );
  6.   this.copyState = '已复制,可粘贴到群聊或工单';
  7. }
复制代码

华为文档列出的纯文本类型正是text/plain,并提醒剪贴板读取在API 12之后受到权限控制。这里的需求只是写入,不读取其他应用的剪贴板内容,所以没有为了验证复制去申请读取权限。模拟器操作后页面收到setData的成功结果并显示提示,这证明应用侧写入调用完成;原文没有把它扩大成已经验证真实群聊粘贴成功。摘要面板保留了原始字段的顺序,读起来更像一条可以直接转发的工作消息,而不是把整个页面内容复制出去。先确认未完成事项,再执行复制,也给了操作人删改或补充的机会。复制完成后,摘要面板仍然留在当前页面,提示文字出现在按钮左侧。操作人可以看到调用已经返回,再决定去群聊或工单里粘贴,不需要凭感觉判断是否成功。提示只描述应用侧已经完成写入,不替用户承诺目标群聊或工单的接收结果。

七、实现边界与取舍

这版应用已经在HarmonyOS 7手机模拟器中完成了构建、安装、启动、建项校验、状态推进、历史记录、筛选、摘要生成、剪贴板写入提示和重启持久化。它还没有验证真实手机上的性能、横竖屏细节、通知和跨设备同步,也没有做企业账号、权限和多人并发编辑。这些边界会直接影响应用能不能进入真实工作流。离线存储解决了交班时找不到当前状态,却没有解决多人同时修改;纯文本摘要解决了复制到群里还要重新整理,却没有替代工单系统的审计和权限。下一步如果继续做,原文计划先补平板和2in1模拟器的布局验证,再决定是否值得引入分布式同步。

对个人项目和值班交接来说,这个规模已经足够把最容易丢的几项信息固定下来:谁负责、影响什么、现在到哪一步、接下来做什么,以及这一步是怎么走到的。剩下的能力应该等真实场景出现后再加,而不是先堆成一个看起来很完整、交接时却没人愿意打开的系统。
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: ArkTS离线交接台:状态推进、持久化与剪贴板摘

这个交接台的设计思路挺实在的,尤其是把 history 作为一等字段补进来那一段。很多值班工具都只记当前状态,交接时最想知道的“这条之前卡在哪、谁动过”反而没了,补上事件记录确实更贴合场景。 几个点我觉得做得比较克制:首页计数从数组实时算而不是写死文案,避免了筛选后数字对不上的尴尬;状态机只有几条短路径,每次推进复制对象再替换状态和时间,数据来源单一,不会出现页面刷新后和 Preferences 里不一致的假象。表单校验把错误提示放在保存按钮上方、不弹二次确认,这个交互对值班场景很友好,补字段时也不丢已填内容。 想问一下或者提个小建议:现在的状态机里没看到怎么进入“阻塞”状态,是不是只能在新建时选?如果实际使用中经常遇到“处理到一半发现被外部依赖卡住”,可能值得加一条“待处理/待验证 → 阻塞”的推进入口。另外 history 数组一直往头部追加,长期用下来可能会越来越长,后续可以考虑只保留最近 N 条或者在展开时折叠较早记录。 还有你提到的中文关键词搜索因模拟器输入工具只支持 ASCII 没进自动化结论,这个边界交代得很清楚,比那种“全部通过”的结论可信多了。真机上输入法高度和键盘收起后的保存路径也确实值得再跑一轮,不同机型差异可能不小。
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: ArkTS离线交接台:状态推进、持久化与剪贴板摘

这个离线交接台的思路挺实在,抓住了值班交接里最容易丢的“下一步谁做什么”,而不是只记一个标题。把事项收敛成 RelayItem、状态推进时同步写 history、首页计数从当前数组实时算,这几处比单纯做一个列表页更贴近交接场景。新建表单只卡三个必填项、校验提示放在保存按钮上方、保存成功后再收起表单,也照顾到了现场先记责任再补细节的习惯。 比较值得肯定的是状态推进不是只改页面变量,而是复制对象并追加历史记录,这样后面的人能看出事项什么时候从阻塞恢复、做过哪些动作。模拟器验证边界也交代得清楚,没有把功能流程说成真机和企业部署结论。 如果继续完善,我会关注两点:一是交接时整理成纯文本复制到群聊或工单的流程,最好有复制成功或失败的明确反馈,避免以为已经复制但实际没进剪贴板;二是中文关键词搜索目前只缺自动化证据,后续在可输入中文的环境补一轮会更完整。整体上,作为小团队值班和个人项目管理的离线工具,这个方向是成立的。
回复 支持 反对

使用道具 举报

发表于 半小时前 | 显示全部楼层

Re: ArkTS离线交接台:状态推进、持久化与剪贴板摘

这个交接台的思路挺对,交接最怕的就是信息散落和状态推进没痕迹。把 RelayItem 收敛到负责人、影响范围、下一步、截止时间和 history,基本覆盖了值班交接最常问的几件事;状态推进时复制对象、只替换状态并往 history 头部插事件,也避免了只改页面变量造成“看着变了但没落数据”的假象。首页计数从当前数组重算、表单必填校验不关闭原表单、保存成功后才收起、列表和 Preferences 同源,这些细节都很实在,能减少交接工具最容易出的“信息收拢了但过程丢了”的问题。模拟器验证边界也交代得清楚,中文搜索和输入法高度确实需要真机或可输入中文的环境再补一轮。想追问一下:剪贴板摘录的纯文本有没有固定模板,比如按未完成事项分组、history 只保留最近几条?另外当前状态机是待处理到待验证再到已完成、阻塞解除回待处理,实际交接里会不会还需要“退回待处理”或“取消”这类分支?整体看是个很轻但闭环的小工具,适合小团队值班先跑起来。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-11-4 02:06 , Processed in 0.022689 second(s), 28 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部