1373 lines
69 KiB
HTML
1373 lines
69 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>NAC AI 资产估值顾问 v2.0 | NewAssetChain</title>
|
||
<meta name="description" content="NAC NewAssetChain RWA专用公链AI估值顾问 — 20大类资产 × 60+司法辖区,专业估值,XTZH三重价值输出">
|
||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>💎</text></svg>">
|
||
<style>
|
||
:root {
|
||
--bg-primary: #0a0e1a;
|
||
--bg-secondary: #0f1628;
|
||
--bg-card: #141c2e;
|
||
--bg-input: #1a2340;
|
||
--accent-gold: #d4a843;
|
||
--accent-gold-light: #f0c060;
|
||
--accent-blue: #3b82f6;
|
||
--accent-cyan: #00bcd4;
|
||
--accent-green: #10b981;
|
||
--accent-purple: #8b5cf6;
|
||
--text-primary: #e8eaf0;
|
||
--text-secondary: #8892a4;
|
||
--text-muted: #4a5568;
|
||
--border: #1e2d4a;
|
||
--border-active: #3b82f6;
|
||
--shadow: 0 4px 24px rgba(0,0,0,0.4);
|
||
--radius: 12px;
|
||
}
|
||
* { margin:0; padding:0; box-sizing:border-box; }
|
||
body {
|
||
font-family: 'PingFang SC', 'Microsoft YaHei', -apple-system, sans-serif;
|
||
background: var(--bg-primary);
|
||
color: var(--text-primary);
|
||
height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* ===== HEADER ===== */
|
||
.header {
|
||
background: var(--bg-secondary);
|
||
border-bottom: 1px solid var(--border);
|
||
padding: 0 20px;
|
||
height: 56px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
flex-shrink: 0;
|
||
}
|
||
.header-left { display:flex; align-items:center; gap:12px; }
|
||
.logo {
|
||
width: 34px; height: 34px;
|
||
background: linear-gradient(135deg, #1e88e5, #00bcd4);
|
||
border-radius: 8px;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 13px; font-weight: 900; color: white; letter-spacing: -1px;
|
||
}
|
||
.header-title { font-size: 15px; font-weight: 700; color: var(--text-primary); }
|
||
.header-subtitle { font-size: 10px; color: var(--text-secondary); margin-top: 1px; }
|
||
.version-badge {
|
||
background: rgba(0,188,212,0.12);
|
||
color: var(--accent-cyan);
|
||
border: 1px solid rgba(0,188,212,0.25);
|
||
padding: 2px 8px; border-radius: 10px; font-size: 10px; font-weight: 600;
|
||
}
|
||
.header-right { display:flex; align-items:center; gap:10px; }
|
||
.xtzh-price-badge {
|
||
background: rgba(212,168,67,0.08);
|
||
border: 1px solid rgba(212,168,67,0.25);
|
||
border-radius: 18px;
|
||
padding: 5px 12px;
|
||
display: flex; align-items: center; gap: 7px;
|
||
cursor: pointer; transition: background 0.2s;
|
||
}
|
||
.xtzh-price-badge:hover { background: rgba(212,168,67,0.15); }
|
||
.xtzh-price-badge .label { font-size: 10px; color: var(--text-secondary); }
|
||
.xtzh-price-badge .price { font-size: 13px; font-weight: 700; color: var(--accent-gold); }
|
||
.price-dot { width:6px; height:6px; border-radius:50%; background:var(--accent-green); animation: pulse 2s infinite; }
|
||
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
|
||
.lang-select {
|
||
background: var(--bg-card); border: 1px solid var(--border);
|
||
color: var(--text-primary); border-radius: 7px;
|
||
padding: 4px 8px; font-size: 11px; cursor: pointer; outline: none;
|
||
}
|
||
|
||
/* ===== MAIN LAYOUT ===== */
|
||
.main { display: flex; flex: 1; overflow: hidden; }
|
||
|
||
/* ===== SIDEBAR ===== */
|
||
.sidebar {
|
||
width: 240px;
|
||
background: var(--bg-secondary);
|
||
border-right: 1px solid var(--border);
|
||
display: flex; flex-direction: column;
|
||
overflow: hidden; flex-shrink: 0;
|
||
}
|
||
.sidebar-header {
|
||
padding: 12px;
|
||
border-bottom: 1px solid var(--border);
|
||
display: flex; align-items: center; gap: 8px;
|
||
}
|
||
.new-chat-btn {
|
||
flex: 1;
|
||
background: linear-gradient(135deg, #1e88e5, #00bcd4);
|
||
color: white; border: none; border-radius: 7px;
|
||
padding: 8px 12px; font-size: 12px; font-weight: 700;
|
||
cursor: pointer; transition: opacity 0.2s;
|
||
}
|
||
.new-chat-btn:hover { opacity: 0.85; }
|
||
.clear-btn {
|
||
background: var(--bg-card); border: 1px solid var(--border);
|
||
color: var(--text-secondary); border-radius: 7px;
|
||
padding: 8px 10px; font-size: 12px; cursor: pointer; transition: all 0.2s;
|
||
}
|
||
.clear-btn:hover { border-color: var(--accent-blue); color: var(--accent-blue); }
|
||
|
||
.sidebar-section { padding: 10px 12px 8px; }
|
||
.sidebar-section-title {
|
||
font-size: 10px; color: var(--text-muted);
|
||
text-transform: uppercase; letter-spacing: 1px; margin-bottom: 7px;
|
||
}
|
||
|
||
/* 辖区下拉 */
|
||
.juris-select {
|
||
width: 100%; background: var(--bg-card); border: 1px solid var(--border);
|
||
color: var(--text-primary); border-radius: 7px;
|
||
padding: 7px 10px; font-size: 12px; cursor: pointer; outline: none;
|
||
appearance: none;
|
||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'%3E%3Cpath fill='%238892a4' d='M5 7L0 2h10z'/%3E%3C/svg%3E");
|
||
background-repeat: no-repeat; background-position: right 8px center; padding-right: 24px;
|
||
transition: border-color 0.2s;
|
||
}
|
||
.juris-select:focus { border-color: var(--accent-cyan); }
|
||
.juris-select option { background: #141c2e; }
|
||
|
||
/* 20大类资产 */
|
||
.asset-cat-select {
|
||
width: 100%; background: var(--bg-card); border: 1px solid var(--border);
|
||
color: var(--text-primary); border-radius: 7px;
|
||
padding: 7px 10px; font-size: 12px; cursor: pointer; outline: none;
|
||
appearance: none;
|
||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'%3E%3Cpath fill='%238892a4' d='M5 7L0 2h10z'/%3E%3C/svg%3E");
|
||
background-repeat: no-repeat; background-position: right 8px center; padding-right: 24px;
|
||
transition: border-color 0.2s; margin-bottom: 6px;
|
||
}
|
||
.asset-cat-select:focus { border-color: var(--accent-blue); }
|
||
.asset-cat-select option { background: #141c2e; }
|
||
|
||
/* 子类标签 */
|
||
.subcat-grid { display: flex; flex-wrap: wrap; gap: 4px; max-height: 120px; overflow-y: auto; }
|
||
.subcat-tag {
|
||
background: var(--bg-card); border: 1px solid var(--border);
|
||
color: var(--text-secondary); border-radius: 5px;
|
||
padding: 3px 7px; font-size: 10px; cursor: pointer; transition: all 0.2s;
|
||
}
|
||
.subcat-tag:hover { border-color: var(--accent-blue); color: var(--accent-blue); }
|
||
.subcat-tag.active { background: rgba(59,130,246,0.12); border-color: var(--accent-blue); color: var(--accent-blue); }
|
||
|
||
/* 历史对话 */
|
||
.history-list { flex: 1; overflow-y: auto; padding: 6px; }
|
||
.history-item {
|
||
padding: 7px 9px; border-radius: 7px; cursor: pointer;
|
||
font-size: 11px; color: var(--text-secondary);
|
||
transition: all 0.2s; white-space: nowrap;
|
||
overflow: hidden; text-overflow: ellipsis; margin-bottom: 2px;
|
||
}
|
||
.history-item:hover { background: var(--bg-card); color: var(--text-primary); }
|
||
.history-item.active { background: rgba(212,168,67,0.08); color: var(--accent-gold); }
|
||
|
||
/* ===== CHAT AREA ===== */
|
||
.chat-area { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
|
||
|
||
/* 顶部数据面板 */
|
||
.data-panel {
|
||
background: linear-gradient(135deg, rgba(30,136,229,0.06), rgba(0,188,212,0.04));
|
||
border-bottom: 1px solid rgba(30,136,229,0.15);
|
||
padding: 8px 20px;
|
||
display: flex; align-items: center; gap: 20px;
|
||
flex-shrink: 0; overflow-x: auto;
|
||
}
|
||
.dp-stat { display: flex; flex-direction: column; flex-shrink: 0; }
|
||
.dp-label { font-size: 9px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
|
||
.dp-value { font-size: 13px; font-weight: 700; color: var(--accent-gold); }
|
||
.dp-value.cyan { color: var(--accent-cyan); }
|
||
.dp-value.green { color: var(--accent-green); }
|
||
.dp-value.blue { color: var(--accent-blue); }
|
||
.dp-sub { font-size: 9px; color: var(--text-muted); }
|
||
.dp-divider { width: 1px; height: 28px; background: var(--border); flex-shrink: 0; }
|
||
|
||
/* 消息列表 */
|
||
.messages {
|
||
flex: 1; overflow-y: auto; padding: 16px 20px;
|
||
display: flex; flex-direction: column; gap: 14px;
|
||
}
|
||
.messages::-webkit-scrollbar { width: 4px; }
|
||
.messages::-webkit-scrollbar-track { background: transparent; }
|
||
.messages::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
|
||
|
||
/* 欢迎界面 */
|
||
.welcome {
|
||
display: flex; flex-direction: column; align-items: center;
|
||
justify-content: flex-start; flex: 1; padding: 24px 20px; text-align: center;
|
||
overflow-y: auto;
|
||
}
|
||
.welcome-icon {
|
||
width: 64px; height: 64px;
|
||
background: linear-gradient(135deg, #1e88e5, #00bcd4);
|
||
border-radius: 18px;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 30px; margin-bottom: 14px;
|
||
box-shadow: 0 8px 28px rgba(30,136,229,0.3);
|
||
}
|
||
.welcome h1 { font-size: 20px; font-weight: 800; margin-bottom: 6px; background: linear-gradient(135deg, #1e88e5, #00bcd4); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; }
|
||
.welcome-desc { font-size: 13px; color: var(--text-secondary); max-width: 520px; line-height: 1.6; margin-bottom: 6px; }
|
||
.welcome-stats { display: flex; gap: 24px; margin: 10px 0 16px; }
|
||
.ws-item { text-align: center; }
|
||
.ws-num { font-size: 20px; font-weight: 800; color: var(--accent-cyan); }
|
||
.ws-label { font-size: 10px; color: var(--text-muted); margin-top: 1px; }
|
||
|
||
/* 快捷卡片 */
|
||
.quick-cards {
|
||
display: grid; grid-template-columns: repeat(3, 1fr);
|
||
gap: 8px; max-width: 720px; width: 100%;
|
||
}
|
||
.quick-card {
|
||
background: var(--bg-card); border: 1px solid var(--border);
|
||
border-radius: var(--radius); padding: 12px 14px;
|
||
cursor: pointer; transition: all 0.2s; text-align: left;
|
||
}
|
||
.quick-card:hover {
|
||
border-color: var(--accent-cyan);
|
||
background: rgba(0,188,212,0.05);
|
||
transform: translateY(-1px); box-shadow: var(--shadow);
|
||
}
|
||
.quick-card .card-icon { font-size: 18px; margin-bottom: 5px; }
|
||
.quick-card .card-title { font-size: 12px; font-weight: 600; color: var(--text-primary); }
|
||
.quick-card .card-desc { font-size: 10px; color: var(--text-secondary); margin-top: 3px; line-height: 1.4; }
|
||
|
||
/* 消息气泡 */
|
||
.message { display: flex; gap: 10px; max-width: 100%; }
|
||
.message.user { flex-direction: row-reverse; }
|
||
.message-avatar {
|
||
width: 30px; height: 30px; border-radius: 7px;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 13px; flex-shrink: 0;
|
||
}
|
||
.message.user .message-avatar { background: linear-gradient(135deg, var(--accent-blue), #1d4ed8); }
|
||
.message.ai .message-avatar { background: linear-gradient(135deg, #1e88e5, #00bcd4); color: white; font-weight: 900; font-size: 11px; }
|
||
.message-content {
|
||
max-width: 78%; background: var(--bg-card); border: 1px solid var(--border);
|
||
border-radius: var(--radius); padding: 11px 14px;
|
||
font-size: 13px; line-height: 1.7;
|
||
}
|
||
.message.user .message-content { background: rgba(59,130,246,0.1); border-color: rgba(59,130,246,0.22); }
|
||
.message-content pre { background: rgba(0,0,0,0.3); border: 1px solid var(--border); border-radius: 7px; padding: 10px; overflow-x: auto; font-size: 11px; margin: 7px 0; }
|
||
.message-content table { border-collapse: collapse; width: 100%; margin: 7px 0; font-size: 12px; }
|
||
.message-content th, .message-content td { border: 1px solid var(--border); padding: 5px 9px; text-align: left; }
|
||
.message-content th { background: rgba(30,136,229,0.1); color: var(--accent-cyan); font-size: 11px; }
|
||
.message-content tr:nth-child(even) td { background: rgba(255,255,255,0.02); }
|
||
.message-content blockquote { border-left: 3px solid var(--accent-cyan); padding-left: 10px; color: var(--text-secondary); margin: 7px 0; }
|
||
.message-content h1 { font-size: 15px; color: var(--accent-cyan); margin: 12px 0 6px; border-bottom: 1px solid var(--border); padding-bottom: 4px; }
|
||
.message-content h2 { font-size: 13px; color: var(--accent-cyan); margin: 10px 0 5px; }
|
||
.message-content h3 { font-size: 12px; color: var(--accent-gold-light); margin: 8px 0 4px; }
|
||
.message-content hr { border: none; border-top: 1px solid var(--border); margin: 10px 0; }
|
||
|
||
/* 打字动画 */
|
||
.typing-indicator { display: flex; gap: 4px; align-items: center; padding: 3px 0; }
|
||
.typing-dot { width: 5px; height: 5px; background: var(--accent-cyan); border-radius: 50%; animation: typing 1.2s infinite; }
|
||
.typing-dot:nth-child(2) { animation-delay: 0.2s; }
|
||
.typing-dot:nth-child(3) { animation-delay: 0.4s; }
|
||
@keyframes typing { 0%,60%,100%{transform:translateY(0);opacity:0.4} 30%{transform:translateY(-5px);opacity:1} }
|
||
.stream-cursor { display: inline-block; width: 2px; height: 14px; background: var(--accent-cyan); animation: blink 0.7s infinite; vertical-align: middle; margin-left: 2px; }
|
||
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0} }
|
||
|
||
/* 估值结果卡片 */
|
||
.valuation-card {
|
||
background: linear-gradient(135deg, rgba(30,136,229,0.08), rgba(0,188,212,0.04));
|
||
border: 1px solid rgba(0,188,212,0.25);
|
||
border-radius: var(--radius); padding: 14px; margin-top: 10px;
|
||
}
|
||
.vc-header { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
|
||
.vc-title { font-size: 13px; font-weight: 700; color: var(--accent-cyan); }
|
||
.vc-badge {
|
||
background: rgba(212,168,67,0.12); color: var(--accent-gold);
|
||
border: 1px solid rgba(212,168,67,0.25);
|
||
padding: 2px 8px; border-radius: 10px; font-size: 10px;
|
||
}
|
||
/* 三重价值网格 */
|
||
.triple-value { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 10px; }
|
||
.tv-item { background: rgba(0,0,0,0.2); border-radius: 8px; padding: 9px 10px; text-align: center; }
|
||
.tv-label { font-size: 9px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 3px; }
|
||
.tv-value { font-size: 15px; font-weight: 800; }
|
||
.tv-value.gold { color: var(--accent-gold); }
|
||
.tv-value.cyan { color: var(--accent-cyan); }
|
||
.tv-value.green { color: var(--accent-green); }
|
||
.tv-sub { font-size: 9px; color: var(--text-muted); margin-top: 2px; }
|
||
/* 质押行 */
|
||
.pledge-row {
|
||
background: rgba(212,168,67,0.06); border: 1px solid rgba(212,168,67,0.18);
|
||
border-radius: 7px; padding: 8px 12px;
|
||
display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;
|
||
}
|
||
.pledge-label { font-size: 11px; color: var(--text-secondary); }
|
||
.pledge-value { font-size: 13px; font-weight: 700; color: var(--accent-gold); }
|
||
/* 置信度条 */
|
||
.confidence-bar { height: 3px; background: var(--border); border-radius: 2px; margin-bottom: 10px; overflow: hidden; }
|
||
.confidence-fill { height: 100%; background: linear-gradient(90deg, var(--accent-blue), var(--accent-cyan)); border-radius: 2px; transition: width 0.8s ease; }
|
||
/* 操作按钮 */
|
||
.chain-actions { display: flex; gap: 7px; flex-wrap: wrap; }
|
||
.chain-btn {
|
||
flex: 1; min-width: 80px; padding: 8px 10px; border-radius: 7px;
|
||
font-size: 11px; font-weight: 600; cursor: pointer; transition: all 0.2s; border: none;
|
||
}
|
||
.chain-btn.primary { background: linear-gradient(135deg, #1e88e5, #00bcd4); color: white; }
|
||
.chain-btn.primary:hover { opacity: 0.85; }
|
||
.chain-btn.secondary { background: transparent; border: 1px solid var(--border); color: var(--text-secondary); }
|
||
.chain-btn.secondary:hover { border-color: var(--accent-cyan); color: var(--accent-cyan); }
|
||
|
||
/* 输入区域 */
|
||
.input-area { padding: 12px 16px; border-top: 1px solid var(--border); background: var(--bg-secondary); }
|
||
.context-bar { display: flex; gap: 6px; margin-bottom: 8px; flex-wrap: wrap; align-items: center; }
|
||
.ctx-chip {
|
||
display: flex; align-items: center; gap: 4px;
|
||
background: var(--bg-card); border: 1px solid var(--border);
|
||
padding: 3px 8px; border-radius: 12px; font-size: 10px; color: var(--text-secondary);
|
||
}
|
||
.ctx-chip.active { border-color: var(--accent-cyan); color: var(--accent-cyan); background: rgba(0,188,212,0.07); }
|
||
.input-wrapper { display: flex; gap: 8px; align-items: flex-end; }
|
||
.chat-input {
|
||
flex: 1; background: var(--bg-card); border: 1px solid var(--border);
|
||
border-radius: var(--radius); padding: 10px 14px;
|
||
color: var(--text-primary); font-size: 13px; resize: none; outline: none;
|
||
min-height: 44px; max-height: 140px; transition: border-color 0.2s;
|
||
font-family: inherit; line-height: 1.5;
|
||
}
|
||
.chat-input:focus { border-color: var(--accent-cyan); }
|
||
.chat-input::placeholder { color: var(--text-muted); }
|
||
.send-btn {
|
||
width: 44px; height: 44px;
|
||
background: linear-gradient(135deg, #1e88e5, #00bcd4);
|
||
border: none; border-radius: 9px; color: white;
|
||
cursor: pointer; transition: opacity 0.2s;
|
||
display: flex; align-items: center; justify-content: center; flex-shrink: 0;
|
||
}
|
||
.send-btn:hover { opacity: 0.85; }
|
||
.send-btn:disabled { opacity: 0.4; cursor: not-allowed; }
|
||
.send-btn svg { width: 18px; height: 18px; fill: white; }
|
||
.toolbar { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; align-items: center; }
|
||
.tool-chip {
|
||
background: var(--bg-card); border: 1px solid var(--border);
|
||
color: var(--text-secondary); border-radius: 12px;
|
||
padding: 3px 10px; font-size: 11px; cursor: pointer; transition: all 0.2s;
|
||
}
|
||
.tool-chip:hover { border-color: var(--accent-blue); color: var(--accent-blue); }
|
||
.tool-chip.active { background: rgba(59,130,246,0.1); border-color: var(--accent-blue); color: var(--accent-blue); }
|
||
.toolbar-hint { margin-left: auto; font-size: 10px; color: var(--text-muted); }
|
||
|
||
/* 滚动条 */
|
||
::-webkit-scrollbar { width: 4px; height: 4px; }
|
||
::-webkit-scrollbar-track { background: transparent; }
|
||
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
|
||
|
||
/* 响应式 */
|
||
@media (max-width: 900px) { .sidebar { display: none; } }
|
||
@media (max-width: 600px) { .quick-cards { grid-template-columns: repeat(2, 1fr); } .data-panel { display: none; } }
|
||
@media (max-width: 400px) { .quick-cards { grid-template-columns: 1fr; } }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- HEADER -->
|
||
<div class="header">
|
||
<div class="header-left">
|
||
<div class="logo">NAC</div>
|
||
<div>
|
||
<div class="header-title" data-i18n="title">NAC AI 资产估值顾问</div>
|
||
<div class="header-subtitle" data-i18n="subtitle">20大类资产 · 60+辖区 · SDR锚定 · 三重价值</div>
|
||
</div>
|
||
<span class="version-badge">v2.0</span>
|
||
</div>
|
||
<div class="header-right">
|
||
<div class="xtzh-price-badge" onclick="refreshXTZHPrice()" title="点击刷新XTZH实时价格">
|
||
<div class="price-dot"></div>
|
||
<div>
|
||
<div class="label">XTZH/USD</div>
|
||
<div class="price" id="header-xtzh-price">加载中...</div>
|
||
</div>
|
||
</div>
|
||
<select class="lang-select" id="langSelect" onchange="switchLanguage(this.value)">
|
||
<option value="zh">🇨🇳 中文</option>
|
||
<option value="en">🇺🇸 English</option>
|
||
<option value="ar">🇸🇦 العربية</option>
|
||
<option value="ja">🇯🇵 日本語</option>
|
||
<option value="ko">🇰🇷 한국어</option>
|
||
<option value="fr">🇫🇷 Français</option>
|
||
<option value="de">🇩🇪 Deutsch</option>
|
||
<option value="ru">🇷🇺 Русский</option>
|
||
<option value="es">🇪🇸 Español</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MAIN -->
|
||
<div class="main">
|
||
|
||
<!-- SIDEBAR -->
|
||
<div class="sidebar">
|
||
<div class="sidebar-header">
|
||
<button class="new-chat-btn" onclick="newChat()" data-i18n="newChat">+ 新建估值</button>
|
||
<button class="clear-btn" onclick="clearMemory()" title="清除对话记忆">🗑</button>
|
||
</div>
|
||
|
||
<!-- 司法辖区选择 -->
|
||
<div class="sidebar-section">
|
||
<div class="sidebar-section-title" data-i18n="jurisdiction">司法辖区</div>
|
||
<select class="juris-select" id="jurisdictionSelect" onchange="setJurisdiction(this.value)">
|
||
<optgroup label="🌏 东亚 / East Asia">
|
||
<option value="HK">🇭🇰 香港 Hong Kong</option>
|
||
<option value="CN">🇨🇳 中国大陆 China Mainland</option>
|
||
<option value="TW">🇹🇼 台湾 Taiwan</option>
|
||
<option value="JP">🇯🇵 日本 Japan</option>
|
||
<option value="KR">🇰🇷 韩国 South Korea</option>
|
||
<option value="MO">🇲🇴 澳门 Macau</option>
|
||
</optgroup>
|
||
<optgroup label="🌏 东南亚 / Southeast Asia">
|
||
<option value="SG">🇸🇬 新加坡 Singapore</option>
|
||
<option value="MY">🇲🇾 马来西亚 Malaysia</option>
|
||
<option value="TH">🇹🇭 泰国 Thailand</option>
|
||
<option value="ID">🇮🇩 印尼 Indonesia</option>
|
||
<option value="PH">🇵🇭 菲律宾 Philippines</option>
|
||
<option value="VN">🇻🇳 越南 Vietnam</option>
|
||
</optgroup>
|
||
<optgroup label="🌍 中东 / Middle East">
|
||
<option value="AE">🇦🇪 阿联酋 UAE</option>
|
||
<option value="SA">🇸🇦 沙特 Saudi Arabia</option>
|
||
<option value="QA">🇶🇦 卡塔尔 Qatar</option>
|
||
<option value="KW">🇰🇼 科威特 Kuwait</option>
|
||
<option value="BH">🇧🇭 巴林 Bahrain</option>
|
||
<option value="IL">🇮🇱 以色列 Israel</option>
|
||
</optgroup>
|
||
<optgroup label="🌍 欧洲 / Europe">
|
||
<option value="GB">🇬🇧 英国 UK</option>
|
||
<option value="DE">🇩🇪 德国 Germany</option>
|
||
<option value="FR">🇫🇷 法国 France</option>
|
||
<option value="CH">🇨🇭 瑞士 Switzerland</option>
|
||
<option value="NL">🇳🇱 荷兰 Netherlands</option>
|
||
<option value="IT">🇮🇹 意大利 Italy</option>
|
||
<option value="ES">🇪🇸 西班牙 Spain</option>
|
||
<option value="EU">🇪🇺 欧盟 EU</option>
|
||
</optgroup>
|
||
<optgroup label="🌎 美洲 / Americas">
|
||
<option value="US">🇺🇸 美国 USA</option>
|
||
<option value="CA">🇨🇦 加拿大 Canada</option>
|
||
<option value="BR">🇧🇷 巴西 Brazil</option>
|
||
<option value="MX">🇲🇽 墨西哥 Mexico</option>
|
||
<option value="CL">🇨🇱 智利 Chile</option>
|
||
<option value="AR">🇦🇷 阿根廷 Argentina</option>
|
||
</optgroup>
|
||
<optgroup label="🌏 大洋洲 / Oceania">
|
||
<option value="AU">🇦🇺 澳大利亚 Australia</option>
|
||
<option value="NZ">🇳🇿 新西兰 New Zealand</option>
|
||
</optgroup>
|
||
<optgroup label="🌍 南亚 / South Asia">
|
||
<option value="IN">🇮🇳 印度 India</option>
|
||
</optgroup>
|
||
<optgroup label="🌍 非洲 / Africa">
|
||
<option value="ZA">🇿🇦 南非 South Africa</option>
|
||
<option value="NG">🇳🇬 尼日利亚 Nigeria</option>
|
||
<option value="EG">🇪🇬 埃及 Egypt</option>
|
||
<option value="KE">🇰🇪 肯尼亚 Kenya</option>
|
||
</optgroup>
|
||
<optgroup label="🌍 其他 / Others">
|
||
<option value="RU">🇷🇺 俄罗斯 Russia</option>
|
||
<option value="TR">🇹🇷 土耳其 Turkey</option>
|
||
</optgroup>
|
||
</select>
|
||
</div>
|
||
|
||
<!-- 20大类资产选择 -->
|
||
<div class="sidebar-section">
|
||
<div class="sidebar-section-title" data-i18n="assetType">资产类别(GNACS)</div>
|
||
<select class="asset-cat-select" id="assetCatSelect" onchange="setAssetCategory(this.value)">
|
||
<option value="real_estate">🏢 GNACS-01 不动产类</option>
|
||
<option value="financial_securities">💹 GNACS-02 金融证券类</option>
|
||
<option value="commodities">🏭 GNACS-03 大宗商品类</option>
|
||
<option value="art_collectibles">🎨 GNACS-04 艺术品与收藏品类</option>
|
||
<option value="intellectual_property">💡 GNACS-05 知识产权类</option>
|
||
<option value="digital_assets">🔗 GNACS-06 数字资产类</option>
|
||
<option value="infrastructure">🏗️ GNACS-07 基础设施类</option>
|
||
<option value="natural_resources">🌿 GNACS-08 自然资源类</option>
|
||
<option value="environmental_rights">🌱 GNACS-09 环境权益类</option>
|
||
<option value="corporate_equity">📊 GNACS-10 企业权益类</option>
|
||
<option value="debt_assets">📋 GNACS-11 债权类</option>
|
||
<option value="insurance_products">🛡️ GNACS-12 保险产品类</option>
|
||
<option value="agricultural_assets">🌾 GNACS-13 农业资产类</option>
|
||
<option value="vehicles">🚗 GNACS-14 交通工具类</option>
|
||
<option value="machinery_equipment">⚙️ GNACS-15 机械设备类</option>
|
||
<option value="data_assets">💾 GNACS-16 数据资产类</option>
|
||
<option value="brand_assets">🏷️ GNACS-17 品牌资产类</option>
|
||
<option value="sports_assets">⚽ GNACS-18 体育资产类</option>
|
||
<option value="entertainment_assets">🎬 GNACS-19 娱乐资产类</option>
|
||
<option value="other_assets">📦 GNACS-20 其他资产类</option>
|
||
</select>
|
||
<!-- 子类标签 -->
|
||
<div class="subcat-grid" id="subcatGrid"></div>
|
||
</div>
|
||
|
||
<!-- 历史对话 -->
|
||
<div class="sidebar-section">
|
||
<div class="sidebar-section-title" data-i18n="history">历史估值</div>
|
||
</div>
|
||
<div class="history-list" id="historyList"></div>
|
||
</div>
|
||
|
||
<!-- CHAT AREA -->
|
||
<div class="chat-area">
|
||
|
||
<!-- 顶部数据面板 -->
|
||
<div class="data-panel" id="dataPanel">
|
||
<div class="dp-stat">
|
||
<div class="dp-label">XTZH/USD</div>
|
||
<div class="dp-value" id="dp-xtzh-price">--</div>
|
||
<div class="dp-sub">SDR锚定</div>
|
||
</div>
|
||
<div class="dp-divider"></div>
|
||
<div class="dp-stat">
|
||
<div class="dp-label">黄金覆盖率</div>
|
||
<div class="dp-value cyan" id="dp-gold">--</div>
|
||
<div class="dp-sub">储备保障</div>
|
||
</div>
|
||
<div class="dp-divider"></div>
|
||
<div class="dp-stat">
|
||
<div class="dp-label">当前辖区</div>
|
||
<div class="dp-value blue" id="dp-jurisdiction">HK</div>
|
||
<div class="dp-sub" id="dp-juris-name">香港</div>
|
||
</div>
|
||
<div class="dp-divider"></div>
|
||
<div class="dp-stat">
|
||
<div class="dp-label">资产类别</div>
|
||
<div class="dp-value green" id="dp-asset-type">不动产</div>
|
||
<div class="dp-sub" id="dp-gnacs">GNACS-01</div>
|
||
</div>
|
||
<div class="dp-divider"></div>
|
||
<div class="dp-stat">
|
||
<div class="dp-label">辖区货币</div>
|
||
<div class="dp-value" id="dp-currency">HKD</div>
|
||
<div class="dp-sub" id="dp-usd-rate">1 HKD ≈ 0.128 USD</div>
|
||
</div>
|
||
<div class="dp-divider"></div>
|
||
<div class="dp-stat">
|
||
<div class="dp-label">监管机构</div>
|
||
<div class="dp-value cyan" id="dp-regulator">SFC/HKMA</div>
|
||
<div class="dp-sub" id="dp-tier">Tier 1</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 消息区域 -->
|
||
<div class="messages" id="messages">
|
||
<!-- 欢迎界面 -->
|
||
<div class="welcome" id="welcome">
|
||
<div class="welcome-icon">💎</div>
|
||
<h1 data-i18n="welcomeTitle">NAC AI 资产估值顾问</h1>
|
||
<p class="welcome-desc" data-i18n="welcomeDesc">基于 NAC 公链原生知识库,支持 20 大类资产 × 60+ 司法辖区。采用 SDR 锚定 XTZH 统一定价,输出当地货币 + USD + XTZH 三重价值,一键申请上链。</p>
|
||
<div class="welcome-stats">
|
||
<div class="ws-item"><div class="ws-num">20</div><div class="ws-label">大类资产</div></div>
|
||
<div class="ws-item"><div class="ws-num">60+</div><div class="ws-label">司法辖区</div></div>
|
||
<div class="ws-item"><div class="ws-num">50+</div><div class="ws-label">估值子类</div></div>
|
||
<div class="ws-item"><div class="ws-num">3</div><div class="ws-label">重价值输出</div></div>
|
||
</div>
|
||
<div class="quick-cards">
|
||
<div class="quick-card" onclick="quickAsk('香港九龙区120平米住宅公寓,市值800万港元,请估算XTZH价值和质押要求')">
|
||
<div class="card-icon">🏠</div>
|
||
<div class="card-title">住宅不动产估值</div>
|
||
<div class="card-desc">香港/新加坡/阿联酋住宅资产三重价值换算</div>
|
||
</div>
|
||
<div class="quick-card" onclick="quickAsk('我有一首原创音乐的版权,每年版税收入约50万元,剩余保护期70年,请用收益法估值')">
|
||
<div class="card-icon">🎵</div>
|
||
<div class="card-title">音乐版权估值</div>
|
||
<div class="card-desc">版税折现法,剩余保护期,授权范围分析</div>
|
||
</div>
|
||
<div class="quick-card" onclick="quickAsk('我有一项发明专利,技术领域是新能源电池,每年许可费收入约200万美元,请估值')">
|
||
<div class="card-icon">🔬</div>
|
||
<div class="card-title">发明专利估值</div>
|
||
<div class="card-desc">许可费节省法/超额收益法,技术替代风险</div>
|
||
</div>
|
||
<div class="quick-card" onclick="quickAsk('某知名艺人的肖像权和商业形象权,年商业化收入约1000万元,请估值')">
|
||
<div class="card-icon">🌟</div>
|
||
<div class="card-title">肖像权/IP估值</div>
|
||
<div class="card-desc">品牌溢价法,商业化收益折现,知名度评估</div>
|
||
</div>
|
||
<div class="quick-card" onclick="quickAsk('新加坡CBD商业写字楼1200平米,年租金收入180万SGD,请用收益法估值并换算XTZH')">
|
||
<div class="card-icon">🏢</div>
|
||
<div class="card-title">商业地产收益法</div>
|
||
<div class="card-desc">收益资本化法,新加坡辖区特定参数</div>
|
||
</div>
|
||
<div class="quick-card" onclick="quickAsk('我有一个注册商标,覆盖全球30个国家,年品牌授权收入约500万美元,请估值')">
|
||
<div class="card-icon">™️</div>
|
||
<div class="card-title">商标权估值</div>
|
||
<div class="card-desc">品牌收益折现,注册地域,市场溢价分析</div>
|
||
</div>
|
||
<div class="quick-card" onclick="quickAsk('我持有某非上市公司30%股权,公司年净利润约2000万元,请用市场乘数法估值')">
|
||
<div class="card-icon">📊</div>
|
||
<div class="card-title">非上市股权估值</div>
|
||
<div class="card-desc">市场乘数法/DCF,流动性折价,控制权溢价</div>
|
||
</div>
|
||
<div class="quick-card" onclick="quickAsk('我有一批碳排放权(VCS标准核证),共100万吨CO2当量,请估值并说明NAC上链流程')">
|
||
<div class="card-icon">🌱</div>
|
||
<div class="card-title">碳排放权估值</div>
|
||
<div class="card-desc">VCS/Gold Standard核证,市场价格法</div>
|
||
</div>
|
||
<div class="quick-card" onclick="quickAsk('一幅毕加索真迹油画,上次拍卖价格为1200万美元,请估值并分析艺术品上链流程')">
|
||
<div class="card-icon">🎨</div>
|
||
<div class="card-title">艺术品估值</div>
|
||
<div class="card-desc">拍卖记录法,专家鉴定,艺术家声誉溢价</div>
|
||
</div>
|
||
<div class="quick-card" onclick="quickAsk('请解释XTZH的SDR锚定定价机制,当前价格如何计算,黄金储备覆盖率是多少')">
|
||
<div class="card-icon">💰</div>
|
||
<div class="card-title">XTZH定价机制</div>
|
||
<div class="card-desc">SDR五货币篮子+黄金储备双重保障原理</div>
|
||
</div>
|
||
<div class="quick-card" onclick="quickAsk('请对比香港、新加坡、阿联酋三个辖区的不动产估值差异,包括资本化率和外籍购房规则')">
|
||
<div class="card-icon">🌍</div>
|
||
<div class="card-title">辖区对比分析</div>
|
||
<div class="card-desc">Tier 1辖区不动产参数对比,外籍规则</div>
|
||
</div>
|
||
<div class="quick-card" onclick="quickAsk('资产上链完整流程是什么?从估值到TOKEN生成、权证发行、代币发行需要哪些步骤')">
|
||
<div class="card-icon">⛓️</div>
|
||
<div class="card-title">一键上链流程</div>
|
||
<div class="card-desc">估值→合规→TOKEN→权证→代币发行</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 输入区域 -->
|
||
<div class="input-area">
|
||
<div class="context-bar" id="contextBar">
|
||
<div class="ctx-chip active" id="ctx-jurisdiction">🌏 <span id="ctx-juris-text">香港</span></div>
|
||
<div class="ctx-chip active" id="ctx-asset">📦 <span id="ctx-asset-text">不动产</span></div>
|
||
<div class="ctx-chip" id="ctx-mode">💎 估值模式</div>
|
||
</div>
|
||
<div class="input-wrapper">
|
||
<textarea
|
||
class="chat-input"
|
||
id="chatInput"
|
||
rows="1"
|
||
placeholder="描述您的资产(类型、位置、面积、价格等),AI将自动估算三重价值..."
|
||
onkeydown="handleKeyDown(event)"
|
||
oninput="autoResize(this)"
|
||
></textarea>
|
||
<button class="send-btn" id="sendBtn" onclick="sendMessage()" title="发送">
|
||
<svg viewBox="0 0 24 24"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
|
||
</button>
|
||
</div>
|
||
<div class="toolbar">
|
||
<div class="tool-chip active" id="chip-valuation" onclick="toggleMode('valuation', this)">💎 估值</div>
|
||
<div class="tool-chip" id="chip-chain" onclick="toggleMode('chain', this)">⛓️ 上链</div>
|
||
<div class="tool-chip" id="chip-compare" onclick="toggleMode('compare', this)">📊 辖区对比</div>
|
||
<div class="tool-chip" id="chip-explain" onclick="toggleMode('explain', this)">📖 方法论</div>
|
||
<div class="tool-chip" id="chip-gnacs" onclick="toggleMode('gnacs', this)">🔖 GNACS</div>
|
||
<div class="toolbar-hint">Enter发送 · Shift+Enter换行</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<script>
|
||
// ============================================================
|
||
// 配置
|
||
// ============================================================
|
||
const CONFIG = {
|
||
valuationApiBase: '/api/v4',
|
||
inferenceApiBase: '/api/inference',
|
||
maxMemory: 12,
|
||
lang: 'zh'
|
||
};
|
||
|
||
// ============================================================
|
||
// 20大类资产定义(与 server.js 知识库对应)
|
||
// ============================================================
|
||
const ASSET_CATEGORIES = {
|
||
real_estate: { name: '不动产', gnacs: 'GNACS-01', icon: '🏢',
|
||
subcats: ['住宅(公寓/别墅)', '商业地产', '工业用地', '农业用地', '基础设施', '酒店/服务式公寓'] },
|
||
financial_securities: { name: '金融证券', gnacs: 'GNACS-02', icon: '💹',
|
||
subcats: ['股票/股权', '债券', '基金份额', '期货/期权', 'REITs', '结构化产品'] },
|
||
commodities: { name: '大宗商品', gnacs: 'GNACS-03', icon: '🏭',
|
||
subcats: ['贵金属(黄金/白银)', '能源(石油/天然气)', '农产品', '工业金属', '稀土/稀有金属'] },
|
||
art_collectibles: { name: '艺术品与收藏品', gnacs: 'GNACS-04', icon: '🎨',
|
||
subcats: ['绘画/油画', '雕塑', '古董/文物', '名酒/威士忌', '名表', '珠宝/宝石', '邮票/钱币'] },
|
||
intellectual_property: { name: '知识产权', gnacs: 'GNACS-05', icon: '💡',
|
||
subcats: ['发明专利', '实用新型专利', '外观设计专利', '版权(文学/音乐/影视)', '商标权', '肖像权/形象权', '地理标志', '商业秘密', '软件著作权', '域名权益'] },
|
||
digital_assets: { name: '数字资产', gnacs: 'GNACS-06', icon: '🔗',
|
||
subcats: ['加密货币', 'NFT艺术', '元宇宙土地', '游戏道具/资产', '数字藏品', 'DeFi份额'] },
|
||
infrastructure: { name: '基础设施', gnacs: 'GNACS-07', icon: '🏗️',
|
||
subcats: ['港口/机场', '能源管道', '通信基础设施', '水务设施', '交通基础设施', '数据中心'] },
|
||
natural_resources: { name: '自然资源', gnacs: 'GNACS-08', icon: '🌿',
|
||
subcats: ['矿产资源', '森林/林地', '水资源', '渔业权', '海洋资源'] },
|
||
environmental_rights: { name: '环境权益', gnacs: 'GNACS-09', icon: '🌱',
|
||
subcats: ['碳排放权(VCS/CDM)', '可再生能源配额(REC)', '排污权', '水权', '生物多样性信用'] },
|
||
corporate_equity: { name: '企业权益', gnacs: 'GNACS-10', icon: '📊',
|
||
subcats: ['上市公司股权', '非上市公司股权', '有限合伙份额', '特许经营权', '并购目标估值'] },
|
||
debt_assets: { name: '债权', gnacs: 'GNACS-11', icon: '📋',
|
||
subcats: ['应收账款', '商业票据', '企业债券', '不良资产', '供应链金融'] },
|
||
insurance_products: { name: '保险产品', gnacs: 'GNACS-12', icon: '🛡️',
|
||
subcats: ['人寿保险现金价值', '年金权益', '保险结构化产品', '再保险权益'] },
|
||
agricultural_assets: { name: '农业资产', gnacs: 'GNACS-13', icon: '🌾',
|
||
subcats: ['耕地/农场', '农业设备', '农业知识产权', '农产品期货', '养殖权益'] },
|
||
vehicles: { name: '交通工具', gnacs: 'GNACS-14', icon: '🚗',
|
||
subcats: ['豪华汽车/超跑', '游艇', '私人飞机', '直升机', '商用车队'] },
|
||
machinery_equipment: { name: '机械设备', gnacs: 'GNACS-15', icon: '⚙️',
|
||
subcats: ['工业设备', '医疗设备', '航空设备', '建筑机械', '精密仪器'] },
|
||
data_assets: { name: '数据资产', gnacs: 'GNACS-16', icon: '💾',
|
||
subcats: ['用户数据集', '医疗/基因数据', '金融数据', 'AI训练数据', '地理数据'] },
|
||
brand_assets: { name: '品牌资产', gnacs: 'GNACS-17', icon: '🏷️',
|
||
subcats: ['企业品牌价值', '产品品牌', '个人品牌/IP', '特许加盟权', '域名品牌'] },
|
||
sports_assets: { name: '体育资产', gnacs: 'GNACS-18', icon: '⚽',
|
||
subcats: ['球员转会权', '体育俱乐部股权', '赛事转播权', '体育场馆', '运动员代言权'] },
|
||
entertainment_assets: { name: '娱乐资产', gnacs: 'GNACS-19', icon: '🎬',
|
||
subcats: ['影视版权', '音乐版权', '游戏IP', '综艺版权', '艺人经纪合同', '流媒体权益'] },
|
||
other_assets: { name: '其他资产', gnacs: 'GNACS-20', icon: '📦',
|
||
subcats: ['特殊用途资产', '混合型资产', '跨类别资产组合'] }
|
||
};
|
||
|
||
// 辖区信息(简化版,完整版从 API 获取)
|
||
const JURISDICTION_INFO = {
|
||
HK: { name: '香港', currency: 'HKD', usdRate: 0.1282, regulator: 'SFC/HKMA', tier: 1, flag: '🇭🇰' },
|
||
CN: { name: '中国大陆', currency: 'CNY', usdRate: 0.1379, regulator: 'CSRC/PBOC', tier: 1, flag: '🇨🇳' },
|
||
TW: { name: '台湾', currency: 'TWD', usdRate: 0.0311, regulator: 'FSC', tier: 2, flag: '🇹🇼' },
|
||
JP: { name: '日本', currency: 'JPY', usdRate: 0.0066, regulator: 'FSA', tier: 1, flag: '🇯🇵' },
|
||
KR: { name: '韩国', currency: 'KRW', usdRate: 0.00073, regulator: 'FSC', tier: 1, flag: '🇰🇷' },
|
||
MO: { name: '澳门', currency: 'MOP', usdRate: 0.1245, regulator: 'AMCM', tier: 2, flag: '🇲🇴' },
|
||
SG: { name: '新加坡', currency: 'SGD', usdRate: 0.7432, regulator: 'MAS', tier: 1, flag: '🇸🇬' },
|
||
MY: { name: '马来西亚', currency: 'MYR', usdRate: 0.2252, regulator: 'SC', tier: 2, flag: '🇲🇾' },
|
||
TH: { name: '泰国', currency: 'THB', usdRate: 0.0278, regulator: 'SEC', tier: 2, flag: '🇹🇭' },
|
||
ID: { name: '印度尼西亚', currency: 'IDR', usdRate: 0.000063, regulator: 'OJK', tier: 2, flag: '🇮🇩' },
|
||
PH: { name: '菲律宾', currency: 'PHP', usdRate: 0.0174, regulator: 'SEC', tier: 2, flag: '🇵🇭' },
|
||
VN: { name: '越南', currency: 'VND', usdRate: 0.0000394, regulator: 'SSC', tier: 3, flag: '🇻🇳' },
|
||
AE: { name: '阿联酋', currency: 'AED', usdRate: 0.2723, regulator: 'DFSA/ADGM', tier: 1, flag: '🇦🇪' },
|
||
SA: { name: '沙特阿拉伯', currency: 'SAR', usdRate: 0.2666, regulator: 'CMA', tier: 1, flag: '🇸🇦' },
|
||
QA: { name: '卡塔尔', currency: 'QAR', usdRate: 0.2747, regulator: 'QFMA', tier: 2, flag: '🇶🇦' },
|
||
KW: { name: '科威特', currency: 'KWD', usdRate: 3.2573, regulator: 'CMA', tier: 2, flag: '🇰🇼' },
|
||
BH: { name: '巴林', currency: 'BHD', usdRate: 2.6525, regulator: 'CBB', tier: 2, flag: '🇧🇭' },
|
||
IL: { name: '以色列', currency: 'ILS', usdRate: 0.2703, regulator: 'ISA', tier: 1, flag: '🇮🇱' },
|
||
GB: { name: '英国', currency: 'GBP', usdRate: 1.2650, regulator: 'FCA', tier: 1, flag: '🇬🇧' },
|
||
DE: { name: '德国', currency: 'EUR', usdRate: 1.0850, regulator: 'BaFin', tier: 1, flag: '🇩🇪' },
|
||
FR: { name: '法国', currency: 'EUR', usdRate: 1.0850, regulator: 'AMF', tier: 1, flag: '🇫🇷' },
|
||
CH: { name: '瑞士', currency: 'CHF', usdRate: 1.1250, regulator: 'FINMA', tier: 1, flag: '🇨🇭' },
|
||
NL: { name: '荷兰', currency: 'EUR', usdRate: 1.0850, regulator: 'AFM', tier: 1, flag: '🇳🇱' },
|
||
IT: { name: '意大利', currency: 'EUR', usdRate: 1.0850, regulator: 'CONSOB', tier: 1, flag: '🇮🇹' },
|
||
ES: { name: '西班牙', currency: 'EUR', usdRate: 1.0850, regulator: 'CNMV', tier: 1, flag: '🇪🇸' },
|
||
EU: { name: '欧盟', currency: 'EUR', usdRate: 1.0850, regulator: 'ESMA', tier: 1, flag: '🇪🇺' },
|
||
US: { name: '美国', currency: 'USD', usdRate: 1.0, regulator: 'SEC/CFTC', tier: 1, flag: '🇺🇸' },
|
||
CA: { name: '加拿大', currency: 'CAD', usdRate: 0.7380, regulator: 'CSA', tier: 1, flag: '🇨🇦' },
|
||
BR: { name: '巴西', currency: 'BRL', usdRate: 0.1980, regulator: 'CVM', tier: 2, flag: '🇧🇷' },
|
||
MX: { name: '墨西哥', currency: 'MXN', usdRate: 0.0492, regulator: 'CNBV', tier: 2, flag: '🇲🇽' },
|
||
CL: { name: '智利', currency: 'CLP', usdRate: 0.00107, regulator: 'CMF', tier: 2, flag: '🇨🇱' },
|
||
AR: { name: '阿根廷', currency: 'ARS', usdRate: 0.00105, regulator: 'CNV', tier: 3, flag: '🇦🇷' },
|
||
AU: { name: '澳大利亚', currency: 'AUD', usdRate: 0.6380, regulator: 'ASIC', tier: 1, flag: '🇦🇺' },
|
||
NZ: { name: '新西兰', currency: 'NZD', usdRate: 0.5980, regulator: 'FMA', tier: 2, flag: '🇳🇿' },
|
||
IN: { name: '印度', currency: 'INR', usdRate: 0.01198, regulator: 'SEBI', tier: 2, flag: '🇮🇳' },
|
||
ZA: { name: '南非', currency: 'ZAR', usdRate: 0.0543, regulator: 'FSCA', tier: 2, flag: '🇿🇦' },
|
||
NG: { name: '尼日利亚', currency: 'NGN', usdRate: 0.000625, regulator: 'SEC', tier: 3, flag: '🇳🇬' },
|
||
EG: { name: '埃及', currency: 'EGP', usdRate: 0.0203, regulator: 'FRA', tier: 3, flag: '🇪🇬' },
|
||
KE: { name: '肯尼亚', currency: 'KES', usdRate: 0.00775, regulator: 'CMA', tier: 3, flag: '🇰🇪' },
|
||
RU: { name: '俄罗斯', currency: 'RUB', usdRate: 0.01095, regulator: 'CBR', tier: 2, flag: '🇷🇺' },
|
||
TR: { name: '土耳其', currency: 'TRY', usdRate: 0.0292, regulator: 'SPK', tier: 2, flag: '🇹🇷' }
|
||
};
|
||
|
||
// 多语言
|
||
const I18N = {
|
||
zh: {
|
||
title: 'NAC AI 资产估值顾问',
|
||
subtitle: '20大类资产 · 60+辖区 · SDR锚定 · 三重价值',
|
||
newChat: '+ 新建估值',
|
||
jurisdiction: '司法辖区',
|
||
assetType: '资产类别(GNACS)',
|
||
history: '历史估值',
|
||
welcomeTitle: 'NAC AI 资产估值顾问',
|
||
welcomeDesc: '基于 NAC 公链原生知识库,支持 20 大类资产 × 60+ 司法辖区。采用 SDR 锚定 XTZH 统一定价,输出当地货币 + USD + XTZH 三重价值,一键申请上链。',
|
||
placeholder: '描述您的资产(类型、位置、面积、价格等),AI将自动估算三重价值...',
|
||
sending: '正在分析...',
|
||
chainBtn: '申请上链',
|
||
detailBtn: '查看详情',
|
||
compareBtn: '辖区对比',
|
||
confidence: '置信度',
|
||
finalXTZH: 'XTZH价值',
|
||
finalUSD: 'USD估值',
|
||
localValue: '当地货币',
|
||
stakeRequired: '质押要求(80%)',
|
||
},
|
||
en: {
|
||
title: 'NAC AI Asset Valuation Advisor',
|
||
subtitle: '20 Asset Classes · 60+ Jurisdictions · SDR-Pegged · Triple Value',
|
||
newChat: '+ New Valuation',
|
||
jurisdiction: 'Jurisdiction',
|
||
assetType: 'Asset Category (GNACS)',
|
||
history: 'History',
|
||
welcomeTitle: 'NAC AI Asset Valuation Advisor',
|
||
welcomeDesc: 'Native NAC blockchain knowledge base supporting 20 asset classes × 60+ jurisdictions. SDR-pegged XTZH pricing with local currency + USD + XTZH triple value output.',
|
||
placeholder: 'Describe your asset (type, location, area, price...) for triple value estimation...',
|
||
sending: 'Analyzing...',
|
||
chainBtn: 'Apply On-Chain',
|
||
detailBtn: 'View Details',
|
||
compareBtn: 'Compare Jurisdictions',
|
||
confidence: 'Confidence',
|
||
finalXTZH: 'XTZH Value',
|
||
finalUSD: 'USD Value',
|
||
localValue: 'Local Currency',
|
||
stakeRequired: 'Stake Required (80%)',
|
||
}
|
||
};
|
||
|
||
// ============================================================
|
||
// 状态管理
|
||
// ============================================================
|
||
let state = {
|
||
messages: [],
|
||
sessionId: generateSessionId(),
|
||
conversationMemory: [],
|
||
currentJurisdiction: 'HK',
|
||
currentAssetCategory: 'real_estate',
|
||
currentSubcat: null,
|
||
currentMode: 'valuation',
|
||
xtzhPrice: null,
|
||
isStreaming: false,
|
||
history: JSON.parse(localStorage.getItem('nac_valuation_history_v2') || '[]')
|
||
};
|
||
|
||
function generateSessionId() {
|
||
return 'vs_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
|
||
}
|
||
|
||
// ============================================================
|
||
// 初始化辖区和资产类别
|
||
// ============================================================
|
||
function setJurisdiction(code) {
|
||
state.currentJurisdiction = code;
|
||
const info = JURISDICTION_INFO[code];
|
||
if (info) {
|
||
document.getElementById('dp-jurisdiction').textContent = code;
|
||
document.getElementById('dp-juris-name').textContent = info.name;
|
||
document.getElementById('dp-currency').textContent = info.currency;
|
||
document.getElementById('dp-usd-rate').textContent = `1 ${info.currency} ≈ ${info.usdRate} USD`;
|
||
document.getElementById('dp-regulator').textContent = info.regulator || 'N/A';
|
||
document.getElementById('dp-tier').textContent = `Tier ${info.tier}`;
|
||
document.getElementById('ctx-juris-text').textContent = info.flag + ' ' + info.name;
|
||
}
|
||
}
|
||
|
||
function setAssetCategory(key) {
|
||
state.currentAssetCategory = key;
|
||
state.currentSubcat = null;
|
||
const cat = ASSET_CATEGORIES[key];
|
||
if (cat) {
|
||
document.getElementById('dp-asset-type').textContent = cat.name;
|
||
document.getElementById('dp-gnacs').textContent = cat.gnacs;
|
||
document.getElementById('ctx-asset-text').textContent = cat.icon + ' ' + cat.name;
|
||
renderSubcats(cat.subcats);
|
||
}
|
||
}
|
||
|
||
function renderSubcats(subcats) {
|
||
const grid = document.getElementById('subcatGrid');
|
||
if (!subcats || subcats.length === 0) { grid.innerHTML = ''; return; }
|
||
grid.innerHTML = subcats.map(s => `<div class="subcat-tag" onclick="selectSubcat(this, '${s.replace(/'/g, '')}')">${s}</div>`).join('');
|
||
}
|
||
|
||
function selectSubcat(el, subcat) {
|
||
document.querySelectorAll('.subcat-tag').forEach(t => t.classList.remove('active'));
|
||
el.classList.add('active');
|
||
state.currentSubcat = subcat;
|
||
// 自动填充输入框提示
|
||
const cat = ASSET_CATEGORIES[state.currentAssetCategory];
|
||
const juris = JURISDICTION_INFO[state.currentJurisdiction];
|
||
const input = document.getElementById('chatInput');
|
||
if (!input.value) {
|
||
input.value = `${juris ? juris.name : state.currentJurisdiction}辖区,${subcat},请提供估值方法和关键参数说明`;
|
||
autoResize(input);
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// XTZH实时价格
|
||
// ============================================================
|
||
async function fetchXTZHPrice() {
|
||
try {
|
||
const res = await fetch(CONFIG.valuationApiBase + '/xtzh-price');
|
||
if (!res.ok) throw new Error('HTTP ' + res.status);
|
||
const data = await res.json();
|
||
state.xtzhPrice = data;
|
||
const usd = parseFloat(data.usd || data.price || 4.3944).toFixed(4);
|
||
document.getElementById('header-xtzh-price').textContent = '$' + usd;
|
||
document.getElementById('dp-xtzh-price').textContent = '$' + usd;
|
||
const goldCov = data.goldCoverage ? (data.goldCoverage * 100).toFixed(0) + '%' : '125%';
|
||
document.getElementById('dp-gold').textContent = goldCov;
|
||
} catch(e) {
|
||
document.getElementById('header-xtzh-price').textContent = '$4.3944';
|
||
document.getElementById('dp-xtzh-price').textContent = '$4.3944';
|
||
document.getElementById('dp-gold').textContent = '125%';
|
||
state.xtzhPrice = { usd: 4.3944, source: 'fallback' };
|
||
}
|
||
}
|
||
|
||
function refreshXTZHPrice() {
|
||
document.getElementById('header-xtzh-price').textContent = '刷新中...';
|
||
fetchXTZHPrice();
|
||
}
|
||
|
||
// ============================================================
|
||
// 模式切换
|
||
// ============================================================
|
||
function toggleMode(mode, el) {
|
||
state.currentMode = mode;
|
||
document.querySelectorAll('.tool-chip').forEach(c => c.classList.remove('active'));
|
||
el.classList.add('active');
|
||
document.getElementById('ctx-mode').textContent = el.textContent;
|
||
document.getElementById('ctx-mode').classList.add('active');
|
||
const input = document.getElementById('chatInput');
|
||
const modeHints = {
|
||
valuation: '描述您的资产(类型、位置、面积、价格等),AI将自动估算三重价值...',
|
||
chain: '描述您希望上链的资产,AI将提供完整的ACC-20上链流程指引...',
|
||
compare: '请输入您想对比的辖区或资产类型,AI将提供详细对比分析...',
|
||
explain: '请输入您想了解的估值方法(如:收益资本化法、许可费节省法等)...',
|
||
gnacs: '请输入您想了解的GNACS资产分类编码或资产类型...'
|
||
};
|
||
input.placeholder = modeHints[mode] || modeHints.valuation;
|
||
}
|
||
|
||
// ============================================================
|
||
// 发送消息
|
||
// ============================================================
|
||
async function sendMessage() {
|
||
const input = document.getElementById('chatInput');
|
||
const text = input.value.trim();
|
||
if (!text || state.isStreaming) return;
|
||
|
||
// 隐藏欢迎界面
|
||
const welcome = document.getElementById('welcome');
|
||
if (welcome) welcome.style.display = 'none';
|
||
|
||
input.value = '';
|
||
input.style.height = 'auto';
|
||
state.isStreaming = true;
|
||
document.getElementById('sendBtn').disabled = true;
|
||
|
||
appendUserMessage(text);
|
||
if (state.messages.length === 1) addToHistory(text.substring(0, 30) + (text.length > 30 ? '...' : ''));
|
||
|
||
const msgId = 'msg_' + Date.now();
|
||
appendAIMessage('', msgId);
|
||
|
||
// 构建消息历史
|
||
state.conversationMemory.push({ role: 'user', content: text });
|
||
if (state.conversationMemory.length > CONFIG.maxMemory * 2) {
|
||
state.conversationMemory = state.conversationMemory.slice(-CONFIG.maxMemory * 2);
|
||
}
|
||
|
||
const jurisInfo = JURISDICTION_INFO[state.currentJurisdiction] || {};
|
||
const catInfo = ASSET_CATEGORIES[state.currentAssetCategory] || {};
|
||
|
||
const requestBody = {
|
||
question: text,
|
||
messages: state.conversationMemory.slice(-CONFIG.maxMemory * 2),
|
||
jurisdictionCode: state.currentJurisdiction,
|
||
assetCategory: state.currentAssetCategory,
|
||
assetSubcat: state.currentSubcat,
|
||
mode: state.currentMode,
|
||
lang: CONFIG.lang,
|
||
context: {
|
||
jurisdiction: state.currentJurisdiction,
|
||
jurisdictionName: jurisInfo.name,
|
||
currency: jurisInfo.currency,
|
||
assetCategory: state.currentAssetCategory,
|
||
assetName: catInfo.name,
|
||
gnacs: catInfo.gnacs,
|
||
subcat: state.currentSubcat
|
||
}
|
||
};
|
||
|
||
try {
|
||
const response = await fetch(CONFIG.inferenceApiBase + '/stream', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(requestBody)
|
||
});
|
||
|
||
if (!response.ok) throw new Error('HTTP ' + response.status);
|
||
|
||
const reader = response.body.getReader();
|
||
const decoder = new TextDecoder();
|
||
let fullContent = '';
|
||
let buffer = '';
|
||
|
||
while (true) {
|
||
const { done, value } = await reader.read();
|
||
if (done) break;
|
||
buffer += decoder.decode(value, { stream: true });
|
||
const lines = buffer.split('\n');
|
||
buffer = lines.pop() || '';
|
||
|
||
for (const line of lines) {
|
||
if (!line.startsWith('data: ')) continue;
|
||
const dataStr = line.slice(6).trim();
|
||
if (dataStr === '[DONE]') {
|
||
removeCursor(msgId);
|
||
updateAIMessage(msgId, fullContent, false);
|
||
state.conversationMemory.push({ role: 'assistant', content: fullContent });
|
||
state.isStreaming = false;
|
||
document.getElementById('sendBtn').disabled = false;
|
||
break;
|
||
}
|
||
try {
|
||
const parsed = JSON.parse(dataStr);
|
||
if (parsed.type === 'valuation_result') {
|
||
renderValuationResult(parsed, msgId);
|
||
continue;
|
||
}
|
||
if (parsed.type === 'chunk' && parsed.content) {
|
||
fullContent += parsed.content;
|
||
updateAIMessage(msgId, fullContent, true);
|
||
} else if (parsed.choices && parsed.choices[0]) {
|
||
const delta = parsed.choices[0].delta;
|
||
if (delta && delta.content) {
|
||
fullContent += delta.content;
|
||
updateAIMessage(msgId, fullContent, true);
|
||
}
|
||
}
|
||
} catch(e) { /* skip */ }
|
||
}
|
||
}
|
||
} catch(e) {
|
||
updateAIMessage(msgId, `**连接错误:** ${e.message}\n\n请检查网络连接后重试。`, false);
|
||
} finally {
|
||
state.isStreaming = false;
|
||
document.getElementById('sendBtn').disabled = false;
|
||
removeCursor(msgId);
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// 渲染估值结果卡片(三重价值)
|
||
// ============================================================
|
||
function renderValuationResult(data, msgId) {
|
||
const v = data.valuation || data;
|
||
const xtzhPrice = (state.xtzhPrice && state.xtzhPrice.usd) ? state.xtzhPrice.usd : 4.3944;
|
||
const jurisInfo = JURISDICTION_INFO[state.currentJurisdiction] || { currency: 'USD', usdRate: 1.0, name: '全球' };
|
||
const catInfo = ASSET_CATEGORIES[state.currentAssetCategory] || { name: '资产', gnacs: 'GNACS-20' };
|
||
const t = I18N[CONFIG.lang] || I18N.zh;
|
||
|
||
const finalXTZH = v.finalXTZH || v.valueXTZH?.amount || 0;
|
||
const finalUSD = v.finalUSD || v.valueUSD?.amount || (finalXTZH * xtzhPrice);
|
||
const finalLocal = v.valueLocal?.amount || (finalUSD / jurisInfo.usdRate);
|
||
const stakeXTZH = finalXTZH * 0.8;
|
||
const confidence = v.confidence || 0.85;
|
||
|
||
const summaryText = `**资产估值完成** ✅\n\n估值方法:${v.valuationMethod || v.methodsUsed?.join(' + ') || '多方法融合'}\n\n> 基于 NAC 原生知识库,${jurisInfo.name}辖区,${catInfo.name}(${catInfo.gnacs})`;
|
||
updateAIMessage(msgId, summaryText, false);
|
||
|
||
const contentEl = document.querySelector('#' + msgId + ' .message-content');
|
||
if (contentEl) {
|
||
const card = document.createElement('div');
|
||
card.className = 'valuation-card';
|
||
card.innerHTML = `
|
||
<div class="vc-header">
|
||
<span class="vc-title">💎 ${t.finalXTZH} 估值结果</span>
|
||
<span class="vc-badge">置信度 ${(confidence*100).toFixed(0)}%</span>
|
||
<span class="vc-badge" style="background:rgba(0,188,212,0.1);color:var(--accent-cyan);border-color:rgba(0,188,212,0.25)">${catInfo.gnacs}</span>
|
||
</div>
|
||
<div class="triple-value">
|
||
<div class="tv-item">
|
||
<div class="tv-label">${t.localValue} (${jurisInfo.currency})</div>
|
||
<div class="tv-value gold">${formatNumber(finalLocal)} ${jurisInfo.currency}</div>
|
||
<div class="tv-sub">${jurisInfo.name}市场价值</div>
|
||
</div>
|
||
<div class="tv-item">
|
||
<div class="tv-label">${t.finalUSD}</div>
|
||
<div class="tv-value cyan">$${formatNumber(finalUSD)}</div>
|
||
<div class="tv-sub">按 ${jurisInfo.currency}/USD 汇率换算</div>
|
||
</div>
|
||
<div class="tv-item">
|
||
<div class="tv-label">${t.finalXTZH}</div>
|
||
<div class="tv-value green">${formatNumber(finalXTZH)} XTZH</div>
|
||
<div class="tv-sub">@$${parseFloat(xtzhPrice).toFixed(4)}/XTZH</div>
|
||
</div>
|
||
</div>
|
||
<div class="pledge-row">
|
||
<span class="pledge-label">🔒 ${t.stakeRequired}(上链质押)</span>
|
||
<span class="pledge-value">${formatNumber(stakeXTZH)} XTZH</span>
|
||
</div>
|
||
<div class="confidence-bar"><div class="confidence-fill" style="width:${confidence*100}%"></div></div>
|
||
<div class="chain-actions">
|
||
<button class="chain-btn primary" onclick="applyOnChain(${finalXTZH.toFixed(2)}, ${finalUSD.toFixed(0)}, '${state.currentJurisdiction}')">
|
||
⛓️ ${t.chainBtn}
|
||
</button>
|
||
<button class="chain-btn secondary" onclick="viewValuationDetail()">📄 ${t.detailBtn}</button>
|
||
<button class="chain-btn secondary" onclick="compareJurisdictions()">🌍 ${t.compareBtn}</button>
|
||
</div>
|
||
`;
|
||
contentEl.appendChild(card);
|
||
}
|
||
scrollToBottom();
|
||
}
|
||
|
||
function formatNumber(n) {
|
||
if (!n || isNaN(n)) return '0';
|
||
if (n >= 1000000) return (n / 1000000).toFixed(2) + 'M';
|
||
if (n >= 1000) return n.toLocaleString('zh-CN', { maximumFractionDigits: 0 });
|
||
return n.toFixed(2);
|
||
}
|
||
|
||
function applyOnChain(xtzh, usd, jurisdiction) {
|
||
const msg = `我希望将这个资产上链,估值为 ${xtzh} XTZH($${usd} USD),辖区 ${jurisdiction}。请告诉我完整的ACC-20上链流程和需要准备的材料。`;
|
||
document.getElementById('chatInput').value = msg;
|
||
toggleMode('chain', document.getElementById('chip-chain'));
|
||
sendMessage();
|
||
}
|
||
|
||
function viewValuationDetail() {
|
||
quickAsk('请详细解释刚才的估值计算过程,包括使用的方法、关键参数、辖区调整系数和三重价值换算逻辑');
|
||
}
|
||
|
||
function compareJurisdictions() {
|
||
const cat = ASSET_CATEGORIES[state.currentAssetCategory] || {};
|
||
quickAsk(`请对比香港、新加坡、阿联酋三个辖区对于${cat.name || '不动产'}的估值差异,包括资本化率、外籍规则和税务考量`);
|
||
}
|
||
|
||
// ============================================================
|
||
// DOM操作
|
||
// ============================================================
|
||
function appendUserMessage(text) {
|
||
const messages = document.getElementById('messages');
|
||
const div = document.createElement('div');
|
||
div.className = 'message user';
|
||
div.innerHTML = `
|
||
<div class="message-avatar">👤</div>
|
||
<div class="message-content">${escapeHtml(text)}</div>
|
||
`;
|
||
messages.appendChild(div);
|
||
state.messages.push({ role: 'user', content: text });
|
||
scrollToBottom();
|
||
}
|
||
|
||
function appendAIMessage(content, id) {
|
||
const messages = document.getElementById('messages');
|
||
const div = document.createElement('div');
|
||
div.className = 'message ai';
|
||
div.id = id;
|
||
div.innerHTML = `
|
||
<div class="message-avatar">NAC</div>
|
||
<div class="message-content">${content ? renderMarkdown(content) : '<div class="typing-indicator"><div class="typing-dot"></div><div class="typing-dot"></div><div class="typing-dot"></div></div>'}</div>
|
||
`;
|
||
messages.appendChild(div);
|
||
scrollToBottom();
|
||
return div;
|
||
}
|
||
|
||
function updateAIMessage(id, content, streaming) {
|
||
const el = document.querySelector('#' + id + ' .message-content');
|
||
if (!el) return;
|
||
el.innerHTML = renderMarkdown(content) + (streaming ? '<span class="stream-cursor"></span>' : '');
|
||
scrollToBottom();
|
||
}
|
||
|
||
function removeCursor(id) {
|
||
const cursor = document.querySelector('#' + id + ' .stream-cursor');
|
||
if (cursor) cursor.remove();
|
||
}
|
||
|
||
function scrollToBottom() {
|
||
const messages = document.getElementById('messages');
|
||
messages.scrollTop = messages.scrollHeight;
|
||
}
|
||
|
||
// ============================================================
|
||
// Markdown渲染
|
||
// ============================================================
|
||
function escapeInline(text) {
|
||
return text.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||
}
|
||
|
||
function applyInline(text) {
|
||
return text
|
||
.replace(/\*\*(.+?)\*\*/g, '<strong style="color:var(--accent-gold-light)">$1</strong>')
|
||
.replace(/\*(.+?)\*/g, '<em style="color:var(--accent-cyan)">$1</em>')
|
||
.replace(/`([^`]+)`/g, '<code style="background:rgba(0,0,0,0.3);padding:2px 5px;border-radius:4px;font-size:11px">$1</code>');
|
||
}
|
||
|
||
function renderMarkdown(text) {
|
||
if (!text) return '';
|
||
const lines = text.split('\n');
|
||
const output = [];
|
||
let inTable = false, tableRows = [], isFirstRow = true;
|
||
let inCode = false, codeLines = [];
|
||
|
||
function flushTable() {
|
||
if (tableRows.length) {
|
||
output.push('<table>' + tableRows.join('') + '</tbody></table>');
|
||
}
|
||
inTable = false; tableRows = []; isFirstRow = true;
|
||
}
|
||
|
||
for (let i = 0; i < lines.length; i++) {
|
||
const line = lines[i];
|
||
const trimmed = line.trim();
|
||
|
||
// 代码块
|
||
if (trimmed.startsWith('```')) {
|
||
if (!inCode) { inCode = true; codeLines = []; continue; }
|
||
else { inCode = false; output.push('<pre><code>' + codeLines.map(l => escapeInline(l)).join('\n') + '</code></pre>'); codeLines = []; continue; }
|
||
}
|
||
if (inCode) { codeLines.push(line); continue; }
|
||
|
||
// 表格
|
||
const isTableRow = /^\|.+\|$/.test(trimmed);
|
||
const isSeparator = /^\|[-|: ]+\|$/.test(trimmed);
|
||
if (isTableRow && !isSeparator) {
|
||
if (!inTable) { inTable = true; isFirstRow = true; tableRows = []; }
|
||
const cells = trimmed.split('|').filter(c => c !== '').map(c => applyInline(escapeInline(c.trim())));
|
||
if (isFirstRow) {
|
||
tableRows.push('<thead><tr>' + cells.map(c => `<th>${c}</th>`).join('') + '</tr></thead><tbody>');
|
||
isFirstRow = false;
|
||
} else {
|
||
tableRows.push('<tr>' + cells.map(c => `<td>${c}</td>`).join('') + '</tr>');
|
||
}
|
||
continue;
|
||
}
|
||
if (isSeparator) continue;
|
||
if (inTable) flushTable();
|
||
|
||
// 普通行
|
||
if (trimmed === '') { output.push('<br>'); continue; }
|
||
if (trimmed === '---' || trimmed === '***') { output.push('<hr>'); continue; }
|
||
|
||
const e = escapeInline(line);
|
||
if (/^### /.test(e)) { output.push(e.replace(/^### (.+)$/, (_, c) => `<h3>${applyInline(c)}</h3>`)); continue; }
|
||
if (/^## /.test(e)) { output.push(e.replace(/^## (.+)$/, (_, c) => `<h2>${applyInline(c)}</h2>`)); continue; }
|
||
if (/^# /.test(e)) { output.push(e.replace(/^# (.+)$/, (_, c) => `<h1>${applyInline(c)}</h1>`)); continue; }
|
||
if (/^> /.test(e)) { output.push(e.replace(/^> (.+)$/, (_, c) => `<blockquote>${applyInline(c)}</blockquote>`)); continue; }
|
||
if (/^[-*] /.test(e)) { output.push(e.replace(/^[-*] (.+)$/, (_, c) => `<li>${applyInline(c)}</li>`)); continue; }
|
||
if (/^\d+\. /.test(e)) { output.push(e.replace(/^\d+\. (.+)$/, (_, c) => `<li>${applyInline(c)}</li>`)); continue; }
|
||
output.push('<p>' + applyInline(e) + '</p>');
|
||
}
|
||
if (inTable) flushTable();
|
||
|
||
return output.join('\n')
|
||
.replace(/(<li>[\s\S]*?<\/li>\n?)+/g, m => `<ul>${m}</ul>`)
|
||
.replace(/<\/ul>\n?<ul>/g, '');
|
||
}
|
||
|
||
function escapeHtml(text) {
|
||
return text.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
||
}
|
||
|
||
// ============================================================
|
||
// 快捷问题
|
||
// ============================================================
|
||
function quickAsk(text) {
|
||
document.getElementById('chatInput').value = text;
|
||
sendMessage();
|
||
}
|
||
|
||
// ============================================================
|
||
// 新建对话 / 清除记忆
|
||
// ============================================================
|
||
function newChat() {
|
||
state.messages = [];
|
||
state.conversationMemory = [];
|
||
state.sessionId = generateSessionId();
|
||
state.isStreaming = false;
|
||
document.getElementById('sendBtn').disabled = false;
|
||
const messages = document.getElementById('messages');
|
||
messages.innerHTML = `
|
||
<div class="welcome" id="welcome">
|
||
<div class="welcome-icon">💎</div>
|
||
<h1 data-i18n="welcomeTitle">NAC AI 资产估值顾问</h1>
|
||
<p class="welcome-desc">基于 NAC 公链原生知识库,支持 20 大类资产 × 60+ 司法辖区。采用 SDR 锚定 XTZH 统一定价,输出当地货币 + USD + XTZH 三重价值,一键申请上链。</p>
|
||
<div class="welcome-stats">
|
||
<div class="ws-item"><div class="ws-num">20</div><div class="ws-label">大类资产</div></div>
|
||
<div class="ws-item"><div class="ws-num">60+</div><div class="ws-label">司法辖区</div></div>
|
||
<div class="ws-item"><div class="ws-num">50+</div><div class="ws-label">估值子类</div></div>
|
||
<div class="ws-item"><div class="ws-num">3</div><div class="ws-label">重价值输出</div></div>
|
||
</div>
|
||
<div class="quick-cards">
|
||
<div class="quick-card" onclick="quickAsk('香港九龙区120平米住宅公寓,市值800万港元,请估算XTZH价值和质押要求')"><div class="card-icon">🏠</div><div class="card-title">住宅不动产估值</div><div class="card-desc">香港/新加坡/阿联酋住宅资产三重价值换算</div></div>
|
||
<div class="quick-card" onclick="quickAsk('我有一首原创音乐的版权,每年版税收入约50万元,剩余保护期70年,请用收益法估值')"><div class="card-icon">🎵</div><div class="card-title">音乐版权估值</div><div class="card-desc">版税折现法,剩余保护期,授权范围分析</div></div>
|
||
<div class="quick-card" onclick="quickAsk('我有一项发明专利,技术领域是新能源电池,每年许可费收入约200万美元,请估值')"><div class="card-icon">🔬</div><div class="card-title">发明专利估值</div><div class="card-desc">许可费节省法/超额收益法,技术替代风险</div></div>
|
||
<div class="quick-card" onclick="quickAsk('某知名艺人的肖像权和商业形象权,年商业化收入约1000万元,请估值')"><div class="card-icon">🌟</div><div class="card-title">肖像权/IP估值</div><div class="card-desc">品牌溢价法,商业化收益折现,知名度评估</div></div>
|
||
<div class="quick-card" onclick="quickAsk('新加坡CBD商业写字楼1200平米,年租金收入180万SGD,请用收益法估值并换算XTZH')"><div class="card-icon">🏢</div><div class="card-title">商业地产收益法</div><div class="card-desc">收益资本化法,新加坡辖区特定参数</div></div>
|
||
<div class="quick-card" onclick="quickAsk('我有一个注册商标,覆盖全球30个国家,年品牌授权收入约500万美元,请估值')"><div class="card-icon">™️</div><div class="card-title">商标权估值</div><div class="card-desc">品牌收益折现,注册地域,市场溢价分析</div></div>
|
||
<div class="quick-card" onclick="quickAsk('我持有某非上市公司30%股权,公司年净利润约2000万元,请用市场乘数法估值')"><div class="card-icon">📊</div><div class="card-title">非上市股权估值</div><div class="card-desc">市场乘数法/DCF,流动性折价,控制权溢价</div></div>
|
||
<div class="quick-card" onclick="quickAsk('我有一批碳排放权(VCS标准核证),共100万吨CO2当量,请估值并说明NAC上链流程')"><div class="card-icon">🌱</div><div class="card-title">碳排放权估值</div><div class="card-desc">VCS/Gold Standard核证,市场价格法</div></div>
|
||
<div class="quick-card" onclick="quickAsk('一幅毕加索真迹油画,上次拍卖价格为1200万美元,请估值并分析艺术品上链流程')"><div class="card-icon">🎨</div><div class="card-title">艺术品估值</div><div class="card-desc">拍卖记录法,专家鉴定,艺术家声誉溢价</div></div>
|
||
<div class="quick-card" onclick="quickAsk('请解释XTZH的SDR锚定定价机制,当前价格如何计算,黄金储备覆盖率是多少')"><div class="card-icon">💰</div><div class="card-title">XTZH定价机制</div><div class="card-desc">SDR五货币篮子+黄金储备双重保障原理</div></div>
|
||
<div class="quick-card" onclick="quickAsk('请对比香港、新加坡、阿联酋三个辖区的不动产估值差异,包括资本化率和外籍购房规则')"><div class="card-icon">🌍</div><div class="card-title">辖区对比分析</div><div class="card-desc">Tier 1辖区不动产参数对比,外籍规则</div></div>
|
||
<div class="quick-card" onclick="quickAsk('资产上链完整流程是什么?从估值到TOKEN生成、权证发行、代币发行需要哪些步骤')"><div class="card-icon">⛓️</div><div class="card-title">一键上链流程</div><div class="card-desc">估值→合规→TOKEN→权证→代币发行</div></div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
function clearMemory() {
|
||
state.conversationMemory = [];
|
||
newChat();
|
||
}
|
||
|
||
// ============================================================
|
||
// 历史记录
|
||
// ============================================================
|
||
function addToHistory(title) {
|
||
const item = { id: state.sessionId, title, time: Date.now() };
|
||
state.history.unshift(item);
|
||
if (state.history.length > 20) state.history = state.history.slice(0, 20);
|
||
localStorage.setItem('nac_valuation_history_v2', JSON.stringify(state.history));
|
||
renderHistory();
|
||
}
|
||
|
||
function renderHistory() {
|
||
const list = document.getElementById('historyList');
|
||
list.innerHTML = state.history.map(item => `
|
||
<div class="history-item ${item.id === state.sessionId ? 'active' : ''}">
|
||
💎 ${item.title}
|
||
<div style="font-size:9px;color:var(--text-muted);margin-top:2px">${new Date(item.time).toLocaleDateString('zh-CN')}</div>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
// ============================================================
|
||
// 语言切换
|
||
// ============================================================
|
||
function switchLanguage(lang) {
|
||
CONFIG.lang = lang;
|
||
document.querySelectorAll('[data-i18n]').forEach(el => {
|
||
const key = el.getAttribute('data-i18n');
|
||
const t = I18N[lang] || I18N.zh;
|
||
if (t[key]) el.textContent = t[key];
|
||
});
|
||
const input = document.getElementById('chatInput');
|
||
const t = I18N[lang] || I18N.zh;
|
||
if (t.placeholder) input.placeholder = t.placeholder;
|
||
}
|
||
|
||
// ============================================================
|
||
// 键盘事件
|
||
// ============================================================
|
||
function handleKeyDown(e) {
|
||
if (e.key === 'Enter' && !e.shiftKey) {
|
||
e.preventDefault();
|
||
sendMessage();
|
||
}
|
||
}
|
||
|
||
function autoResize(el) {
|
||
el.style.height = 'auto';
|
||
el.style.height = Math.min(el.scrollHeight, 140) + 'px';
|
||
}
|
||
|
||
// ============================================================
|
||
// 初始化
|
||
// ============================================================
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
fetchXTZHPrice();
|
||
setInterval(fetchXTZHPrice, 60000);
|
||
renderHistory();
|
||
setJurisdiction('HK');
|
||
setAssetCategory('real_estate');
|
||
document.getElementById('chatInput').focus();
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|