Files
g3fo-recurring-investment/schedule_invest_plan_design_v1.3.html
T

1178 lines
63 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-HK">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PRP (Periodic Recurring Program) v1.2 — System Design Document | N2N-AFE</title>
<style>
:root {
--bg: #0f1117;
--surface: #161822;
--surface2: #1c1f2e;
--border: #2a2d3c;
--text: #d0d3e0;
--text2: #9094a8;
--text3: #686b7d;
--accent: #5b8def;
--accent2: #7b61ff;
--green: #34d399;
--red: #f87171;
--amber: #fbbf24;
--cyan: #22d3ee;
--pink: #f472b6;
--orange: #fb923c;
--radius: 8px;
--radius-lg: 12px;
}
* { margin:0; padding:0; box-sizing:border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang HK", "Microsoft JhengHei", sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.7;
font-size: 14px;
}
.container { max-width: 1040px; margin:0 auto; padding: 32px 24px 80px; }
header {
text-align: center;
padding: 48px 0 32px;
border-bottom: 1px solid var(--border);
margin-bottom: 40px;
}
header .badge {
display: inline-block;
background: var(--accent);
color: #fff;
font-size: 11px;
font-weight: 600;
padding: 3px 12px;
border-radius: 20px;
letter-spacing: 1px;
text-transform: uppercase;
margin-bottom: 16px;
}
header h1 { font-size: 28px; font-weight: 700; color: #fff; margin-bottom: 8px; }
header .sub { color: var(--text2); font-size: 14px; }
header .meta { margin-top: 20px; display:flex; justify-content:center; gap:32px; flex-wrap:wrap; }
header .meta span { color: var(--text3); font-size:12px; }
header .meta b { color: var(--text2); }
nav.toc {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 24px 28px;
margin-bottom: 40px;
}
nav.toc h2 { font-size: 15px; color: #fff; margin-bottom: 12px; }
nav.toc ol { padding-left: 20px; }
nav.toc li { margin: 6px 0; }
nav.toc a { color: var(--accent); text-decoration:none; }
nav.toc a:hover { color: #fff; }
.section { margin-bottom: 48px; }
.section h2 {
font-size: 20px; color: #fff;
padding-bottom: 8px; border-bottom: 2px solid var(--accent);
margin-bottom: 20px; display: flex; align-items: center; gap: 10px;
}
.section h2 .num {
background: var(--accent); color: #fff; font-size: 13px;
width: 28px; height: 28px;
display: flex; align-items: center; justify-content: center;
border-radius: 6px; flex-shrink: 0;
}
.section h3 { font-size: 16px; color: #fff; margin: 24px 0 12px; padding-bottom: 6px; border-bottom: 1px solid var(--border); }
.info-card {
background: var(--surface); border: 1px solid var(--border);
border-radius: var(--radius-lg); padding: 20px 24px; margin-bottom: 16px;
}
.info-card .label { color: var(--text2); font-size: 12px; margin-bottom: 4px; }
.info-card .value { color: #fff; font-size: 18px; font-weight: 600; }
table {
width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 13px;
}
thead th {
background: var(--surface2); color: var(--text2); font-weight: 600;
text-align: left; padding: 10px 14px; border-bottom: 2px solid var(--border);
font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px;
}
tbody td { padding: 10px 14px; border-bottom: 1px solid var(--border); color: var(--text); }
tbody tr:hover { background: var(--surface2); }
td code, th code { background: var(--surface2); padding: 2px 6px; border-radius: 4px; font-size: 12px; color: var(--accent); }
td .tag {
display: inline-block; padding: 2px 8px; border-radius: 4px;
font-size: 11px; font-weight: 600;
}
.tag-green { background: #064e3b; color: #34d399; }
.tag-blue { background: #1e3a5f; color: #60a5fa; }
.tag-amber { background: #78350f; color: #fbbf24; }
.tag-red { background: #7f1d1d; color: #f87171; }
.tag-purple { background: #4c1d95; color: #c084fc; }
.tag-cyan { background: #164e63; color: #22d3ee; }
.code-block {
background: var(--surface); border: 1px solid var(--border);
border-radius: var(--radius); padding: 20px 24px; margin: 16px 0;
overflow-x: auto;
font-family: "SF Mono", "Fira Code", "Consolas", monospace;
font-size: 12px; line-height: 1.8;
}
.code-block .kw { color: #c084fc; }
.code-block .str { color: #34d399; }
.code-block .cm { color: var(--text3); }
.code-block .fn { color: #fbbf24; }
.code-block .var { color: #60a5fa; }
.grid2 { display:grid; grid-template-columns:1fr 1fr; gap:16px; }
.grid3 { display:grid; grid-template-columns:1fr 1fr 1fr; gap:16px; }
.flow-step {
display: flex; gap: 12px; align-items: flex-start; margin-bottom: 12px;
}
.flow-step .step-num {
width: 28px; height: 28px; background: var(--accent); color: #fff;
border-radius: 50%; display: flex; align-items: center; justify-content: center;
font-size: 12px; font-weight: 700; flex-shrink: 0; margin-top: 2px;
}
.flow-step .step-body { flex: 1; }
.flow-step .step-title { color: #fff; font-weight: 600; margin-bottom: 2px; }
.flow-step .step-desc { color: var(--text2); font-size: 13px; }
.arch-layer {
border: 1px solid var(--border); border-radius: var(--radius);
padding: 16px 20px; margin-bottom: 12px; position: relative;
}
.arch-layer.layer-front { border-left: 4px solid var(--accent); }
.arch-layer.layer-trade { border-left: 4px solid var(--green); }
.arch-layer.layer-settle { border-left: 4px solid var(--amber); }
.arch-layer h4 { font-size:13px; color:#fff; margin-bottom:4px; }
.arch-layer p { font-size:12px; color:var(--text2); }
.ui-widget {
background: var(--surface); border: 1px solid var(--border);
border-radius: var(--radius-lg); overflow: hidden; margin-bottom: 20px;
}
.ui-widget .widget-header {
background: var(--surface2); padding: 10px 16px;
border-bottom: 1px solid var(--border);
display: flex; align-items: center; gap: 8px;
}
.ui-widget .widget-header .dot { width:10px; height:10px; border-radius:50%; background: var(--text3); }
.ui-widget .widget-header .dot.active { background: var(--green); }
.ui-widget .widget-title { color: var(--text2); font-size: 12px; flex:1; }
.ui-widget .widget-body { padding: 20px; }
.ui-widget .mock-row {
display: flex; gap: 12px; align-items: center;
padding: 10px 0; border-bottom: 1px solid var(--border);
}
.ui-widget .mock-field {
background: var(--surface2); border: 1px solid var(--border);
border-radius: 6px; padding: 10px 14px; flex: 1;
font-size: 12px; color: var(--text2);
}
.ui-widget .mock-field.required { border-color: var(--amber); }
.ui-widget .mock-btn {
background: var(--accent); color: #fff; border: none;
border-radius: 6px; padding: 8px 16px; font-size: 12px; cursor: pointer;
}
.ui-widget .mock-btn.ghost { background: transparent; border: 1px solid var(--border); color: var(--text2); }
.ui-widget .mock-btn.danger { background: var(--red); }
.ui-widget .field-hint { font-size: 10px; color: var(--text3); margin-top: 2px; }
.ui-widget .field-hint.warn { color: var(--amber); }
.flow-arrow { display: flex; align-items: center; justify-content: center; color: var(--text3); font-size: 20px; padding: 8px 0; }
.note {
background: #1e3a5f; border-left: 4px solid var(--accent);
padding: 14px 18px; border-radius: 0 var(--radius) var(--radius) 0;
margin: 16px 0; font-size: 13px; color: #bfdbfe;
}
.note strong { color: #fff; }
.note.amber { background: #78350f; border-left-color: var(--amber); color: #fde68a; }
.resp-grid {
display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 8px; font-size: 12px;
}
.resp-grid .resp-header { color: var(--text3); font-weight: 600; padding: 6px 0; border-bottom: 1px solid var(--border); }
.resp-grid .resp-cell { padding: 6px 0; border-bottom: 1px solid var(--border); }
.forecast-box {
background: var(--surface2); border: 1px solid var(--border);
border-radius: var(--radius); padding: 16px 20px; text-align: center;
}
.forecast-box .fv { font-size: 20px; color: var(--green); font-weight: 700; }
.forecast-box .fl { font-size: 11px; color: var(--text3); margin-top: 2px; }
footer {
text-align: center; padding: 40px 0 20px;
border-top: 1px solid var(--border); margin-top: 60px;
color: var(--text3); font-size: 12px;
}
.toggle-group {
display: flex; gap: 4px; background: var(--surface2); border-radius: 6px; padding: 3px;
}
.toggle-opt {
padding: 6px 12px; border-radius: 4px; font-size: 12px;
color: var(--text2); cursor: pointer; border: none; background: transparent;
}
.toggle-opt.active { background: var(--accent); color: #fff; }
</style>
</head>
<body>
<div class="container">
<header>
<div class="badge">System Design Document</div>
<h1>PRP (Periodic Recurring Program)</h1>
<p class="sub">定期投资 — 系统设计方案</p>
<div class="meta">
<span>项目: <b>G3SF / G3SB</b></span>
<span>版本: <b>v1.3</b></span>
<span>日期: <b>2026-08-03</b></span>
<span>分类: <b>Internal</b></span>
<span>作者: <b>Jagon Li</b></span>
</div>
</header>
<nav class="toc">
<h2>目录</h2>
<ol>
<li><a href="#c1">项目概述 & 集成全景</a></li>
<li><a href="#c2">功能需求规格</a></li>
<li><a href="#c3">数据模型设计</a></li>
<li><a href="#c4">UI/UX 设计建议</a></li>
<li><a href="#c5">技术架构 & 集成方案</a></li>
<li style="list-style:none;padding-left:20px;font-size:12px;color:var(--text3);">5.3 错误处理与重试机制(新增)</li>
</ol>
</nav>
<div class="section" id="c1">
<h2><span class="num">1</span> 项目概述 & 集成全景</h2>
<h3>1.1 业务背景</h3>
<p>N2N-AFE 为券商和银行提供一体化交易解决方案已超过 43 年。随着零售投资者对「被动定投」和「自动化理财」需求的快速增长,券商客户迫切需要一套内嵌于现有交易系统的<strong>PRP(Periodic Recurring Program,定期投资)</strong>功能。</p>
<p>该模块允许投资者设定自动化定额定期投资,系统按设定频率通过券商自有交易通道执行下单,并由结算系统自动更新持仓,全程可追踪、可修改、可审计。</p>
<h3>1.2 N2N-AFE 产品集成全景</h3>
<div class="grid2" style="margin: 20px 0;">
<div class="info-card">
<div class="label">投资者入口</div>
<div class="value" style="font-size:14px;">eServices</div>
<div style="color:var(--text2);font-size:12px;">Web 门户</div>
</div>
<div class="info-card">
<div class="label">员工操作</div>
<div class="value" style="font-size:14px;">ProX</div>
<div style="color:var(--text2);font-size:12px;">专业交易终端</div>
</div>
<div class="info-card">
<div class="label">员工操作</div>
<div class="value" style="font-size:14px;">OMC</div>
<div style="color:var(--text2);font-size:12px;">运营管理中心</div>
</div>
<div class="info-card">
<div class="label">后端处理</div>
<div class="value" style="font-size:14px;">G3SF + G3SB</div>
<div style="color:var(--text2);font-size:12px;">前台交易 + 后台结算</div>
</div>
</div>
<h3>1.3 设计原则</h3>
<div class="grid2">
<div class="info-card">
<div class="label" style="color:var(--accent);">01</div>
<div class="value" style="font-size:14px;">嵌入式 Widget 架构</div>
<div style="color:var(--text2);font-size:12px;">同一组件,跨 5 个宿主产品复用,响应式自适应</div>
</div>
<div class="info-card">
<div class="label" style="color:var(--green);">02</div>
<div class="value" style="font-size:14px;">零外部依赖</div>
<div style="color:var(--text2);font-size:12px;">不接入 IBKR 或第三方 API,完全走券商自有 OMS 通道</div>
</div>
<div class="info-card">
<div class="label" style="color:var(--amber);">03</div>
<div class="value" style="font-size:14px;">现有系统无缝集成</div>
<div style="color:var(--text2);font-size:12px;">G3SF 管理计划/订单,G3SB 处理成交/结算(Settlement)/持仓更新 — 复用现有交易与结算基础设施</div>
</div>
<div class="info-card">
<div class="label" style="color:var(--purple);">04</div>
<div class="value" style="font-size:14px;">专业级 UI/UX</div>
<div style="color:var(--text2);font-size:12px;">简洁、大气、信息密度适中,适配金融场景</div>
</div>
</div>
<h3>1.4 核心业务流程图</h3>
<div style="background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-lg);padding:24px;margin:16px 0;text-align:center;line-height:2.2;">
<span class="tag tag-blue">投资者</span> → <span style="color:var(--accent);">创建 PRP 计划</span> → <span class="tag tag-purple">G3SF 存储</span> → <span style="color:var(--amber);">Scheduler 定时触发</span> → <span class="tag tag-green">G3SF 生成订单</span> → <span class="tag tag-cyan">券商 OMS</span> → <span class="tag tag-amber">G3SB 结算</span> → <span style="color:var(--green);">更新持仓</span> → <span class="tag tag-purple">邮件通知</span> → <span class="tag tag-blue">投资者</span>
</div>
</div>
<div class="section" id="c2">
<h2><span class="num">2</span> 功能需求规格</h2>
<h3>2.1 角色定义</h3>
<table>
<thead><tr><th>角色</th><th>描述</th><th>权限范围</th></tr></thead>
<tbody>
<tr><td><span class="tag tag-blue">Investor</span></td><td>券商终端投资者</td><td>创建/修改/查看/暂停/恢复/取消 自己的 PRP 计划</td></tr>
<tr><td><span class="tag tag-green">Staff</span></td><td>券商运营/客服人员</td><td>监控全部计划、系统配置、报表导出、手动干预</td></tr>
<tr><td><span class="tag tag-purple">Admin</span></td><td>系统管理员</td><td>市场规则配置、费率模板、通知模板、数据维护</td></tr>
</tbody>
</table>
<h3>2.2 投资者端功能(A 模块)</h3>
<div class="info-card" style="margin-top:16px;">
<div class="value" style="font-size:15px;">A1 — 创建 PRP 投资计划</div>
<table>
<thead><tr><th>步骤</th><th>字段</th><th>类型</th><th>说明</th></tr></thead>
<tbody>
<tr><td>1</td><td>标的代码</td><td>搜索框</td><td>支持代码/名称搜索,自动补全,显示交易所+币种</td></tr>
<tr><td>2</td><td>每次投入金额</td><td>数值</td><td>按币种单位</td></tr>
<tr><td>3</td><td>投资频率</td><td>下拉</td><td>每日 / 每周 / 每月</td></tr>
<tr>
<td>4</td><td>频率日</td><td>选择器</td>
<td>每周=选周一到周五;每月=选 1-28 号<br><span style="color:var(--amber);font-size:11px;">如果所选日期为非交易日,订单将于下一个交易日执行</span></td>
</tr>
<tr><td>5</td><td>开始日期</td><td>日期选择</td><td>必须大于当前日期(最小为 T+1)</td></tr>
<tr>
<td>6</td><td>结束方式</td><td>切换</td>
<td>
选项 A: 设定结束日期(日期选择)<br>
选项 B: 设定投资次数(输入轮数,如 12 次 = 一年)<br>
<span style="color:var(--text2);font-size:11px;">如选择"无截止日期"(Good Till Cancel),请将结束日期留空</span>
</td>
</tr>
<tr><td>7</td><td>碎股/零股处理</td><td>单选</td><td>向上取整 / 向下取整 / 四舍五入 / 允许碎股</td></tr>
</tbody>
</table>
<div style="color:var(--text2);font-size:12px;padding-top:8px;">确认前实时预览 → 展示预估执行次数、总投资额、费用估算</div>
</div>
<div class="info-card">
<div class="value" style="font-size:15px;">A2 — 查看和管理计划</div>
<ul style="padding-left:20px;color:var(--text2);font-size:13px;line-height:2;">
<li>计划列表,卡片式布局,显示:标的名称/代码、频率、累计投入、当前市值、盈亏%</li>
<li>状��标签:<span class="tag tag-green">进行中</span> <span class="tag tag-amber">已暂停</span> <span class="tag tag-blue">已完成</span> <span class="tag tag-red">已取消</span></li>
<li>计划详情页:参数完整展示 + 投资曲线图(累计投入 vs 市值/盈亏)</li>
<li>执行历史明细表(分页、日期筛选、导出 CSV)</li>
<li>投资进度条(已执行次数 / 总计划次数)</li>
<li style="color:var(--text);"><strong>持仓不足时的 PnL 展示逻辑:</strong>
如果系统内持有的该标的股数 < PRP 累计购入的总股数(即部分股票已被卖出),PnL 按「当前持仓部分 + PRP 交易历史总盈亏」分别列示:
<br>① 当前持仓市值 vs 当前持仓成本 → 持仓 PnL
<br>② PRP 历史累计:总买入金额 vs 总卖出金额 + 剩余持仓市值 → PRP 总回报
</li>
</ul>
</div>
<div class="info-card">
<div class="value" style="font-size:15px;">A3 — 修改计划(进行中)</div>
<table>
<thead><tr><th>可修改字段</th><th>不可修改字段</th></tr></thead>
<tbody>
<tr><td>每次投入金额、频率、频率日、结束方式(日期/次数)、碎股处理方式</td><td>标的代码、开始日期(若需改=取消重建)</td></tr>
</tbody>
</table>
<div style="color:var(--text2);font-size:12px;padding-top:8px;">修改即时生效(下次执行使用新参数),全部修改记录到审计表</div>
</div>
<div class="grid2">
<div class="info-card">
<div class="value" style="font-size:15px;">A4 — 暂停/恢复/取消</div>
<div style="color:var(--text2);font-size:12px;">暂停:计划保留,停止后续执行。恢复:继续按原参数执行。取消:永久终止。</div>
</div>
<div class="info-card">
<div class="value" style="font-size:15px;">A5 — 投资预测</div>
<div style="color:var(--text2);font-size:12px;">输入预估年化回报率 → 输出总投资额、预估终值、预估收益、DCA 成本摊平曲线图</div>
</div>
</div>
<div class="note">
<strong>A5 示例:</strong>投资者设定每月投入 $1,000 买入 NVDA,持续 30 年(360 次),预估年化回报 12%。系统计算:总投资额 = $360,000;按 DCA + 复利计算,预估投资组合终值约 $3,520,000(约为总投入的 <strong>9.8 倍</strong>);累计收益约 $3,160,000。下方的双线图直观展示:即使每笔投入金额不大,透过长期纪律性定投 + 复利效应,30 年后投资组合价值可达总投入的 8-10 倍。系统计算:总投资额 = $36,000;按 10% 复利计算预估终值 ≈ $41,780;预估收益 ≈ $5,780;并展示「累计投入 vs 预估市值」累积曲线图。
</div>
<h3>2.3 员工端功能(B 模块)</h3>
<div class="grid2">
<div class="info-card">
<div class="value" style="font-size:15px;">B1 — 计划监控</div>
<ul style="padding-left:16px;color:var(--text2);font-size:12px;line-height:2;">
<li>全部计划总览(按状态/交易所/投资者筛选)</li>
<li>今日待执行清单</li>
<li>执行结果监控(成功/失败/异常)</li>
<li>异常即时告警</li>
</ul>
</div>
<div class="info-card">
<div class="value" style="font-size:15px;">B2 — 系统配置</div>
<ul style="padding-left:16px;color:var(--text2);font-size:12px;line-height:2;">
<li>市场参数管理</li>
<li>交易时间窗口配置</li>
<li>通知模板编辑</li>
<li>风控规则设置</li>
</ul>
</div>
</div>
<div class="info-card">
<div class="value" style="font-size:15px;">B3 — 报表中心</div>
<div style="color:var(--text2);font-size:12px;">日度执行汇总 · 月度计划统计 · 费用/佣金明细 · 异常/失败清单</div>
</div>
</div>
<div class="section" id="c3">
<h2><span class="num">3</span> 数据模型设计</h2>
<div class="note">
<strong>说明:</strong>投资者与账户管理 (investors / investor_accounts) 由现有系统处理,PRP 模块不重复设计。以下仅列 PRP 特有数据表。
</div>
<h3>3.1 投资计划主表 — plans</h3>
<table>
<thead><tr><th>字段</th><th>类型</th><th>约束</th><th>说明</th></tr></thead>
<tbody>
<tr><td><code>plan_id</code></td><td>VARCHAR(32)</td><td>PK</td><td>如 PRP-20260801-0001</td></tr>
<tr><td><code>client_id</code></td><td>VARCHAR(32)</td><td>NOT NULL</td><td>关联投资者(沿用现有系统 client_id)</td></tr>
<tr><td><code>account_id</code></td><td>VARCHAR(32)</td><td>NOT NULL</td><td>关联交易账户</td></tr>
<tr><td><code>instrument_code</code></td><td>VARCHAR(20)</td><td>NOT NULL</td><td>标的代码(G3SF 标准格式)</td></tr>
<tr><td><code>exchange_id</code></td><td>VARCHAR(10)</td><td>NOT NULL</td><td>交易所代码(沿用现有系统)</td></tr>
<tr><td><code>amount_per_time</code></td><td>DECIMAL(18,4)</td><td>NOT NULL</td><td>每次投入金额</td></tr>
<tr><td><code>frequency</code></td><td>ENUM</td><td>NOT NULL</td><td>DAILY / WEEKLY / MONTHLY</td></tr>
<tr><td><code>frequency_day</code></td><td>TINYINT</td><td></td><td>WEEKLY=1-5(周一到周五), MONTHLY=1-28</td></tr>
<tr><td><code>start_date</code></td><td>DATE</td><td>NOT NULL</td><td>计划开始日期</td></tr>
<tr><td><code>end_date</code></td><td>DATE</td><td>NULL</td><td>NULL=无限期;非空=指定结束日期</td></tr>
<tr><td><code>total_rounds</code></td><td>INT</td><td>NULL</td><td>计划执行总次数(与 end_date 互斥,二选一)</td></tr>
<tr><td><code>fractional_handling</code></td><td>ENUM</td><td>NOT NULL</td><td>ROUND_UP / ROUND_DOWN / NEAREST / ALLOW_FRACTIONAL</td></tr>
<tr><td><code>status</code></td><td>ENUM</td><td>NOT NULL</td><td>ACTIVE / PAUSED / COMPLETED / CANCELLED</td></tr>
<tr><td><code>total_invested</code></td><td>DECIMAL(18,4)</td><td>DEFAULT 0</td><td>累计已投入金额</td></tr>
<tr><td><code>total_units</code></td><td>DECIMAL(18,6)</td><td>DEFAULT 0</td><td>累计已购份额</td></tr>
<tr><td><code>avg_cost</code></td><td>DECIMAL(18,6)</td><td>DEFAULT 0</td><td>平均成本价</td></tr>
<tr><td><code>execution_count</code></td><td>INT</td><td>DEFAULT 0</td><td>已执行次数</td></tr>
<tr><td><code>created_at</code></td><td>DATETIME</td><td>NOT NULL</td><td></td></tr>
<tr><td><code>updated_at</code></td><td>DATETIME</td><td>NOT NULL</td><td></td></tr>
<tr><td><code>created_by</code></td><td>VARCHAR(32)</td><td>NOT NULL</td><td>client_id 或 staff_id</td></tr>
</tbody>
</table>
<div class="note">
<strong>公司行动处理:</strong>若标的发生公司行动产生并行交易代码(如供股产生供股权、拆股产生临时代码等),PRP 计划仅跟踪原 <code>instrument_code</code>,不自动切换至新代码。因公司行动产生的持仓或权益变化由 G3SB 结算系统按常规公司行动流程处理,不影响 PRP 的定投执行。
</div>
<h3>3.2 执行记录表 — plan_executions</h3>
<table>
<thead><tr><th>字段</th><th>类型</th><th>说明</th></tr></thead>
<tbody>
<tr><td><code>execution_id</code></td><td>VARCHAR(32) PK</td><td>如 EXEC-20260801-0001</td></tr>
<tr><td><code>plan_id</code></td><td>VARCHAR(32) FK</td><td>关联计划</td></tr>
<tr><td><code>scheduled_date</code></td><td>DATE</td><td>计划执行日期</td></tr>
<tr><td><code>actual_time</code></td><td>DATETIME</td><td>实际执行时间</td></tr>
<tr><td><code>amount</code></td><td>DECIMAL(18,4)</td><td>本次投入金额</td></tr>
<tr><td><code>execution_price</code></td><td>DECIMAL(18,6)</td><td>实际成交均价</td></tr>
<tr><td><code>quantity_full</code></td><td>INT</td><td>整股数量</td></tr>
<tr><td><code>quantity_fractional</code></td><td>DECIMAL(18,6)</td><td>碎股数量(如有)</td></tr>
<tr><td><code>total_quantity</code></td><td>DECIMAL(18,6)</td><td>总份额</td></tr>
<tr><td><code>commission</code></td><td>DECIMAL(18,4)</td><td>佣金</td></tr>
<tr><td><code>other_fees</code></td><td>DECIMAL(18,4)</td><td>其他费用</td></tr>
<tr><td><code>status</code></td><td>ENUM</td><td>PENDING / EXECUTED / PARTIAL / FAILED / SKIPPED</td></tr>
<tr><td><code>g3sf_order_id</code></td><td>VARCHAR(32)</td><td>G3SF 订单编号(可通过订单 ID 追溯全部关联信息)</td></tr>
<tr><td><code>trade_remark</code></td><td>VARCHAR(100)</td><td>成交备注标记为 PRP 投资计划</td></tr>
<tr><td><code>error_code</code></td><td>VARCHAR(20)</td><td>失败错误码:SHORTFUND / SUSPENDED / PRICE_REJECTED / SYSTEM_ERROR</td></tr>
<tr><td><code>error_msg</code></td><td>TEXT</td><td>失败详情</td></tr>
<tr><td><code>notification_sent</code></td><td>BOOLEAN</td><td>邮件通知是否已发送</td></tr>
</tbody>
</table>
<div class="note">
<strong>停牌处理:</strong>若计划执行日标的股票处于停牌状态,系统将标记执行记录为 REJECTED(error_code=<code>SUSPENDED</code>),发送邮件通知投资者"标的已停牌",该笔执行不会补单。系统在下一个计划执行周期继续按正常流程处理。
</div>
<h3>3.3 修改审计表 — plan_modifications</h3>
<table>
<thead><tr><th>字段</th><th>类型</th><th>说明</th></tr></thead>
<tbody>
<tr><td><code>mod_id</code></td><td>VARCHAR(32) PK</td><td>修改编号</td></tr>
<tr><td><code>plan_id</code></td><td>VARCHAR(32) FK</td><td>关联计划</td></tr>
<tr><td><code>field_changed</code></td><td>VARCHAR(50)</td><td>修改字段名</td></tr>
<tr><td><code>old_value</code></td><td>TEXT</td><td>旧值(JSON)</td></tr>
<tr><td><code>new_value</code></td><td>TEXT</td><td>新值(JSON)</td></tr>
<tr><td><code>modified_by</code></td><td>VARCHAR(32)</td><td>修改人</td></tr>
<tr><td><code>modified_by_role</code></td><td>ENUM</td><td>INVESTOR / STAFF / SYSTEM</td></tr>
<tr><td><code>modified_at</code></td><td>DATETIME</td><td>修改时间</td></tr>
<tr><td><code>reason</code></td><td>VARCHAR(200)</td><td>修改原因</td></tr>
</tbody>
</table>
<h3>3.4 系统配置表 — system_config</h3>
<div class="note amber">
<strong>说明:</strong>系统配置相关表结构及字段细节由开发团队根据具体实现需求自行设计。本表仅供概念参考,不作为强制规范。
</div>
<table>
<thead><tr><th>字段</th><th>类型</th><th>说明</th></tr></thead>
<tbody>
<tr><td><code>config_key</code></td><td>VARCHAR(100) PK</td><td>配置键</td></tr>
<tr><td><code>config_value</code></td><td>TEXT</td><td>配置值(JSON)</td></tr>
<tr><td><code>updated_by</code></td><td>VARCHAR(32)</td><td>更新人</td></tr>
<tr><td><code>updated_at</code></td><td>DATETIME</td><td>更新时间</td></tr>
</tbody>
</table>
</div>
<div class="section" id="c4">
<h2><span class="num">4</span> UI/UX 设计建议</h2>
<h3>4.1 嵌入环境概览</h3>
<table>
<thead><tr><th>宿主产品</th><th>用户</th><th>设备</th><th>分辨率参考</th><th>布局策略</th></tr></thead>
<tbody>
<tr><td>eServices</td><td><span class="tag tag-blue">Investor</span></td><td>Desktop Browser</td><td>1280-1920px</td><td>侧栏 / 全宽卡片式</td></tr>
<tr><td>ProX</td><td><span class="tag tag-green">Staff</span></td><td>Desktop</td><td>1440-2560px</td><td>全宽表格 + 侧栏筛选</td></tr>
<tr><td>OMC</td><td><span class="tag tag-green">Staff</span></td><td>Desktop</td><td>1280-1920px</td><td>全宽控制面板</td></tr>
</tbody>
</table>
<h3>4.2 投资者 Widget — 创建 PRP 计划页面</h3>
<div class="ui-widget">
<div class="widget-header">
<div class="dot active"></div><div class="dot"></div><div class="dot"></div>
<div class="widget-title">eServices — PRP 定期投资</div>
</div>
<div class="widget-body">
<div style="font-size:13px;color:#fff;margin-bottom:12px;font-weight:600;">创建 PRP 定期投资计划</div>
<div style="display:flex;gap:12px;margin-bottom:12px;">
<div style="flex:1;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">Step 1: 选择标的</div>
<div class="mock-field">搜索股票代码... NVDA</div>
</div>
<div style="flex:1;background:var(--surface2);border:1px solid var(--border);border-radius:6px;padding:10px 14px;">
<div style="font-size:10px;color:var(--text3);margin-bottom:2px;">标的资料 (Instrument Master)</div>
<div style="font-size:14px;color:#fff;font-weight:600;">NVIDIA Corp</div>
</div>
</div>
<div style="display:flex;gap:12px;margin-bottom:12px;">
<div style="flex:1;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">每次金额</div>
<div class="mock-field">$ 1,000 USD</div>
</div>
<div style="flex:1;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">频率</div>
<div class="toggle-group">
<button class="toggle-opt">每日</button>
<button class="toggle-opt active">每周</button>
<button class="toggle-opt">每月</button>
</div>
</div>
<div style="flex:1;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">执行日</div>
<div class="mock-field">周三 ▼</div>
<div class="field-hint warn">如遇非交易日,自动顺延至下一个交易日</div>
</div>
</div>
<div style="display:flex;gap:12px;margin-bottom:12px;">
<div style="flex:1;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">开始日期 *</div>
<div class="mock-field required">2026-08-03 (必须 &gt; 今日)</div>
</div>
<div style="flex:1;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">结束日期</div>
<div class="mock-field">2027-08-03</div>
<div style="display:flex;align-items:center;gap:6px;margin-top:6px;">
<input type="checkbox" checked style="accent-color:var(--green);width:14px;height:14px;cursor:pointer;margin:0;" id="gtc-cb">
<label for="gtc-cb" style="font-size:11px;color:var(--text2);cursor:pointer;">Good Till Cancel (勾选后结束日期自动禁用)</label>
</div>
</div>
<div style="flex:1;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">碎股处理</div>
<div class="mock-field">允许碎股 ▼</div>
</div>
</div>
<div style="display:flex;align-items:center;justify-content:space-between;">
<div style="font-size:12px;color:var(--text2);">
预估: <span style="color:#fff;">52次/年</span> · 年投入 <span style="color:#fff;">$52,000</span> · 费用约 <span style="color:#fff;">$26/年</span>
</div>
<button class="mock-btn">确认创建</button>
</div>
</div>
</div>
<table style="font-size:12px;margin-top:8px;">
<thead><tr><th colspan="2" style="text-align:center;background:var(--surface);color:var(--accent);">UI 字段中英对照 (Bilingual Reference) — 创建 PRP 计划</th></tr></thead>
<tbody>
<tr><td>选择标的</td><td>Select Instrument</td></tr>
<tr><td>搜索股票代码...</td><td>Search stock code...</td></tr>
<tr><td>标的资料 (Instrument Master)</td><td>Instrument Master</td></tr>
<tr><td>每次金额</td><td>Amount per Time</td></tr>
<tr><td>频率</td><td>Frequency</td></tr>
<tr><td>每日 / 每周 / 每月</td><td>Daily / Weekly / Monthly</td></tr>
<tr><td>执行日</td><td>Execution Day</td></tr>
<tr><td>如遇非交易日,自动顺延至下一个交易日</td><td>If non-trading day, deferred to next trading day</td></tr>
<tr><td>开始日期 *</td><td>Start Date *</td></tr>
<tr><td>必须 > 今日</td><td>Must be > today</td></tr>
<tr><td>结束日期</td><td>End Date</td></tr>
<tr><td>Good Till Cancel (勾选后结束日期自动禁用)</td><td>Good Till Cancel (Checking disables end date)</td></tr>
<tr><td>碎股处理</td><td>Fractional Share Handling</td></tr>
<tr><td>允许碎股</td><td>Allow Fractional Shares</td></tr>
<tr><td>确认创建</td><td>Confirm Creation</td></tr>
<tr><td>预估</td><td>Estimate</td></tr>
</tbody>
</table>
<h3>4.3 投资者 Widget — 计划列表页</h3>
<div class="ui-widget">
<div class="widget-header">
<div class="dot active"></div><div class="dot"></div><div class="dot"></div>
<div class="widget-title">我的 PRP 投资计划</div>
</div>
<div class="widget-body">
<div class="mock-row" style="color:var(--text2);font-size:11px;border-bottom:2px solid var(--border);">
<div style="flex:2;">标的</div><div style="flex:1;">频率</div><div style="flex:1;">累计投入</div><div style="flex:1;">持仓市值 / 盈亏</div><div style="flex:1;">PRP 总回报</div><div style="flex:0.5;"></div>
</div>
<div class="mock-row" style="cursor:pointer;">
<div style="flex:2;"><span style="color:#fff;font-weight:600;">NVDA</span> <span style="color:var(--text2);font-size:11px;">NVIDIA Corp</span></div>
<div style="flex:1;font-size:12px;">每周三</div>
<div style="flex:1;font-size:12px;">$8,000</div>
<div style="flex:1;"><span style="color:var(--green);">$9,240</span> <span style="color:var(--green);font-size:11px;">+15.5%</span></div>
<div style="flex:1;"><span style="color:var(--green);">+$1,240</span> <span style="color:var(--green);font-size:10px;">(+15.5%)</span></div>
<div style="flex:0.5;"><span class="tag tag-green">进行中</span></div>
</div>
<div class="mock-row" style="cursor:pointer;">
<div style="flex:2;"><span style="color:#fff;font-weight:600;">QQQ</span> <span style="color:var(--text2);font-size:11px;">Invesco QQQ</span></div>
<div style="flex:1;font-size:12px;">每周一</div>
<div style="flex:1;font-size:12px;">$12,500</div>
<div style="flex:1;"><span style="color:var(--green);">$13,800</span> <span style="color:var(--green);font-size:11px;">+10.4%</span></div>
<div style="flex:1;"><span style="color:var(--green);">+$1,300</span> <span style="color:var(--green);font-size:10px;">(+10.4%)</span></div>
<div style="flex:0.5;"><span class="tag tag-green">进行中</span></div>
</div>
<div class="mock-row" style="cursor:pointer;opacity:0.6;">
<div style="flex:2;"><span style="color:#fff;font-weight:600;">0700</span> <span style="color:var(--text2);font-size:11px;">Tencent</span></div>
<div style="flex:1;font-size:12px;">每月 1 号</div>
<div style="flex:1;font-size:12px;">HK$15,000</div>
<div style="flex:1;"><span style="color:var(--red);">HK$13,200</span> <span style="color:var(--red);font-size:11px;">-12.0%</span></div>
<div style="flex:1;">
<div style="font-size:10px;color:var(--text3);">已卖出部分</div>
<span style="color:var(--amber);">HK$-1,800</span> <span style="color:var(--amber);font-size:10px;">(-12%)</span>
</div>
<div style="flex:0.5;"><span class="tag tag-amber">已暂停</span></div>
</div>
</div>
</div>
<table style="font-size:12px;margin-top:8px;">
<thead><tr><th colspan="2" style="text-align:center;background:var(--surface);color:var(--accent);">UI 字段中英对照 (Bilingual Reference) — 计划列表</th></tr></thead>
<tbody>
<tr><td>我的 PRP 投资计划</td><td>My PRP Investment Plans</td></tr>
<tr><td>标的</td><td>Instrument</td></tr>
<tr><td>频率</td><td>Frequency</td></tr>
<tr><td>累计投入</td><td>Total Invested</td></tr>
<tr><td>持仓市值 / 盈亏</td><td>Position Value / P&L</td></tr>
<tr><td>PRP 总回报</td><td>PRP Total Return</td></tr>
<tr><td>每周三 / 每周一 / 每月 1 号</td><td>Every Wednesday / Every Monday / 1st of month</td></tr>
<tr><td>已卖出部分</td><td>Partially Sold</td></tr>
<tr><td>进行中</td><td>Active</td></tr>
<tr><td>已暂停</td><td>Paused</td></tr>
</tbody>
</table>
<h3>4.4 投资者 Widget — 修改 PRP 计划页面</h3>
<div class="ui-widget">
<div class="widget-header">
<div class="dot active"></div><div class="dot"></div><div class="dot"></div>
<div class="widget-title">修改 PRP 计划 — NVDA (NVIDIA Corp)</div>
</div>
<div class="widget-body">
<div style="font-size:12px;color:var(--text2);margin-bottom:16px;">
计划编号: <span style="color:#fff;">PRP-20260801-0001</span> · 创建于: <span style="color:#fff;">2026-07-15</span> · 已执行: <span style="color:#fff;">2次</span>
</div>
<div style="display:flex;gap:12px;margin-bottom:12px;">
<div style="flex:1;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">标的代码(不可修改)</div>
<div class="mock-field" style="opacity:0.5;">NVDA</div>
</div>
<div style="flex:1;background:var(--surface2);border:1px solid var(--border);border-radius:6px;padding:10px 14px;">
<div style="font-size:10px;color:var(--text3);margin-bottom:2px;">标的���料 (Instrument Master)</div>
<div style="font-size:14px;color:#fff;font-weight:600;">NVIDIA Corp</div>
</div>
</div>
<div style="display:flex;gap:12px;margin-bottom:12px;">
<div style="flex:1;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">每次金额</div>
<div class="mock-field">$ 2,000 USD (原: $1,000)</div>
<div class="field-hint">修改后下次执行生效</div>
</div>
<div style="flex:1;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">频率</div>
<div class="toggle-group">
<button class="toggle-opt">每日</button>
<button class="toggle-opt">每周</button>
<button class="toggle-opt active">每月</button>
</div>
</div>
<div style="flex:1;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">碎股处理</div>
<div class="mock-field">向下取整 ▼ (原: 允许碎股)</div>
</div>
</div>
<div style="display:flex;gap:12px;margin-bottom:12px;">
<div style="flex:1;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">修改原因</div>
<div class="mock-field">增加每月投资金额</div>
<div class="field-hint warn">全部修改将记录至审计日志</div>
</div>
</div>
<div style="display:flex;gap:12px;align-items:center;justify-content:space-between;">
<div style="font-size:12px;color:var(--text2);">
修改后预估: <span style="color:#fff;">12次/年</span> · 年投入 <span style="color:#fff;">$24,000</span>
</div>
<div style="display:flex;gap:8px;">
<button class="mock-btn ghost">取消</button>
<button class="mock-btn">确认修改</button>
</div>
</div>
</div>
</div>
<table style="font-size:12px;margin-top:8px;">
<thead><tr><th colspan="2" style="text-align:center;background:var(--surface);color:var(--accent);">UI 字段中英对照 (Bilingual Reference) — 修改 PRP 计划</th></tr></thead>
<tbody>
<tr><td>修改 PRP 计划</td><td>Modify PRP Plan</td></tr>
<tr><td>计划编号</td><td>Plan ID</td></tr>
<tr><td>创建于</td><td>Created</td></tr>
<tr><td>已执行</td><td>Executed</td></tr>
<tr><td>标的代码(不可修改)</td><td>Instrument Code (Non-modifiable)</td></tr>
<tr><td>标的资料 (Instrument Master)</td><td>Instrument Master</td></tr>
<tr><td>每次金额</td><td>Amount per Time</td></tr>
<tr><td>修改后下次执行生效</td><td>Takes effect on next execution</td></tr>
<tr><td>频率</td><td>Frequency</td></tr>
<tr><td>每日 / 每周 / 每月</td><td>Daily / Weekly / Monthly</td></tr>
<tr><td>碎股处理</td><td>Fractional Share Handling</td></tr>
<tr><td>向下取整 / 允许碎股</td><td>Round Down / Allow Fractional</td></tr>
<tr><td>修改原因</td><td>Reason for Modification</td></tr>
<tr><td>全部修改将记录至审计日志</td><td>All modifications recorded in audit log</td></tr>
<tr><td>修改后预估</td><td>Revised Estimate</td></tr>
<tr><td>取消</td><td>Cancel</td></tr>
<tr><td>确认修改</td><td>Confirm Modification</td></tr>
</tbody>
</table>
<h3>4.5 投资者 Widget — A5 投资预测</h3>
<div class="ui-widget">
<div class="widget-header">
<div class="dot active"></div><div class="dot"></div><div class="dot"></div>
<div class="widget-title">投资预测 — PRP 定期投资模拟</div>
</div>
<div class="widget-body">
<div style="display:flex;gap:16px;margin-bottom:16px;flex-wrap:wrap;">
<div style="flex:1;min-width:180px;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">计划参数</div>
<div class="mock-field" style="margin-bottom:2px;">NVDA · 每月 $1,000</div>
<div class="field-hint">30 年 · 360 次执行</div>
</div>
<div style="flex:1;min-width:180px;">
<div style="font-size:11px;color:var(--text3);margin-bottom:4px;">预估年化回报率</div>
<div style="display:flex;align-items:center;gap:8px;">
<div class="mock-field" style="flex:1;">12%</div>
<button class="mock-btn ghost" style="padding:8px 10px;font-size:11px;">更新</button>
</div>
</div>
</div>
<div class="grid3" style="margin-bottom:16px;">
<div class="forecast-box">
<div class="fl">总投资额</div>
<div class="fv" style="color:var(--accent);">$360,000</div>
<div style="font-size:10px;color:var(--text3);">(30年 x $12,000/年)</div>
</div>
<div class="forecast-box">
<div class="fl">预估组合市值</div>
<div class="fv">$3,520,000</div>
<div style="font-size:10px;color:var(--green);">9.8x 总投入</div>
</div>
<div class="forecast-box">
<div class="fl">累计复利收益</div>
<div class="fv" style="color:var(--green);">+$3,160,000</div>
<div style="font-size:10px;color:var(--green);">+878%</div>
</div>
</div>
<div style="background:var(--surface2);border:1px solid var(--border);border-radius:var(--radius);padding:20px 12px 16px;">
<div style="color:var(--text3);font-size:11px;margin-bottom:4px;text-align:center;">Demostration — DCA vs Portfolio Value (30-Year Projection)</div>
<svg viewBox="0 0 660 400" width="100%" style="display:block;">
<defs>
<linearGradient id="shadowAccent" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#5b8def" stop-opacity="0.15"/>
<stop offset="100%" stop-color="#5b8def" stop-opacity="0"/>
</linearGradient>
<linearGradient id="shadowGreen" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#34d399" stop-opacity="0.12"/>
<stop offset="100%" stop-color="#34d399" stop-opacity="0"/>
</linearGradient>
</defs>
<g transform="translate(0, 20)">
<line x1="72" y1="340" x2="648" y2="340" stroke="#2a2d3c" stroke-width="1"/>
<line x1="72" y1="340" x2="72" y2="20" stroke="#2a2d3c" stroke-width="1"/>
<line x1="72" y1="291" x2="648" y2="291" stroke="#1c1f2e" stroke-width="0.5" stroke-dasharray="4 4"/>
<line x1="72" y1="242" x2="648" y2="242" stroke="#1c1f2e" stroke-width="0.5" stroke-dasharray="4 4"/>
<line x1="72" y1="193" x2="648" y2="193" stroke="#1c1f2e" stroke-width="0.5" stroke-dasharray="4 4"/>
<line x1="72" y1="144" x2="648" y2="144" stroke="#1c1f2e" stroke-width="0.5" stroke-dasharray="4 4"/>
<line x1="72" y1="95" x2="648" y2="95" stroke="#1c1f2e" stroke-width="0.5" stroke-dasharray="4 4"/>
<line x1="72" y1="46" x2="648" y2="46" stroke="#1c1f2e" stroke-width="0.5" stroke-dasharray="4 4"/>
<text x="64" y="344" text-anchor="end" font-size="10" fill="#686b7d">$0</text>
<text x="64" y="295" text-anchor="end" font-size="10" fill="#686b7d">$0.5M</text>
<text x="64" y="246" text-anchor="end" font-size="10" fill="#686b7d">$1.0M</text>
<text x="64" y="197" text-anchor="end" font-size="10" fill="#686b7d">$1.5M</text>
<text x="64" y="148" text-anchor="end" font-size="10" fill="#686b7d">$2.0M</text>
<text x="64" y="99" text-anchor="end" font-size="10" fill="#686b7d">$2.5M</text>
<text x="64" y="50" text-anchor="end" font-size="10" fill="#686b7d">$3.0M</text>
<text x="72" y="360" text-anchor="middle" font-size="10" fill="#686b7d">0</text>
<text x="168" y="360" text-anchor="middle" font-size="10" fill="#686b7d">5</text>
<text x="264" y="360" text-anchor="middle" font-size="10" fill="#686b7d">10</text>
<text x="360" y="360" text-anchor="middle" font-size="10" fill="#686b7d">15</text>
<text x="456" y="360" text-anchor="middle" font-size="10" fill="#686b7d">20</text>
<text x="552" y="360" text-anchor="middle" font-size="10" fill="#686b7d">25</text>
<text x="648" y="360" text-anchor="middle" font-size="10" fill="#686b7d">30</text>
<text x="360" y="382" text-anchor="middle" font-size="10" fill="#686b7d">年份</text>
<polyline points="72,340 168,334 264,328 360,322 456,317 552,311 648,305" fill="none" stroke="#5b8def" stroke-width="2.5" stroke-linejoin="round"/>
<polygon points="72,340 168,334 264,328 360,322 456,317 552,311 648,305 648,340 72,340" fill="url(#shadowAccent)"/>
<polyline points="72,340 168,332 264,317 360,291 456,244 552,156 648,0" fill="none" stroke="#34d399" stroke-width="2.5" stroke-linejoin="round"/>
<polygon points="72,340 168,332 264,317 360,291 456,244 552,156 648,0 648,340 72,340" fill="url(#shadowGreen)"/>
<circle cx="648" cy="0" r="4" fill="#34d399"/>
<text x="654" y="4" font-size="10" fill="#34d399" font-weight="600">$3.52M</text>
<circle cx="648" cy="305" r="3" fill="#5b8def"/>
<text x="654" y="309" font-size="10" fill="#5b8def" font-weight="600">$360K</text>
<text x="516" y="120" font-size="10" fill="#34d399" font-weight="600">投资组合市值 (12% CAGR)</text>
<text x="516" y="296" font-size="10" fill="#5b8def" font-weight="600">累计投入 (Cost Basis)</text>
<line x1="500" y1="116" x2="470" y2="135" stroke="#34d399" stroke-width="0.8"/>
<line x1="500" y1="292" x2="470" y2="310" stroke="#5b8def" stroke-width="0.8"/>
</g>
</svg>
<div style="display:flex;justify-content:center;gap:40px;margin-top:4px;font-size:11px;">
<div style="display:flex;align-items:center;gap:6px;">
<div style="width:12px;height:3px;background:#5b8def;border-radius:2px;"></div>
<span style="color:#9094a8;">累计投入 (30年共 $360K)</span>
</div>
<div style="display:flex;align-items:center;gap:6px;">
<div style="width:12px;height:3px;background:#34d399;border-radius:2px;"></div>
<span style="color:#9094a8;">投资组合市值 (终值 $3.52M, 9.8x)</span>
</div>
</div>
</div>
<div class="note amber" style="margin-top:12px;">
<strong>关键洞察:</strong>即使每笔只需 $1,000/月,经过 30 年纪律性定投 + 12% 年化复利,投资组合市值可达总投入的 <strong>9.8 倍</strong>。这正是 DCA 定投的核心价值 — 时间 + 复利 = 财富增长的最大杠杆。
</div>
</div>
</div>
<table style="font-size:12px;margin-top:8px;">
<thead><tr><th colspan="2" style="text-align:center;background:var(--surface);color:var(--accent);">UI 字段中英对照 (Bilingual Reference) — 投资预测</th></tr></thead>
<tbody>
<tr><td>投资预测 — PRP 定期投资模拟</td><td>Investment Forecast — PRP Recurring Investment Simulation</td></tr>
<tr><td>计划参数</td><td>Plan Parameters</td></tr>
<tr><td>预估年化回报率</td><td>Estimated Annualized Return</td></tr>
<tr><td>更新 / 计算</td><td>Update / Calculate</td></tr>
<tr><td>总投资额</td><td>Total Investment</td></tr>
<tr><td>预估组合市值</td><td>Estimated Portfolio Value</td></tr>
<tr><td>累计复利收益</td><td>Cumulative Compound Returns</td></tr>
<tr><td>投资组合市值 (12% CAGR)</td><td>Portfolio Value (12% CAGR)</td></tr>
<tr><td>累计投入 (Cost Basis)</td><td>Total Invested (Cost Basis)</td></tr>
<tr><td>关键洞察</td><td>Key Insight</td></tr>
</tbody>
</table>
<h3>4.6 员工 Widget — 计划监控 (ProX / OMC)</h3>
<div class="ui-widget">
<div class="widget-header">
<div class="dot active"></div><div class="dot"></div><div class="dot"></div>
<div class="widget-title">ProX / OMC — PRP 计划监控面板</div>
</div>
<div class="widget-body">
<div style="display:flex;gap:12px;margin-bottom:16px;flex-wrap:wrap;">
<div class="mock-field" style="max-width:140px;">全部交易所 ▼</div>
<div class="mock-field" style="max-width:140px;">全部状态 ▼</div>
<div class="mock-field" style="max-width:200px;">搜索客户/代码...</div>
<button class="mock-btn">刷新</button>
<button class="mock-btn ghost">导出 CSV</button>
</div>
<div style="font-size:12px;color:var(--text2);margin-bottom:12px;">
活跃计划: <b style="color:#fff;">1,247</b> · 今日待执行: <b style="color:var(--accent);">83</b> · 异常: <b style="color:var(--red);">2</b>
</div>
<table style="margin:0;">
<thead><tr><th>计划编号</th><th>客户ID</th><th>标的</th><th>金额</th><th>频率</th><th>状态</th><th>操作</th></tr></thead>
<tbody>
<tr><td>PRP-0001</td><td>C12034</td><td>NVDA</td><td>$1,000</td><td>每月</td><td><span class="tag tag-green">ACTIVE</span></td><td><button class="mock-btn ghost" style="padding:4px 10px;font-size:11px;">详情</button> <button class="mock-btn ghost" style="padding:4px 10px;font-size:11px;">代客修改</button></td></tr>
<tr style="background:var(--surface2);"><td>PRP-0042</td><td>C08712</td><td>0700</td><td>HK$5,000</td><td>每周</td><td><span class="tag tag-green">ACTIVE</span></td><td><button class="mock-btn ghost" style="padding:4px 10px;font-size:11px;">详情</button> <button class="mock-btn ghost" style="padding:4px 10px;font-size:11px;">代客修改</button></td></tr>
<tr><td>PRP-0103</td><td>C29105</td><td>AAPL</td><td>$500</td><td>每日</td><td><span class="tag tag-amber">PAUSED</span></td><td><button class="mock-btn ghost" style="padding:4px 10px;font-size:11px;">详情</button> <button class="mock-btn ghost" style="padding:4px 10px;font-size:11px;">代客修改</button></td></tr>
</tbody>
</table>
<div class="field-hint" style="margin-top:8px;">支持双击表格行快速进入修改模式,员工可代投资者修改计划参数。修改操作记录审计日志并标记 modified_by_role=STAFF。</div>
</div>
</div>
<table style="font-size:12px;margin-top:8px;">
<thead><tr><th colspan="2" style="text-align:center;background:var(--surface);color:var(--accent);">UI 字段中英对照 (Bilingual Reference) — 员工计划监控</th></tr></thead>
<tbody>
<tr><td>计划监控面板</td><td>Plan Monitoring Dashboard</td></tr>
<tr><td>全部交易所</td><td>All Exchanges</td></tr>
<tr><td>全部状态</td><td>All Statuses</td></tr>
<tr><td>搜索客户/代码...</td><td>Search client/code...</td></tr>
<tr><td>刷新</td><td>Refresh</td></tr>
<tr><td>导出 CSV</td><td>Export CSV</td></tr>
<tr><td>活跃计划</td><td>Active Plans</td></tr>
<tr><td>今日待执行</td><td>Today Pending</td></tr>
<tr><td>异常</td><td>Anomalies</td></tr>
<tr><td>计划编号</td><td>Plan ID</td></tr>
<tr><td>客户ID</td><td>Client ID</td></tr>
<tr><td>标的</td><td>Instrument</td></tr>
<tr><td>金额</td><td>Amount</td></tr>
<tr><td>频率</td><td>Frequency</td></tr>
<tr><td>状态</td><td>Status</td></tr>
<tr><td>操作</td><td>Actions</td></tr>
<tr><td>详情</td><td>Details</td></tr>
<tr><td>代客修改</td><td>Modify on Behalf</td></tr>
<tr><td>支持双击表格行快速进入修改模式...</td><td>Double-click row to enter modification mode...</td></tr>
</tbody>
</table>
<h3>4.7 员工 Widget — B3 报表样本</h3>
<div class="ui-widget">
<div class="widget-header">
<div class="dot active"></div><div class="dot"></div><div class="dot"></div>
<div class="widget-title">OMC — PRP 月度报表 (2026年7月)</div>
</div>
<div class="widget-body">
<div style="display:flex;gap:12px;margin-bottom:16px;flex-wrap:wrap;">
<div class="mock-field" style="max-width:140px;">2026 年 7 月</div>
<div class="mock-field" style="max-width:140px;">全部交易所 ▼</div>
<button class="mock-btn">导出 PDF</button>
<button class="mock-btn ghost">导出 Excel</button>
</div>
<div class="grid3" style="margin-bottom:16px;">
<div class="forecast-box">
<div class="fl">活跃计划数</div>
<div class="fv" style="color:#fff;">1,247</div>
<div style="font-size:10px;color:var(--green);">+38 vs 上月</div>
</div>
<div class="forecast-box">
<div class="fl">月执行次数</div>
<div class="fv" style="color:#fff;">18,962</div>
<div style="font-size:10px;color:var(--green);">成功率 99.2%</div>
</div>
<div class="forecast-box">
<div class="fl">月总投入金额</div>
<div class="fv" style="color:#fff;">US$8.3M</div>
<div style="font-size:10px;color:var(--text2);">折合 HK$64.7M / CNY59.6M</div>
</div>
</div>
<table style="margin:0;">
<thead><tr><th>交易所</th><th>活跃计划</th><th>执行次数</th><th>成功</th><th>失败</th><th>总金额</th><th>平均每笔</th></tr></thead>
<tbody>
<tr><td>US</td><td>852</td><td>13,440</td><td>13,350</td><td style="color:var(--red);">90</td><td>$6.2M</td><td>$464</td></tr>
<tr><td>HK</td><td>298</td><td>4,312</td><td>4,288</td><td style="color:var(--red);">24</td><td>HK$16.4M</td><td>HK$3,820</td></tr>
<tr><td>CN</td><td>97</td><td>1,210</td><td>1,196</td><td style="color:var(--red);">14</td><td>CNY5.8M</td><td>CNY4,849</td></tr>
</tbody>
</table>
<div style="margin-top:12px;font-size:12px;color:var(--text2);">
失败清单 (TOP 3): <span style="color:var(--red);">资金不足 (62)</span> · <span style="color:var(--red);">停牌 (38)</span> · <span style="color:var(--red);">系统超时 (28)</span>
</div>
</div>
</div>
<table style="font-size:12px;margin-top:8px;">
<thead><tr><th colspan="2" style="text-align:center;background:var(--surface);color:var(--accent);">UI 字段中英对照 (Bilingual Reference) — 月度报表</th></tr></thead>
<tbody>
<tr><td>月度报表</td><td>Monthly Report</td></tr>
<tr><td>导出 PDF</td><td>Export PDF</td></tr>
<tr><td>导出 Excel</td><td>Export Excel</td></tr>
<tr><td>活跃计划数</td><td>Active Plans</td></tr>
<tr><td>月执行次数</td><td>Monthly Executions</td></tr>
<tr><td>月总投入金额</td><td>Monthly Total Investment</td></tr>
<tr><td>交易所</td><td>Exchange</td></tr>
<tr><td>成功</td><td>Success</td></tr>
<tr><td>失败</td><td>Failed</td></tr>
<tr><td>总金额</td><td>Total Amount</td></tr>
<tr><td>平均每笔</td><td>Avg per Trade</td></tr>
<tr><td>失败清单 (TOP 3)</td><td>Failure List (TOP 3)</td></tr>
</tbody>
</table>
<h3>4.8 设计风格</h3>
<div class="note">
<strong>说明:</strong>PRP Widget 的视觉风格(配色、字体、间距、组件样式)应与嵌入的宿主产品(eServices / ProX / OMC)保持一致,由开发团队按各产品现有 Design System 实现。本报告中的 Wireframe 仅供布局参考。
</div>
</div>
<div class="section" id="c5">
<h2><span class="num">5</span> 技术架构 & 集成方案</h2>
<h3>5.1 N2N-AFE 系统集成架构</h3>
<div class="arch-layer layer-front">
<h4>展示层 — Embedded Widget</h4>
<p>投资者端 (eServices) + 员工端 (ProX / OMC) — 同一组件,通过 G3SF API 通信。</p>
</div>
<div class="flow-arrow">▼</div>
<div class="arch-layer layer-trade">
<h4>G3SF — 前台交易系统</h4>
<p>
<strong>存储:</strong> 计划数据 (plans)、执行记录 (executions)、审计日志 (modifications)<br>
<strong>调度:</strong> 08:00 HKT(亚洲市场)/ 20:00 HKT(美股市场)定时扫描待执行计划<br>
<strong>订单生成:</strong> 根据计划参数 + 市场规则计算股数、生成订单发送至券商 OMS<br>
<strong>API:</strong> RESTful API 供 Widget 调用
</p>
</div>
<div class="flow-arrow">▼</div>
<div class="arch-layer layer-settle">
<h4>G3SB — 后台结算系统</h4>
<p>
PRP 成交数据基于现有 G3SB 与券商 OMS 之间的数据交换机制处理,无需新增接口。成交回报中标记 <code>trade_remark</code> 为 PRP 投资计划,G3SB 据此更新投资者持仓并将执行结果回写 execution 记录。
</p>
</div>
<div class="flow-arrow">▼</div>
<div class="arch-layer layer-data">
<h4>数据层 — 使用现有数据库</h4>
<p>
PRP 数据表 (plans / plan_executions / plan_modifications) 存放于现有 G3SF 数据库实例中,无需新建独立数据库。通过 <code>g3sf_order_id</code> 与订单系统关联追踪。
</p>
</div>
<h3>5.2 数据流详解</h3>
<div class="flow-step">
<div class="step-num">1</div>
<div class="step-body">
<div class="step-title">投资者创建 PRP 计划 → Widget 调用 G3SF API</div>
<div class="step-desc">POST /api/prp/plans → G3SF 校验参数 → 存入 plans 表 → 返回 plan_id</div>
</div>
</div>
<div class="flow-step">
<div class="step-num">2</div>
<div class="step-body">
<div class="step-title">Scheduler 定时扫描 → 生成执行记录</div>
<div class="step-desc">08:00 / 20:00 HKT → 查询 ACTIVE 计划,判断今天是否为执行日 → INSERT INTO plan_executions (PENDING)</div>
</div>
</div>
<div class="flow-step">
<div class="step-num">3</div>
<div class="step-body">
<div class="step-title">计算股数 → 生成订单 → 发送至券商 OMS</div>
<div class="step-desc">G3SF 根据 fractional_handling 计算 quantity → 创建 G3SF 订单(trade_remark="PRP") → 路由至券商 OMS</div>
</div>
</div>
<div class="flow-step">
<div class="step-num">4</div>
<div class="step-body">
<div class="step-title">OMS 成交 → G3SB 结算 → 更新持仓</div>
<div class="step-desc">基于现有 G3SB-OMS 数据交换 → 结算处理 → 更新投资者持仓 → 回写 execution(EXECUTED, price, fees)</div>
</div>
</div>
<div class="flow-step">
<div class="step-num">5</div>
<div class="step-body">
<div class="step-title">更新计划累计统计 + 发送邮件通知</div>
<div class="step-desc">更新 plans(total_invested / total_units / avg_cost / execution_count) → 发送执行成功邮件给投资者</div>
</div>
</div>
<h3>5.3 错误处理与重试机制</h3>
<div class="info-card">
<div class="value" style="font-size:15px;">5.3.1 资金不足处理 (SHORTFUND)</div>
<ul style="padding-left:20px;color:var(--text2);font-size:13px;line-height:2;">
<li>系统在生成订单前,通过 G3SF 尝试<strong>预留/冻结</strong>购买所需资金(金额 + 预估费用)</li>
<li>若账户可用资金不足 → 执行记录标记为 <span class="tag tag-red">REJECTED</span>(error_code=<code>SHORTFUND</code>)</li>
<li>发送邮件通知客户:<strong>PRP 执行失败 — 账户资金不足</strong>,邮件包含:计划详情、所需金额、账户可用余额</li>
<li>客户需自行手动补购该期份额(系统<strong>不追溯补单</strong>)</li>
<li>系统在<strong>下一执行周期</strong>自动重新触发(按正常计划参数执行,不累积失败期数)</li>
</ul>
</div>
<div class="info-card">
<div class="value" style="font-size:15px;">5.3.2 标的停牌处理 (SUSPENDED)</div>
<ul style="padding-left:20px;color:var(--text2);font-size:13px;line-height:2;">
<li>执行日扫描时,校验标的交易状态</li>
<li>若标的处于停牌状态 → 执行记录标记为 <span class="tag tag-amber">REJECTED</span>(error_code=<code>SUSPENDED</code>)</li>
<li>发送邮件通知客户:<strong>PRP 执行失败 — 标的已停牌</strong></li>
<li>该笔不补单,系统在<strong>下一执行周期</strong>按正常流程重新尝试</li>
</ul>
</div>
<div class="info-card">
<div class="value" style="font-size:15px;">5.3.3 无效订单��格重试 (PRICE_REJECTED)</div>
<ul style="padding-left:20px;color:var(--text2);font-size:13px;line-height:2;">
<li>若订单提交至交易所后因<strong>无效价格</strong>(如超出涨跌停范围、报价单位不符等)被拒绝</li>
<li>系统自动重试,重试次数 <strong>X</strong> 由系统配置(默认 3 次),每次间隔 <strong>Y 秒</strong>(默认 30 秒)</li>
<li>每次重试时重新获取最新市价并调整订单价格</li>
<li>重试 X 次后仍全部失败 → 执行记录标记为 <span class="tag tag-red">FAILED</span>(error_code=<code>PRICE_REJECTED</code>)</li>
<li>发送邮件通知客户:<strong>PRP 执行失败 — 订单价格无效,已重试 X 次</strong></li>
</ul>
</div>
<h4 style="color:#fff;font-size:13px;margin-top:20px;">5.3.4 拒绝邮件清单</h4>
<table>
<thead><tr><th>error_code</th><th>邮件主题</th><th>触发条件</th><th>后续动作</th></tr></thead>
<tbody>
<tr><td><span class="tag tag-red">SHORTFUND</span></td><td>PRP 执行失败 — 账户资金不足</td><td>预扣资金时账户余额不足</td><td>客户手动补购;下周期自动重试</td></tr>
<tr><td><span class="tag tag-amber">SUSPENDED</span></td><td>PRP 执行失败 — 标的已停牌</td><td>执行日标的处于停牌状态</td><td>下周期自动重试</td></tr>
<tr><td><span class="tag tag-purple">PRICE_REJECTED</span></td><td>PRP 执行失败 — 订单价格无效</td><td>交易所拒单,重试 X 次后仍失败</td><td>标记 FAILED,不再重试</td></tr>
<tr><td><span class="tag tag-blue">SYSTEM_ERROR</span></td><td>PRP 执行失败 — 系统异常</td><td>G3SF/G3SB 内部错误或超时</td><td>员工人工介入</td></tr>
</tbody>
</table>
<h4 style="color:#fff;font-size:13px;margin-top:20px;">5.3.5 系统配置参数</h4>
<div class="code-block">
<span class="kw">execution</span>:
<span class="cm"># 价格重试</span>
<span class="var">price_retry_count</span>: <span class="str">3</span> <span class="cm"># 无效价格最大重试次数</span>
<span class="var">price_retry_interval_sec</span>: <span class="str">30</span> <span class="cm"># 每次重试间隔(秒)</span>
<span class="cm"># 资金预扣</span>
<span class="var">prehold_fund_check</span>: <span class="str">true</span> <span class="cm"># 执行前是否预扣资金检查</span>
<span class="var">prehold_buffer_pct</span>: <span class="str">5</span> <span class="cm"># 预扣金额缓冲百分比(覆盖费用波动)</span>
<span class="cm"># 交易状态检查</span>
<span class="var">check_trading_status</span>: <span class="str">true</span> <span class="cm"># 执行前检查标的是否可交易</span>
</div>
<h3>5.4 API 接口规范(建议)</h3>
<table>
<thead><tr><th>方法</th><th>路径</th><th>说明</th><th>调用方</th></tr></thead>
<tbody>
<tr><td><span class="tag tag-green">POST</span></td><td><code>/api/v1/prp/plans</code></td><td>创建 PRP 计划</td><td>Investor Widget</td></tr>
<tr><td><span class="tag tag-blue">GET</span></td><td><code>/api/v1/prp/plans?client_id=...</code></td><td>查询客户计划列表</td><td>Investor Widget</td></tr>
<tr><td><span class="tag tag-blue">GET</span></td><td><code>/api/v1/prp/plans/{plan_id}</code></td><td>计划详情</td><td>Investor & Staff Widget</td></tr>
<tr><td><span class="tag tag-amber">PUT</span></td><td><code>/api/v1/prp/plans/{plan_id}</code></td><td>修改计划</td><td>Investor Widget</td></tr>
<tr><td><span class="tag tag-amber">PATCH</span></td><td><code>/api/v1/prp/plans/{plan_id}/status</code></td><td>暂停/恢复/取消</td><td>Investor & Staff Widget</td></tr>
<tr><td><span class="tag tag-blue">GET</span></td><td><code>/api/v1/prp/plans/{plan_id}/executions</code></td><td>执行历史</td><td>Investor Widget</td></tr>
<tr><td><span class="tag tag-blue">GET</span></td><td><code>/api/v1/prp/staff/executions/today</code></td><td>今日执行清单</td><td>Staff Widget</td></tr>
<tr><td><span class="tag tag-blue">GET</span></td><td><code>/api/v1/prp/staff/plans?status=...&exchange=...</code></td><td>员工计划总览</td><td>Staff Widget</td></tr>
<tr><td><span class="tag tag-blue">GET</span></td><td><code>/api/v1/prp/staff/reports/monthly</code></td><td>月度报表</td><td>Staff Widget</td></tr>
</tbody>
</table>
</div>
<footer>
N2N-AFE — PRP (Periodic Recurring Program) System Design v1.3<br>
Prepared by Jagon Li · 2026-08-03 · Internal Document
</footer>
</div>
</body>
</html>