feat(定时任务): 新增第九个 HTML 模板 no.9(只展示)

- no.9.html(160KB)复制进 templates/no9/;数据用 `const DATA = {…}`(= 前有空格,同 no.6),
  当前引擎正则要求 const DATA=,不匹配,故先注册为 convertible=False 只展示
- 前端下拉/参考列表自动出现 no.9
- 测试覆盖 no.9 存在/只展示/文件可读

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
董宏凯andClaude Opus 4.8 committed 2026-06-24 18:17:56 +08:00
1 parent 31cd19aabb
commit 8678ceb422
2 files changed
+75

No files matched your search

@@ -193,6 +193,15 @@ TEMPLATES: tuple[TemplateSpec, ...] = (
# 当前引擎只支持 const VAR= 行注入,故暂注册为只展示;接转换需扩展元素注入。
convertible=False,
),
TemplateSpec(
id="no9",
name="no.9",
description="",
file="no9/no9.html",
# 数据用 `const DATA = {…}`(= 前有空格,同 no.6),当前引擎正则要求 const DATA=,不匹配,
# 故暂注册为只展示;接转换需放宽行注入正则。
convertible=False,
),
)
_TEMPLATES_BY_ID: dict[str, TemplateSpec] = {t.id: t for t in TEMPLATES}
@@ -0,0 +1,66 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>美国涉华决策咨询群体专题库</title>
<style>
:root{--bg:#f6f7f9;--panel:#fff;--text:#1f2933;--muted:#5b6573;--line:#d8dee8;--red:#8b1e1e;--red2:#5f1515;--gold:#c9a227;--green:#2f6f5e;--blue:#245c7a;--purple:#6b4e9b;--tag:#f1f3f6;--shadow:0 12px 30px rgba(25,35,55,.08);--radius:16px}*{box-sizing:border-box}body{margin:0;font-family:"Microsoft YaHei","PingFang SC","Noto Sans CJK SC",Arial,sans-serif;background:radial-gradient(circle at 12% 0%,rgba(139,30,30,.16),transparent 25%),linear-gradient(180deg,#fff,var(--bg) 280px);color:var(--text)}.app{max-width:1440px;margin:0 auto;padding:24px}.hero{background:linear-gradient(135deg,var(--red2),var(--red));color:#fff;border-radius:24px;padding:28px 32px;box-shadow:var(--shadow);position:relative;overflow:hidden}.hero:after{content:"";position:absolute;right:-80px;top:-80px;width:260px;height:260px;border:36px solid rgba(255,255,255,.08);border-radius:50%}.hero h1{margin:0 0 8px;font-size:32px;letter-spacing:.5px}.hero p{margin:0;color:rgba(255,255,255,.86);line-height:1.65;max-width:980px}.meta-row{display:flex;flex-wrap:wrap;gap:8px;margin-top:18px}.hero-badge{padding:6px 10px;border:1px solid rgba(255,255,255,.35);border-radius:999px;font-size:12px;background:rgba(255,255,255,.08)}.search-panel{margin:18px 0 14px;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:14px;display:grid;grid-template-columns:1fr auto auto;gap:12px;box-shadow:var(--shadow);align-items:center}.search-panel input,.search-panel select{border:1px solid var(--line);border-radius:12px;padding:12px 14px;font-size:14px;outline:none;background:#fff}.search-panel input:focus,.search-panel select:focus{border-color:rgba(139,30,30,.55);box-shadow:0 0 0 3px rgba(139,30,30,.08)}.tab-bar{display:flex;gap:8px;overflow-x:auto;padding:6px 2px 12px;scrollbar-width:thin}.tab-btn{flex:0 0 auto;border:1px solid var(--line);background:#fff;color:var(--text);border-radius:999px;padding:10px 15px;cursor:pointer;font-size:14px;transition:.2s;white-space:nowrap}.tab-btn:hover{border-color:var(--red);color:var(--red)}.tab-btn.active{background:var(--red);color:#fff;border-color:var(--red)}.content{background:rgba(255,255,255,.74);border:1px solid var(--line);border-radius:24px;padding:18px;box-shadow:var(--shadow);min-height:680px}.summary{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(260px,.8fr);gap:16px;margin-bottom:18px}.summary-card{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:18px}.summary-card h2{margin:0 0 8px;font-size:22px}.summary-card p{margin:0;color:var(--muted);line-height:1.75}.stat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}.stat{border:1px solid var(--line);background:linear-gradient(180deg,#fff,#fafafa);border-radius:14px;padding:12px}.stat b{display:block;color:var(--red);font-size:24px}.stat span{color:var(--muted);font-size:12px}.grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}.grid.two{grid-template-columns:repeat(2,minmax(0,1fr))}.card{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:16px;box-shadow:0 4px 14px rgba(25,35,55,.04);transition:.18s;min-height:180px;display:flex;flex-direction:column;gap:10px}.card:hover{transform:translateY(-2px);border-color:rgba(139,30,30,.45);box-shadow:var(--shadow)}.card h3{margin:0;font-size:18px;line-height:1.35}.card .sub,.sub{color:var(--muted);font-size:13px;line-height:1.5}.card p{color:var(--muted);margin:0;line-height:1.7;font-size:14px}.tags{display:flex;flex-wrap:wrap;gap:6px}.tag{display:inline-flex;align-items:center;border-radius:999px;background:var(--tag);color:#3e4652;padding:5px 9px;font-size:12px;max-width:100%}.tag.red{background:rgba(139,30,30,.1);color:var(--red)}.tag.green{background:rgba(47,111,94,.12);color:var(--green)}.tag.blue{background:rgba(36,92,122,.12);color:var(--blue)}.tag.purple{background:rgba(107,78,155,.12);color:var(--purple)}.btn{margin-top:auto;align-self:flex-start;border:1px solid var(--red);color:var(--red);background:#fff;border-radius:999px;padding:8px 12px;cursor:pointer}.btn:hover{background:var(--red);color:#fff}.table-wrap{overflow:auto;border:1px solid var(--line);border-radius:var(--radius);background:#fff}table{width:100%;border-collapse:collapse;font-size:14px}th,td{padding:12px;border-bottom:1px solid var(--line);vertical-align:top;text-align:left}th{background:#fafafa;color:#333;position:sticky;top:0;z-index:1}tr:hover td{background:#fff8f8}.chain{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:16px}.chain-title{display:flex;justify-content:space-between;gap:12px;align-items:center}.steps{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px;align-items:center}.step{padding:8px 10px;border:1px solid var(--line);border-radius:10px;background:#fafafa;font-size:13px}.arrow{color:var(--red);font-weight:bold}.role-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px}.role-card{background:linear-gradient(180deg,#fff,#fbfbfb);border:1pxLine truncated
</style>
</head>
<body>
<div class="app">
<header class="hero" id="hero"></header>
<section class="search-panel">
<input id="globalSearch" placeholder="搜索机构、人物、议题、政策工具、地方议题..." />
<select id="scopeSelect"><option value="current">当前栏目搜索</option><option value="all">全库搜索</option></select>
<select id="quickFilter"><option value="">全部类型/标签</option></select>
</section>
<nav class="tab-bar" id="tabBar"></nav>
<main class="content"><section id="tabSummary"></section><section id="tabContent"></section></main>
</div>
<div id="detailModal" class="modal hidden"><div class="modal-content"><div class="modal-head"><div><h2 id="modalTitle">详情</h2><div id="modalSubtitle" style="opacity:.85;margin-top:6px;"></div></div><button class="modal-close" onclick="closeModal()">关闭</button></div><div class="modal-body" id="modalBody"></div></div></div>
<script>
const DATA = {"meta": {"title": "美国涉华决策咨询群体专题库", "subtitle": "机构、人物、资金、议题联盟、国家安全化、涉台政策想象、媒体传播与地方嵌入综合展示", "version": "v1.0", "language": "zh-CN", "lastUpdated": "2026-06-24", "coreJudgment": "美国涉华决策咨询群体不是统一指挥的单一集团,而是围绕台湾、科技、供应链、人权、军事安全、地方治理等议题形成的半制度化议题联盟生态。", "dataPrinciples": ["仅使用公开来源研究框架和可核验字段,不纳入个人隐私数据。", "资金关联不等于政策操控,需要结合公开披露、报告内容、听证记录和政策采纳路径交叉判断。", "避免简单使用“亲华/反华”二分标签,改用强竞争、克制、商业稳定、技术安全、人权优先、二轨交流等功能性标签。"], "dataScope": ["国会与准官方机构", "主流战略智库", "强硬派与保守派倡议机构", "克制派与外交派机构", "技术政策机构", "产业协会与商业组织", "人权与价值观组织", "二轨交流机构", "媒体传播节点", "地方政策网络"]}, "tabs": [{"id": "overview", "name": "总体生态", "description": "展示群体边界、生态分层、核心判断和总体运行机制。"}, {"id": "institutions", "name": "机构资料库", "description": "展示核心机构分类、职能、议题、政策倾向和影响路径。"}, {"id": "persons", "name": "人物与旋转门", "description": "展示核心人物、公开履历、机构流动和议题专长。"}, {"id": "funding", "name": "资金利益链", "description": "展示资金类型、产业关联、政府合同、基金会和议题关系。"}, {"id": "alliances", "name": "议题联盟", "description": "展示不同涉华议题上的主推联盟、制衡力量和政策工具。"}, {"id": "securitization", "name": "安全化机制", "description": "展示普通议题如何被转化为国家安全议题。"}, {"id": "taiwan", "name": "涉台政策想象", "description": "展示台湾在美国政策咨询群体中的八重角色。"}, {"id": "policyTools", "name": "政策工具", "description": "展示听证、报告、法案、行政规则、制裁、出口管制等制度化路径。"}, {"id": "media", "name": "媒体传播", "description": "展示智库报告、国会听证、媒体报道和社交平台之间的传播链。"}, {"id": "opinion", "name": "民意反应", "description": "展示美国公众、党派、年龄、企业、亚裔社群等不同群体反应。"}, {"id": "local", "name": "地方嵌入", "description": "展示涉华议题如何进入州议会、农地、大学、采购、港口和养老金。"}, {"id": "trends", "name": "危机与趋势", "description": "展示危机阶段作用、未来十年趋势和长期演化方向。"}], "overview": {"coreJudgment": "美国涉华决策咨询群体不是统一集团,而是由国会机构、准官方委员会、战略智库、保守派倡议网络、克制派智库、技术政策机构、产业协会、人权组织、二轨交流平台、媒体节点和地方政策网络共同构成的复杂生态。", "definition": {"broad": "通过报告、听证、证词、简报、媒体评论、产业游说、二轨交流、地方倡议等方式影响美国对华政策的机构与人物网络。", "narrow": "持续生产涉华政策知识并对国会、行政部门、产业界、媒体或地方政府具有可验证影响力的机构、专家和利益网络。"}, "inclusionCriteria": ["涉华议题持续性", "政策接口清晰", "公开输出稳定", "影响对象明确", "来源可验证", "议题代表性较强", "网络连接性较高"], "exclusionCriteria": ["普通社交媒体用户", "偶发评论者", "无公开资料私人顾问", "阴谋论型自媒体", "个人隐私数据"], "ecosystemLayers": [{"name": "国会与准官方政策知识层", "representativeEntities": ["USCC", "CECC", "CRS", "众议院中共问题特设委员会"], "functions": ["议题设置", "年度报告", "国会听证", "政策建议"], "influenceTargets": ["国会", "行政部门", "媒体", "政策圈"], "summary": "最接近正式政策流程,能够把涉华议题转化为听证、报告、建议和立法语言。"}, {"name": "主流战略智库层", "representativeEntities": ["CSIS", "RAND", "CNAS", "Brookings", "CFR", "Carnegie", "Stimson"], "functions": ["战略研究", "政策分析", "人才储备", "媒体解释"], "influenceTargets": ["政府", "国会", "盟友", "公众"], "summary": "承担政策知识生产、概念生产和专家解释功能,是涉华战略讨论的核心区。"}, {"name": "强硬派与保守派倡议层", "representativeEntities": ["Heritage", "Hudson", "AEI", "Hoover", "FDD", "Project 2049"], "functions": ["强硬政策倡议", "制裁", "脱钩", "军事威慑", "地方反制"], "influenceTargets": ["共和党网络", "州政府", "保守派媒体", "国会"], "summarLine truncated
let currentTab = 'overview', keyword = '', quickFilter = '';
const dataMap = {institutions:'institutions',persons:'persons',funding:'fundingChains',alliances:'issueAlliances',securitization:'securitizationCases',taiwan:'taiwanPolicyImaginations',policyTools:'policyTools',media:'mediaPropagation',opinion:'publicOpinion',local:'localEmbedding'};
function arr(v){return Array.isArray(v)?v:(v?[v]:[])}
function escapeHtml(str){return String(str??'').replace(/[&<>"']/g,s=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[s]))}
function tagClass(t){const s=String(t); if(s.includes('强')||s.includes('安全')||s.includes('威慑')||s.includes('制裁'))return'red'; if(s.includes('克制')||s.includes('稳定')||s.includes('交流')||s.includes('外交'))return'green'; if(s.includes('技术')||s.includes('AI')||s.includes('芯片')||s.includes('数据'))return'blue'; if(s.includes('人权')||s.includes('民主')||s.includes('价值'))return'purple'; return''}
function tags(list,limit=8){return `<div class="tags">${arr(list).slice(0,limit).map(x=>`<span class="tag ${tagClass(x)}">${escapeHtml(x)}</span>`).join('')}</div>`}
function includesKeyword(item){if(!keyword)return true; return JSON.stringify(item).toLowerCase().includes(keyword.toLowerCase())}
function matchesFilter(item){return !quickFilter || JSON.stringify(item).includes(quickFilter)}
function filterList(list){return list.filter(x=>includesKeyword(x)&&matchesFilter(x))}
function allItems(){let groups=['institutions','persons','fundingChains','issueAlliances','securitizationCases','taiwanPolicyImaginations','policyTools','mediaPropagation','publicOpinion','localEmbedding']; let all=[]; groups.forEach(g=>DATA[g].forEach(x=>all.push(x))); DATA.crisisAndTrends.futureTrends.forEach(x=>all.push(x)); return all}
function findItem(id){return allItems().find(x=>x.id===id)}
function titleOf(x){return x.name||x.issue||x.topic||x.role||x.group||x.trend||x.originalIssue||'详情'}
function init(){renderHero();renderTabs();renderQuickFilterOptions();document.getElementById('globalSearch').addEventListener('input',e=>{keyword=e.target.value.trim();renderTab()});document.getElementById('scopeSelect').addEventListener('change',renderTab);document.getElementById('quickFilter').addEventListener('change',e=>{quickFilter=e.target.value;renderTab()});renderTab()}
function renderHero(){const m=DATA.meta;document.getElementById('hero').innerHTML=`<h1>${m.title}</h1><p>${m.subtitle}</p><div class="meta-row"><span class="hero-badge">版本:${m.version}</span><span class="hero-badge">更新时间:${m.lastUpdated}</span><span class="hero-badge">数据范围:${m.dataScope.length} 类主体</span><span class="hero-badge">核心判断:半制度化议题联盟生态</span></div>`}
function renderTabs(){document.getElementById('tabBar').innerHTML=DATA.tabs.map(t=>`<button class="tab-btn ${t.id===currentTab?'active':''}" onclick="switchTab('${t.id}')">${t.name}</button>`).join('')}
function switchTab(id){currentTab=id;renderTabs();renderQuickFilterOptions();renderTab()}
function renderQuickFilterOptions(){const select=document.getElementById('quickFilter'); const key=dataMap[currentTab]; let list=key?DATA[key]:(currentTab==='trends'?DATA.crisisAndTrends.futureTrends:[]); const opts=new Set(); list.forEach(item=>{['type','subType','priority','securityLevel','localLevel','rotationStrength','status'].forEach(k=>item[k]&&opts.add(item[k])); arr(item.policyOrientation).forEach(x=>opts.add(x)); arr(item.personTypes).forEach(x=>opts.add(x));}); select.innerHTML='<option value="">全部类型/标签</option>'+[...opts].sort().map(o=>`<option value="${escapeHtml(o)}">${escapeHtml(o)}</option>`).join(''); quickFilter=''}
function renderSummary(){const t=DATA.tabs.find(x=>x.id===currentTab); const stat=Object.entries(DATA.statistics).slice(0,6).map(([k,v])=>`<div class="stat"><b>${v}</b><span>${k}</span></div>`).join(''); document.getElementById('tabSummary').innerHTML=`<div class="summary"><div class="summary-card"><h2>${t.name}</h2><p>${t.description}</p></div><div class="summary-card"><div class="stat-grid">${stat}</div></div></div>`}
function renderTab(){renderSummary(); if(document.getElementById('scopeSelect').value==='all'&&keyword){renderGlobalResults();return} if(currentTab==='overview')renderOverview(); else if(currentTab==='institutions')renderInstitutions(); else if(currentTab==='persons')renderPersons(); else if(currentTab==='funding')renderFunding(); else if(currentTab==='alliances')renderAlliances(); else if(currentTab==='securitization')renderSecuritization(); else if(currentTab==='taiwan')renderTaiwan(); else if(currentTab==='policyTools')renderPolicyTools(); else if(currentTab==='media')renderMedia(); else if(currentTab==='opinion')renderOpinion(); else if(currentTab==='local')renderLocal(); else if(currentTab==='trends')renderTrends()}
function renderOverview(){const o=DATA.overview; const layers=filterList(o.ecosystemLayers); document.getElementById('tabContent').innerHTML=`<div class="notice">${DATA.meta.dataPrinciples.join(' ')}</div><div class="grid">${layers.map((x,i)=>`<div class="card"><h3>${x.name}</h3><div class="sub">代表主体:${x.representativeEntities.join('、')}</div>${tags(x.functions)}<p>${x.summary}</p><button class="btn" onclick="openLayer(${i})">查看详情</button></div>`).join('')}</div><h2 style="margin:24px 0 12px;">运行机制</h2><div class="grid">${o.mechanisms.map(m=>`<div class="chain"><div class="chain-title"><h3>${m.name}</h3></div><div class="steps">${m.steps.map((s,i)=>`<span class="step">${s}</span>${i<m.steps.length-1?'<span class="arrow">→</span>':''}`).join('')}</div></div>`).join('')}</div>`}
function openLayer(i){openModal('生态层详情',DATA.overview.ecosystemLayers[i])}
function renderInstitutions(){const list=filterList(DATA.institutions); document.getElementById('tabContent').innerHTML=list.length?`<div class="grid">${list.map(x=>`<div class="card"><h3>${x.shortName}|${x.name}</h3><div class="sub">${x.englishName}</div>${tags([x.type,x.subType,x.priority])}${tags(x.policyOrientation)}<p>${x.summary}</p><div class="sub">涉华:${arr(x.chinaIssues).slice(0,5).join('、')}</div><div class="sub">涉台:${arr(x.taiwanIssues).slice(0,4).join('、')}</div><button class="btn" onclick="openById('机构详情','${x.id}')">查看详情</button></div>`).join('')}</div>`:'<div class="empty">没有匹配的机构数据</div>'}
function renderPersons(){const list=filterList(DATA.persons); document.getElementById('tabContent').innerHTML=list.length?`<div class="grid">${list.map(x=>`<div class="card"><h3>${x.name}${x.chineseName?'|'+x.chineseName:''}</h3><div class="sub">${x.currentRole}</div>${tags(x.personTypes)}${tags([x.rotationStrength,...arr(x.policyOrientation)],6)}<p>${x.summary}</p><div class="sub">关联机构:${arr(x.relatedInstitutions).slice(0,5).join('、')}</div><button class="btn" onclick="openById('人物详情','${x.id}')">查看详情</button></div>`).join('')}</div>`:'<div class="empty">没有匹配的人物数据</div>'}
function renderFunding(){const list=filterList(DATA.fundingChains); document.getElementById('tabContent').innerHTML=`<div class="notice">资金关联不等于政策操控。页面仅展示公开研究中可作为线索的资金、项目、机构与议题关系,具体影响需要结合公开披露、报告内容、听证记录和政策采纳路径交叉判断。</div><div class="funding-layout"><div class="funding-legend"><span class="tag red">资金来源</span><span class="tag blue">相关机构</span><span class="tag purple">关联议题</span><span class="tag green">政策输出</span></div>${list.map(x=>`<div class="funding-map-card"><div class="funding-map-head"><div><h3>${x.name}</h3><p class="funding-map-sub">${x.summary}</p></div><span class="tag ${tagClass(x.evidenceStrength)}">证据强度:${x.evidenceStrength}</span></div><div class="funding-topline">${tags([...(arr(x.fundingSources).slice(0,2).map(i=>'资金线索|'+i)),...(arr(x.relatedInstitutions).slice(0,2).map(i=>'机构节点|'+i)),...(arr(x.relatedIssues).slice(0,2).map(i=>'议题节点|'+i))],6)}</div><div class="funding-graph"><div class="funding-col col-source"><div class="funding-col-title"><span>资金来源</span><span class="funding-col-index">01</span></div><div class="funding-node-list">${arr(x.fundingSources).map(i=>`<span class="funding-node source">${i}</span>`).join('')}</div></div><div class="funding-link"><span>→</span></div><div class="funding-col col-inst"><div class="funding-col-title"><span>相关机构</span><span class="funding-col-index">02</span></div><div class="funding-node-list">${arr(x.relatedInstitutions).map(i=>`<span class="funding-node inst">${i}</span>`).join('')}</div></div><div class="funding-link"><span>→</span></div><div class="funding-col col-issue"><div class="funding-col-title"><span>关联议题</span><span class="funding-col-index">03</span></div><div class="funding-node-list">${arr(x.relatedIssues).map(i=>`<span class="funding-node issue">${i}</span>`).join('')}</div></div><div class="funding-link"><span>→</span></div><div class="funding-col col-output"><div class="funding-col-title"><span>政策输出</span><span class="funding-col-index">04</span></div><div class="funding-node-list">${arr(x.policyOutputs).map(i=>`<span class="funding-node output">${i}</span>`).join('')}</div></div></div><div class="funding-note"><b>分析提示:</b>${x.riskNotes}</div><div class="funding-actions"><button class="btn" onclick="openById('资金链详情','${x.id}')">查看详情</button></div></div>`).join('')}</div>`}
function renderAlliances(){const list=filterList(DATA.issueAlliances); document.getElementById('tabContent').innerHTML=`<div class="table-wrap"><table><thead><tr><th>议题</th><th>主推联盟</th><th>制衡联盟</th><th>代表机构</th><th>政策工具</th><th>分歧轴</th><th>详情</th></tr></thead><tbody>${list.map(x=>`<tr><td><b>${x.issue}</b><br><span class="sub">${x.summary}</span></td><td>${tags(x.mainAlliance)}</td><td>${tags(x.counterAlliance)}</td><td>${arr(x.representativeInstitutions).join('、')}</td><td>${tags(x.policyTools)}</td><td>${arr(x.disputeAxes).join('<br>')}</td><td><button class="btn" onclick="openById('议题联盟详情','${x.id}')">查看</button></td></tr>`).join('')}</tbody></table></div>`}
function renderSecuritization(){const list=filterList(DATA.securitizationCases); document.getElementById('tabContent').innerHTML=`<div class="grid two">${list.map(x=>`<div class="chain"><div class="chain-title"><h3>${x.originalIssue} → ${x.securitizedIssue}</h3><span class="tag red">${x.securityLevel}</span></div><p style="color:var(--muted);line-height:1.7;">${x.summary}</p><div class="steps">${arr(x.steps).map((s,i)=>`<span class="step">${s}</span>${i<x.steps.length-1?'<span class="arrow">→</span>':''}`).join('')}</div><button class="btn" onclick="openById('安全化案例详情','${x.id}')">查看详情</button></div>`).join('')}</div>`}
function renderTaiwan(){const list=filterList(DATA.taiwanPolicyImaginations); document.getElementById('tabContent').innerHTML=`<div class="role-grid">${list.map(x=>`<div class="role-card" onclick="openById('涉台角色详情','${x.id}')"><h3>${x.role}</h3><p style="color:var(--muted);line-height:1.7;">${x.meaning}</p>${tags(x.policyImplications,4)}<p style="margin-top:10px;color:var(--muted);">${x.summary}</p></div>`).join('')}</div>`}
function renderPolicyTools(){const list=filterList(DATA.policyTools); document.getElementById('tabContent').innerHTML=`<div class="grid">${list.map(x=>`<div class="card"><h3>${x.name}</h3>${tags([x.type])}${tags(x.applicableIssues,5)}<p>${x.summary}</p><div class="sub">路径:${arr(x.institutionalPath).join(' → ')}</div><button class="btn" onclick="openById('政策工具详情','${x.id}')">查看详情</button></div>`).join('')}</div>`}
function renderMedia(){const list=filterList(DATA.mediaPropagation); document.getElementById('tabContent').innerHTML=`<div class="grid two">${list.map(x=>`<div class="chain"><div class="chain-title"><h3>${x.topic}</h3></div><p style="color:var(--muted);line-height:1.7;">${x.summary}</p><div class="steps"><span class="step">${x.sourceStage}</span><span class="arrow">→</span><span class="step">媒体/平台</span><span class="arrow">→</span><span class="step">公众认知</span><span class="arrow">→</span><span class="step">政策反馈</span></div>${tags(x.commonFrames,6)}<button class="btn" onclick="openById('传播议题详情','${x.id}')">查看详情</button></div>`).join('')}</div>`}
function renderOpinion(){const list=filterList(DATA.publicOpinion); document.getElementById('tabContent').innerHTML=`<div class="grid">${list.map(x=>`<div class="card"><h3>${x.group}</h3><p>${x.attitude}</p>${tags(x.relatedIssues,6)}<div class="sub">可能反应:${arr(x.potentialReaction).join(';')}</div><button class="btn" onclick="openById('群体反应详情','${x.id}')">查看详情</button></div>`).join('')}</div>`}
function renderLocal(){const list=filterList(DATA.localEmbedding); document.getElementById('tabContent').innerHTML=`<div class="grid">${list.map(x=>`<div class="card"><h3>${x.issue}</h3>${tags([x.localLevel,x.status])}${tags(x.securityFrame,4)}<p>${x.summary}</p><div class="sub">政策工具:${arr(x.policyTools).join('、')}</div><button class="btn" onclick="openById('地方嵌入详情','${x.id}')">查看详情</button></div>`).join('')}</div>`}
function renderTrends(){const stages=DATA.crisisAndTrends.crisisStages.filter(x=>includesKeyword(x)&&matchesFilter(x)); const trends=DATA.crisisAndTrends.futureTrends.filter(x=>includesKeyword(x)&&matchesFilter(x)); document.getElementById('tabContent').innerHTML=`<h2>危机阶段作用</h2><div class="timeline">${stages.map(x=>`<div class="timeline-item"><h3>${x.stage}</h3><p style="color:var(--muted);line-height:1.7;">${x.summary}</p>${tags(x.consultingGroupRoles)}<div class="sub">代表主体:${arr(x.representativeActors).join('、')}</div></div>`).join('')}</div><h2 style="margin-top:24px;">未来十年趋势</h2><div class="grid">${trends.map(x=>`<div class="card"><h3>${x.trend}</h3><p>${x.description}</p>${tags(x.relatedIssues)}<div class="sub">代表机构:${arr(x.representativeInstitutions).join('、')}</div><button class="btn" onclick="openById('趋势详情','${x.id}')">查看详情</button></div>`).join('')}</div>`}
function renderGlobalResults(){const results=allItems().filter(x=>includesKeyword(x)&&matchesFilter(x)); document.getElementById('tabContent').innerHTML=`<div class="notice">全库搜索结果:${results.length} 条。点击卡片查看二级详情。</div><div class="grid">${results.map(x=>`<div class="card"><h3>${titleOf(x)}</h3>${tags([typeLabel(x)])}<p>${x.summary||x.description||x.attitude||''}</p><button class="btn" onclick="openById('${typeLabel(x)}详情','${x.id}')">查看详情</button></div>`).join('')||'<div class="empty">没有匹配结果</div>'}</div>`}
function typeLabel(x){if(DATA.institutions.includes(x))return'机构'; if(DATA.persons.includes(x))return'人物'; if(DATA.fundingChains.includes(x))return'资金链'; if(DATA.issueAlliances.includes(x))return'议题联盟'; if(DATA.securitizationCases.includes(x))return'安全化案例'; if(DATA.taiwanPolicyImaginations.includes(x))return'涉台角色'; if(DATA.policyTools.includes(x))return'政策工具'; if(DATA.mediaPropagation.includes(x))return'媒体传播'; if(DATA.publicOpinion.includes(x))return'民意反应'; if(DATA.localEmbedding.includes(x))return'地方嵌入'; return'趋势'}
function openById(kind,id){const item=findItem(id); if(item)openModal(kind,item)}
function openModal(title,item){document.getElementById('modalTitle').textContent=title+'|'+titleOf(item); document.getElementById('modalSubtitle').textContent=item.summary||item.description||item.attitude||''; const skip=new Set(['id','summary']); const body=[]; for(const [k,v] of Object.entries(item)){if(skip.has(k))continue; if(k==='careerPath'&&Array.isArray(v)){body.push(`<div class="detail-section"><h4>公开履历 / 旋转门路径</h4><div class="timeline">${v.map(c=>`<div class="timeline-item"><b>${escapeHtml(c.period)}</b>|${escapeHtml(c.institution)}|${escapeHtml(c.role)}<br><span class="sub">${escapeHtml(c.sector)}</span></div>`).join('')}</div></div>`)} else if(Array.isArray(v)){body.push(`<div class="detail-section"><h4>${fieldName(k)}</h4>${tags(v,80)}</div>`)} else if(typeof v==='object'&&v){body.push(`<div class="detail-section"><h4>${fieldName(k)}</h4><pre style="white-space:pre-wrap;line-height:1.6;background:#fafafa;border:1px solid var(--line);border-radius:12px;padding:12px;">${escapeHtml(JSON.stringify(v,null,2))}</pre></div>`)} else {body.push(`<div class="detail-section"><div class="kv"><div class="k">${fieldName(k)}</div><div>${escapeHtml(v)}</div></div></div>`)}} document.getElementById('modalBody').innerHTML=body.join(''); document.getElementById('detailModal').classList.remove('hidden')}
function closeModal(){document.getElementById('detailModal').classList.add('hidden')}
function fieldName(k){const map={name:'名称',englishName:'英文名称',shortName:'简称',type:'类型',subType:'子类型',policyOrientation:'政策倾向',chinaIssues:'涉华议题',taiwanIssues:'涉台议题',mainOutputs:'主要输出',influenceTargets:'影响对象',priority:'优先级',currentInstitution:'当前机构',currentRole:'当前职务',personTypes:'人物类型',careerPath:'公开履历',relatedInstitutions:'关联机构',influenceChannels:'影响渠道',rotationStrength:'旋转门强度',fundingSources:'资金来源',relatedIssues:'关联议题',policyOutputs:'政策输出',evidenceStrength:'证据强度',riskNotes:'风险提示',mainAlliance:'主推联盟',counterAlliance:'制衡联盟',representativeInstitutions:'代表机构',representativePersons:'代表人物',policyTools:'政策工具',disputeAxes:'分歧轴',originalIssue:'原始议题',securitizedIssue:'安全化后议题',steps:'过程链条',keyActors:'关键行为体',securityLevel:'安全化程度',role:'角色',meaning:'含义',representativeGroups:'代表群体',policyImplications:'政策含义',counterViews:'制衡观点',mainActors:'主要行为体',applicableIssues:'适用议题',institutionalPath:'制度化路径',policyEffects:'政策效果',topic:'主题',sourceStage:'传播起点',sourceActors:'源头行为体',amplificationChannels:'放大渠道',commonFrames:'常见框架',targetAudiences:'目标受众',feedbackToPolicy:'政策反馈',group:'群体',attitude:'态度',potentialReaction:'可能反应',balancingFactors:'制衡因素',localLevel:'地方层级',securityFrame:'安全化框架',counterActors:'反向制衡',controversies:'争议点',status:'状态',trend:'趋势',description:'说明'}; return map[k]||k}
document.getElementById('detailModal').addEventListener('click',e=>{if(e.target.id==='detailModal')closeModal()}); init();
</script>
</body>
</html>