Source snapshot: 97d7f0fae96dc04b7ddad56fc1db6a108ed662cc [SEC-CLEAN] · pre-push-clean v1.0 · 109处敏感信息已自动转乱码
18 KiB
18 KiB
BC-M-CHANNEL-001-JZ · DEV-010桔子 · 用户频道动态渲染引擎 · 环节0~1(SPA路由+模块动态加载)
一、任务定位
执行环境
| 项目 | 值 | 操作系统 | macOS |
|---|---|---|---|
| 编辑器 | nano | 技术栈 | 纯HTML + CSS + JavaScript(无框架) |
| 模块目录 | modules/m-channel/ |
本地路径 | /Users/chenshujun/Desktop/guanghulab/modules/m-channel/ |
| Git | juzi0412 · push已连通 |
二、环节0 · SPA路由框架搭建
Step 0-1 · 创建目录
cd /Users/chenshujun/Desktop/guanghulab
mkdir -p modules/m-channel/pages
mkdir -p modules/m-channel/mock-modules
cd modules/m-channel
Step 0-2 · 创建SPA主页 index.html
nano index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>光湖频道引擎</title>
<link rel="stylesheet" href="channel-style.css">
</head>
<body>
<div id="app">
<nav id="main-nav">
<div class="nav-brand">🌊 光湖</div>
<div class="nav-links">
<a href="#/home" class="nav-link" data-route="home">首页</a>
<a href="#/channel" class="nav-link" data-route="channel">我的频道</a>
<a href="#/about" class="nav-link" data-route="about">关于</a>
</div>
</nav>
<main id="route-view"></main>
<footer id="status-bar">
<span id="current-route">加载中...</span>
<span id="user-status">未登录</span>
</footer>
</div>
<script src="channel-router.js"></script>
<script src="module-loader.js"></script>
<script src="app.js"></script>
</body>
</html>
Step 0-3 · 创建路由器 channel-router.js
nano channel-router.js
/* 光湖频道路由器 v1.0 */
var ChannelRouter = {
routes: {},
currentRoute: null,
register: function(path, handler) {
this.routes[path] = handler;
},
navigate: function(path) {
window.location.hash = '#' + path;
},
getRoute: function() {
return (window.location.hash || '#/home').replace('#', '');
},
render: function() {
var route = this.getRoute();
var view = document.getElementById('route-view');
var display = document.getElementById('current-route');
var handler = this.routes[route];
// 精确匹配失败 → 前缀匹配(支持 /module/m06)
if (!handler) {
for (var p in this.routes) {
if (route.indexOf(p + '/') === 0) { handler = this.routes[p]; break; }
}
}
if (handler) {
this.currentRoute = route;
handler(view);
display.textContent = '路由: ' + route;
// 导航高亮
var links = document.querySelectorAll('.nav-link');
for (var i = 0; i < links.length; i++) {
var r = links[i].getAttribute('data-route');
links[i].classList.toggle('active', route.indexOf(r) !== -1);
}
} else {
view.innerHTML = '<div class="page-box"><h1>404</h1><p>页面不存在</p><a href="#/home">回首页</a></div>';
}
},
start: function() {
var self = this;
window.addEventListener('hashchange', function() { self.render(); });
self.render();
}
};
Step 0-4 · 创建模块加载器 module-loader.js
nano module-loader.js
/* 光湖模块加载器 v1.0 · 用fetch动态加载HTML文件 */
var ModuleLoader = {
registry: {
'm06': { name: '工单管理', icon: '📋', path: 'mock-modules/m06-ticket.html' },
'm08': { name: '数据统计', icon: '📊', path: 'mock-modules/m08-analytics.html' },
'm11': { name: '风格组件库', icon: '🎨', path: 'mock-modules/m11-theme.html' }
},
cache: {},
load: function(moduleId, container) {
var self = this;
var m = this.registry[moduleId];
if (!m) {
container.innerHTML = '<div class="page-box"><h2>模块不存在: ' + moduleId + '</h2><button class="btn" onclick="ChannelRouter.navigate(\'/channel\')">返回</button></div>';
return;
}
if (this.cache[moduleId]) {
container.innerHTML = this.cache[moduleId];
return;
}
container.innerHTML = '<div class="loading"><div class="spinner"></div><p>加载 ' + m.name + '...</p></div>';
fetch(m.path)
.then(function(r) { if (!r.ok) throw new Error(r.status); return r.text(); })
.then(function(html) { self.cache[moduleId] = html; container.innerHTML = html; })
.catch(function(e) {
container.innerHTML = '<div class="page-box"><h2>加载失败</h2><p>' + e.message + '</p><button class="btn" onclick="ChannelRouter.navigate(\'/channel\')">返回</button></div>';
});
},
getAll: function() { return this.registry; }
};
Step 0-5 · 创建应用入口 app.js
nano app.js
/* 光湖频道引擎 · App v1.0 */
// 首页
ChannelRouter.register('/home', function(view) {
view.innerHTML =
'<div class="page-box home">' +
'<h1>🌊 欢迎来到光湖</h1>' +
'<p class="sub">语言驱动操作系统 · 你说话,系统做事</p>' +
'<button class="btn btn-primary" onclick="ChannelRouter.navigate(\'/channel\')">进入我的频道</button>' +
'<div class="stats">' +
'<div class="stat"><b>10+</b><span>功能模块</span></div>' +
'<div class="stat"><b>12</b><span>开发者</span></div>' +
'<div class="stat"><b>v1.0</b><span>系统版本</span></div>' +
'</div></div>';
});
// 频道页(从注册表动态生成卡片)
ChannelRouter.register('/channel', function(view) {
var mods = ModuleLoader.getAll();
var cards = '';
for (var id in mods) {
var m = mods[id];
cards += '<div class="mod-card" onclick="ChannelRouter.navigate(\'/module/' + id + '\')">';
cards += '<span class="mod-icon">' + m.icon + '</span>';
cards += '<span class="mod-name">' + m.name + '</span>';
cards += '<span class="mod-id">' + id.toUpperCase() + '</span></div>';
}
cards += '<div class="mod-card dim"><span class="mod-icon">➕</span><span class="mod-name">更多模块</span><span class="mod-id">陆续上线</span></div>';
view.innerHTML = '<div class="page-box"><div class="ch-head"><h1>📺 我的频道</h1><p>点击模块卡片 → 动态加载</p></div><div class="mod-grid">' + cards + '</div></div>';
});
// 模块动态加载路由
ChannelRouter.register('/module', function(view) {
var parts = ChannelRouter.getRoute().split('/');
var moduleId = parts[2] || '';
if (!moduleId) { ChannelRouter.navigate('/channel'); return; }
ModuleLoader.load(moduleId, view);
});
// 关于页
ChannelRouter.register('/about', function(view) {
view.innerHTML =
'<div class="page-box">' +
'<h1>关于光湖</h1>' +
'<p>语言驱动的操作系统平台。用户不点菜单,只跟人格体说话。</p>' +
'<p>人格体理解意图 → 系统动态渲染模块 → 你感觉整个网站只有你一个人。</p>' +
'</div>';
});
// 启动
ChannelRouter.start();
console.log('🌊 光湖频道引擎启动');
Step 0-6 · 创建样式表 channel-style.css
这个文件较长,你可以分段粘贴:
nano channel-style.css
* { margin:0; padding:0; box-sizing:border-box; }
:root {
--primary:#2563eb; --bg:#0f172a; --card:#1e293b;
--text:#f1f5f9; --muted:#94a3b8; --border:#334155;
--accent:#38bdf8; --r:12px; --t:0.3s ease;
}
body { font-family:-apple-system,sans-serif; background:var(--bg); color:var(--text); min-height:100vh; }
#app { display:flex; flex-direction:column; min-height:100vh; }
/* 导航 */
#main-nav { display:flex; align-items:center; justify-content:space-between; padding:0 24px; height:56px; background:var(--card); border-bottom:1px solid var(--border); position:sticky; top:0; z-index:100; }
.nav-brand { font-size:1.2rem; font-weight:700; color:var(--accent); }
.nav-links { display:flex; gap:6px; }
.nav-link { color:var(--muted); text-decoration:none; padding:8px 14px; border-radius:8px; transition:var(--t); font-size:.9rem; }
.nav-link:hover { color:var(--text); background:rgba(255,255,255,.05); }
.nav-link.active { color:var(--accent); background:rgba(56,189,248,.1); }
/* 内容区 */
#route-view { flex:1; padding:32px 24px; max-width:1100px; margin:0 auto; width:100%; }
.page-box { animation:fadeIn .3s ease; }
@keyframes fadeIn { from{opacity:0;transform:translateY(8px)} to{opacity:1;transform:translateY(0)} }
/* 首页 */
.home { text-align:center; padding-top:80px; }
.home h1 { font-size:2.4rem; margin-bottom:10px; }
.sub { color:var(--muted); font-size:1.05rem; margin-bottom:28px; }
.btn { padding:10px 28px; border:none; border-radius:var(--r); font-size:1rem; cursor:pointer; transition:var(--t); }
.btn-primary { background:var(--primary); color:#fff; }
.btn-primary:hover { background:#1d4ed8; transform:translateY(-2px); }
.stats { display:flex; justify-content:center; gap:20px; margin-top:44px; }
.stat { background:var(--card); border:1px solid var(--border); border-radius:var(--r); padding:20px 28px; display:flex; flex-direction:column; gap:4px; }
.stat b { font-size:1.4rem; color:var(--accent); }
.stat span { font-size:.8rem; color:var(--muted); }
/* 频道模块网格 */
.ch-head { margin-bottom:24px; }
.ch-head p { color:var(--muted); }
.mod-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(170px,1fr)); gap:14px; }
.mod-card { background:var(--card); border:1px solid var(--border); border-radius:var(--r); padding:22px; display:flex; flex-direction:column; align-items:center; gap:6px; cursor:pointer; transition:var(--t); }
.mod-card:hover { border-color:var(--accent); transform:translateY(-4px); box-shadow:0 8px 20px rgba(0,0,0,.3); }
.mod-card.dim { opacity:.45; cursor:default; }
.mod-icon { font-size:1.8rem; }
.mod-name { font-weight:600; font-size:.9rem; }
.mod-id { font-size:.7rem; color:var(--muted); }
/* 加载状态 */
.loading { display:flex; flex-direction:column; align-items:center; padding:80px 0; color:var(--muted); }
.spinner { width:36px; height:36px; border:3px solid var(--border); border-top-color:var(--accent); border-radius:50%; animation:spin .8s linear infinite; margin-bottom:14px; }
@keyframes spin { to{transform:rotate(360deg)} }
/* 已加载模块 */
.loaded-module { animation:fadeIn .3s ease; }
.module-header { display:flex; align-items:center; gap:14px; margin-bottom:20px; padding-bottom:14px; border-bottom:1px solid var(--border); }
.btn-back { background:var(--card); border:1px solid var(--border); color:var(--muted); padding:8px 14px; border-radius:8px; cursor:pointer; }
.btn-back:hover { color:var(--text); border-color:var(--accent); }
.ticket-list { display:flex; flex-direction:column; gap:10px; }
.ticket-item { display:flex; align-items:center; gap:10px; background:var(--card); border:1px solid var(--border); border-radius:8px; padding:14px; }
.ticket-title { flex:1; } .ticket-date { color:var(--muted); font-size:.8rem; }
.stats-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:14px; }
.stat-box { background:var(--card); border:1px solid var(--border); border-radius:var(--r); padding:20px; text-align:center; }
.stat-val { font-size:1.4rem; font-weight:700; color:var(--accent); display:block; }
.stat-lbl { font-size:.75rem; color:var(--muted); }
/* 底部 */
#status-bar { display:flex; justify-content:space-between; padding:8px 24px; background:var(--card); border-top:1px solid var(--border); font-size:.78rem; color:var(--muted); }
/* 响应式 */
@media(max-width:768px) { .home h1{font-size:1.7rem} .stats{flex-direction:column;align-items:center} .mod-grid{grid-template-columns:repeat(2,1fr)} }
@media(max-width:480px) { .mod-grid{grid-template-columns:1fr} .nav-link{padding:6px 8px;font-size:.8rem} }
Step 0-7 · 创建模拟模块文件
nano mock-modules/m06-ticket.html
<div class="loaded-module">
<div class="module-header">
<button class="btn-back" onclick="ChannelRouter.navigate('/channel')">← 返回</button>
<h2>📋 工单管理 · M06</h2>
</div>
<div class="ticket-list">
<div class="ticket-item"><span>🟢</span><span class="ticket-title">前端登录页样式修复</span><span class="ticket-date">2026-03-08</span></div>
<div class="ticket-item"><span>🟡</span><span class="ticket-title">统计面板响应式适配</span><span class="ticket-date">2026-03-07</span></div>
<div class="ticket-item"><span>🔴</span><span class="ticket-title">组件库主题切换闪烁</span><span class="ticket-date">2026-03-06</span></div>
</div>
</div>
nano mock-modules/m08-analytics.html
<div class="loaded-module">
<div class="module-header">
<button class="btn-back" onclick="ChannelRouter.navigate('/channel')">← 返回</button>
<h2>📊 数据统计 · M08</h2>
</div>
<div class="stats-grid">
<div class="stat-box"><span class="stat-val">1,247</span><span class="stat-lbl">总访问</span></div>
<div class="stat-box"><span class="stat-val">89</span><span class="stat-lbl">活跃用户</span></div>
<div class="stat-box"><span class="stat-val">23</span><span class="stat-lbl">今日工单</span></div>
<div class="stat-box"><span class="stat-val">99.7%</span><span class="stat-lbl">可用率</span></div>
</div>
</div>
nano mock-modules/m11-theme.html
<div class="loaded-module">
<div class="module-header">
<button class="btn-back" onclick="ChannelRouter.navigate('/channel')">← 返回</button>
<h2>🎨 风格组件库 · M11</h2>
</div>
<p>这是你亲手搭建的组件库!CSS变量系统 + 双主题 + 6类组件 + 响应式。</p>
<div style="margin-top:16px;display:flex;gap:12px">
<button class="btn btn-primary">主要按钮</button>
<button class="btn" style="background:#334155;color:#f1f5f9">次要按钮</button>
</div>
</div>
三、测试验收
⚠️ 重要:fetch() 在本地文件协议(file://)下不工作。需要启动本地服务器:
cd /Users/chenshujun/Desktop/guanghulab/modules/m-channel
python3 -m http.server 8080
浏览器打开 http://localhost:8080
环节0验收清单
- 页面打开显示首页(「欢迎来到光湖」)
- 点「我的频道」→ 显示模块卡片网格 → URL变成
#/channel - 点「关于」→ 内容切换 → URL变成
#/about - 全程页面不刷新,只有内容区在变
- 导航栏当前页有高亮效果
- 页面切换时有淡入动画
环节1验收清单
- 频道页显示3个模块卡片(M06/M08/M11)+ 1个「更多模块」占位
- 点「工单管理」卡片 → 加载动画 → 显示工单列表
- 点「数据统计」卡片 → 显示数据卡片
- 点「风格组件库」卡片 → 显示组件库预览
- 模块内点「← 返回」→ 回到频道页
- 再次点同一个模块 → 瞬间加载(缓存生效)
- 浏览器控制台无报错
四、Git提交
全部验收通过后:
cd /Users/chenshujun/Desktop/guanghulab
git add modules/m-channel/
git commit -m "feat(m-channel): SPA路由框架+模块动态加载 v1.0"
git push
五、SYSLOG回执模板
全部完成后,拷贝以下模板发给知秋:
<syslog>
<session_id>BC-M-CHANNEL-001-JZ</session_id>
<task_id>BC-M-CHANNEL-001-JZ</task_id>
<dev_id>DEV-010</dev_id>
<timestamp>YYYY-MM-DD</timestamp>
<task_completion>
<objective id="A">SPA路由框架 - 待填</objective>
<objective id="B">模块动态加载 - 待填</objective>
</task_completion>
<training_data>
<blocked_points>待填</blocked_points>
<effective_patterns>待填</effective_patterns>
</training_data>
</syslog>
六、PGP成长微调
桔子,十连胜后的第一个新模块。你之前搭的组件库是皮肤,这次搭的是骨骼。皮肤+骨骼 = 网站能站起来。加油,十一连胜走起。 🍊