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
| name | nav-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% 以内完整展示,则裁剪;否则整页
- 使用
page.get_text("words")精确定位目标金额/文字坐标 - 红色描边 3px(PIL ImageDraw),无填充,边距外扩 3px
- 只标注与当前核对项直接相关的 1-3 个关键数字(如余额金额、交易金额、利息金额),禁止圈整行或大面积区域
- 截图渲染 DPI ≥ 150(裁剪截图用 4x zoom 确保清晰)
<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)
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/
输入
target_dir:基金期间文件夹绝对路径- profile:
<target_dir>/.cortex/nav_profile.json - 数据:
<target_dir>/.cortex/nav_data/tb.json、cash_balances.json、bank_transactions.json、nominee_cashflow.json、payment_log.json、summary_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.md8 个 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
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>"
.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 或更高 zoom(fitz.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 Summary:
cash_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
- TB Balance 取值截图:
cash_balance_summary.png(Cash Appraisal / FS Pack Cash sheet,对应 TB 余额来源) - Bank Statement Balance 截图(第三方原始证据):每个账户期末月的银行对账单截图(
bank_<bank>_<期末月>_p1.png)+ Nominee 平台期末月结单截图(nominee_<platform>_<期末月>_cashflow.png,has_nominee == true时)。每个账户单独一张,不可合并。
.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 Charges、Bank Interest Income、Admin/AML/FATCA fees、Distribution from "[基金简称]"(如 Distribution from "HongShan CGFV")、Distribution to LP、Management Fee、Audit Fee、B/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弹窗向用户确认汇率,不得自行假设或使用网络搜索汇率
Distribution Income Supporting 规则(Section 2~4 强制)
对于性质标签为分配款收入 (Distribution Income) 的银行流水,Supporting 面板必须包含 Distribution Notice 或 Distribution Summary 作为第三方原始证据,不可仅依赖银行流水截图。
1. 查找路径:穿透对应投资标的文件夹(Investment/[code]投资名/)的所有子文件夹(包括 Notice/、sub/、ILPA/ 等)查找 Distribution Notice 文件。文件名通常包含 Distribution Notice、Distribution、Cash Distribution 等关键词。
2. 截图生成:找到 Distribution Notice PDF 后,使用 PyMuPDF (fitz) 将首页渲染为 PNG 截图,保存至 .cortex/screenshots/cash/ 目录,命名规则:dist_notice_<投资简称>_<月份>.png。
3. Supporting 面板组合:每笔 Distribution Income 流水的 Supporting 面板必须同时展示:
- 银行流水截图(入账记录)
- Distribution Notice 截图(第三方原始证据,确认分配金额与性质)
ask_questions 向用户确认,不得静默跳过。确认选项包括:
- 使用 CAS (Capital Account Statement) 作为替代证据
- 使用银行流水作为唯一证据并标注"未找到独立 Distribution Notice"
- 标注缺失并继续
📄 Dist Notice,提示审阅人可点击查看。
Distribution to LP Supporting 规则(Section 2~4 强制)
对于性质标签为分配款支出 (Distribution to LP) 的银行流水,Supporting 面板必须包含 Distribution Summary(分配款审批文件)作为第三方原始证据。
1. 查找路径:在基金期间文件夹根目录查找 Distribution Summary 文件,常见文件名模式:
付款申请单_Distribution.pdfDistribution Summary*.pdfDistribution Notice to LP*.pdfBoard ResolutionDistribution.pdf
.cortex/screenshots/cash/dist_summary_to_lp.png。
3. Supporting 面板组合:所有 Distribution to LP 流水的 Supporting 面板必须同时展示:
- 银行流水截图(出账记录)
- Distribution Summary 截图(审批/授权文件,确认分配对象与金额)
ask_questions 向用户确认,不得静默跳过。确认选项包括:
- 使用 Payment Log 中的 PN 作为替代证据
- 使用银行流水作为唯一证据并标注"未找到 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 | 4× | 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 单独运行时同样适用。用户选择「跳过」则不上传该报告,「全部取消」则终止。不允许通过任何"批处理静默上传"绕过此关卡。
`