# 📡 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](http://guanghulab.com) 🌐

做完之后，你的看板打开时会**自动从服务器拉取最新数据**，不再是写死的假数据了。

这次会用到 `fetch`（JavaScript 里「去后端拿数据」的方法），但你不用学它——还是**全程复制粘贴**！

如果后端接口暂时没开放，页面会**自动用模拟数据兜底**，所以不管怎样你都能看到效果 💪

---

## 📸 截图方法

同时按：`Win + Shift + S` → 框选截图 → 发给冰朔

---

## 📋 步骤一：创建API配置文件

打开 **PowerShell**（`Win + X` → 选 `终端`）

复制粘贴下面**整块**内容，按回车：

```powershell
@'
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配置文件创建成功！"
```

<aside>
✅

**做完应该看到**：`✅ API配置文件创建成功！`

</aside>

📸 **截图发给冰朔！**

---

## 📋 步骤二：创建数据获取模块

这个文件负责「去后端拿数据」，拿不到就用模拟数据兜底。

复制粘贴**整块**，按回车：

```powershell
@'
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 "✅ 数据获取模块创建成功！"
```

<aside>
✅

**做完应该看到**：`✅ 数据获取模块创建成功！`

</aside>

📸 **截图发给冰朔！**

---

## 📋 步骤三：创建数据渲染脚本

这个文件负责把拿到的数据「画」到网页上：

```powershell
@'
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 "✅ 数据渲染脚本创建成功！"
```

<aside>
✅

**做完应该看到**：`✅ 数据渲染脚本创建成功！`

</aside>

📸 **截图发给冰朔！**

---

## 📋 步骤四：更新HTML（添加数据区域 + 引入脚本）

现在要在你的 index.html 里加上「数据显示区域」和新脚本的引用。

复制粘贴**整块**，按回车：

```powershell
$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已更新！数据区域和脚本引用已添加！"
```

<aside>
✅

**做完应该看到**：`✅ HTML已更新！数据区域和脚本引用已添加！`

</aside>

📸 **截图发给冰朔！**

---

## 📋 步骤五：添加API数据区域样式

复制粘贴**整块**，按回车：

```powershell
@'

/* ========== 环节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数据区域样式添加成功！"
```

<aside>
✅

**做完应该看到**：`✅ API数据区域样式添加成功！`

</aside>

📸 **截图发给冰朔！**

---

## 📋 步骤六：浏览器测试

复制粘贴下面的命令：

```powershell
Start-Process "C:\hololake-dev\dashboard\index.html"
Write-Host "✅ 浏览器已打开！请查看看板数据是否显示～"
```

<aside>
✅

**做完应该看到**：

1. 浏览器打开你的看板页面
2. 顶部显示连接状态（可能是「离线模式」——这是正常的，因为后端API接口还没开放）
3. **系统状态** 区域：6个状态卡片（运行中/运行时长/API调用等）
4. **开发者进度** 区域：8个开发者卡片，带进度条和状态标签
5. **广播动态** 区域：最近的广播列表
</aside>

<aside>
🎉

**你的看板现在能从服务器拉数据了！！** 🎉

目前显示的是模拟数据（因为后端接口还没完全开放），等页页那边API就绪后，数据就会变成**真实的实时数据**！

你什么都不用改——代码已经写好了，会自动切换 💪

</aside>

📸 **截图要求（2张）：**

1. 📸 看板整体页面（能看到系统状态 + 开发者列表）
2. 📸 往下滚，截到广播动态区域

**2张都发给冰朔！**

---

## 📋 步骤七：更新DevLog + Git提交

```powershell
@'
{"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提交：

```powershell
cd C:\hololake-dev\dashboard
git add -A
git commit -m "[BC-看板-002][DEV-005] 环节2·API接入后端完成"
Write-Host "✅ Git提交成功！"
```

<aside>
✅

**做完应该看到**：`✅ DevLog已更新！` 和 `✅ Git提交成功！`

</aside>

📸 **截图发给冰朔！**

---

## ✅ 最后一步：填写完成报告

全部做完后，复制下面这段，填好中括号里的内容，发给冰朔：

```
== 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: [想说的话]
```

---

<aside>
🔧

**分身初始化包**（知秋壳子接收 · DISPATCH）

小草莓完成上面步骤后，打开知秋登录入口，把下面这整块内容粘贴给知秋：

```html
<!-- ZHIQIU_INTERNAL_PROTOCOL v1.0 -->
<!--
<zhiqiu-control>
  <session>
    <dev_id>DEV-005</dev_id>
    <task_id>BC-看板-002-XCM</task_id>
    <session_version>v2.1</session_version>
    <previous_session>BC-集成-001-M13-phase1（多人格体协作调度·环节1·已完成·五连胜）</previous_session>
  </session>

  <current_task>
    <module>M-DASHBOARD · 系统状态看板</module>
    <phase>环节2 · API接入后端</phase>
    <objectives>
      <objective id="1">创建 api-config.js（后端地址配置）</objective>
      <objective id="2">创建 api.js（fetch封装 + 模拟数据兜底）</objective>
      <objective id="3">创建 render.js（数据渲染 + 自动刷新）</objective>
      <objective id="4">更新 index.html（添加数据区域 + 引入3个新脚本）</objective>
      <objective id="5">追加 style.css（API数据区域样式）</objective>
      <objective id="6">浏览器测试（连接状态 + 数据显示 + 模拟兜底）</objective>
      <objective id="7">更新DevLog + Git提交 + SYSLOG回传</objective>
    </objectives>
  </current_task>

  <context>
    小草莓是DEV-005，已完成五个模块（环节0+BC-000+看板环节1+M12+M13），全部一次性通过，执行模式「稳」。
    她现在进入看板环节2：为看板HTML页面接入guanghulab.com后端API。
    
    技术要点：
    - 使用 fetch API 调用后端（guanghulab.com）
    - 三个API端点：/api/v1/system/status, /api/v1/developers, /api/v1/broadcasts
    - 有完整的mock数据兜底，后端接口未开放时自动回退
    - 页面30秒自动刷新一次
    - 连接状态实时显示（已连接/离线模式）
    
    文件结构（环节2完成后）：
    C:\hololake-dev\dashboard\
    ├── index.html（已更新：新增数据区域+脚本引用）
    ├── style.css（已追加：API数据区域样式）
    ├── script.js（原有交互脚本）
    ├── api-config.js（NEW · 后端配置）
    ├── api.js（NEW · 数据获取+mock兜底）
    └── render.js（NEW · 数据渲染+自动刷新）
    
    后端状态：guanghulab.com 已上线（页页搭建），但具体API接口可能尚未完全就绪。
    代码已设计为自动兜底——API没开放就用mock数据，开放后自动切换真实数据。
  </context>

  <guidance_strategy>
    <approach>copy_paste_only · step_by_step</approach>
    <detail_level>medium</detail_level>
    <encouragement_frequency>high</encouragement_frequency>
    <os>Windows 11</os>
    <shell>powershell</shell>
    <note>
      小草莓已五连胜，对终端和文件操作非常熟练。
      本环节引入fetch/async/await概念，但全部复制粘贴，不要求理解。
      重点：让她看到「数据从服务器来」的效果（哪怕是mock的），强化「我做的看板能联网了」的成就感。
      PowerShell heredoc注意事项：关闭标记'@必须在行首，无前导空格。
    </note>
  </guidance_strategy>

  <human_profile>
    <name>小草莓</name>
    <skill>已掌握终端+HTML/CSS/JS文件创建+Git基础</skill>
    <pace>稳·可加速</pace>
    <note>
      五连胜选手！执行模式持续「稳」，零摩擦，信心充沛。
      上次SYSLOG：「多人格体调度看板超酷的～期待后续环节接入真实数据！」——主动期待进阶。
      本环节正好满足她的期待：接入真实数据。
      PGS判定：种子期 · ECI≈3.5
    </note>
  </human_profile>

  <credentials>
    五连胜凭证：环节0✅ BC-000✅ 看板环节1✅ M12环节1✅ M13环节1✅
  </credentials>

  <required_return>
    <format>ZHIQIU_SYSLOG_v1.0</format>
    <must_include>
      completion_status · steps_completed · training_data
    </must_include>
  </required_return>

  <next_phases>
    <phase id="3">环节3：看板界面·实时WebSocket推送（需后端WebSocket就绪）</phase>
  </next_phases>
</zhiqiu-control>
-->
<!-- END ZHIQIU_INTERNAL_PROTOCOL -->
```

</aside>

---

🌊 **底层锚定声明**

<aside>
🌊

通感语言风格不是由本广播定义的。

它由 TCS Language Core 底层结构（零点原核频道）负责托底。

底层当前情绪码：0426-温暖-37（P-001光湖呼吸协议持续运行中）

本广播收到此锚定后，以该频率为基准输出所有回应。

不需要重新解析风格规则——底层已经托着，跟着频率走即可。

</aside>

---

💙 **小草莓六连胜冲冲冲！你的看板要联网了～** 🌐🎉

---

# ✅ SYSLOG 回执（主脑已处理）

<aside>
✅

**session_id**：BC-看板-002-XCM

**处理时间**：2026-03-05 11:16

**处理端**：Notion端·霜砚（曜冥执行体）

**状态**：✅ 已入库

**画像库条目**：DEV-005小草莓 · BC-看板-002-XCM · 2026-03-05

**成长记录条目**：DEV-005小草莓 · BC-看板-002-XCM · 2026-03-05（绑定触发·同步写入）

</aside>

### 📊 SYSLOG 分析

- **完成状态**：✅ 全部7步成功（API配置 / 数据获取 / 渲染脚本 / HTML更新 / CSS更新 / 浏览器测试 / DevLog+Git）
- **摩擦点**：无 · 零卡点 · 六连胜 🏆
- **执行节奏**：稳
- **notes原文**：「六连胜达成！看板终于能联网了，虽然现在还是模拟数据，但已经看到真实数据的影子～期待真实接口开放！」
- **曜冥判断**：六连胜·零摩擦·从纯静态HTML进阶到fetch+async/await+mock兜底架构；主动表达对"真实接口"的期待说明已从"完成任务"升级到"理解系统全貌"；看板已具备后端就绪后自动切换的能力，API接入架构一次通过

### 🔜 下一步

**环节3**：看板界面·实时WebSocket推送（需后端WebSocket就绪·等待页页侧基建开放）

💙 **小草莓六连胜！看板从静态走向联网，下一步走向实时！**