返回资讯中心
外部精选
软件工程
#开发者实时流

TreasuryFlow:为小企业提供隔夜银行流水与账簿核对工具

来源标题:Show HN: TreasuryFlow, an overnight bank-vs-books check for small businesses

TreasuryFlow 在 Show HN 上发布,帮助小企业将银行流水与内部账簿进行隔夜自动核对。其匿名演示在首次解析到生成示例 JSON 的整个启动过程中设有一个 10 秒的截止时间,超时则展示错误提示。

Hacker News 最新michaelgdwn2026/11/13 · 今天22 分钟阅读

以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。

示例看板未能加载 请重试。 重试 返回 TreasuryFlow

} catch (_) {} // 匿名演示启动只有一个截止时间,从首次解析到示例 JSON 加载完成。 // 这段代码位于 portal 模块之前,不需要远程辅助脚本。 var _demoBootAttempt = null; var _demoBootGeneration = 0; function _newDemoBootAttempt() { var previous = _demoBootAttempt; if (previous) { previous.failed = true; clearTimeout(previous.timer); previous.controller.abort(); if (previous.reject) previous.reject(new Error('Demo boot superseded')); } var attempt = { generation: ++_demoBootGeneration, started: false, failed: false, controller: new AbortController(), reject: null, timer: null }; _demoBootAttempt = attempt; attempt.timer = setTimeout(function () { if (_demoBootAttempt !== attempt) return; attempt.failed = true; attempt.controller.abort(); if (attempt.reject) attempt.reject(new Error('Demo boot deadline exceeded')); _renderDemoBootError(); }, 10000); return attempt; } function _beginDemoBootAttempt() { var attempt = _demoBootAttempt; // 初始解析的看门狗负责初始截止时间;bootstrap 不能重置它。 if (attempt && !attempt.started) { if (attempt.failed) return null; } else { attempt = _newDemoBootAttempt(); attempt.started = true; } return attempt; } function _finishDemoBootAttempt(attempt) { if (_demoBootAttempt !== attempt || attempt.failed) return false; clearTimeout(attempt.timer); attempt.reject = null; return true; } (function demoBootSeam() { try { if (new URLSearchParams(window.location.search).get('demo') === 'true') { document.documentElement.classList.add('tf-demo-boot'); _newDemoBootAttempt(); } } catch (e) { /* 尽力而为——最坏情况下认证浮层照旧显示 / } })(); // ── R-1074:演示模式绝不沿用已存储的会话 ────────────────────── // ?demo=true 过去会保留已登录浏览器中存储的 token,于是页面变成了 // 该账号的“尚无银行”预览:所有 // _demoMode && !token 判断都会走实时读取,示例的 Jobs 页面 // 也会调用该账号自己的端点。对于本次页面浏览,已存储的 // 会话被视为不存在(即访客窗口看到的页面),并且无法 // 被移除;它也绝不会被更改。从演示中进行的登录会存储一个新的 // token,从而结束这层保护。 (function demoSessionShield() { try { if (new URLSearchParams(window.location.search).get('demo') !== 'true') return; var KEY = 'tf_portal_token', P = Storage.prototype, get = P.getItem, set = P.setItem, del = P.removeItem; if (!get.call(localStorage, KEY)) return; var on = true, mine = function (s, k) { return on && s === localStorage && String(k) === KEY; }; P.getItem = function (k) { return mine(this, k) ? null : get.apply(this, arguments); }; P.removeItem = function (k) { if (!mine(this, k)) return del.apply(this, arguments); }; P.setItem = function (k) { if (mine(this, k)) on = false; return set.apply(this, arguments); }; window._tfDemoShieldsSession = function () { return on; }; } catch (e) { / 存储不可用:没有任何已存储内容需要保护 / } })(); // ── 登录入口预绘制接缝(收尾波次,2026-06-09)────────────── // 这是 ?signin=1 对应演示接缝的镜像:回访客户绝不能 // 在 _applySigninDoor 重写卡片之前看到试用获客文案闪现。 // 在首次绘制前打上 .tf-signin-boot 标记;下面的 CSS // 会隐藏注册 H1/副标题/CTA,直到 _applySigninDoor(完整 // 应用逻辑)替换文案并清除该类。 // 已有会话在 /me 返回之前先等待,然后再选择已认证 // 界面或登录界面。已存储的 token 本身从不授予访问权限。 (function sessionBootSeam() { try { if ((localStorage.getItem('tf_portal_token') || localStorage.getItem('tf_device_hint')) && new URLSearchParams(window.location.search).get('demo') !== 'true') { document.documentElement.classList.add('tf-session-boot'); } } catch (e) { / 存储不可用:普通登录界面照常显示 / } })(); (function signinBootSeam() { try { if (new URLSearchParams(window.location.search).get('signin') === '1') { document.documentElement.classList.add('tf-signin-boot'); } } catch (e) { / 尽力而为——最坏情况下试用卡片照旧闪现 / } })(); // 邀请接受入口预绘制接缝(Brief 8):队友通过 // ?invite=TOKEN 进入时,绝不能在看到预览请求重写卡片之前 // 看到试用注册文案闪现。隐藏方式与登录启动相同。 (function inviteBootSeam() { try { if (new URLSearchParams(window.location.search).get('invite')) { document.documentElement.classList.add('tf-signin-boot'); } } catch (e) { / 尽力而为——最坏情况下试用卡片照旧闪现 / } })(); // 客户邀请入口(?bk_invite=TOKEN):事务所的客户是在 // 事务所品牌下进入的,因此卡片上的首页标题在那里绝不显示, // 哪怕一帧也不行(创始人 2026-11-05 允许在账户 // 尚不存在时显示,但这个入口属于事务所)。_applyClientInviteDoor() 会写入 // 该入口自己的文案并清除该类。 (function clientInviteBootSeam() { try { if (new URLSearchParams(window.location.search).get('bk_invite')) { document.documentElement.classList.add('tf-client-invite-boot'); } } catch (e) { / 不依赖存储;最坏情况下标题闪现 */ } })(); // 提前点击接缝(R-0888):注册按钮早在定义其处理程序的 // 主脚本解析完成之前就已绘制出来(Fast 3G 下 1.0 秒出现, // 14.7 秒才可用,2026-11-07 走查),此时点击会抛出“未 // 定义”并且毫无反应。在真正的函数替换桩函数并且页面 // 脚本已运行(tfTrack、tfFirstUtm 在主代码块之后)之前, // 首次点击会将其按钮置灰;之后若按钮仍显示,则重放一次。 // 60 秒后它放弃并重新启用。由 // test_portal_first_paint_browser.py 固定验证。 (function earlyTapSeam() {

(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →