Skill Hub · 诺亚 AI 能力中心 静态参考版

让每一个技能成为可信资产 —— 诺亚 Agent 生态的技能资产中心:统一注册、检测把关、按需复用。本站为 skill-hub.noahgroup.com 于 2026-08-21 的全量数据镜像。

镜像采集 2026-08-2166 个已发布技能18 个分类 · 3 条分发渠道含技能包 SKILL.md 全文
← 返回目录

nav-review-cash-report

SKILL_772916121 · vv1.1 · Olive 海外运营 · Owner:Olive 基金运营 · 发布于 2026-08-10
调用 34 下载 0 点赞 0 浏览 0
简介
基于独立证据生成交互式NAV现金复核HTML报告并上传系统
触发词
生成Cash Review,现金复核,NAV对账
分发渠道
ARK Engine
功能测试
✅ 通过 · 业务评审:✅ 通过
技能包文件
nav-review-cash-report/SKILL.md、nav-review-cash-report/SKILL.md.bak、nav-review-cash-report/references/cash_review_html_template.html、nav-review-cash-report/references/cash_review_template.md
使用示例:请根据现有数据生成NAV现金复核HTML报告

SKILL.md 全文

Frontmatter

namenav-review-cash-report
description|

`

---
name: nav-review-cash-report
description: 'NAV 复核第三阶段 — Cash Review:基于 nav-review-identify 的 profile 与 nav-review-collect 的数据/截图,生成交互式 Cash Review HTML 报告(含多币种余额换算USD加总、Distribution Income需Distribution Notice支撑、Distribution to LP需Distribution Summary支撑),并上传 HTML 报告至 iGowin 系统 Cash 类 subject。触发场景:被 nav-review-report 调度 skill 调用,或用户单独要求"生成 Cash Review"、"出现金复核报告"。'
---

NAV Review Stage 3.1 — Cash Review 报告生成与上传 (HTML 版)

⛔ 模板强制遵循规则(最高优先级,不可跳过)

生成 HTML 报告时,必须先 read_file("references/cash_review_html_template.html") 加载模板,然后严格按照模板的完整结构生成报告。禁止自行设计布局、样式或交互方式。 具体要求: 1. 三栏布局不可变更:左侧导航栏(240px, 深色背景) + 中间复核面板(flex:1) + 右侧 Supporting 证据面板(500px, 浅灰背景),三者缺一不可 2. CSS/JS 必须从模板复制:不得自行编写替代样式或脚本,必须使用模板中定义的完整 CSS 和 Vanilla JS 交互逻辑 3. Section 结构必须与模板一致:按模板定义的 Section 顺序和内容结构生成,不得省略、合并或重新排序 4. 交互行为必须保留.interactive-row + data-supporting-id 的点击联动、双击 Lightbox 预览等交互功能必须完整实现 5. Status 列不可省略:银行交易表必须包含 Status 列,使用模板定义的 .status-tag 样式和标准性质标签 6. 禁止降级为单栏/双栏布局:任何情况下不得生成简单的单页报告或传统文档式布局 违反上述任何一条即视为报告生成失败,必须重新生成。 ---

⛔ Supporting 证据来源限制(强制,最高优先级)

只有第三方/外部独立文件才能作为 Supporting 证据。基金自身内部系统生成的文件严禁作为 Supporting。 | 禁止作为 Supporting | 允许作为 Supporting | |---|---| | ❌ Investment Position Appraisal (IPA/N4) | ✅ 银行对账单(DBS Bank Statement 等) | | ❌ Trial Balance (TB) / TB Detail | ✅ 基金行政管理人报表(Citco MV Statement 等) | | ❌ Purchases and Sales Report | ✅ 交易合同/确认函(Contract Note) | | ❌ Nominal Ledger / Detailed General Ledger | ✅ 银行付款确认(Cash Payment Confirmation) | | ❌ Statement of Operations (SOFI) | ✅ 托管人报告 | | ❌ Change in Unrealized Gains Losses Report | ✅ Payment Log(独立第三方核对记录) | 核对逻辑:中间面板的复核数据可引用 IPA/TB 数字进行对比展示,但右侧 Supporting 面板只展示第三方证据截图来佐证这些数字的正确性。如果某个核对项无对应第三方文件,则该行不设置 Supporting 证据(不点击),仅在中间面板以文字展示核对结果。 ---

⛔ Supporting 面板截图与计算过程规则(强制)

规则 A:高清截图 + 红框高亮关键数据

每个 .supporting-item 必须包含对应源文件的高清截图(base64 内嵌),且用红框高亮标注关键数字/字段: 1. 截图范围 — 按数据密度决定
  • 数据集中在 1-2 行的(如银行对账单中单笔交易、单个账户余额行)→ 使用 clip_box 裁剪,只截取文档标题行 + 关键数据行区域,无需整页
  • 数据分布跨多行或多页的(如完整银行对账单交易流水、完整 Payment Log)→ 保留整页或多页展示
  • 判断标准:如果关键数据能在 PDF 页面高度的 30% 以内完整展示,则裁剪;否则整页
2. 红框高亮规则
  • 使用 page.get_text("words") 精确定位目标金额/文字坐标
  • 红色描边 3px(PIL ImageDraw),无填充,边距外扩 3px
  • 只标注与当前核对项直接相关的 1-3 个关键数字(如余额金额、交易金额、利息金额),禁止圈整行或大面积区域
  • 截图渲染 DPI ≥ 150(裁剪截图用 4x zoom 确保清晰)
3. 截图分段标题:每张截图上方须有 <div class="sup-section-label"> 标注来源文件名和取数用途,如 "DBS Bank Statement — Closing Balance (May-31)"

规则 B:计算过程 Supporting(涉及测算时强制输出)

当复核过程中涉及数值测算(而非简单读取对比)时,必须在该行对应的 .supporting-item 最下方新增一个计算过程区块。典型场景包括但不限于:
  • 多币种余额换算加总(= 各币种余额 × 汇率 后求和)
  • 银行余额推算验证(= Opening + Credits − Debits = Closing)
  • YTD 利息收入汇总(= Jan-Mar + Apr + May = YTD Total)
  • 赎回应付款核对(= Contract Note Amount + Accrued Interest)
计算过程区块格式(混合样式)
html <div class="calc-block"> <div class="calc-title">📐 Calculation: [计算目的,如 "May Closing Balance Verification"]</div> <pre class="calc-steps"> Step 1: Opening Balance (from DBS Statement) Opening = 2,763,897.06 Step 2: Subtract redemption payment (15-May) Payment = 2,541,047.79 (to ARK GROUP HOLDINGS) Step 3: Add interest (30-May) Interest = 2,419.18 Step 4: Expected Closing = 2,763,897.06 − 2,541,047.79 + 2,419.18 = 225,268.45 </pre> <div class="calc-result">✓ Result: USD 225,268.45 — matches DBS Statement closing & TB</div> </div>
CSS 样式(须写入 HTML <style> 中)
css .calc-block { margin-top: 12px; border: 1px solid #E2E8F0; border-radius: 6px; overflow: hidden; background: #FAFBFC; } .calc-title { padding: 8px 12px; font-size: 12px; font-weight: 600; color: #1E293B; background: #F1F5F9; border-bottom: 1px solid #E2E8F0; } .calc-steps { padding: 10px 14px; font-size: 11px; font-family: 'Consolas', 'Courier New', monospace; line-height: 1.6; color: #334155; white-space: pre-wrap; margin: 0; background: #FAFBFC; } .calc-result { padding: 8px 12px; font-size: 12px; font-weight: 600; color: #0A8754; background: #E6F4ED; border-top: 1px solid #B7E4C7; }
执行规则
  • 简单读取对比(TB 余额 = Bank 余额)→ 不需要计算过程,只需截图
  • 涉及加减运算推导(Opening ± Transactions = Closing)→ 必须输出计算过程
  • 多币种换算加总 → 必须输出计算过程
  • 计算过程中引用的每个输入值须标注来源文件(如 "from DBS Statement"、"from Payment Log")
  • 最终结果行必须标注验证状态(matches / differs from 目标值)
---

When to Use

  • nav-review-report 调度 skill 在 Stage 3.1 自动调用
  • 用户单独说"生成 Cash Review"、"出现金复核报告"
  • 已存在 <target_dir>/.cortex/nav_profile.json<target_dir>/.cortex/nav_data/<target_dir>/.cortex/screenshots/cash/
本 skill 只生成 Cash Review HTML 交互式报告 + iGowin 上传。HTML 即为最终交付物,不再生成 Word 或 PDF。 ---

输入

  • target_dir:基金期间文件夹绝对路径
  • profile:<target_dir>/.cortex/nav_profile.json
  • 数据:<target_dir>/.cortex/nav_data/tb.jsoncash_balances.jsonbank_transactions.jsonnominee_cashflow.jsonpayment_log.jsonsummary_log.json
  • 截图:<target_dir>/.cortex/screenshots/cash/*.png

输出

| 报告 | HTML 文件名 | iGowin Subject | |------|------------|----------------| | Cash Review | Cash Review - [基金名] [YYYYMMDD].html | Cash Long(或基金 Cash Subject) | HTML 交互式报告输出至 <target_dir>/ 根目录(用户双击可直接在浏览器中打开),并作为 iGowin 系统上传的最终交付物。中间脚本放 <target_dir>/.cortex/。 ---

外置文件索引

| 文件 | 路径 | 加载时机 | |------|------|---------| | Cash Review 内容模板 | references/cash_review_template.md | 启动时 read_file(Section 结构 + 性质标签表) | | Cash Review HTML 模板 | references/cash_review_html_template.html | 启动时 read_file(固定 HTML/CSS/JS 结构,含 Status 列) | | iGowin 上传流程 | ../nav-review-report/references/igowin_upload.md | 上传阶段 read_file |
所有路径相对于 skill 目录:c:\Users\syy10787\.cortex\skills\nav-review-cash-report\
---

UI 与格式约束

HTML 报告为最终交付物,必须采用响应式、现代化双栏交互式设计,提供极佳的屏幕核对体验:

1. 结构与排版布局

  • 最左侧 - 导航栏 (.sidebar)
  • 固定在左侧 (position: fixed; width: 240px; height: 100vh; background: #2F3542; color: #FFF;)。
  • 包含导航标题(基金名称和 NAV 日期)以及 Cash Review 全部 Section 的快速定位链接(Section 数量随 period_type 与 has_nominee 动态调整,详见 Step 2)。
  • 中间 - 复核结果主面板 (.review-panel)
  • 位于导航右侧 (margin-left: 240px; flex: 1; padding: 30px;)。
  • 展示逐项复核表格、逻辑分析段落和 PASS/FAIL 结论。
  • 表格行若有对应 Supporting 证据,必须添加 .interactive-row 类,并设置 data-supporting-id="[ID]" 属性。
  • 最右侧 - Supporting 证据直观查看面板 (.supporting-panel)
  • 宽度 500px,贴在右侧 (position: sticky; top: 0; height: 100vh; overflow-y: auto; background: #F1F5F9;)。
  • 集中展示复核截图。每个截图容器为 .supporting-item,并带有唯一的 id(与主面板行的 data-supporting-id 对应)。
  • 默认隐藏其他,仅激活并高亮当前点击或 hover 行对应的 Supporting 截图。

2. 交互体验设计 (Vanilla JS)

  • 页面加载时默认激活并高亮第一个有 Supporting 的表格行,并在右侧面板展示对应的截图。
  • 当用户点击主面板中的 .interactive-row 时,通过 JS 移除先前的激活状态,在当前点击行添加 .highlighted(浅蓝色背景与蓝色边框),并在右侧面板中平滑滚动并展示对应的 Supporting 截图 (scrollIntoView({ behavior: 'smooth' }))。
  • 双击图片 → 全屏 Lightbox 预览(含 −/倍数/+/Reset 工具栏 + 滚轮缩放 + 拖拽平移):Supporting 面板中的截图默认以正常尺寸内嵌显示,hover 时光标变为 zoom-in 提示可放大。双击任一截图弹出全屏半透明遮罩 lightbox(position: fixed; inset: 0; background: rgba(0,0,0,0.88)),图片居中展示。遮罩顶部固定一个工具栏(<div class="lightbox-toolbar">),含 、当前倍数(如 100%)、+Reset 五个元素。按钮 +/−0.25× 步进调节 lightbox 内图片大小(范围 0.5×~4×,初始 1×);Reset 恢复 1× 并清空平移偏移;、点击遮罩空白处或按 Esc 关闭 lightbox。在遮罩内使用鼠标 滚轮缩放(步进 0.1×以光标点为锚点保持视觉中心);图片放大超出可视区时,按住左键可上下左右拖拽平移(cursor 变为 grab / grabbing)。

3. 颜色与视觉风格

  • 主题背景:#F8FAFC
  • 文字字体:"Segoe UI", "Microsoft YaHei", Arial, sans-serif
  • 结论横幅:
  • PASS:背景 #E2EFDA,文字 #375623,左边框 5px 实线 #548235
  • FAIL:背景 #FCE4D6,文字 #C65911,左边框 5px 实线 #C65911
  • 表格样式:边框 #E2E8F0,表头背景 #F1F5F9 加粗,奇偶行交替背景。
---

执行流程

Step 1:加载 profile + 数据 + 模板

编写 Python 脚本加载数据:
python import os, json, base64 BASE = r"<target_dir>" PROFILE = json.load(open(os.path.join(BASE, ".cortex", "nav_profile.json"), encoding="utf-8"))
加载 <target_dir>/.cortex/nav_data/ 下对应的全部 Cash 核对 JSON 数据(tb / cash_balances / bank_transactions / nominee_cashflow / payment_log / summary_log)。

同时 read_file("references/cash_review_template.md") 获取全部 8 个 Section 模板与性质标签表。
read_file("references/cash_review_html_template.html") 获取固定的 HTML/CSS/JS 模板结构(含三栏布局、Status 列样式、Status 标签色彩体系、交互式 JS 脚本)。生成报告时必须严格遵循此 HTML 模板的结构和样式,特别是 Account Reconciliation 表格的 Status 列不得省略。

Step 2:生成交互式 HTML 报告

使用 Python 脚本拼装 HTML 字符串,将数据填入 HTML/CSS 模板中: 1. 渲染左侧导航栏:根据 cash_review_template.md 8 个 Section 顺序生成链接:
  • Section 1: Cash Balance Check
  • Section 2~4: 银行流水逐月梳理(quarterly = 三个月 + Subsequent 一月;monthly = 当月 + Subsequent 一月)
  • Section 5: Period Summary(quarterly 必须,monthly 可省)
  • Section 6: Nominee 子账户(仅 profile.has_nominee == true 时输出)
  • Section 7: Payment Log Evidence
  • Section 8: Conclusion
2. 渲染中间复核面板:按 cash_review_template.md 的 8 个 Section 顺序构建。每张交易表的有支撑证据的行加上 class="interactive-row" data-supporting-id="support-[来源标识]",例如:
  • Cash Balance Check 行 → data-supporting-id="support-cash-balance"
  • 每月银行交易行 → data-supporting-id="support-bank-<bank>-<month>"
  • Nominee Cashflow 行 → data-supporting-id="support-nominee-<platform>-<month>"
  • Payment Log 行 → data-supporting-id="support-pl-<PN>"
3. 渲染右侧 Supporting 面板:在 .supporting-panel 中,针对每个截图,渲染 <div id="support-[标识]" class="supporting-item">,内部包含来自 .cortex/screenshots/cash/ 目录的图片。 ⚠️ 截图内嵌强制规则:所有截图必须以 base64 data URI 内嵌到 HTML 文件中,禁止使用相对路径或外部文件引用。实现方式:在 Python 脚本中,对每个 PNG 文件读取二进制内容并转为 base64 编码,然后以 data:image/png;base64,<base64_string> 格式写入 <img src="...">⚠️ 截图清晰度强制规则:使用 PyMuPDF (fitz) 渲染 PDF 页面为 PNG 时,必须使用 3x 或更高 zoomfitz.Matrix(3, 3)fitz.Matrix(4, 4)),确保文字和数字在浏览器中清晰可读。2x zoom 不足以保证小字清晰度。
python import base64 def embed_image(base_dir, folder, filename): """读取截图文件并返回 base64 data URI""" path = os.path.join(base_dir, ".cortex", "screenshots", folder, filename) if os.path.exists(path): with open(path, "rb") as f: data = base64.b64encode(f.read()).decode("utf-8") return f"data:image/png;base64,{data}" return "" # 文件不存在时返回空字符串
   HTML 中使用:<img src="{embed_image(BASE, 'cash', 'cash_balance_summary.png')}" alt="Cash Balance Summary">

   > 理由:内嵌截图使 HTML 文件完全自包含,双击即可在任何位置打开查看,不依赖 .cortex/ 目录结构。上传至 iGowin 后也能直接在浏览器中完整展示,无需额外文件。

   Supporting 面板必须覆盖以下截图分组(按 cash_review_template.md 截图清单):
  • Cash Balance Summarycash_balance_summary.png
  • 银行对账单(每月一张)bank_<bank>_<month>_p1.png,subsequent 月份用 bank_<bank>_<month>_subsequent.png
  • Nominee Cashflow(每月一张,has_nominee 为 true 时)nominee_<platform>_<month>_cashflow.png
  • Payment Log 行截图PL_<PN>.png
  • PI 文件截图PI_<PN>.png
  • Email 证据(如有):email_<source>.png
⚠️ Cash Balance Check(Section 1)Supporting 强制规则:Section 1 每行的 Supporting 面板必须同时展示两类截图,缺一不可:
  • TB Balance 取值截图cash_balance_summary.png(Cash Appraisal / FS Pack Cash sheet,对应 TB 余额来源)
  • Bank Statement Balance 截图(第三方原始证据):每个账户期末月的银行对账单截图(bank_<bank>_<期末月>_p1.png)+ Nominee 平台期末月结单截图(nominee_<platform>_<期末月>_cashflow.pnghas_nominee == true 时)。每个账户单独一张,不可合并。
实现方式:每个 Section 1 行(每个账户一行)对应一个独立 .supporting-item,内部用分段标题(<div class="img-title">,样式见下文)将多张截图分组展示,每段标题清晰标注取数用途(账户名 + 期末月份)。所有 <img> 标签的 src 均使用 embed_image() 返回的 base64 data URI。 > 分段标题样式padding:8px 12px; font-size:12px; color:#475569; background:#F8FAFC; border-bottom:1px solid #E2E8F0; border-top:1px solid #E2E8F0; margin: 10px -15px;(首段无 border-top)。 > 强制原因:Section 1 是 TB 与第三方银行对账单的三方匹配陈述。仅展示 Cash Appraisal 截图等同于自证(Cash Appraisal 与 TB 同源于外包商系统),必须同时呈现银行/Nominee 第三方原始余额截图,让审阅人一眼判断 "TB 余额 = 银行对账单余额" 是否成立。 4. 嵌入交互式 JS 脚本(双击截图 → 全屏 Lightbox 预览 + 工具栏缩放 + 滚轮缩放 + 拖拽平移): CSS 新增(在 <style> 末尾添加):
css / ── Supporting 图片悬停提示 ── / .supporting-item img {{ cursor: zoom-in; transition: opacity 0.15s; }} .supporting-item img:hover {{ opacity: 0.9; }} / ── Lightbox 全屏遮罩 ── / .lightbox-overlay {{ display: none; position: fixed; inset: 0; background: rgba(0, 0, 0, 0.88); z-index: 9999; overflow: hidden; }} .lightbox-overlay.active {{ display: block; }} .lightbox-toolbar {{ position: fixed; top: 12px; left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: 8px; padding: 6px 12px; background: rgba(255, 255, 255, 0.95); border-radius: 8px; box-shadow: 0 4px 14px rgba(0,0,0,0.35); font-size: 12px; color: #1E293B; z-index: 10000; user-select: none; }} .lightbox-btn {{ border: 1px solid #CBD5E1; background: #F8FAFC; color: #1E293B; width: 30px; height: 26px; line-height: 1; font-size: 14px; border-radius: 4px; cursor: pointer; padding: 0; }} .lightbox-btn:hover {{ background: #E2E8F0; }} .lightbox-btn.reset, .lightbox-btn.close {{ width: auto; padding: 0 10px; font-size: 11px; }} .lightbox-btn.close {{ border-color: #FCA5A5; color: #B91C1C; background: #FEF2F2; }} .lightbox-level {{ min-width: 46px; text-align: center; font-variant-numeric: tabular-nums; }} .lightbox-stage {{ position: absolute; inset: 0; overflow: auto; cursor: grab; display: flex; align-items: center; justify-content: center; }} .lightbox-stage.grabbing {{ cursor: grabbing; }} .lightbox-stage img {{ max-width: 95vw; max-height: 95vh; transform-origin: center center; user-select: none; -webkit-user-drag: none; transition: transform 0.05s linear; box-shadow: 0 0 30px rgba(0,0,0,0.5); }}
   HTML 结构(在 </body> 之前注入一次即可):
   
html <div class="lightbox-overlay" id="lightbox" aria-hidden="true"> <div class="lightbox-toolbar"> <button class="lightbox-btn" data-zoom="out" title="缩小">−</button> <span class="lightbox-level">100%</span> <button class="lightbox-btn" data-zoom="in" title="放大">+</button> <button class="lightbox-btn reset" data-zoom="reset" title="重置">Reset</button> <button class="lightbox-btn close" data-zoom="close" title="关闭">✕ 关闭</button> </div> <div class="lightbox-stage" id="lightbox-stage"> <img id="lightbox-img" src="" alt="Zoomed view" /> </div> </div>
   JS 完整脚本
html <script> document.addEventListener('DOMContentLoaded', function() { const rows = document.querySelectorAll('.interactive-row'); const items = document.querySelectorAll('.supporting-item'); const placeholder = document.getElementById('no-supporting-placeholder'); // ── Interactive row ↔ Supporting panel ── if (items.length > 0) { activateSupporting(items[0].id); const firstRow = document.querySelector('.interactive-row[data-supporting-id="' + items[0].id + '"]'); if (firstRow) firstRow.classList.add('highlighted'); } rows.forEach(row => { row.addEventListener('click', function() { rows.forEach(r => r.classList.remove('highlighted')); this.classList.add('highlighted'); activateSupporting(this.getAttribute('data-supporting-id')); }); }); function activateSupporting(id) { if (!id) return; const targetItem = document.getElementById(id); if (targetItem) { if (placeholder) placeholder.style.display = 'none'; items.forEach(i => i.classList.remove('active')); targetItem.classList.add('active'); targetItem.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } } // ── 双击 Supporting 截图 → 全屏 Lightbox 预览 ── const ZOOM_MIN = 0.5, ZOOM_MAX = 4.0, STEP_BTN = 0.25, STEP_WHEEL = 0.1; const overlay = document.getElementById('lightbox'); const stage = document.getElementById('lightbox-stage'); const lbImg = document.getElementById('lightbox-img'); const lbLevel = overlay ? overlay.querySelector('.lightbox-level') : null; let scale = 1; const apply = () => { if (lbImg) lbImg.style.transform = 'scale(' + scale + ')'; if (lbLevel) lbLevel.textContent = Math.round(scale * 100) + '%'; }; const setScale = v => { scale = Math.min(ZOOM_MAX, Math.max(ZOOM_MIN, v)); apply(); }; function openLightbox(src, alt) { if (!overlay || !lbImg) return; lbImg.src = src; lbImg.alt = alt || 'Zoomed view'; scale = 1; apply(); if (stage) { stage.scrollLeft = 0; stage.scrollTop = 0; } overlay.classList.add('active'); overlay.setAttribute('aria-hidden', 'false'); } function closeLightbox() { if (!overlay) return; overlay.classList.remove('active'); overlay.setAttribute('aria-hidden', 'true'); if (lbImg) lbImg.src = ''; } document.querySelectorAll('.supporting-item img').forEach(img => { img.addEventListener('dblclick', function(e) { e.preventDefault(); e.stopPropagation(); openLightbox(this.src, this.alt); }); }); if (overlay) { // 工具栏 overlay.querySelectorAll('.lightbox-btn').forEach(btn => { btn.addEventListener('click', e => { e.preventDefault(); e.stopPropagation(); const action = btn.getAttribute('data-zoom'); if (action === 'in') setScale(scale + STEP_BTN); if (action === 'out') setScale(scale - STEP_BTN); if (action === 'reset') { if (stage) { stage.scrollLeft = 0; stage.scrollTop = 0; } setScale(1); } if (action === 'close') closeLightbox(); }); }); // 点击遮罩空白处关闭(点到图片或工具栏不关闭) overlay.addEventListener('click', e => { if (e.target === overlay || e.target === stage) closeLightbox(); }); // Esc 关闭 document.addEventListener('keydown', e => { if (e.key === 'Escape' && overlay.classList.contains('active')) closeLightbox(); }); // 滚轮缩放(以光标点为锚点) stage.addEventListener('wheel', e => { if (!overlay.classList.contains('active')) return; e.preventDefault(); const rect = stage.getBoundingClientRect(); const px = e.clientX - rect.left + stage.scrollLeft; const py = e.clientY - rect.top + stage.scrollTop; const oldScale = scale; setScale(scale + (e.deltaY < 0 ? STEP_WHEEL : -STEP_WHEEL)); const ratio = scale / oldScale; stage.scrollLeft = px * ratio - (e.clientX - rect.left); stage.scrollTop = py * ratio - (e.clientY - rect.top); }, { passive: false }); // 拖拽平移 let dragging = false, sx = 0, sy = 0, ssl = 0, sst = 0; stage.addEventListener('mousedown', e => { if (e.button !== 0) return; if (e.target.closest('.lightbox-toolbar')) return; dragging = true; sx = e.clientX; sy = e.clientY; ssl = stage.scrollLeft; sst = stage.scrollTop; stage.classList.add('grabbing'); e.preventDefault(); }); document.addEventListener('mousemove', e => { if (!dragging) return; stage.scrollLeft = ssl - (e.clientX - sx); stage.scrollTop = sst - (e.clientY - sy); }); document.addEventListener('mouseup', () => { if (!dragging) return; dragging = false; stage.classList.remove('grabbing'); }); } }); </script>
5. 将完整 HTML 内容写入 <target_dir>/Cash Review - [基金名] [YYYYMMDD].html。

---

Cash Review 强制总则(不可破坏)

1. Cash Appraisal 余额检查必须放在报告最开头(Section 1):各账户 TB 余额 vs 银行对账单余额一一比对,结论横幅 ✅ ALL ACCOUNTS MATCH 或 ⚠️ DISCREPANCY FOUND。 2. 覆盖期内全部月份 — monthly = 当月 + Subsequent 一月;quarterly = 整季三个月 + Subsequent 一月,每月独立 Section,不得只展示季末月。若某月对账单缺失,必须显式写明并解释 B/F 余额。 3. Nominee 现金账项每月一节 —— 当月若无现金活动(无 redemption / withdrawal / deposit),Cashflow Statement 页本身不会出现,此时不得用其他页替代,必须直接写:"現金賬項(Cashflow Statement):本月無現金活動,不適用"。 4. 绝不用 Journal Entry(JE)作为支撑证据。任何溯源若指向 JE,必须继续往底层挖到 Payment Log、PI 文件 + 发票、银行流水、或标的基金 statement。 5. 每笔银行交易必须有性质标签(Bank Charge / 管理费 / 投资款支出 / 分配款支出 / 分配款收入 / 与 Nominee 资金往来 / 利息收入 / B/F / FATCA 费用 / 审计费 等),用语必须从 cash_review_template.md 的标准用语表中选取。每笔流水的性质标签必须在表格最后一列 "Status" 中显示,标准取值包括但不限于:Bank ChargesBank Interest IncomeAdmin/AML/FATCA feesDistribution from "[基金简称]"(如 Distribution from "HongShan CGFV")、Distribution to LPManagement FeeAudit FeeB/F Balance。 6. 多币种银行账户余额必须换算为 USD 加总(见下方"多币种余额换算规则")。 7. 分配款收入 (Distribution Income) 流水必须增加 Distribution Notice 作为 Supporting(见下方"Distribution Income Supporting 规则")。 8. 分配款支出 (Distribution to LP) 流水必须增加 Distribution Summary 作为 Supporting(见下方"Distribution to LP Supporting 规则")。

截图禁忌

  • 绝不把 JE 作为支撑证据
  • 可接受来源:Payment Log 行、PI 文件、银行对账单、标的基金 Capital Call / Distribution Notice、Nominee/Broker statement
  • Payment Log 截图必出(每个匹配的 PN 一张行截图 + 一张 PI 文件截图)

多币种余额换算规则(Section 1 强制)

当银行账户为多币种账户(如 DBS Multi-Currency Savings Account 同时持有 USD / HKD / CNY / EUR 子账户)时,Cash Balance Check(Section 1)必须: 1. 逐币种分行展示:每个币种子账户单独一行,列出 Original Balance(原币金额)、FX Rate to USD、USD Equivalent。 2. 加总行:在所有币种行之后,增加一行"XXX Bank Total (USD Equivalent)",将所有币种的 USD Equivalent 加总。 3. TB 比对只核对换算后 USD Total 与 TB Balance 的差异,不单独核对 USD 子账户与银行 USD 余额的差异。因为 TB 余额已包含所有币种换算后的总额,单独比对 USD 子账户会产生误导性差异。 4. 汇率取值优先级
  • ① 优先从工作区中的汇率图表(如 FX Rate Chart PDF / Excel)获取期末汇率
  • ② 若无汇率图表,从银行对账单 Account Summary 页获取银行内部汇率
  • ③ 若以上均无,必须使用 ask_questions 弹窗向用户确认汇率,不得自行假设或使用网络搜索汇率
5. 汇率标注:在 Section 1 下方差异说明区域,必须显式标注所使用的汇率(如 "HKD/USD = 0.12849, CNY/USD = 0.142512")及来源(如 "confirmed by fund accountant")。 6. 差异判定:USD Total 与 TB 差异 < 1 USD 视为 FX 尾差 PASS;差异 ≥ 1 USD 需分析原因。

Distribution Income Supporting 规则(Section 2~4 强制)

对于性质标签为 分配款收入 (Distribution Income) 的银行流水,Supporting 面板必须包含 Distribution Notice 或 Distribution Summary 作为第三方原始证据,不可仅依赖银行流水截图。 1. 查找路径:穿透对应投资标的文件夹(Investment/[code]投资名/)的所有子文件夹(包括 Notice/sub/ILPA/ 等)查找 Distribution Notice 文件。文件名通常包含 Distribution NoticeDistributionCash Distribution 等关键词。 2. 截图生成:找到 Distribution Notice PDF 后,使用 PyMuPDF (fitz) 将首页渲染为 PNG 截图,保存至 .cortex/screenshots/cash/ 目录,命名规则:dist_notice_<投资简称>_<月份>.png。 3. Supporting 面板组合:每笔 Distribution Income 流水的 Supporting 面板必须同时展示:
  • 银行流水截图(入账记录)
  • Distribution Notice 截图(第三方原始证据,确认分配金额与性质)
4. 未找到处理:若穿透所有子文件夹后仍未找到 Distribution Notice,必须使用 ask_questions 向用户确认,不得静默跳过。确认选项包括:
  • 使用 CAS (Capital Account Statement) 作为替代证据
  • 使用银行流水作为唯一证据并标注"未找到独立 Distribution Notice"
  • 标注缺失并继续
5. Supporting 列标注:在交易表的 Supporting 列,对有 Distribution Notice 的行标注 📄 Dist Notice,提示审阅人可点击查看。

Distribution to LP Supporting 规则(Section 2~4 强制)

对于性质标签为 分配款支出 (Distribution to LP) 的银行流水,Supporting 面板必须包含 Distribution Summary(分配款审批文件)作为第三方原始证据。 1. 查找路径:在基金期间文件夹根目录查找 Distribution Summary 文件,常见文件名模式:
  • 付款申请单_Distribution.pdf
  • Distribution Summary*.pdf
  • Distribution Notice to LP*.pdf
  • Board ResolutionDistribution.pdf
2. 截图生成:找到后渲染首页为 PNG,保存至 .cortex/screenshots/cash/dist_summary_to_lp.png。 3. Supporting 面板组合:所有 Distribution to LP 流水的 Supporting 面板必须同时展示:
  • 银行流水截图(出账记录)
  • Distribution Summary 截图(审批/授权文件,确认分配对象与金额)
4. 未找到处理:若未找到 Distribution Summary,必须使用 ask_questions 向用户确认,不得静默跳过。确认选项包括:
  • 使用 Payment Log 中的 PN 作为替代证据
  • 使用银行流水作为唯一证据并标注"未找到 Distribution Summary"
  • 标注缺失并继续
5. Supporting 列标注:在交易表的 Supporting 列,对有 Distribution Summary 的行标注 📄 Dist Summary,提示审阅人可点击查看。 6. 多笔合并展示:同一日多笔 Distribution to LP(如分配给不同 LP)共享同一份 Distribution Summary 时,所有相关行的 Supporting 面板均可引用同一截图。 ---

Step 3:上传 iGowin

read_file("../nav-review-report/references/igowin_upload.md") 获取上传流程,然后执行 6 步(上传 HTML 文件本身,不再做 Word / PDF 转换): 1. get_nav_packs(fund_name) → 获取 applicationNo 2. get_subject_names(application_no) → 找到 Cash 类 subject_name 3. get_upload_url(file_name, content_type="text/html") → 拿到 uploadUrl + objectName 4. ⚠️ 上传前确认关卡(强制):调用 ask_questions 弹窗向用户展示完整上传摘要并取得明确确认。摘要必须包含:基金名、NAV 日期、流程单号、目标 subject、文件名、文件大小(MB)、报告核对结论(PASS / FAIL,及差异金额)。选项至少包含「确认上传」「跳过该报告」「全部取消」。未取得确认前,不得执行 Step 5 的 PUT 上传或 Step 6 的 save_check_result。即便此前在主 skill 入口已确认整体计划,此处仍须再次确认(理由见 igowin_upload.md 的"强制原则"段)。 5. PowerShell 上传(仅在 Step 4 通过后执行):Invoke-WebRequest -UseBasicParsing -Method Put -Uri $uploadUrl -InFile $htmlPath -ContentType "text/html" 6. save_check_result(object_name, file_name, subject_name, application_no)(仅在 Step 5 PUT 返回 200 OK 后执行) ---

完成检查表

  • [ ] HTML 交互式报告已落盘,能双击打开且最左侧包含清晰导航栏(Section 数量随 period_type 与 has_nominee 动态调整)
  • [ ] 中间复核行与右侧 Supporting 截图具备联动点击高亮、平滑滚动体验
  • [ ] 双击 Supporting 截图打开全屏 Lightbox 预览:遮罩顶部含 / 倍数 / + / Reset / 工具栏(按钮 0.25× 步进、范围 0.5×~4×);遮罩内支持鼠标滚轮缩放(步进 0.1×、以光标点为锚点)与上下左右拖拽平移;点击遮罩空白处、 或按 Esc 关闭
  • [ ] 所有截图以 base64 data URI 内嵌到 HTML 文件中,HTML 文件完全自包含,双击即可在任何位置打开查看;截图渲染使用 3x+ zoom 确保清晰度
  • [ ] **Cash Balance Check(Section 1)每行 Supporting 面板同时包含 TB Balance 取值截图(cash_balance_summary.png)和对应账户的 Bank Statement Balance 第三方原始证据截图(bank_.png / nominee_.png)**,分段标题清晰标注账户与期末月份
  • [ ] Cash Balance Check(Section 1)TB 余额、Cash Appraisal 余额、银行对账单余额三方匹配
  • [ ] 多币种银行账户余额已换算为 USD 加总,逐币种分行展示(Original Balance + FX Rate + USD Equivalent),汇率来源已标注,无汇率图表时已弹窗确认
  • [ ] 分配款收入 (Distribution Income) 流行 Supporting 面板包含 Distribution Notice 截图,未找到时已向用户确认
  • [ ] 分配款支出 (Distribution to LP) 流行 Supporting 面板包含 Distribution Summary 截图,未找到时已向用户确认
  • [ ] 每月银行交易表覆盖 quarterly 全部三个月 + Subsequent 一月(monthly 报告则当月 + Subsequent 一月)
  • [ ] Payment Log 截图覆盖期内每个匹配的 PN(PL 行截图 + PI 文件截图)
  • [ ] 结论横幅颜色正确(PASS 绿底 / FAIL 红底)
  • [ ] 上传前确认关卡已执行:在 PUT 上传前已用 ask_questions 向用户展示上传摘要(基金名 / NAV 日期 / 流程单号 / subject / 文件名 / 大小 / 核对结论)并取得明确「确认上传」回应;如用户选择跳过则未调用 save_check_result,并在交付总结中标注"用户选择不上传"
  • [ ] iGowin applicationNo 匹配当期,并且 save_check_result 返回成功(HTML 文件已成功上传至 Cash 类 subject)
---

截图质量与标注规则

截图清晰度要求(最高质量)

清晰度为第一优先级。所有内嵌 HTML 的截图必须确保数字、文字在浏览器中完全清晰可读。 | 参数 | 值 | 说明 | |------|-----|------| | DPI | 150 | HTML 内嵌 JPEG 渲染分辨率 | | JPEG quality | 85 | 高品质,文字无锯齿 | | 红框线宽 | 3px | PIL ImageDraw,高清图上清晰可见 | | 落盘 PNG | 300 DPI | 独立 PNG 文件最高清晰度 | | 宽表 zoom | | IPA 等宽表裁剪用 4x zoom | 不设单文件体积上限。如需控制体积,通过 clip_box 裁剪区域(只截关键数据行),禁止降低 DPI 或 quality
python import fitz, io, base64 from PIL import Image, ImageDraw def screenshot_for_embed(pdf_path, page_num, red_rects=None, clip_box=None, dpi=150, quality=85): """高清 JPEG 截图用于 HTML 内嵌""" doc = fitz.open(pdf_path) page = doc[page_num] mat = fitz.Matrix(dpi/72, dpi/72) pix = page.get_pixmap(matrix=mat, clip=fitz.Rect(*clip_box) if clip_box else None) img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples) if red_rects: draw = ImageDraw.Draw(img) scale = dpi / 72.0 ox, oy = (clip_box[0], clip_box[1]) if clip_box else (0, 0) for box in red_rects: draw.rectangle([(box[0]-ox)scale-1, (box[1]-oy)scale-1, (box[2]-ox)scale+1, (box[3]-oy)scale+1], outline='red', width=3) buf = io.BytesIO() img.save(buf, format='JPEG', quality=quality, optimize=True) doc.close() return f"data:image/jpeg;base64,{base64.b64encode(buf.getvalue()).decode()}"

截图红框标注规则

所有 Supporting 截图必须用红框高亮关键数字,帮助审阅人快速定位: 1. 定位方法:使用 page.get_text("words") 从 PDF 精确提取文字坐标 2. 标注内容:仅标注与当前核对项直接相关的金额数字(如余额、交易金额、份额) 3. 红框样式:红色描边 3px(PIL),无填充,略扩展 3px 边距 4. 禁止:圈整行或大区域、使用不透明填充、标注非关键信息

数据层级标注强制规则 (Data Hierarchy)

报告中必须严格区分 Reference(被核对对象)Supporting(第三方证据): | Category | Documents | 标签色 | |----------|-----------|--------| | Reference(被核对) | TB, Cash Appraisal, Statement of Operations | 紫色 #f3e5f5 | | Supporting(第三方证据) | Bank Statement (DBS/HSBC等), Nominee Statement | 绿色 #e8f5e9 |
  • FS Pack 内部报告永远不能标记为 Supporting
  • Cash Appraisal 与 TB 同源于外包商系统,属于 Reference
  • 只有银行对账单等独立第三方文件才能作为 Supporting
---

关键注意事项

1. 本 skill 只负责 Cash Review,不涉及 Investment Cost 或 UGL。 2. HTML 即最终交付物:不再生成 Word 或 PDF,所有上传与展示统一基于 HTML 文件。 3. 所有截图必须以 base64 data URI 内嵌到 HTML 文件中,使 HTML 完全自包含,不依赖外部文件。禁止使用相对路径或外部文件引用。 4. 不要使用任何第三方繁重 JS 库,交互动作必须全部由精简的原生 Vanilla JS 编写。 5. 截图全部来自 nav-review-collect 的输出目录 screenshots/cash/,本 skill 不再现场制作截图。 6. 结论横幅一律先 PASS 再列发现,FAIL 必须说明具体差异金额与建议跟进项。 7. 绝不用 JE 作为支撑证据,任何溯源必须往底层挖到 Payment Log、PI 文件、银行流水等。 8. 每笔银行交易性质标签 必须从 cash_review_template.md 标准用语表中选,禁止自创。 9. Cash Balance Check Supporting 必须双覆盖:Section 1 每个账户行的 supporting 同时展示 Cash Appraisal 截图(TB 取值)+ 该账户期末月银行/Nominee 对账单截图(第三方余额取值),不允许只展示 Cash Appraisal。 10. 多币种余额必须换算为 USD 加总:DBS 等多币种账户需逐币种分行展示原币余额、汇率、USD 等值,然后加总与 TB 比对。只核对换算后 USD total 与 TB 的差异,不单独核对 USD 子账户差异。无汇率图表时必须弹窗确认,不得自行假设汇率。 11. Distribution Income 必须有 Distribution Notice 支撑:穿透投资标的文件夹所有子文件夹查找 Distribution Notice,未找到时必须弹窗确认。Supporting 面板同时展示银行流水 + Distribution Notice 截图。 12. Distribution to LP 必须有 Distribution Summary 支撑:查找付款申请单/Distribution Summary 文件,未找到时必须弹窗确认。Supporting 面板同时展示银行流水 + Distribution Summary 截图。 13. iGowin 上传前必须经过 ask_questions 强制确认PUT 上传与 save_check_result 都是不可逆操作,因此在调用 get_upload_url 之后、PUT 之前必须ask_questions 弹窗向用户确认(含基金名 / NAV 日期 / 流程单号 / subject / 文件名 / 文件大小 / 核对结论)。即使本 skill 被 nav-review 主 skill 调用、用户已在主入口确认过整体计划,此处仍须再次确认;本 skill 单独运行时同样适用。用户选择「跳过」则不上传该报告,「全部取消」则终止。不允许通过任何"批处理静默上传"绕过此关卡。
`