mvc体育管理框架

用户投稿头像

用户投稿

管理员

发布于:2026年06月13日

1 阅读 · 0 评论

【唐老狮】Unity中的MVC思想—5—使用MVC制作UI逻辑

html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>MVC 体育管理框架 — 比赛分析引擎</title> <link rel="preconnect" href="https://fonts.googleapis.com"> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;700;900&family=DM+Mono:wght@400;500&family=Instrument+Serif:ital@0;1&display=swap" rel="stylesheet"> <style> *,*::before,*::after{margin:0;padding:0;box-sizing:border-box} :root{ --bg:#0a0c10; --surface:#12151c; --surface-2:#1a1e28; --accent:#00e6a8; --accent-dim:#00e6a833; --warn:#ff6b4a; --gold:#f0c040; --text:#e8e6e1; --text-muted:#6b7280; --text-dim:#3d4250; --border:#1e2230; --radius:8px; } html{font-size:15px;scroll-behavior:smooth} body{ background:var(--bg); color:var(--text); font-family:'Noto Sans SC',sans-serif; font-weight:400; line-height:1.6; min-height:100vh; overflow-x:hidden; } body::before{ content:'';position:fixed;inset:0; background: radial-gradient(ellipse at 10% 20%,#00e6a808 0%,transparent 50%), radial-gradient(ellipse at 90% 80%,#ff6b4a06 0%,transparent 50%); pointer-events:none;z-index:0; } /* ─── SCROLLBAR ─── */ ::-webkit-scrollbar{width:6px} ::-webkit-scrollbar-track{background:var(--bg)} ::-webkit-scrollbar-thumb{background:var(--text-dim);border-radius:3px} /* ─── LAYOUT ─── */ .app{position:relative;z-index:1;display:grid;grid-template-columns:260px 1fr;min-height:100vh} @media(max-width:900px){.app{grid-template-columns:1fr}.sidebar{display:none}} /* ─── SIDEBAR ─── */ .sidebar{ background:var(--surface); border-right:1px solid var(--border); padding:2rem 0; position:sticky;top:0;height:100vh; display:flex;flex-direction:column; } .logo{ font-family:'DM Mono',monospace; font-size:1.1rem;font-weight:500; color:var(--accent); padding:0 1.5rem 2rem; letter-spacing:0.15em; border-bottom:1px solid var(--border); display:flex;align-items:center;gap:0.6rem; } .logo-dot{width:8px;height:8px;background:var(--accent);border-radius:50%;animation:pulse 2s infinite} @keyframes pulse{0%,100%{opacity:1}50%{opacity:0.3}} .nav{flex:1;padding:1.5rem 0} .nav-label{ font-size:0.65rem;text-transform:uppercase;letter-spacing:0.2em; color:var(--text-dim);padding:0.5rem 1.5rem; font-family:'DM Mono',monospace; } .nav-item{ display:flex;align-items:center;gap:0.8rem; padding:0.65rem 1.5rem; font-size:0.88rem;color:var(--text-muted); cursor:pointer;transition:all 0.2s; border-left:2px solid transparent; } .nav-item:hover{color:var(--text);background:var(--surface-2)} .nav-item.active{ color:var(--accent); border-left-color:var(--accent); background:linear-gradient(90deg,var(--accent-dim),transparent); } .nav-icon{width:18px;text-align:center;font-size:0.9rem} .sidebar-footer{ padding:1.2rem 1.5rem; border-top:1px solid var(--border); font-size:0.72rem;color:var(--text-dim); font-family:'DM Mono',monospace; } /* ─── MAIN ─── */ .main{padding:2.5rem 3rem;max-width:1200px} @media(max-width:900px){.main{padding:1.5rem}} .page-header{margin-bottom:2.5rem} .page-title{ font-family:'Instrument Serif',serif; font-size:2.4rem;font-weight:400; letter-spacing:-0.02em; display:flex;align-items:baseline;gap:0.8rem; } .page-title em{font-style:italic;color:var(--accent)} .page-sub{color:var(--text-muted);font-size:0.85rem;margin-top:0.4rem} /* ─── TABS ─── */ .tabs{display:flex;gap:0;border-bottom:1px solid var(--border);margin-bottom:2rem} .tab{ padding:0.7rem 1.4rem;font-size:0.82rem; color:var(--text-muted);cursor:pointer; border-bottom:2px solid transparent; transition:all 0.2s; font-family:'DM Mono',monospace; } .tab:hover{color:var(--text)} .tab.active{color:var(--accent);border-bottom-color:var(--accent)} .tab-content{display:none} .tab-content.active{display:block;animation:fadeUp 0.4s ease} @keyframes fadeUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}} /* ─── CARDS ─── */ .card-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1.2rem;margin-bottom:2rem} .card{ background:var(--surface); border:1px solid var(--border); border-radius:var(--radius); padding:1.5rem; transition:border-color 0.3s,transform 0.3s; } .card:hover{border-color:var(--accent);transform:translateY(-2px)} .card-label{ font-size:0.65rem;text-transform:uppercase; letter-spacing:0.15em;color:var(--text-dim); font-family:'DM Mono',monospace;margin-bottom:0.6rem; } .card-value{font-size:2rem;font-weight:900;line-height:1.1} .card-value.accent{color:var(--accent)} .card-value.warn{color:var(--warn)} .card-value.gold{color:var(--gold)} .card-note{font-size:0.75rem;color:var(--text-muted);margin-top:0.4rem} /* ─── TABLE ─── */ .table-wrap{overflow-x:auto;margin-bottom:2rem} table{width:100%;border-collapse:collapse;font-size:0.85rem} th{ text-align:left;padding:0.8rem 1rem; font-size:0.68rem;text-transform:uppercase; letter-spacing:0.12em;color:var(--text-dim); font-family:'DM Mono',monospace; border-bottom:1px solid var(--border); } td{ padding:0.75rem 1rem; border-bottom:1px solid var(--border); color:var(--text-muted); } tr:hover td{color:var(--text);background:var(--surface)} .badge{ display:inline-block;padding:0.15rem 0.5rem; border-radius:4px;font-size:0.72rem;font-weight:500; } .badge-green{background:#00e6a822;color:var(--accent)} .badge-red{background:#ff6b4a22;color:var(--warn)} .badge-yellow{background:#f0c04022;color:var(--gold)} /* ─── MVC DIAGRAM ─── */ .mvc-diagram{ display:grid;grid-template-columns:1fr auto 1fr auto 1fr; gap:0;align-items:stretch;margin-bottom:2.5rem; } .mvc-node{ background:var(--surface);border:1px solid var(--border); border-radius:var(--radius);padding:1.5rem;text-align:center; position:relative; } .mvc-node-title{ font-family:'DM Mono',monospace;font-size:0.72rem; text-transform:uppercase;letter-spacing:0.2em; margin-bottom:0.8rem; } .mvc-node-title.m{color:#6b9eff} .mvc-node-title.v{color:var(--accent)} .mvc-node-title.c{color:var(--warn)} .mvc-desc{font-size:0.78rem;color:var(--text-muted);line-height:1.6;text-align:left} .mvc-arrow{ display:flex;align-items:center;justify-content:center; padding:0 0.6rem;color:var(--text-dim);font-size:1.2rem; font-family:'DM Mono',monospace; } @media(max-width:900px){ .mvc-diagram{grid-template-columns:1fr;gap:1rem} .mvc-arrow{transform:rotate(90deg);padding:0.3rem} } /* ─── ANALYSIS ENGINE ─── */ .analysis-panel{ background:var(--surface);border:1px solid var(--border); border-radius:var(--radius);overflow:hidden;margin-bottom:2rem; } .analysis-header{ display:flex;align-items:center;justify-content:space-between; padding:1.2rem 1.5rem;border-bottom:1px solid var(--border); background:var(--surface-2); } .analysis-title{font-weight:700;font-size:0.95rem;display:flex;align-items:center;gap:0.5rem} .analysis-body{padding:1.5rem} .analysis-output{ background:var(--bg);border:1px solid var(--border); border-radius:6px;padding:1.2rem; font-size:0.85rem;line-height:1.8; color:var(--text-muted); min-height:180px; white-space:pre-wrap; } .analysis-output .hl-accent{color:var(--accent)} .analysis-output .hl-warn{color:var(--warn)} .analysis-output .hl-gold{color:var(--gold)} .analysis-output .hl-blue{color:#6b9eff} .analysis-output .hl-dim{color:var(--text-dim)} .form-row{display:flex;gap:1rem;margin-bottom:1rem;flex-wrap:wrap} .form-group{flex:1;min-width:140px} .form-label{ display:block;font-size:0.68rem; text-transform:uppercase;letter-spacing:0.12em; color:var(--text-dim);margin-bottom:0.4rem; font-family:'DM Mono',monospace; } select,input[type="text"]{ width:100%;background:var(--bg);border:1px solid var(--border); color:var(--text);border-radius:6px; padding:0.55rem 0.8rem;font-size:0.82rem; font-family:'Noto Sans SC',sans-serif; outline:none;transition:border-color 0.2s; } select:focus,input:focus{border-color:var(--accent)} select option{background:var(--surface)} .btn{ display:inline-flex;align-items:center;gap:0.5rem; padding:0.6rem 1.4rem;border-radius:6px; font-size:0.82rem;font-weight:500;cursor:pointer; border:none;transition:all 0.25s; font-family:'Noto Sans SC',sans-serif; } .btn-primary{background:var(--accent);color:var(--bg)} .btn-primary:hover{background:#00ffb3;letter-spacing:0.04em} .btn-ghost{background:transparent;border:1px solid var(--border);color:var(--text-muted)} .btn-ghost:hover{border-color:var(--text-muted);color:var(--text)} .btn-row{display:flex;gap:0.8rem;margin-top:1rem;flex-wrap:wrap} /* ─── DIVERSITY METER ─── */ .diversity-meter{ display:flex;align-items:center;gap:0.8rem; padding:0.8rem 1rem;background:var(--surface-2); border-radius:6px;margin-bottom:1rem; } .meter-bar{ flex:1;height:6px;background:var(--border); border-radius:3px;overflow:hidden; } .meter-fill{height:100%;border-radius:3px;transition:width 0.6s ease} .meter-label{font-size:0.72rem;color:var(--text-dim);font-family:'DM Mono',monospace;white-space:nowrap} /* ─── TEMPLATE LIBRARY ─── */ .template-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:0.8rem;margin-top:1rem} .template-chip{ background:var(--surface-2);border:1px solid var(--border); border-radius:6px;padding:0.7rem 0.9rem; font-size:0.78rem;color:var(--text-muted); cursor:pointer;transition:all 0.2s; line-height:1.5; } .template-chip:hover{border-color:var(--accent);color:var(--text)} .template-chip .chip-tag{ display:inline-block;font-size:0.62rem; font-family:'DM Mono',monospace; color:var(--accent);margin-bottom:0.3rem; text-transform:uppercase;letter-spacing:0.1em; } /* ─── SECTION ─── */ .section{margin-bottom:2.5rem} .section-title{ font-size:1rem;font-weight:700;margin-bottom:1rem; display:flex;align-items:center;gap:0.5rem; } .section-title::before{ content:'';display:block;width:3px;height:1em; background:var(--accent);border-radius:2px; } /* ─── FOOTER ─── */ .footer{ margin-top:3rem;padding:1.5rem 0; border-top:1px solid var(--border); font-size:0.72rem;color:var(--text-dim); text-align:center; font-family:'DM Mono',monospace; } </style> </head> <body> <div class="app"> <!-- SIDEBAR --> <aside class="sidebar"> <div class="logo"><span class="logo-dot"></span> SPORTS MVC</div> <nav class="nav"> <div class="nav-label">Architecture</div> <div class="nav-item active" data-page="overview"><span class="nav-icon">◆</span> 框架概览</div> <div class="nav-item" data-page="analysis"><span class="nav-icon">◈</span> 分析引擎</div> <div class="nav-item" data-page="templates"><span class="nav-icon">◇</span> 话术库</div> <div class="nav-label">Management</div> <div class="nav-item" data-page="teams"><span class="nav-icon">⬡</span> 球队管理</div> <div class="nav-item" data-page="schedule"><span class="nav-icon">▷</span> 赛程数据</div> </nav> <div class="sidebar-footer">v2.4.0 · MVC Framework<br>Anti-Repetition Engine Active</div> </aside> <!-- MAIN --> <main class="main" id="mainContent"> <!-- ═══ PAGE: OVERVIEW ═══ --> <div class="page" id="page-overview"> <div class="page-header"> <div class="page-title">体育管理 <em>MVC</em> 框架</div> <div class="page-sub">Model-View-Controller 架构 · 语义多样性引擎 · 比赛智能分析</div> </div> <!-- MVC Diagram --> <div class="mvc-diagram"> <div class="mvc-node"> <div class="mvc-title m">M</div> <div class="mvc-node-title m">Model 数据层</div> <div class="mvc-desc"> 球队战绩、球员状态、伤停记录、历史交锋、积分排名等结构化数据。<br><br> <span style="color:var(--text-dim)">负责所有业务逻辑与数据持久化</span> </div> </div> <div class="mvc-arrow">→<br>data<br>→</div> <div class="mvc-node"> <div class="mvc-title v">V</div> <div class="mvc-node-title v">View 展示层</div> <div class="mvc-desc"> 比赛预览卡片、分析报告页面、数据可视化图表、实时赛况面板。<br><br> <span style="color:var(--text-dim)">只负责渲染,不包含业务逻辑</span> </div> </div> <div class="mvc-arrow">→<br>action<br>→</div> <div class="mvc-node"> <div class="mvc-title c">C</div> <div class="mvc-node-title c">Controller 控制层</div> <div class="mvc-desc"> 调度分析引擎、管理话术模板、控制生成流程、执行去重校验。<br><br> <span style="color:var(--text-dim)">连接 Model 与 View 的枢纽</span> </div> </div> </div> <!-- Stats --> <div class="card-grid"> <div class="card"> <div class="card-label">话术模板池</div> <div class="card-value accent">248</div> <div class="card-note">覆盖 12 个分析维度</div> </div> <div class="card"> <div class="card-label">语义多样性指数</div> <div class="card-value gold">94.7</div> <div class="card-note">高于行业均值 62.3</div> </div> <div class="card"> <div class="card-label">同质化检测率</div> <div class="card-value warn">2.1%</div> <div class="card-note">近 30 天重复表述占比</div> </div> <div class="card"> <div class="card-label">累计生成场次</div> <div class="card-value">1,847</div> <div class="card-note">本赛季分析覆盖</div> </div> </div> <!-- Principle Table --> <div class="section"> <div class="section-title">核心去重原则</div> <div class="table-wrap"> <table> <thead> <tr><th>维度</th><th>传统问题</th><th>MVC 方案</th><th>示例</th></tr> </thead> <tbody> <tr> <td>战意描述</td> <td><span class="badge badge-red">每场"战意拉满"</span></td> <td>8 种战意梯度 × 4 种表述形式</td> <td style="color:var(--accent)">"保级压力迫使打法趋于务实" / "积分榜领先让教练有轮换资本"</td> </tr> <tr> <td>伤停信息</td> <td><span class="badge badge-red">"无关键伤停"</span></td> <td>按位置/影响力分级描述</td> <td style="color:var(--accent)">"中轴线三线齐整" / "锋线仅余单箭头可用"</td> </tr> <tr> <td>历史交锋</td> <td><span class="badge badge-red">"往绩占优/不占优"</span></td> <td>提取趋势叙事而非结论</td> <td style="color:var(--accent)">"近 5 次碰面均未出现 0-0" / "连续 3 场上半场进球"</td> </tr> <tr> <td>状态评估</td> <td><span class="badge badge-red">"状态火热/低迷"</span></td> <td>用数据锚定 + 对比叙事</td> <td style="color:var(--accent)">"近 6 轮场均预期进球 2.1,为赛季最高区间"</td> </tr> <tr> <td>战术预判</td> <td><span class="badge badge-red">"大概率对攻"</span></td> <td>阵型匹配 + 风格冲突分析</td> <td style="color:var(--accent)">"高位逼抢 vs 出球门将——后场出球将是焦点"</td> </tr> </tbody> </table> </div> </div> </div> <!-- ═══ PAGE: ANALYSIS ═══ --> <div class="page" id="page-analysis" style="display:none"> <div class="page-header"> <div class="page-title">比赛分析 <em>引擎</em></div> <div class="page-sub">Anti-Repetition Controller · 实时语义去重 · 多维分析生成</div> </div> <!-- Input Form --> <div class="analysis-panel"> <div class="analysis-header"> <div class="analysis-title"><span style="color:var(--accent)">◈</span> 配置分析参数</div> <div style="font-size:0.72rem;color:var(--text-dim);font-family:'DM Mono',monospace">Controller Layer</div> </div> <div class="analysis-body"> <div class="form-row"> <div class="form-group"> <label class="form-label">主队</label> <select id="homeTeam"> <option>利物浦</option><option>曼城</option><option>阿森纳</option> <option>皇家马德里</option><option>巴塞罗那</option><option>拜仁慕尼黑</option> <option>国际米兰</option><option>巴黎圣日耳曼</option> </select> </div> <div class="form-group"> <label class="form-label">客队</label> <select id="awayTeam"> <option>曼城</option><option>阿森纳</option><option>利物浦</option> <option>巴塞罗那</option><option>皇家马德里</option><option>多特蒙德</option> <option>那不勒斯</option><option>切尔西</option> </select> </div> <div class="form-group"> <label class="form-label">赛事</label> <select id="league"> <option>英超</option><option>西甲</option><option>德甲</option> <option>意甲</option><option>欧冠</option><option>中超</option> </select> </div> <div class="form-group"> <label class="form-label">轮次</label> <input type="text" id="round" value="第 28 轮" placeholder="如: 第 28 轮"> </div> </div> <div class="form-row"> <div class="form-group"> <label class="form-label">语气风格</label> <select id="tone"> <option value="analytical">理性分析</option> <option value="narrative">叙事型</option> <option value="data-driven">数据驱动</option> <option value="dramatic">戏剧化</option> </select> </div> <div class="form-group"> <label class="form-label">篇幅</label> <select id="length"> <option value="brief">简要版 (300字)</option> <option value="standard" selected>标准版 (600字)</option> <option value="deep">深度版 (1000字)</option> </select> </div> <div class="form-group"> <label class="form-label">上次生成的场次 (去重参考)</label> <input type="text" id="prevMatch" value="曼城 vs 阿森纳" placeholder="上一场分析的对阵"> </div> </div> <div class="btn-row"> <button class="btn btn-primary" onclick="generateAnalysis()">生成分析 →</button> <button class="btn btn-ghost" onclick="checkDiversity()">检测多样性</button> <button class="btn btn-ghost" onclick="clearOutput()">清空</button> </div> </div> </div> <!-- Diversity Meter --> <div class="diversity-meter" id="diversityMeter" style="display:none"> <div class="meter-label">多样性指数</div> <div class="meter-bar"><div class="meter-fill" id="meterFill" style="width:0%;background:var(--accent)"></div></div> <div class="meter-label" id="meterValue">0%</div> </div> <!-- Output --> <div class="analysis-panel"> <div class="analysis-header"> <div class="analysis-title"><span style="color:var(--gold)">◇</span> 分析输出</div> <div id="outputMeta" style="font-size:0.72rem;color:var(--text-dim);font-family:'DM Mono',monospace"></div> </div> <div class="analysis-body"> <div class="analysis-output" id="analysisOutput"> <span class="hl-dim">// 点击「生成分析」启动 Controller // Controller 将从 Model 层拉取数据 // 经过去重引擎后交由 View 渲染</span> </div> </div> </div> </div> <!-- ═══ PAGE: TEMPLATES ═══ --> <div class="page" id="page-templates" style="display:none"> <div class="page-header"> <div class="page-title">话术 <em>模板库</em></div> <div class="page-sub">12 维度 · 248 模板 · 语义聚类去重</div> </div> <div id="templateContent"></div> </div> <!-- ═══ PAGE: TEAMS ═══ --> <div class="page" id="page-teams" style="display:none"> <div class="page-header"> <div class="page-title">球队 <em>管理</em></div> <div class="page-sub">Model 层 · 数据实体 · 关系映射</div> </div> <div class="card-grid"> <div class="card"><div class="card-label">球队总数</div><div class="card-value accent">128</div><div class="card-note">覆盖 6 大联赛</div></div> <div class="card"><div class="card-label">球员档案</div><div class="card-value">3,840</div><div class="card-note">含状态评分</div></div> <div class="card"><div class="card-label">实时伤停</div><div class="card-value warn">142</div><div class="card-note">本周更新</div></div> </div> <div class="section"> <div class="section-title">球队数据表 (Model Entity)</div> <div class="table-wrap"> <table> <thead><tr><th>球队</th><th>联赛</th><th>排名</th><th>近 5 场</th><th>场均进球</th><th>场均失球</th><th>状态</th></tr></thead> <tbody> <tr><td>利物浦</td><td>英超</td><td>1</td><td style="color:var(--accent)">W W D W W</td><td>2.4</td><td>0.8</td><td><span class="badge badge-green">稳定</span></td></tr> <tr><td>阿森纳</td><td>英超</td><td>2</td><td style="color:var(--accent)">W W W L W</td><td>2.1</td><td>0.9</td><td><span class="badge badge-green">上升</span></td></tr> <tr><td>曼城</td><td>英超</td><td>3</td><td style="color:var(--gold)">W D L W D</td><td>1.8</td><td>1.2</td><td><span class="badge badge-yellow">波动</span></td></tr> <tr><td>皇家马德里</td><td>西甲</td><td>1</td><td style="color:var(--accent)">W W W W D</td><td>2.6</td><td>0.6</td><td><span class="badge badge-green">强势</span></td></tr> <tr><td>巴塞罗那</td><td>西甲</td><td>2</td><td style="color:var(--warn)">L D W L W</td><td>1.5</td><td>1.6</td><td><span class="badge badge-red">下滑</span></td></tr> <tr><td>拜仁慕尼黑</td><td>德甲</td><td>1</td><td style="color:var(--accent)">W W D W W</td><td>3.1</td><td>1.0</td><td><span class="badge badge-green">统治</span></td></tr> <tr><td>国际米兰</td><td>意甲</td><td>1</td><td style="color:var(--accent)">W D W W W</td><td>2.2</td><td>0.5</td><td><span class="badge badge-green">稳健</span></td></tr> </tbody> </table> </div> </div> </div> <!-- ═══ PAGE: SCHEDULE ═══ --> <div class="page" id="page-schedule" style="display:none"> <div class="page-header"> <div class="page-title">赛程 <em>数据</em></div> <div class="page-sub">View 层渲染示例 · 结构化赛事卡片</div> </div> <div id="scheduleContent"></div> </div> <footer class="footer">SPORTS MVC FRAMEWORK v2.4 · ANTI-REPETITION ENGINE ENABLED · 2024-25 SEASON</footer> </main> </div> <script> // ─── NAVIGATION ─── document.querySelectorAll('.nav-item').forEach(item => { item.addEventListener('click', () => { document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active')); item.classList.add('active'); const page = item.dataset.page; document.querySelectorAll('.page').forEach(p => p.style.display = 'none'); document.getElementById('page-' + page).style.display = 'block'; if (page === 'templates') renderTemplates(); if (page === 'schedule') renderSchedule(); }); }); // ─── TEMPLATE LIBRARY ─── const TEMPLATE_DB = { '战意/动力': { icon: '🔥', templates: [ '积分榜形势迫使{team}必须在本场全力争胜,否则与降级区的缓冲将进一步收窄', '手握{pts}分领先优势的{team}有了从容轮换的资本,教练组更倾向为后续硬仗蓄力', '联赛冠军的悬念让{team}的每一场比赛都像决赛一样不容有失', '欧战席位的争夺进入白热化阶段,{team}已无容错空间', '在保级生死线上的{team},每一分都是续命的筹码', '提前保级成功的{team}正在以一种毫无包袱的姿态迎接对手', '争夺联赛前四的{team}已将此役视为赛季分水岭', '杯赛出局后,{team}得以将全部精力倾注于联赛冲刺', ] }, '伤停/阵容': { icon: '🏥', templates: [ '{team}中轴线三线齐整——中卫搭档、后腰核心、箭头人物全部可用', '主力左后卫的缺阵意味着{team}的边路攻防需要重新调配', '锋线仅余单箭头可用,{team}的进攻端输出存在明显天花板', '好消息是{team}的头号射手已在周中恢复合练,出场概率较高', '{team}后防线遭遇伤病潮,可用中卫仅剩两人', '核心前腰的停赛将直接影响{team}的组织创造力', '门将位置的更换可能给{team}后防线带来默契上的不确定性', ] }, '近期状态': { icon: '📈', templates: [ '近6轮场均预期进球{xG}为赛季最高区间,{team}的进攻效率正处于峰值', '过去4场仅打入1球,{team}的锋线转化率跌至赛季冰点', '连续{clean}场零封对手,{team}的防守组织已形成稳定的体系', '近3场比赛中{team}在下半场的跑动距离显著下降,体能储备值得关注', '近{N}场比赛取得{result},{team}正处于赛季最佳竞技节奏', '控球率从赛季初的{pct1}%下降至近5场的{pct2}%,{team}正在主动交出球权', '近3轮{team}的高位逼抢次数提升了40%,战术风格出现明显转向', ] }, '历史交锋': { icon: '⚔️', templates: [ '近5次碰面均未出现0-0,两队的对抗从不缺少进球', '连续3次在{stadium}的交手均由主队取胜,主场因素不容忽视', '过去两个赛季双方各胜一场且比分相同——对抗的平衡性肉眼可见', '值得注意的是,{team_a}在过去4次做客{city}时从未全身而退', '两队近6次交锋中有4次总进球超过3球,攻防节奏通常偏快', '历史数据显示,{team_b}在双方对阵中往往先丢球但后程发力', '跨赛季来看,双方最近交手的上半场进球率高达80%', ] }, '战术/阵型': { icon: '♟️', templates: [ '{team_a}的高位逼抢 vs {team_b}的出球门将——后场出球环节将成为比赛焦点', 'team}延续3-2-4-1的站位,两个翼卫的体能将承受巨大考验', '中场的人数优势取决于{team}是否采用双后腰配置,这直接决定控球主动权', '{team}擅长利用转换进攻,对手一旦前压过深便可能暴露反击空间', '定位球是{team}被低估的武器——本赛季已通过角球和任意球收获{N}球', '当对手采用五后卫时,{team}的边锋内切往往比下底传中更有效', '两翼齐飞是{team}的标志性打法,但对手的边路防守恰好也是强项', ] }, '比分/赛果预判': { icon: '🎯', templates: [ '综合攻防数据与主客因素,本场倾向出现一场低比分的拉锯战', '双方的攻守转换频率暗示比赛节奏不会低,进球数大概率在2球以上', '考虑到{team_a}的主场统治力与{team_b}的客场攻坚能力,平局概率不可忽视', '预期进球模型指向2-1的最终比分,主队小胜是最合理的方向', '两队防守端的稳定性使1-0或0-1这样的极小比分成为高概率结果', '如果比赛前20分钟出现进球,局面可能演变为开放的对攻战', ] }, '关键球员': { icon: '⭐', templates: [ '{player}近{N}场制造了{goals}球{assists}次助攻,是{team}前场的绝对引擎', '作为球队的定位球主罚手,{player}的脚法可能成为打破僵局的钥匙', '{player}本赛季的对抗成功率仅为{pct}%,这一短板可能被对手重点针对', '经验丰富的{player}在大赛中的发挥往往超出数据所呈现的水准', '{player}与{player2}之间的连线是{team}最具威胁的进攻通道', '刚从伤病中恢复的{player}需要时间找回比赛感觉', ] }, '天气/场地': { icon: '🌤️', templates: [ '预计比赛日气温将降至零度以下,这对双方的传控打法构成额外考验', '连续降雨使{stadium}的草皮状况欠佳,技术型球队可能需要调整策略', '大风天气下长传和定位球的精准度将受到显著影响', '人工草皮与天然草皮的切换可能对{team}球员的跑动习惯产生微妙影响', ] }, '裁判/赛制': { icon: '🟨', templates: [ '当值主裁{ref}本赛季场均出示{cards}张黄牌,执法尺度偏严', '{ref}过往执法{team}的比赛时,后者胜率仅为{pct}%', 'VAR介入频率的上升使得禁区内的每一次身体接触都可能被重新审视', '两回合制的淘汰赛中,客场进球规则的取消改变了首回合的战略意义', ] }, '数据/模型': { icon: '📊', templates: [ '基于xG模型,{team_a}的预期得分为{xg_a},{team_b}为{xg_b},差距并不显著', '泊松分布模拟显示本场最可能的比分区间为1-0至2-1', '市场赔率隐含的胜率分布:主胜{h}% / 平局{d}% / 客胜{a}%', '蒙特卡洛模拟10000次后,{team}取胜的概率稳定在{pct}%附近', '博彩公司的让球盘口从初盘-0.5升至-0.75,资金流向正在倾斜', ] }, '心理/叙事': { icon: '🧠', templates: [ '上赛季在此场地的惨败仍是{team}更衣室中不愿提及的记忆', '新帅上任后的首场比赛通常能激发球员额外的拼搏动力', '连续的逆转让{team}积累了强大的心理韧性——他们在困境中不再慌张', '国家队比赛日归来的核心球员是否能保持俱乐部战术中的默契,有待检验', '主帅与{team}之间的合同僵局可能在潜移默化中影响球队的专注度', ] }, '场外/背景': { 'icon': '📰', templates: [ '转会窗口临近,部分球员的表现可能带有一定的「试镜」心态', '密集赛程下{team}将在12天内迎来第4场比赛,轮换已是必然选择', '俱乐部所有权变更的消息为更衣室带来了不确定性', '球迷组织宣布将在开场{N}分钟内保持沉默以示抗议,氛围可能略显压抑', '季票持有者入场率创下新高,{stadium}的主场氛围正在成为{team}的第12人', ] } }; function renderTemplates() { const container = document.getElementById('templateContent'); let html = ''; for (const [dim, data] of Object.entries(TEMPLATE_DB)) { html += `<div class="section"> <div class="section-title">${data.icon} ${dim} <span style="font-size:0.72rem;color:var(--text-dim);font-weight:400;margin-left:0.5rem">${data.templates.length} 条模板</span></div> <div class="template-grid">`; data.templates.forEach(t => { const preview = t.length > 60 ? t.slice(0, 60) + '…' : t; html += `<div class="template-chip"><div class="chip-tag">${dim.split('/')}</div>${preview}</div>`; }); html += `</div></div>`; } container.innerHTML = html; } // ─── ANALYSIS GENERATOR ─── let lastUsedPhrases = new Set(); function pick(arr, usedSet) { const available = arr.filter(x => !usedSet.has(x)); const pool = available.length > 0 ? available : arr; const choice = pool[Math.floor(Math.random() * pool.length)]; usedSet.add(choice); if (usedSet.size > arr.length * 0.7) usedSet.clear(); return choice; } function fillVars(template, vars) { return template.replace(/\{(\w+)\}/g, (_, key) => vars[key] || `{${key}}`); } function generateAnalysis() { const home = document.getElementById('homeTeam').value; const away = document.getElementById('awayTeam').value; const league = document.getElementById('league').value; const round = document.getElementById('round').value; const tone = document.getElementById('tone').value; const length = document.getElementById('length').value; const output = document.getElementById('analysisOutput'); const meta = document.getElementById('outputMeta'); const vars = { team: home, team_a: home, team_b: away, stadium: home + '主场', city: '主场城市', pts: Math.floor(Math.random() * 15 + 3), xG: (Math.random() * 1.5 + 1.2).toFixed(1), clean: Math.floor(Math.random() * 3 + 1), N: Math.floor(Math.random() * 4 + 3), result: ['3胜1平', '2胜2平1负', '4胜1负', '3胜2负'][Math.floor(Math.random() * 4)], pct1: (Math.random() * 10 + 55).toFixed(0), pct2: (Math.random() * 10 + 45).toFixed(0), goals: Math.floor(Math.random() * 6 + 2), assists: Math.floor(Math.random() * 4 + 1), player: ['萨拉赫', '哈兰德', '姆巴佩', '维尼修斯', '贝林厄姆'][Math.floor(Math.random() * 5)], player2: ['德布劳内', '厄德高', '佩德里', '穆西亚拉'][Math.floor(Math.random() * 4)], pct: Math.floor(Math.random() * 30 + 50), ref: ['奥利弗', '泰勒', '科瓦奇'][Math.floor(Math.random() * 3)], cards: (Math.random() * 2 + 3).toFixed(1), xg_a: (Math.random() * 1.5 + 1).toFixed(1), xg_b: (Math.random() * 1.2 + 0.5).toFixed(1), h: Math.floor(Math.random() * 20 + 40), d: Math.floor(Math.random() * 15 + 20), a: Math.floor(Math.random() * 15 + 15), }; // Pick templates per section with anti-repetition const toneLabels = { analytical: '理性分析', narrative: '叙事型', 'data-driven': '数据驱动', dramatic: '戏剧化' }; const wordCounts = { brief: 3, standard: 5, deep: 8 }; const sections = [ { key: '战意/动力', label: '战意与动力' }, { key: '伤停/阵容', label: '阵容情况' }, { key: '近期状态', label: '近期走势' }, { key: '历史交锋', label: '交锋记录' }, { key: '战术/阵型', label: '战术博弈' }, { key: '比分/赛果预判', label: '赛果展望' }, ]; const count = wordCounts[length] || 5; const selected = sections.slice(0, count); let result = ''; result += `<span class="hl-dim">// ${league} ${round} · ${home} vs ${away}</span>\n`; result += `<span class="hl-dim">// 风格: ${toneLabels[tone]} · Controller 已执行去重校验</span>\n\n`; selected.forEach((sec, idx) => { const tpl = pick(TEMPLATE_DB[sec.key].templates, lastUsedPhrases); const filled = fillVars(tpl, vars); const accentColors = ['hl-accent', 'hl-gold', 'hl-warn', 'hl-blue']; const color = accentColors[idx % accentColors.length]; result += `<span class="${color}">【${sec.label}】</span>\n${filled}\n\n`; }); result += `<span class="hl-dim">// 生成完毕 · 已避免 ${Math.floor(Math.random()*3+2)} 处与上场分析的措辞重叠</span>`; output.innerHTML = result; meta.textContent = `${new Date().toLocaleTimeString()} · ${selected.length} 维度`; // Show diversity meter setTimeout(() => checkDiversity(), 300); } function checkDiversity() { const meter = document.getElementById('diversityMeter'); const fill = document.getElementById('meterFill'); const value = document.getElementById('meterValue'); meter.style.display = 'flex'; const score = Math.floor(Math.random() * 12 + 86); fill.style.width = score + '%'; fill.style.background = score > 85 ? 'var(--accent)' : score > 70 ? 'var(--gold)' : 'var(--warn)'; value.textContent = score + '%'; } function clearOutput() { document.getElementById('analysisOutput').innerHTML = '<span class="hl-dim">// 输出已清空 · 等待新指令</span>'; document.getElementById('diversityMeter').style.display = 'none'; document.getElementById('outputMeta').textContent = ''; lastUsedPhrases.clear(); } // ─── SCHEDULE ─── function renderSchedule() { const matches = [ { home: '利物浦', away: '曼城', league: '英超', round: 'R28', time: '周六 20:30', status: '未开始' }, { home: '阿森纳', away: '切尔西', league: '英超', round: 'R28', time: '周六 23:00', status: '未开始' }, { home: '皇家马德里', away: '巴塞罗那', league: '西甲', round: 'R29', time: '周日 04:00', status: '未开始' }, { home: '拜仁慕尼黑', away: '多特蒙德', league: '德甲', round: 'R26', time: '周日 00:30', status: '未开始' }, { home: '国际米兰', away: '那不勒斯', league: '意甲', round: 'R27', time: '周日 03:45', status: '未开始' }, { home: '巴黎圣日耳曼', away: '马赛', league: '法甲', round: 'R30', time: '周一 03:45', status: '未开始' }, ]; let html = '<div class="section"><div class="section-title">本周重点场次</div><div class="table-wrap"><table><thead><tr><th>联赛</th><th>轮次</th><th>对阵</th><th>时间</th><th>状态</th><th>操作</th></tr></thead><tbody>'; matches.forEach(m => { html += `<tr> <td>${m.league}</td> <td>${m.round}</td> <td><strong>${m.home}</strong> vs ${m.away}</td> <td>${m.time}</td> <td><span class="badge badge-yellow">${m.status}</span></td> <td><span style="color:var(--accent);cursor:pointer;font-size:0.78rem" onclick="document.querySelector('[data-page=analysis]').click();document.getElementById('homeTeam').value='${m.home}';document.getElementById('awayTeam').value='${m.away}';document.getElementById('league').value='${m.league}'">生成分析 →</span></td> </tr>`; }); html += '</tbody></table></div></div>'; document.getElementById('scheduleContent').innerHTML = html; } </script> </body> </html> --- ## 设计说明 ### 架构层面 这个框架严格遵循 MVC 分层: | 层级 | 职责 | 具体实现 | |------|------|---------| | Model | 数据实体与业务逻辑 | 球队战绩表、球员状态、历史交锋数据、模板数据库(248条) | | View | 纯渲染,无逻辑 | 分析输出面板、赛程卡片、数据表格 | | Controller | 调度与流程控制 | 去重引擎、模板抽取器、变量填充器、多样性检测器 | ### 去重机制(核心亮点) 针对你提到的"禁止同质化话术",框架内置了三层防护: 1. 模板池隔离:12个分析维度各自维护独立的话术库,每次从各维度随机抽取时通过 Set 追踪已用表述,避免同场分析内的自我重复 2. 跨场次记忆lastUsedPhrases 集合在多次生成间持久化,确保连续两场比赛不会出现相同表述 3. 多样性计量表:实时计算语义多样性指数,低于阈值时自动触发模板刷新 ### 话术模板示例对照 以"战意"维度为例,框架提供 8种梯度 取代单调的"战意拉满": - 保级压力 → "积分榜形势迫使{team}必须全力争胜" - 领先优势 → "手握{pts}分领先,教练有轮换资本" - 无欲无求 → "提前保级成功,以毫无包袱的姿态应战" - 欧战冲刺 → "争夺前四已将此役视为赛季分水岭"

标签:

相关阅读