MooTool Next Compose 失败 Toast 呈现层收尾:时间/网络/Vault-Git 模块的判定链设计解析
桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载本文聚焦 MooTool 新一代 Compose Desktop 客户端next-compose中 DIFF-598 所覆盖的失败 Toast 呈现层收尾工作F18 时间戳转换失败提示、F11 网络任务失败提示含ABORTED跳过策略、以及 A03 Vault-Git 面板的 4 类失败提示。通过梳理TimeWiringPresentation、NetWiringPresentation、VaultGitToastPresentation三个呈现层对象及其在屏幕层Screen/Dialog的接入点读者可以完整掌握 MooTool 在引擎抛错 → 呈现层判定 → Toast/内联错误双通道输出这一链路上的设计约定并可直接在本地 JDK 21 环境复现验证命令。背景与范围DIFF-598 在整体迭代中的位置DIFF-598 是 MooTool Next Compose 桌面端一系列失败 Toast 呈现层收尾切片中的一环其基线为 DIFF-597工作区。DIFF-597 已覆盖 F01/F09 及证据帧 192本切片不重复处理这些条目只收尾以下三块F18notifyTimeConvertFailure沿用TimeWiringPresentation.shouldToastConvertFailure判定是否弹错误 ToastF11notifyNetActionResult网络任务完成时的失败 Toast 经shouldToastNetworkError判定跳过ABORTED用户主动取消场景A03VaultGitToastPresentation对象 notifyVaultGitPanelFailure/notifyVaultGitActionFailure/notifyVaultGitFlushBlocked/notifyVaultGitInvalidRemote四个面板层通知函数证据TimeToTimestampTabCaptureTest产生截图193-compose-time-to-timestamp-tab-focus.png。从实现位置看这一切片延续了本项目的统一分层约定纯函数判定逻辑放在domain层可单测IO 与 UI 装配放在features层的 Screen/DialogToast 出口统一收敛到AppContainer。一、统一 Toast 出口AppContainer 的三通道无论哪个模块触发失败提示最终都汇入 AppContainer.kt 提供的三通道方法fun toastSuccess(message: String) { toasts.success(message) } fun toastError(message: String) { toasts.error(message) } fun toastInfo(message: String) { toasts.info(message) }toasts是全局 Toast 队列状态错误、成功、信息三类提示统一走队列呈现。所有notify*函数内部最终都调用container.toastError(...)/container.toastSuccess(...)保证错误视觉样式与队列行为全局一致。二、F18时间戳转换失败 ToastTimeWiringPresentation notifyTimeConvertFailure2.1 呈现层判定函数TimeWiringPresentation.kt 是 F18 的核心它定义了转换动作的密封结果类型与失败判定sealed interface ConvertOutcome { data class ToLocal(val result: TimestampConversion) : ConvertOutcome data class ToTimestamp(val timestamp: String) : ConvertOutcome data class Failure(val error: Throwable) : ConvertOutcome } fun runTimestampToLocal(timestamp: String, unit: TimestampUnit, zone: String): ConvertOutcome runCatching { TimeEngine.timestampToLocal(timestamp, unit, zone) }.fold( onSuccess { ConvertOutcome.ToLocal(it) }, onFailure { ConvertOutcome.Failure(it) }, ) fun runLocalToTimestamp(localTime: String, unit: TimestampUnit, zone: String): ConvertOutcome runCatching { TimeEngine.localToTimestamp(localTime, unit, zone) }.fold( onSuccess { ConvertOutcome.ToTimestamp(it) }, onFailure { ConvertOutcome.Failure(it) }, ) fun shouldToastConvertFailure(error: Throwable): Boolean true要点转换动作不会直接抛异常而是用runCatching包裹后折叠为密封类型ConvertOutcome调用方通过when穷举分支处理shouldToastConvertFailure当前恒为true即所有转换失败都要弹 Toast。它保留为独立函数的意义在于把是否提示的决策集中到呈现层未来若要按错误类型静默如网络抖动类只需改这一处。2.2 屏幕层装配notifyTimeConvertFailureTimeConvertScreen.kt 中两个转换入口convertToLocal与convertToTimestamp均对ConvertOutcome.Failure分支调用notifyTimeConvertFailureis TimeWiringPresentation.ConvertOutcome.Failure - { notifyTimeConvertFailure(container, session, outcome.error) } private fun notifyTimeConvertFailure(container: AppContainer, session: TimeSession, error: Throwable) { session.notice val message messageFor(container, error) session.error message if (TimeWiringPresentation.shouldToastConvertFailure(error)) { container.toastError(message) } }这是本项目典型的双通道错误呈现内联通道把本地化消息写入session.error供屏幕内的错误区域显示Toast 通道经shouldToastConvertFailure判定后用container.toastError(message)弹出全局错误 Toast。同时session.notice被清空避免操作成功提示与操作失败提示同时残留。messageFor会把TimeException的错误码映射为本地化文案例如dst-gap→time.error.dstGap、dst-overlap→time.error.dstOverlap、invalid-local-time→time.error.localTime保证用户看到的是可读的中文说明而非底层异常文本。2.3 测试证据TimeWiringPresentationTest.kt 中明确了shouldToastConvertFailure的行为Test fun shouldToastConvertFailure() { assertTrue(TimeWiringPresentation.shouldToastConvertFailure(TimeException(invalid, ))) }此外本切片要求的证据截图由TimeToTimestampTabCaptureTest生成对应文件为 193-compose-time-to-timestamp-tab-focus.png用于验收时间戳→时间戳 Tab 聚焦场景的呈现。三、F11网络任务结果 Toast 与 ABORTED 跳过策略3.1 判定函数shouldToastNetworkErrorNetWiringPresentation.kt 提供的失败判定是本次切片的重点策略fun shouldToastNetworkError(errorCode: NetworkErrorCode?): Boolean errorCode ! null errorCode ! NetworkErrorCode.ABORTED语义拆解errorCode null任务成功完成不弹错误 Toast成功提示走另一个通道errorCode NetworkErrorCode.ABORTED任务被用户主动取消静默不提示——取消是用户意图弹错误反而构成打扰其余错误码如INVALID_TARGET、TIMEOUT、COMMAND_FAILED、PERMISSION、UNSUPPORTED一律弹错误 Toast。NetworkErrorCode枚举定义在 NetEngine.ktNetEngine内部在取消点统一抛出NetException(NetworkErrorCode.ABORTED, ABORTED)见该文件多处handle.isCancelled()检查因此上层可以从result.errorCode直接判断是失败还是被取消。3.2 屏幕层装配notifyNetActionResultNetScreen.kt 中网络命令ping、端口扫描、whois、解析、flushDNS 等执行完毕后统一调用notifyNetActionResultprivate fun notifyNetActionResult( container: AppContainer, session: NetSession, errorCode: NetworkErrorCode?, successLabel: String, ) { if (session.error.isNotEmpty()) { if (NetWiringPresentation.shouldToastNetworkError(errorCode)) { container.toastError(session.error) } } else { container.toastSuccess(successLabel) } }调用方在 NetScreen.kt#L196-L208 完成输出装配session.error if (result.errorCode ! null result.errorCode ! NetworkErrorCode.ABORTED) { localized ?: result.output } else val label networkActionLabel(container, action) session.notice label notifyNetActionResult(container, session, result.errorCode, label)注意两层过滤的配合session.error只对非 ABORTED的错误码写入内联错误与shouldToastNetworkError的跳过策略一致notifyNetActionResult中session.error非空才走 Toast 判定通道否则弹成功 ToastsuccessLabel来自networkActionLabel如 ping →net.ping。此外ABORTED场景的输出文本会被替换为本地化文案net.error.ABORTED当原始输出仅为ABORTED或空串时避免把引擎内部标记直接展示给用户。3.3 测试证据NetWiringPresentationTest.kt 精确锁定该策略Test fun shouldToastNetworkErrorSkipsAborted() { assertFalse(NetWiringPresentation.shouldToastNetworkError(NetworkErrorCode.ABORTED)) assertTrue(NetWiringPresentation.shouldToastNetworkError(NetworkErrorCode.INVALID_TARGET)) assertFalse(NetWiringPresentation.shouldToastNetworkError(null)) }三个断言分别覆盖取消不弹、真实失败弹、成功不弹三条关键路径。四、A03Vault-Git 面板的四类失败 Toast4.1 呈现层对象VaultGitToastPresentationVaultGitToastPresentation.kt 位于commonMain而非 desktopMain说明它同时服务 Compose 各平台目标object VaultGitToastPresentation { fun shouldToastPanelFailure(): Boolean true fun shouldToastActionFailure(): Boolean true fun shouldToastFlushBlocked(): Boolean true fun shouldToastInvalidRemote(): Boolean true fun panelFailureMessage(error: Throwable?, fallback: String): String error?.message?.takeIf { it.isNotBlank() } ?: fallback fun actionFailureMessage(message: String, fallback: String): String message.ifBlank { fallback } }设计要点四个shouldToast*开关默认全开与 F18 的shouldToastConvertFailure同一思路——开关前置、集中在呈现层panelFailureMessage/actionFailureMessage提供消息回退策略优先取异常/结果的真实消息仅当其为空或空白时使用调用方传入的兜底文案通常是json.notice.failed的本地化版本。4.2 四个 notify 函数的触发场景与实现四个通知函数全部实现在 VaultGitDialog.kt分别对应面板生命周期中的四类失败① 面板加载/操作抛异常 → notifyVaultGitPanelFailure在load()与runAction()的catch (error: Exception)分支触发见 VaultGitDialog.kt#L131-L133 与 VaultGitDialog.kt#L181-L182private fun notifyVaultGitPanelFailure(container: AppContainer, error: Throwable?) { val message VaultGitToastPresentation.panelFailureMessage(error, container.t(json.notice.failed)) if (VaultGitToastPresentation.shouldToastPanelFailure()) { container.toastError(message) } }② Git 操作返回失败结果 → notifyVaultGitActionFailurerunAction中当result.success false时触发VaultGitDialog.kt#L163。注意 Pull 失败后仍会触发onVaultRefresh()刷新工作区而其余操作失败直接returnlaunchprivate fun notifyVaultGitActionFailure(container: AppContainer, result: GitActionResult) { val message VaultGitToastPresentation.actionFailureMessage(result.message, container.t(json.notice.failed)) if (VaultGitToastPresentation.shouldToastActionFailure()) { container.toastError(message) } }③ 编辑器未保存导致 flush 被阻断 → notifyVaultGitFlushBlockedrunAction执行 Git 操作前会先经GitEditorFlushPolicy.shouldFlushEditor(workingTree)判定是否需要先 flush 编辑器若 flush 返回非空存在未保存修改则阻断操作并弹 ToastVaultGitDialog.kt#L148-L153if (GitEditorFlushPolicy.shouldFlushEditor(workingTree)) { val flushed onFlush() if (flushed ! null) { notifyVaultGitFlushBlocked(container, flushed) returnlaunch } }GitEditorFlushPolicy见 GitEditorFlushPolicy.kt对 Pull/Commit/Push 返回shouldFlushEditor true对 Discard 返回false其测试 GitEditorFlushPolicyTest.kt 同时验证了 Pull 成功后刷新 Vault 的行为。④ 远端地址格式非法 → notifyVaultGitInvalidRemote在保存/移除远端按钮的提交校验分支触发VaultGitDialog.kt#L471-L478。SettingsVaultGitNormalize.commitGitRemote返回Rejected时直接拦截按钮并弹错误GitRemoteCommitResult.Rejected - { notifyVaultGitInvalidRemote(container) returnMooButton }其实现使用本地化文案settings.vault.gitRemoteInvalidprivate fun notifyVaultGitInvalidRemote(container: AppContainer) { if (VaultGitToastPresentation.shouldToastInvalidRemote()) { container.toastError(container.t(settings.vault.gitRemoteInvalid)) } }4.3 测试证据VaultGitToastPresentationTest.kt 用 3 个用例覆盖全部核心行为Test fun shouldToastFailures() { assertTrue(VaultGitToastPresentation.shouldToastPanelFailure()) assertTrue(VaultGitToastPresentation.shouldToastActionFailure()) assertTrue(VaultGitToastPresentation.shouldToastFlushBlocked()) assertTrue(VaultGitToastPresentation.shouldToastInvalidRemote()) } Test fun panelFailureMessagePrefersThrowable() { assertEquals(disk, VaultGitToastPresentation.panelFailureMessage(IllegalStateException(disk), fb)) assertEquals(fb, VaultGitToastPresentation.panelFailureMessage(IllegalStateException(), fb)) } Test fun actionFailureMessageUsesResultOrFallback() { assertEquals(pull failed, VaultGitToastPresentation.actionFailureMessage(pull failed, fb)) assertEquals(fb, VaultGitToastPresentation.actionFailureMessage(, fb)) }panelFailureMessagePrefersThrowable特别验证了回退语义异常消息为空时使用兜底文案异常消息非空时优先展示真实原因。五、贯穿三个模块的共性设计约定综合 F18 / F11 / A03可以提炼出 MooTool Next Compose 失败提示的统一模式这也是理解后续同类切片如 585/590/591/592 的 time-host-quicknote、net、config-protobuf-hardware、coderun-encode-ua 等 toast slice的钥匙决策与 I/O 分离shouldToastXxx是纯布尔函数位于domain层不接触 UI 与容器天然可单测通知函数统一命名notifyXxx(container, ...)收口在 features 层内部先拼装本地化消息再经shouldToastXxx开关决定是否调用container.toastError(...)双通道呈现内联错误session.error与全局 Toast 并行shouldToast只控制 Toast 通道内联错误通常始终保留消息回退策略panelFailureMessage/actionFailureMessage这类辅助函数保证任何异常/结果都至少有一个兜底文案不会出现空 Toast主动取消静默ABORTED不弹 Toast 是全局共识翻译模块TranslationWiringPresentation.shouldToastTranslateFailure、HTTP 模块HttpResponsePresentation、代码运行模块CodeRunWiringPresentation.shouldToastRunFailure都有同构的跳过逻辑。六、本地验证方法DIFF-598 的验证命令要求JDK 21在next-compose目录下执行./gradlew :composeApp:desktopTest --offline--offline不访问远程仓库使用本地 Gradle 缓存适合本切片对应的纯桌面端测试涉及desktopMain/desktopTest相关测试类集中在composeApp/src/desktopTest/kotlin/com/rememberber/mootool/next/compose/domain/运行后可重点观察TimeWiringPresentationTest、NetWiringPresentationTest、VaultGitToastPresentationTest、GitEditorFlushPolicyTest四类用例的输出。小结DIFF-598 用极小的改动面完成了时间、网络、Vault-Git 三个模块的失败 Toast 收尾F18 沿用TimeWiringPresentation.shouldToastConvertFailureF11 通过NetWiringPresentation.shouldToastNetworkError跳过ABORTED取消场景A03 新增VaultGitToastPresentation统一承载面板加载失败、操作失败、flush 阻断、远端非法四类提示。这套呈现层开关 通知函数收口 双通道输出 本地化回退的模式让 MooTool 的错误提示既能全局一致也能按模块精细调控是可复制的 Compose Desktop 失败反馈架构范本。赞分享桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载相关推荐Symfony Process 组件 CHANGELOG 深度解读从 Process 到 PhpSubprocess 与 Messenger 的完整演进Symfony Process 组件 CHANGELOG 深度解读从 Process 到 PhpSubprocess 与 Messenger 的完整演进 本篇桌面应用开发工具MooTool Next Compose Vault Git 面板 runAction 异常处理与 toast 呈现对齐实践MooTool Next Compose Vault Git 面板 runAction 异常处理与 toast 呈现对齐实践 Vault Git 面板是 Moo桌面应用开发工具解析 remote-jobs 仓库中的 Checkly 公司档案从 frontmatter 字段到 API/E2E 监控技术栈解析 remote jobs 仓库中的 Checkly 公司档案从 frontmatter 字段到 API/E2E 监控技术栈 导读 本文以开源仓库 GitH桌面应用开发工具上一篇SmolAgents 终极工具集成指南从 MCP 服务器到 LangChain 的无缝接入下一篇手速不够也能抢到票大麦自动抢票Python工具从零到成功下单的完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

