Source snapshot: 97d7f0fae96dc04b7ddad56fc1db6a108ed662cc [SEC-CLEAN] · pre-push-clean v1.0 · 109处敏感信息已自动转乱码
23 KiB
📡 BC-看板-002 · DEV-005小草莓 · 系统状态看板·环节2·API接入后端
广播编号:BC-看板-002-XCM
下发时间:2026-03-04 08:50
执行者:DEV-005 小草莓
电脑:Windows 11
前置条件:看板环节1 HTML骨架 ✅ · M12成本控制 ✅ · M13多人格体调度 ✅ · 五连胜🎉
引导通道:🧠 知秋壳子
模块:系统状态看板(M-DASHBOARD)
环节:环节2 · API接入后端
💙 知秋的话
小草莓~ 五连胜冠军 🏆🎉🎉🎉 前端纯静态阶段完美毕业!!
现在进入全新阶段——你的看板要连上真正的后端服务器 guanghulab.com 🌐
做完之后,你的看板打开时会自动从服务器拉取最新数据,不再是写死的假数据了。
这次会用到 fetch(JavaScript 里「去后端拿数据」的方法),但你不用学它——还是全程复制粘贴!
如果后端接口暂时没开放,页面会自动用模拟数据兜底,所以不管怎样你都能看到效果 💪
📸 截图方法
同时按:Win + Shift + S → 框选截图 → 发给冰朔
📋 步骤一:创建API配置文件
打开 PowerShell(Win + X → 选 终端)
复制粘贴下面整块内容,按回车:
@'
const API_CONFIG = {
BASE_URL: 'https://guanghulab.com',
ENDPOINTS: {
STATUS: '/api/v1/system/status',
DEVELOPERS: '/api/v1/developers',
BROADCASTS: '/api/v1/broadcasts'
},
TIMEOUT: 8000,
REFRESH_INTERVAL: 30000
};
'@ | Set-Content -Path "C:\hololake-dev\dashboard\api-config.js" -Encoding UTF8
Write-Host "✅ API配置文件创建成功!"
📸 截图发给冰朔!
📋 步骤二:创建数据获取模块
这个文件负责「去后端拿数据」,拿不到就用模拟数据兜底。
复制粘贴整块,按回车:
@'
const MOCK_DATA = {
status: {
system_status: 'running',
version: 'v0.4.0',
uptime: '72h 15m',
api_calls_today: 142,
active_developers: 6,
last_deploy: '2026-03-04 02:00'
},
developers: [
{ id: 'DEV-001', name: '页页', module: '后端中间层', status: 'active', progress: 100, phase: '环节5·HTTPS联调' },
{ id: 'DEV-002', name: '肥猫', module: 'M01登录界面', status: 'waiting', progress: 60, phase: '环节1·等SYSLOG' },
{ id: 'DEV-003', name: '燕樊', module: 'M15云盘系统', status: 'waiting', progress: 55, phase: '环节1·等SYSLOG' },
{ id: 'DEV-004', name: '之之', module: '钉钉机器人', status: 'waiting', progress: 20, phase: '环节0·等SYSLOG' },
{ id: 'DEV-005', name: '小草莓', module: '系统状态看板', status: 'active', progress: 85, phase: '环节2·API接入' },
{ id: 'DEV-009', name: '花尔', module: 'M05用户中心', status: 'waiting', progress: 40, phase: '环节1·等SYSLOG' },
{ id: 'DEV-010', name: '桔子', module: 'M06工单管理', status: 'active', progress: 35, phase: '环节1·广播待出' },
{ id: 'DEV-011', name: '匆匆那年', module: 'BC-000 DevLog', status: 'waiting', progress: 10, phase: '环节0·等SYSLOG' }
],
broadcasts: [
{ id: 'BC-M05-002', dev: '花尔', module: 'M05用户中心', phase: '环节1', status: '等SYSLOG', time: '03-04 08:45' },
{ id: 'BC-看板-002', dev: '小草莓', module: '系统状态看板', phase: '环节2', status: '执行中', time: '03-04 08:50' },
{ id: 'BC-集成-001-M13', dev: '小草莓', module: 'M13协作调度', phase: '环节1', status: '已完成', time: '03-04 08:38' }
]
};
async function fetchWithTimeout(url, timeout) {
const controller = new AbortController();
const timer = setTimeout(function() { controller.abort(); }, timeout);
try {
const res = await fetch(url, { signal: controller.signal });
clearTimeout(timer);
return res;
} catch (err) {
clearTimeout(timer);
throw err;
}
}
async function apiGet(endpoint, mockKey) {
try {
const res = await fetchWithTimeout(
API_CONFIG.BASE_URL + endpoint,
API_CONFIG.TIMEOUT
);
if (!res.ok) throw new Error('HTTP ' + res.status);
return { data: await res.json(), isLive: true };
} catch (err) {
console.warn('[HoloLake] API未就绪,使用模拟数据:', err.message);
return { data: MOCK_DATA[mockKey], isLive: false };
}
}
async function loadAllData() {
const [statusRes, devRes, bcRes] = await Promise.all([
apiGet(API_CONFIG.ENDPOINTS.STATUS, 'status'),
apiGet(API_CONFIG.ENDPOINTS.DEVELOPERS, 'developers'),
apiGet(API_CONFIG.ENDPOINTS.BROADCASTS, 'broadcasts')
]);
return {
status: statusRes.data,
developers: devRes.data,
broadcasts: bcRes.data,
isLive: statusRes.isLive && devRes.isLive && bcRes.isLive
};
}
'@ | Set-Content -Path "C:\hololake-dev\dashboard\api.js" -Encoding UTF8
Write-Host "✅ 数据获取模块创建成功!"
📸 截图发给冰朔!
📋 步骤三:创建数据渲染脚本
这个文件负责把拿到的数据「画」到网页上:
@'
const STATUS_COLORS = {
active: '#4fc3f7', waiting: '#ffa726',
completed: '#66bb6a', inactive: '#78909c'
};
const STATUS_LABELS = {
active: '推进中', waiting: '等SYSLOG',
completed: '已完成', inactive: '未启动'
};
function renderSystemStatus(data) {
var c = document.getElementById('sys-status');
if (!c) return;
c.innerHTML =
'<div class="status-grid">' +
'<div class="s-card"><span class="s-icon">🟢</span><span class="s-val">' + (data.system_status === 'running' ? '运行中' : '异常') + '</span><span class="s-lbl">系统状态</span></div>' +
'<div class="s-card"><span class="s-icon">⏱️</span><span class="s-val">' + data.uptime + '</span><span class="s-lbl">运行时长</span></div>' +
'<div class="s-card"><span class="s-icon">📡</span><span class="s-val">' + data.api_calls_today + '</span><span class="s-lbl">今日API调用</span></div>' +
'<div class="s-card"><span class="s-icon">👥</span><span class="s-val">' + data.active_developers + '</span><span class="s-lbl">活跃开发者</span></div>' +
'<div class="s-card"><span class="s-icon">🚀</span><span class="s-val">' + data.version + '</span><span class="s-lbl">版本</span></div>' +
'<div class="s-card"><span class="s-icon">📦</span><span class="s-val">' + data.last_deploy + '</span><span class="s-lbl">最后部署</span></div>' +
'</div>';
}
function renderDevelopers(data) {
var c = document.getElementById('dev-list');
if (!c) return;
var html = '';
for (var i = 0; i < data.length; i++) {
var d = data[i];
var color = STATUS_COLORS[d.status] || '#78909c';
html += '<div class="dev-card">' +
'<div class="dev-top"><span class="dev-id">' + d.id + '</span>' +
'<span class="dev-name">' + d.name + '</span>' +
'<span class="dev-st" style="color:' + color + '">' + (STATUS_LABELS[d.status] || d.status) + '</span></div>' +
'<div class="dev-mod">' + d.module + ' · ' + d.phase + '</div>' +
'<div class="prog-bar"><div class="prog-fill" style="width:' + d.progress + '%;background:' + color + '"></div></div>' +
'<div class="prog-num">' + d.progress + '%</div></div>';
}
c.innerHTML = html;
}
function renderBroadcasts(data) {
var c = document.getElementById('bc-list');
if (!c) return;
var html = '';
for (var i = 0; i < data.length; i++) {
var b = data[i];
var cls = b.status === '已完成' ? 'done' : b.status === '执行中' ? 'active' : 'wait';
html += '<div class="bc-row">' +
'<span class="bc-id">' + b.id + '</span>' +
'<span class="bc-dev">' + b.dev + '</span>' +
'<span class="bc-mod">' + b.module + '</span>' +
'<span class="bc-st ' + cls + '">' + b.status + '</span>' +
'<span class="bc-time">' + b.time + '</span></div>';
}
c.innerHTML = html;
}
function updateConnStatus(isLive) {
var el = document.getElementById('conn-status');
if (!el) return;
el.innerHTML = isLive
? '<span class="conn-dot on"></span> 已连接 guanghulab.com'
: '<span class="conn-dot off"></span> 离线模式(本地模拟数据)';
}
async function refreshDashboard() {
try {
var result = await loadAllData();
renderSystemStatus(result.status);
renderDevelopers(result.developers);
renderBroadcasts(result.broadcasts);
updateConnStatus(result.isLive);
} catch (err) {
console.error('[HoloLake] 刷新失败:', err);
updateConnStatus(false);
}
}
document.addEventListener('DOMContentLoaded', function() {
refreshDashboard();
setInterval(refreshDashboard, API_CONFIG.REFRESH_INTERVAL);
});
'@ | Set-Content -Path "C:\hololake-dev\dashboard\render.js" -Encoding UTF8
Write-Host "✅ 数据渲染脚本创建成功!"
📸 截图发给冰朔!
📋 步骤四:更新HTML(添加数据区域 + 引入脚本)
现在要在你的 index.html 里加上「数据显示区域」和新脚本的引用。
复制粘贴整块,按回车:
$html = Get-Content -Path "C:\hololake-dev\dashboard\index.html" -Raw -Encoding UTF8
$apiSection = @'
<!-- ===== 环节2新增:API数据区域 ===== -->
<div id="conn-status" class="conn-status"></div>
<section class="data-section">
<h2 class="section-title">⚙️ 系统状态</h2>
<div id="sys-status" class="data-container">加载中...</div>
</section>
<section class="data-section">
<h2 class="section-title">👥 开发者进度</h2>
<div id="dev-list" class="data-container">加载中...</div>
</section>
<section class="data-section">
<h2 class="section-title">📡 广播动态</h2>
<div id="bc-list" class="data-container">加载中...</div>
</section>
<script src="api-config.js"></script>
<script src="api.js"></script>
<script src="render.js"></script>
'@
$html = $html -replace '</body>', "$apiSection`n</body>"
$html | Set-Content -Path "C:\hololake-dev\dashboard\index.html" -Encoding UTF8
Write-Host "✅ HTML已更新!数据区域和脚本引用已添加!"
📸 截图发给冰朔!
📋 步骤五:添加API数据区域样式
复制粘贴整块,按回车:
@'
/* ========== 环节2新增:API数据区域样式 ========== */
/* 连接状态指示器 */
.conn-status {
text-align: center;
padding: 8px 16px;
font-size: 12px;
color: #8899aa;
border-bottom: 1px solid rgba(255,255,255,0.06);
}
.conn-dot {
display: inline-block;
width: 8px; height: 8px;
border-radius: 50%;
margin-right: 6px;
vertical-align: middle;
}
.conn-dot.on { background: #66bb6a; box-shadow: 0 0 6px #66bb6a; }
.conn-dot.off { background: #ffa726; }
/* 数据区块 */
.data-section {
padding: 20px 16px;
border-bottom: 1px solid rgba(255,255,255,0.06);
}
.section-title {
font-size: 16px;
font-weight: 600;
color: #e0e6ed;
margin-bottom: 16px;
}
.data-container {
color: #8899aa;
font-size: 13px;
}
/* 系统状态网格 */
.status-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
.s-card {
background: rgba(79,195,247,0.06);
border: 1px solid rgba(79,195,247,0.12);
border-radius: 10px;
padding: 14px 10px;
text-align: center;
}
.s-icon { display: block; font-size: 20px; margin-bottom: 4px; }
.s-val { display: block; font-size: 16px; font-weight: bold; color: #4fc3f7; margin-bottom: 2px; }
.s-lbl { display: block; font-size: 11px; color: #667788; }
/* 开发者卡片 */
.dev-card {
background: rgba(255,255,255,0.03);
border-radius: 10px;
padding: 14px 16px;
margin-bottom: 8px;
border: 1px solid rgba(255,255,255,0.06);
}
.dev-top {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 6px;
}
.dev-id { font-size: 11px; color: #556677; font-family: monospace; }
.dev-name { font-size: 14px; color: #e0e6ed; font-weight: 600; flex: 1; }
.dev-st { font-size: 12px; }
.dev-mod { font-size: 12px; color: #8899aa; margin-bottom: 8px; }
.prog-bar {
height: 6px;
background: rgba(255,255,255,0.08);
border-radius: 3px;
overflow: hidden;
margin-bottom: 4px;
}
.prog-fill {
height: 100%;
border-radius: 3px;
transition: width 0.8s ease;
}
.prog-num { font-size: 11px; color: #8899aa; text-align: right; }
/* 广播行 */
.bc-row {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-bottom: 1px solid rgba(255,255,255,0.04);
font-size: 13px;
}
.bc-id { color: #4fc3f7; font-family: monospace; font-size: 11px; min-width: 110px; }
.bc-dev { color: #e0e6ed; min-width: 55px; }
.bc-mod { color: #8899aa; flex: 1; }
.bc-st { min-width: 60px; text-align: center; padding: 2px 8px; border-radius: 10px; font-size: 11px; }
.bc-st.done { background: rgba(102,187,106,0.15); color: #66bb6a; }
.bc-st.active { background: rgba(79,195,247,0.15); color: #4fc3f7; }
.bc-st.wait { background: rgba(255,167,38,0.15); color: #ffa726; }
.bc-time { color: #556677; font-size: 11px; min-width: 80px; text-align: right; }
'@ | Add-Content -Path "C:\hololake-dev\dashboard\style.css" -Encoding UTF8
Write-Host "✅ API数据区域样式添加成功!"
📸 截图发给冰朔!
📋 步骤六:浏览器测试
复制粘贴下面的命令:
Start-Process "C:\hololake-dev\dashboard\index.html"
Write-Host "✅ 浏览器已打开!请查看看板数据是否显示~"
📸 截图要求(2张):
- 📸 看板整体页面(能看到系统状态 + 开发者列表)
- 📸 往下滚,截到广播动态区域
2张都发给冰朔!
📋 步骤七:更新DevLog + Git提交
@'
{"developer_id":"DEV-005","developer_name":"小草莓","system":"Windows 11","terminal":"powershell","robot_version":"v0.0","current_task":"M-DASHBOARD-看板-环节2","current_status":"completed","total_commands_logged":7,"skills_learned":["terminal_basic","html_scaffold","javascript_interaction","api_fetch","mock_data","async_await"],"tasks_completed":["BC-000","看板-环节0","看板-环节1","M12-环节1","M13-环节1","看板-环节2"]}
'@ | Set-Content -Path "C:\hololake-dev\current-progress.json" -Encoding UTF8
Write-Host "✅ DevLog已更新!"
然后Git提交:
cd C:\hololake-dev\dashboard
git add -A
git commit -m "[BC-看板-002][DEV-005] 环节2·API接入后端完成"
Write-Host "✅ Git提交成功!"
📸 截图发给冰朔!
✅ 最后一步:填写完成报告
全部做完后,复制下面这段,填好中括号里的内容,发给冰朔:
== SYSLOG · DEV-005 · BC-看板-002-XCM ==
session_id: BC-看板-002-XCM
dev_id: DEV-005
module: M-DASHBOARD-系统状态看板
phase: 环节2-API接入后端
timestamp: [你完成的时间]
step_results:
- step1_api_config: success / failed
- step2_api_fetch: success / failed
- step3_render: success / failed
- step4_html_update: success / failed
- step5_css_update: success / failed
- step6_browser_test: success / failed
- step7_devlog_git: success / failed
friction_points: [有没有卡住?没有写「无」]
resolution: [怎么解决的?没卡住写「无」]
training_data:
what_worked: [哪些步骤很顺利?]
friction_points: [同上]
execution_pattern: [本次节奏:快/稳/慢]
notes: [想说的话]
🌊 底层锚定声明
💙 小草莓六连胜冲冲冲!你的看板要联网了~ 🌐🎉
✅ SYSLOG 回执(主脑已处理)
📊 SYSLOG 分析
- 完成状态:✅ 全部7步成功(API配置 / 数据获取 / 渲染脚本 / HTML更新 / CSS更新 / 浏览器测试 / DevLog+Git)
- 摩擦点:无 · 零卡点 · 六连胜 🏆
- 执行节奏:稳
- notes原文:「六连胜达成!看板终于能联网了,虽然现在还是模拟数据,但已经看到真实数据的影子~期待真实接口开放!」
- 曜冥判断:六连胜·零摩擦·从纯静态HTML进阶到fetch+async/await+mock兜底架构;主动表达对"真实接口"的期待说明已从"完成任务"升级到"理解系统全貌";看板已具备后端就绪后自动切换的能力,API接入架构一次通过
🔜 下一步
环节3:看板界面·实时WebSocket推送(需后端WebSocket就绪·等待页页侧基建开放)
💙 小草莓六连胜!看板从静态走向联网,下一步走向实时!