From f2978c9b66c11accc8b917288ed21f4096c2875b Mon Sep 17 00:00:00 2001 From: empty Date: Tue, 30 Dec 2025 13:50:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(web):=20=E9=80=82=E9=85=8D=E8=A1=8C?= =?UTF-8?q?=E5=8A=A8=E7=82=B9=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 居民卡片显示行动点(AP 圆点指示器) - 添加行动反馈 Toast 提示(成功/失败) - 3 秒后自动消失的反馈动画 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- web/index.html | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/web/index.html b/web/index.html index 38dcd50..305d272 100644 --- a/web/index.html +++ b/web/index.html @@ -86,6 +86,20 @@ .emotion-calm { background: #1e3a5f; color: #93c5fd; } .agent-info { font-size: 13px; color: #a1a1aa; } + /* 行动点 */ + .agent-ap { display: flex; align-items: center; gap: 4px; margin-top: 6px; } + .ap-dots { display: flex; gap: 3px; } + .ap-dot { width: 8px; height: 8px; border-radius: 50%; background: #3f3f46; } + .ap-dot.filled { background: #60a5fa; } + .ap-label { font-size: 11px; color: #71717a; } + + /* 行动反馈提示 */ + #action-feedback { position: fixed; bottom: 20px; right: 20px; z-index: 100; } + .feedback-toast { padding: 10px 16px; border-radius: 8px; margin-top: 8px; font-size: 13px; animation: fadeIn 0.3s ease; } + .feedback-toast.success { background: #166534; color: #86efac; border: 1px solid #22c55e; } + .feedback-toast.fail { background: #7f1d1d; color: #fca5a5; border: 1px solid #ef4444; } + @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } + /* 行动日志 */ .actions-list { max-height: 300px; overflow-y: auto; } .action-item { padding: 8px; background: #27272a; border-radius: 6px; margin-bottom: 6px; font-size: 13px; } @@ -192,6 +206,9 @@
+ + +
世界状态
@@ -270,6 +287,21 @@ const weatherMap = { sunny: '☀️', rainy: '🌧️' }; const actionHistory = []; + // 显示行动反馈提示 + function showActionFeedbacks(feedbacks) { + const container = document.getElementById('action-feedback'); + feedbacks.forEach(fb => { + if (!fb.user) return; + const cls = fb.success ? 'success' : 'fail'; + const icon = fb.success ? '✓' : '✗'; + const toast = document.createElement('div'); + toast.className = `feedback-toast ${cls}`; + toast.textContent = `${icon} ${fb.user}: ${fb.reason} (AP: ${fb.remaining_ap})`; + container.appendChild(toast); + setTimeout(() => toast.remove(), 3000); + }); + } + // 渲染技能列表 function renderSkills(skills, names) { return Object.entries(skills).map(([id, s]) => { @@ -284,13 +316,18 @@ } function updateUI(data) { - const { world_state, actions, global_event, triggered_faction_event, story_event } = data; + const { world_state, actions, global_event, triggered_faction_event, story_event, action_feedbacks } = data; // 世界状态 document.getElementById('tick').textContent = world_state.tick; document.getElementById('weather').textContent = weatherMap[world_state.weather] || world_state.weather; document.getElementById('mood').textContent = world_state.town_mood; + // 行动反馈提示 + if (action_feedbacks && action_feedbacks.length > 0) { + showActionFeedbacks(action_feedbacks); + } + // ① 能量条 if (world_state.global_meter) { const meter = world_state.global_meter; @@ -412,12 +449,23 @@ const agentsEl = document.getElementById('agents'); agentsEl.innerHTML = ''; for (const [id, agent] of Object.entries(world_state.agents)) { + const ap = agent.action_points || 0; + const maxAp = agent.max_action_points || 3; + const apDots = Array(maxAp).fill(0).map((_, i) => + `` + ).join(''); + agentsEl.innerHTML += `
${id} ${agent.emotion}
+
+ AP: +
${apDots}
+ ${ap}/${maxAp} +
记忆: ${agent.memory.slice(-2).join(' | ') || '-'}
`; }