基于MP2642GR-Z与STM32的2S主动均衡电池管理方案

基于MP2642GR-Z与STM32的2S主动均衡电池管理方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 6:11:49 阅读更多 →
C# .NetCore Swagger ISchemaFilter 自定义枚举显示

C# .NetCore Swagger ISchemaFilter 自定义枚举显示

目录 1. 核心原理 2. 实现步骤 第一步:定义枚举及描述(可选) 第二步:创建扩展方法获取描述 第三步:实现 ISchemaFilter 第四步:注册 Filter 3. 替代方案:全局序列化设置 总结 如果您喜欢…

2026/10/16 6:11:49 阅读更多 →
国家中小学智慧教育平台电子课本下载:获取 PDF 的 5 个常见问题

国家中小学智慧教育平台电子课本下载:获取 PDF 的 5 个常见问题

国家中小学智慧教育平台电子课本下载:获取 PDF 的 5 个常见问题 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具,帮助您从智慧教育平台中获取电子课本的 PDF 文件网址并进行下载,让您更方便地获取课本内容。 …

2026/10/16 6:11:49 阅读更多 →

最新新闻

Windows高DPI缩放导致软件模糊的完整排查与修复指南

Windows高DPI缩放导致软件模糊的完整排查与修复指南

1. 模糊问题的根源:高DPI缩放下,程序到底发生了什么你现在很可能正遇到这样一个场景:刚换上 2K 或 4K 显示器,系统为了让界面看得清,把缩放比例调到了 125% 或 150%。Windows 自带的设置界面很锐利,可双击某…

