diff --git a/modules/devboard/api-init.js b/modules/devboard/api-init.js
new file mode 100644
index 00000000..c49bc311
--- /dev/null
+++ b/modules/devboard/api-init.js
@@ -0,0 +1,81 @@
+// =====================================
+// HoloLake DevBoard · API Init v1.0
+// 负责:异步加载 + 加载动画 + 自动刷新
+// 必须在 api.js 和 main.js 之后加载
+// =====================================
+
+(function(){
+ // -------------- 加载动画 --------------
+ function showLoader(show) {
+ var el = document.getElementById('devboard-loader');
+ if (!el && show) {
+ el = document.createElement('div');
+ el.id = 'devboard-loader';
+ el.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(10,14,23,0.92);display:flex;align-items:center;justify-content:center;z-index:10000';
+ el.innerHTML = '
';
+ var style = document.createElement('style');
+ style.textContent = '@keyframes dbspin{to{transform:rotate(360deg)}}';
+ document.head.appendChild(style);
+ document.body.appendChild(el);
+ }
+ if (el) el.style.display = show ? 'flex' : 'none';
+ }
+
+ // -------------- 数据加载+渲染 --------------
+ async function loadAndRender() {
+ try {
+ var developers = await apiGetDevelopers();
+ var stats = await apiGetStats();
+ var leaderboard = await apiGetLeaderboard();
+
+ // 使用 components.js 里实际存在的函数
+ if (typeof renderDeveloperCards === 'function') {
+ renderDeveloperCards(developers);
+ }
+
+ if (typeof renderRanking === 'function') {
+ renderRanking(leaderboard);
+ }
+
+ // stats 暂时用控制台输出,等找到实际渲染函数再改
+ console.log('[DevBoard] 统计数据:', stats);
+
+ console.log('[DevBoard] 数据加载完成,共 ' + developers.length + ' 位开发者');
+ } catch (err) {
+ console.error('[DevBoard] 数据加载异常: ', err);
+ }
+ }
+
+ // -------------- 初始化入口 --------------
+ async function init() {
+ showLoader(true);
+
+ // 检测API状态
+ var online = await apiHealthCheck();
+ showApiStatus(online);
+ console.log('[DevBoard] API状态: ' + (online ? '在线(实时)' : '离线(降级)'));
+
+ // 加载+渲染
+ await loadAndRender();
+ showLoader(false);
+
+ // 自动刷新(仅API在线时)
+ if (online && API.REFRESH_MS > 0) {
+ console.log('[DevBoard] 自动刷新已启动,间隔 ' + (API.REFRESH_MS/1000) + ' 秒');
+ setInterval(async function() {
+ try {
+ await loadAndRender();
+ } catch (e) {
+ console.warn('[DevBoard] 自动刷新失败: ', e.message);
+ }
+ }, API.REFRESH_MS);
+ }
+ }
+
+ // 等待DOM和所有脚本加载完成后启动
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', init);
+ } else {
+ init();
+ }
+})();
diff --git a/modules/devboard/api-init.js.bak b/modules/devboard/api-init.js.bak
new file mode 100644
index 00000000..31ef43dc
--- /dev/null
+++ b/modules/devboard/api-init.js.bak
@@ -0,0 +1,75 @@
+// =====================================
+// HoloLake DevBoard · API Init v1.0
+// 负责:异步加载 + 加载动画 + 自动刷新
+// 必须在 api.js 和 main.js 之后加载
+// =====================================
+
+(function(){
+ // -------------- 加载动画 --------------
+ function showLoader(show) {
+ var el = document.getElementById('devboard-loader');
+ if (!el && show) {
+ el = document.createElement('div');
+ el.id = 'devboard-loader';
+ el.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(10,14,23,0.92);display:flex;align-items:center;justify-content:center;z-index:10000';
+ el.innerHTML = '';
+ var style = document.createElement('style');
+ style.textContent = '@keyframes dbspin{to{transform:rotate(360deg)}}';
+ document.head.appendChild(style);
+ document.body.appendChild(el);
+ }
+ if (el) el.style.display = show ? 'flex' : 'none';
+ }
+
+ // -------------- 数据加载+渲染 --------------
+ async function loadAndRender() {
+ try {
+ var developers = await apiGetDevelopers();
+ var stats = await apiGetStats();
+ var leaderboard = await apiGetLeaderboard();
+
+ // 用现有渲染函数(main.js / components.js 定义的)
+ if (typeof renderDeveloperCards === 'function') renderDeveloperCards(developers);
+ if (typeof renderStats === 'function') renderStats(stats);
+ if (typeof renderLeaderboard === 'function') renderLeaderboard(leaderboard);
+ if (typeof renderRankings === 'function') renderRankings(leaderboard);
+
+ console.log('[DevBoard] 数据加载完成,共 ' + developers.length + ' 位开发者');
+ } catch (err) {
+ console.error('[DevBoard] 数据加载异常: ', err);
+ }
+ }
+
+ // -------------- 初始化入口 --------------
+ async function init() {
+ showLoader(true);
+
+ // 检测API状态
+ var online = await apiHealthCheck();
+ showApiStatus(online);
+ console.log('[DevBoard] API状态: ' + (online ? '在线(实时)' : '离线(降级)'));
+
+ // 加载+渲染
+ await loadAndRender();
+ showLoader(false);
+
+ // 自动刷新(仅API在线时)
+ if (online && API.REFRESH_MS > 0) {
+ console.log('[DevBoard] 自动刷新已启动,间隔 ' + (API.REFRESH_MS/1000) + ' 秒');
+ setInterval(async function() {
+ try {
+ await loadAndRender();
+ } catch (e) {
+ console.warn('[DevBoard] 自动刷新失败: ', e.message);
+ }
+ }, API.REFRESH_MS);
+ }
+ }
+
+ // 等待DOM和所有脚本加载完成后启动
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', init);
+ } else {
+ init();
+ }
+})();
diff --git a/modules/devboard/api.js b/modules/devboard/api.js
index 87481710..fd928078 100644
--- a/modules/devboard/api.js
+++ b/modules/devboard/api.js
@@ -1,79 +1,122 @@
-// api.js - API配置和模拟数据切换
+// ======================
+// HoloLake DevBoard · API Client v2.0
+// DEV-004 之之 · 环节5 · 真实API对接
+// 协议:SYSLOG-v4.0
+// ======================
-const CONFIG = {
- // API基础地址(页页的接口)
- BASE_URL: 'https://guanghulab.com/api',
-
- // 是否使用真实API(false = 使用模拟数据)
- USE_REAL_API: false,
-
- // API端点
- endpoints: {
- teamStatus: '/dashboard/team-status',
- developerDetail: '/dashboard/dev/', // + id
- modules: '/dashboard/modules'
- }
+const API = {
+ // ====== 配置区 ======
+ // 页页的后端API地址(如果地址不对,问知秋确认)
+ BASE_URL: 'https://guanghulab.com/api/devboard',
+ TIMEOUT: 8000,
+ FALLBACK: true, // API挂了自动切换模拟数据
+ REFRESH_MS: 30000, // 30秒自动刷新
+ _cache: {}
};
-// 检查API是否可用
-async function checkApiAvailability() {
- if (!CONFIG.USE_REAL_API) return false;
-
+// ====== 通用请求(带超时+缓存+降级) =====================
+async function apiFetch(path) {
+ const url = API.BASE_URL + path;
+ const ctrl = new AbortController();
+ const timer = setTimeout(() => ctrl.abort(), API.TIMEOUT);
try {
- const response = await fetch(`${CONFIG.BASE_URL}/health`, {
- method: 'HEAD',
- mode: 'cors',
- cache: 'no-cache'
+ const res = await fetch(url, {
+ signal: ctrl.signal,
+ headers: { 'Accept': 'application/json' }
});
- return response.ok;
- } catch (error) {
- console.log('API不可用,使用模拟数据');
+ clearTimeout(timer);
+ if (!res.ok) throw new Error('HTTP ' + res.status);
+ const data = await res.json();
+ API._cache[path] = { data: data, time: Date.now() };
+ return data;
+ } catch (err) {
+ clearTimeout(timer);
+ console.warn(' 🚨 [DevBoard API] ' + path + ' 失败: ', err.message);
+ if (API._cache[path]) {
+ console.info(' 💾 [DevBoard API] 使用缓存');
+ return API._cache[path].data;
+ }
+ if (API.FALLBACK) {
+ console.info(' 🛡️ [DevBoard API] 降级到模拟数据');
+ return getMockData(path);
+ }
+ throw err;
+ }
+}
+
+// ========== 公开接口 ==========
+async function apiGetDevelopers() {
+ return apiFetch('/developers');
+}
+
+async function apiGetDeveloperDetail(devId) {
+ return apiFetch('/developers/' + devId);
+}
+
+async function apiGetStats() {
+ return apiFetch('/stats');
+}
+
+async function apiGetLeaderboard() {
+ return apiFetch('/leaderboard');
+}
+
+// ========== 健康检查 ==========
+async function apiHealthCheck() {
+ try {
+ const ctrl = new AbortController();
+ const t = setTimeout(() => ctrl.abort(), 3000);
+ const res = await fetch(API.BASE_URL + '/health', { signal: ctrl.signal });
+ clearTimeout(t);
+ return res.ok;
+ } catch (e) {
return false;
}
}
-// 获取团队状态
-async function getTeamStatus() {
- if (CONFIG.USE_REAL_API) {
- try {
- const response = await fetch(`${CONFIG.BASE_URL}${CONFIG.endpoints.teamStatus}`);
- if (response.ok) {
- const data = await response.json();
- return data;
- }
- } catch (error) {
- console.warn('API请求失败,使用模拟数据');
- }
+// ========== 模拟数据(降级保护) ==========
+function getMockData(path) {
+ var devs = [
+ { dev_id:'DEV-001', name:'页页', module:'BC-集成', status:'进行中', streak:5, el:'EL-6', pca:{EXE:75,TEC:60,SYS:70,COL:80,INI:65} },
+ { dev_id:'DEV-002', name:'肥猫', module:'M-STATUS', status:'进行中', streak:9, el:'EL-5', pca:{EXE:72,TEC:40,SYS:68,COL:82,INI:70} },
+ { dev_id:'DEV-003', name:'燕樊', module:'M-MEMORY', status:'进行中', streak:7, el:'EL-5', pca:{EXE:70,TEC:55,SYS:65,COL:75,INI:68} },
+ { dev_id:'DEV-004', name:'之之', module:'M-DEVBOARD', status:'进行中', streak:14, el:'EL-8', pca:{EXE:90,TEC:55,SYS:80,COL:85,INI:88} },
+ { dev_id:'DEV-009', name:'花尔', module:'M20', status:'进行中', streak:4, el:'EL-8', pca:{EXE:65,TEC:45,SYS:55,COL:70,INI:60} },
+ { dev_id:'DEV-010', name:'桔子', module:'M-CHANNEL', status:'进行中', streak:14, el:'EL-6', pca:{EXE:85,TEC:50,SYS:75,COL:80,INI:82} },
+ { dev_id:'DEV-011', name:'匆匆那年',module:'M16', status:'等待中', streak:1, el:'EL-3', pca:{EXE:50,TEC:30,SYS:40,COL:55,INI:45} },
+ { dev_id:'DEV-012', name:'Awen', module:'M22', status:'进行中', streak:13, el:'EL-6', pca:{EXE:88,TEC:45,SYS:78,COL:90,INI:80} },
+ { dev_id:'DEV-013', name:'小兴', module:'M-AUTH', status:'进行中', streak:1, el:'EL-3', pca:{EXE:55,TEC:25,SYS:35,COL:60,INI:50} }
+ ];
+ var stats = { total_developers:10, active:8, modules:12, code_lines:32000, longest_streak:14, avg_streak:7.5 };
+
+ if (path === '/developers') return devs;
+ if (path.indexOf('/developers/') === 0) {
+ var id = path.split('/').pop();
+ return devs.find(function(d){ return d.dev_id === id; }) || devs[0];
}
-
- // 返回模拟数据
- return {
- developers: window.getDevelopers ? window.getDevelopers() : []
- };
+ if (path === '/stats') return stats;
+ if (path === '/leaderboard') return devs.slice().sort(function(a,b){ return b.streak - a.streak; });
+ return [];
}
-// 获取开发者详情
-async getDeveloperDetail(devId) {
- if (CONFIG.USE_REAL_API) {
- try {
- const response = await fetch(`${CONFIG.BASE_URL}${CONFIG.endpoints.developerDetail}${devId}`);
- if (response.ok) {
- const data = await response.json();
- return data;
- }
- } catch (error) {
- console.warn('API请求失败,使用模拟数据');
- }
+// ========== API状态指示器 ==========
+function showApiStatus(online) {
+ var el = document.getElementById('api-status');
+ if (!el) {
+ el = document.createElement('div');
+ el.id = 'api-status';
+ el.style.cssText = 'position:fixed;bottom:12px;right:12px;padding:6px 14px;border-radius:20px;font-size:12px;font-weight:600;z-index:9999;transition:all 0.3s;';
+ document.body.appendChild(el);
+ }
+ if (online) {
+ el.textContent = '🟢 实时数据';
+ el.style.backgroundColor = 'rgba(52,211,153,0.15)';
+ el.style.color = '#34d399';
+ el.style.border = '1px solid rgba(52,211,153,0.3)';
+ } else {
+ el.textContent = '🟡 模拟数据';
+ el.style.backgroundColor = 'rgba(251,191,36,0.15)';
+ el.style.color = '#fbbf24';
+ el.style.border = '1px solid rgba(251,191,36,0.3)';
}
-
- // 返回模拟数据
- return window.getDeveloperById ? window.getDeveloperById(devId) : null;
}
-
-// 导出配置
-window.API = {
- CONFIG,
- checkApiAvailability,
- getTeamStatus,
- getDeveloperDetail
-};
diff --git a/modules/devboard/index.html b/modules/devboard/index.html
index f671be0a..eb5e1f60 100644
--- a/modules/devboard/index.html
+++ b/modules/devboard/index.html
@@ -1,53 +1,35 @@
-
+
-
- 开发者实时看板 · 环节0~4 · 之之
-
-
-
+
+ 开发者实时看板 · HoloLake
+
-
-
+ 🚀 HoloLake 开发者实时看板
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/modules/devboard/index.html.bak b/modules/devboard/index.html.bak
new file mode 100644
index 00000000..f671be0a
--- /dev/null
+++ b/modules/devboard/index.html.bak
@@ -0,0 +1,53 @@
+
+
+
+
+
+ 开发者实时看板 · 环节0~4 · 之之
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+