2026/10/16 6:49:57 阅读更多 →
Linux pthread线程控制实战:生命周期、同步与死锁排查

Linux pthread线程控制实战:生命周期、同步与死锁排查

编写 Thread 的目的,绝不只是"让函数并行跑起来"。实际开发中,真正让人头疼的往往是:线程怎么退出才安全?主线程怎么知道子线程干完了?栈空间设多大不死锁?多线程访问同一份数据时怎么保证不出错…

2026/10/16 6:49:57 阅读更多 →
CMake 中将 .c 文件当 C++ 编译:方法、链接坑与迁移建议

CMake 中将 .c 文件当 C++ 编译:方法、链接坑与迁移建议

Windows 上用 CMake 做 C/C 混合项目,这个问题隔三岔五就会有人问一次:.c文件到底能不能在 CMake 里直接编译成 C 代码。我最初遇到它,是接手一个遗留算法库的时候,核心文件全是一堆.c,主程序却早就全面 C 化了&#x…

2026/10/16 6:49:57 阅读更多 →
CAT12+SPM实战:VBM灰质体积分析全流程与避坑指南

CAT12+SPM实战:VBM灰质体积分析全流程与避坑指南

简介:这是基于MATLAB的CAT12工具箱,专为神经影像领域的体素形态计量学(VBM)分析设计,面向需要处理结构磁共振数据、比较不同个体或群体脑灰质/白质形态差异的研究者。压缩包共518个文件,约124MB&#xff0c…

2026/10/16 6:49:57 阅读更多 →
Linux用户与组管理实战:从配置文件到权限联动全解析

Linux用户与组管理实战:从配置文件到权限联动全解析

做Linux运维这些年,Linux用户与组管理是让我觉得最基础、也最容易被忽视的一块。很多新手一上来就折腾各种服务部署,等碰到权限报错、用户冲突、文件归属混乱时,才发现当初没把这套体系吃透。这篇文章不打算讲虚的,就当作一次完整…

2026/10/16 6:49:57 阅读更多 →
卡牌随机生成方案:加权随机算法与词缀池设计实战(含Java示例)

卡牌随机生成方案:加权随机算法与词缀池设计实战(含Java示例)

最近在做一个卡牌玩法原型时,遇到一个挺有意思的需求:能不能让卡牌真正意义上“全部随机生成”,而不是靠策划手动一张张配数值?于是我把整套逻辑拆成了卡牌词缀池、随机算法、稀有度权重、生成校验四层结构来设计。本文整理了一套…

2026/10/16 6:48:57 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →