From be4220cbf7f63893b67eb8508af2b66739bc4eb0 Mon Sep 17 00:00:00 2001
From: juzi0412 <1824680224@QQ.com>
Date: Sat, 7 Mar 2026 14:05:33 +0800
Subject: [PATCH 01/19] =?UTF-8?q?DEV-010=20=E6=A1=94=E5=AD=90=20M06?=
=?UTF-8?q?=E5=B7=A5=E5=8D=95=E7=AE=A1=E7=90=86=20+=20M08=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE=E7=BB=9F=E8=AE=A1=E9=9D=A2=E6=9D=BF=20=E4=B8=8A?=
=?UTF-8?q?=E4=BC=A0=E5=AE=8C=E6=88=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
dashboard/app.js | 189 +++++++++
dashboard/index.html | 182 ++++++++
dashboard/style.css | 889 +++++++++++++++++++++++++++++++++++++++
ticket-system/index.html | 809 +++++++++++++++++++++++++++++++++++
ticket-system/script.js | 301 +++++++++++++
ticket-system/style.css | 527 +++++++++++++++++++++++
6 files changed, 2897 insertions(+)
create mode 100644 dashboard/app.js
create mode 100644 dashboard/index.html
create mode 100644 dashboard/style.css
create mode 100644 ticket-system/index.html
create mode 100644 ticket-system/script.js
create mode 100644 ticket-system/style.css
diff --git a/dashboard/app.js b/dashboard/app.js
new file mode 100644
index 00000000..d673f333
--- /dev/null
+++ b/dashboard/app.js
@@ -0,0 +1,189 @@
+// HoloLake 数据统计面板 · 交互脚本 v2(含导出 + 环形图)
+
+window.addEventListener('load', function() {
+ // 条形图动画
+ setTimeout(function() {
+ var bars = document.querySelectorAll('.bar-fill');
+ bars.forEach(function(bar) {
+ var percent = bar.getAttribute('data-percent');
+ bar.style.width = percent + '%';
+ });
+ }, 300);
+
+ // 柱状图动画
+ setTimeout(function() {
+ var trendBars = document.querySelectorAll('.trend-bar');
+ trendBars.forEach(function(bar) {
+ var height = bar.getAttribute('data-height');
+ var fill = bar.querySelector('.trend-fill');
+ fill.style.height = height + '%';
+ });
+ }, 600);
+
+ // 环形图绘制函数
+ function drawDonut(percentages) {
+ var segments = document.querySelectorAll('.donut-segment');
+ var total = 377; // 2 * Math.PI * 60 ≈ 377
+ var cumulative = 0;
+ segments.forEach(function(seg, i) {
+ var value = percentages[i] || 0;
+ var dashArray = (value / 100 * total) + ' ' + total;
+ seg.setAttribute('stroke-dasharray', dashArray);
+ seg.setAttribute('stroke-dashoffset', 0);
+ });
+ }
+
+ // 当前选中的时间范围
+ var currentRange = 'today';
+
+ // 模拟数据
+ var mockData = {
+ today: {
+ users: '128', chats: '1,024', personas: '6', api: '3,892',
+ bars: [72,15,8,3,2],
+ trends: [45,62,38,78,55,90,85],
+ donut: [72,15,8,3,2],
+ apiTotal: '3,892'
+ },
+ week: {
+ users: '128', chats: '6,847', personas: '6', api: '24,103',
+ bars: [68,18,9,3,2],
+ trends: [320,415,380,450,290,520,480],
+ donut: [68,18,9,3,2],
+ apiTotal: '24,103'
+ },
+ month: {
+ users: '128', chats: '28,392', personas: '6', api: '98,741',
+ bars: [65,20,10,3,2],
+ trends: [1200,1450,1100,1680,1320,1890,1750],
+ donut: [65,20,10,3,2],
+ apiTotal: '98,741'
+ }
+ };
+
+ // 更新所有图表和数字
+ function updateStats(range) {
+ currentRange = range;
+ var data = mockData[range];
+
+ // 更新统计卡片
+ var values = document.querySelectorAll('.stat-value');
+ values[0].textContent = data.users;
+ values[1].textContent = data.chats;
+ values[2].textContent = data.personas;
+ values[3].textContent = data.api;
+
+ // 更新条形图
+ var bars = document.querySelectorAll('.bar-fill');
+ bars.forEach(function(bar, i) {
+ bar.style.width = '0%';
+ setTimeout(function() {
+ bar.style.width = data.bars[i] + '%';
+ }, 100);
+ });
+
+ // 更新百分比文字
+ var barValues = document.querySelectorAll('.bar-value');
+ data.bars.forEach(function(v, i) {
+ barValues[i].textContent = v + '%';
+ });
+
+ // 更新柱状图
+ var maxTrend = Math.max.apply(null, data.trends);
+ var trendBars = document.querySelectorAll('.trend-bar');
+ trendBars.forEach(function(bar, i) {
+ var fill = bar.querySelector('.trend-fill');
+ fill.style.height = '0%';
+ setTimeout(function() {
+ fill.style.height = Math.round(data.trends[i] / maxTrend * 90) + '%';
+ }, 100);
+ });
+
+ // 更新环形图
+ drawDonut(data.donut);
+ document.querySelector('.donut-center-value').textContent = data.apiTotal;
+
+ // 更新图例百分比
+ var legendPercents = document.querySelectorAll('.legend-percent');
+ data.donut.forEach(function(v, i) {
+ legendPercents[i].textContent = v + '%';
+ });
+ }
+
+ // 时间选择器切换
+ var timeButtons = document.querySelectorAll('.time-btn');
+ timeButtons.forEach(function(btn) {
+ btn.addEventListener('click', function() {
+ timeButtons.forEach(function(b) { b.classList.remove('active'); });
+ btn.classList.add('active');
+ var range = btn.getAttribute('data-range');
+ updateStats(range);
+ });
+ });
+
+ // 初始化环形图(今日数据)
+ drawDonut(mockData.today.donut);
+
+ // 卡片点击高亮
+ var cards = document.querySelectorAll('.stat-card');
+ cards.forEach(function(card) {
+ card.addEventListener('click', function() {
+ cards.forEach(function(c) { c.style.borderColor = 'rgba(255,255,255,0.06)'; });
+ card.style.borderColor = 'rgba(79, 195, 247, 0.5)';
+ });
+ });
+
+ // CSV 导出功能
+ var exportBtn = document.getElementById('exportBtn');
+ var toast = document.getElementById('exportToast');
+
+ exportBtn.addEventListener('click', function() {
+ var data = mockData[currentRange];
+ var models = ['DeepSeek', '通义千问', 'Kimi', '豆包', 'GPT/Claude'];
+ var days = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
+
+ var csv = '\uFEFF'; // BOM for Chinese support
+ csv += 'HoloLake 数据统计报表\n';
+ csv += '时间范围,' + currentRange + '\n';
+ csv += '导出时间,' + new Date().toLocaleString('zh-CN') + '\n\n';
+
+ csv += '【统计概览】\n';
+ csv += '指标,数值,变化\n';
+ csv += '总用户,' + data.users + ',↑12%\n';
+ csv += '今日对话,' + data.chats + ',↑8%\n';
+ csv += '活跃人格体,' + data.personas + ',—\n';
+ csv += 'API调用,' + data.api + ',↓3%\n\n';
+
+ csv += '【模型调用分布】\n';
+ csv += '模型,占比\n';
+ models.forEach(function(m, i) {
+ csv += m + ',' + data.donut[i] + '%\n';
+ });
+ csv += '\n';
+
+ csv += '【每日对话趋势】\n';
+ csv += '日期,对话次数\n';
+ days.forEach(function(d, i) {
+ csv += d + ',' + data.trends[i] + '\n';
+ });
+
+ // 创建下载链接
+ var blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
+ var link = document.createElement('a');
+ var url = URL.createObjectURL(blob);
+ link.href = url;
+ link.setAttribute('download', 'hololake_stats_' + currentRange + '.csv');
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ URL.revokeObjectURL(url);
+
+ // 显示提示
+ toast.classList.add('show');
+ setTimeout(function() {
+ toast.classList.remove('show');
+ }, 2000);
+ });
+
+ console.log('HoloLake Analytics v2 · 交互已加载');
+});
diff --git a/dashboard/index.html b/dashboard/index.html
new file mode 100644
index 00000000..a4782efb
--- /dev/null
+++ b/dashboard/index.html
@@ -0,0 +1,182 @@
+
+
+
+
+
+ HoloLake · 数据统计
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
👥
+
128
+
总用户
+
↑ 12%
+
+
+
💬
+
1,024
+
今日对话
+
↑ 8%
+
+
+
+
⚡
+
3,892
+
API调用
+
↓ 3%
+
+
+
+
+
🔀 模型调用占比
+
+
+
+
DeepSeek 72%
+
通义千问 15%
+
Kimi 8%
+
豆包 3%
+
GPT/Claude 2%
+
+
+
+
+
+
+
+
+
+
最近活动
+
+
+
+
+
用户「星河」与 知秋 完成了32轮对话
+
5分钟前
+
+
+
+
+
+
新用户「雨落」注册并激活了人格体
+
12分钟前
+
+
+
+
+
+
DeepSeek API 调用量达到今日峰值(420次/小时)
+
28分钟前
+
+
+
+
+
+
人格体「小坍缩核」记忆库自动归档完成
+
1小时前
+
+
+
+
+
+
用户「晚风」上传了3个文件到云盘
+
2小时前
+
+
+
+
+
+
+
+
+ CSV已下载!
+
+
+
+
diff --git a/dashboard/style.css b/dashboard/style.css
new file mode 100644
index 00000000..428962ee
--- /dev/null
+++ b/dashboard/style.css
@@ -0,0 +1,889 @@
+/* HoloLake 数据统计面板 · 样式表 */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
+ background: linear-gradient(135deg, #0a1628 0%, #1a2a4a 50%, #0d1f3c 100%);
+ color: #e0e6ed;
+ min-height: 100vh;
+}
+
+.container {
+ max-width: 640px;
+ margin: 0 auto;
+ padding: 0 20px;
+}
+
+/* 顶部导航 */
+.top-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 16px 0;
+ border-bottom: 1px solid rgba(255,255,255,0.1);
+}
+
+.logo {
+ font-size: 20px;
+ font-weight: bold;
+}
+
+.nav-links a {
+ color: #8899aa;
+ text-decoration: none;
+ margin-left: 16px;
+ font-size: 14px;
+}
+
+.nav-links a.active {
+ color: #4fc3f7;
+}
+
+.nav-links a:hover {
+ color: #fff;
+}
+
+/* 页面标题 */
+.page-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 24px 0 16px;
+}
+
+.page-header h1 {
+ font-size: 22px;
+ font-weight: 700;
+}
+
+.time-selector {
+ display: flex;
+ gap: 6px;
+}
+
+.time-btn {
+ background: rgba(255,255,255,0.06);
+ color: #8899aa;
+ border: 1px solid rgba(255,255,255,0.1);
+ padding: 6px 14px;
+ border-radius: 20px;
+ font-size: 13px;
+ cursor: pointer;
+ transition: all 0.3s;
+}
+
+.time-btn.active {
+ background: rgba(79,195,247,0.15);
+ color: #4fc3f7;
+ border-color: rgba(79,195,247,0.4);
+}
+
+.time-btn:hover {
+ border-color: rgba(79,195,247,0.3);
+ color: #b0c4d8;
+}
+
+/* 统计卡片 */
+.stats-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 12px;
+ padding-bottom: 24px;
+}
+
+.stat-card {
+ background: rgba(255,255,255,0.04);
+ border-radius: 16px;
+ padding: 20px 16px;
+ border: 1px solid rgba(255,255,255,0.06);
+ transition: all 0.3s;
+ cursor: pointer;
+}
+
+.stat-card:hover {
+ background: rgba(79,195,247,0.06);
+ border-color: rgba(79,195,247,0.2);
+ transform: translateY(-2px);
+}
+
+.stat-icon {
+ font-size: 24px;
+ margin-bottom: 8px;
+}
+
+.stat-value {
+ font-size: 32px;
+ font-weight: 800;
+ margin-bottom: 4px;
+}
+
+.stat-label {
+ font-size: 13px;
+ color: #8899aa;
+ margin-bottom: 6px;
+}
+
+.stat-change {
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.stat-change.up { color: #4caf50; }
+.stat-change.down { color: #ef5350; }
+.stat-change.same { color: #8899aa; }
+
+/* 区块通用 */
+.section {
+ padding-bottom: 28px;
+}
+
+.section h2 {
+ font-size: 16px;
+ font-weight: 600;
+ margin-bottom: 16px;
+}
+
+/* 横向条形图 */
+.bar-chart {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.bar-row {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.bar-label {
+ font-size: 13px;
+ color: #aab;
+ min-width: 70px;
+ text-align: right;
+}
+
+.bar-track {
+ flex: 1;
+ height: 22px;
+ background: rgba(255,255,255,0.04);
+ border-radius: 11px;
+ overflow: hidden;
+}
+
+.bar-fill {
+ height: 100%;
+ border-radius: 11px;
+ transition: width 1.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
+}
+
+.bar-fill.deepseek { background: linear-gradient(90deg, #4fc3f7, #29b6f6); }
+.bar-fill.qwen { background: linear-gradient(90deg, #7c4dff, #651fff); }
+.bar-fill.kimi { background: linear-gradient(90deg, #ff7043, #f4511e); }
+.bar-fill.doubao { background: linear-gradient(90deg, #66bb6a, #43a047); }
+.bar-fill.premium { background: linear-gradient(90deg, #ffd54f, #ffb300); }
+
+.bar-value {
+ font-size: 13px;
+ color: #8899aa;
+ min-width: 36px;
+ font-weight: 600;
+}
+
+/* 每日趋势柱状图 */
+.trend-chart {
+ display: flex;
+ align-items: flex-end;
+ justify-content: space-between;
+ height: 160px;
+ padding: 16px 0;
+ border-bottom: 1px solid rgba(255,255,255,0.08);
+}
+
+.trend-bar {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ flex: 1;
+ height: 100%;
+ justify-content: flex-end;
+ gap: 8px;
+}
+
+.trend-fill {
+ width: 28px;
+ border-radius: 6px 6px 2px 2px;
+ background: linear-gradient(180deg, #4fc3f7, rgba(79,195,247,0.3));
+ transition: height 1s cubic-bezier(0.25, 0.46, 0.45, 0.94);
+ height: 0;
+}
+
+.trend-bar span {
+ font-size: 11px;
+ color: #667;
+}
+
+/* 最近活动 */
+.activity-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0;
+}
+
+.activity-item {
+ display: flex;
+ align-items: flex-start;
+ gap: 12px;
+ padding: 12px 0;
+ border-bottom: 1px solid rgba(255,255,255,0.04);
+}
+
+.activity-item:last-child {
+ border-bottom: none;
+}
+
+.activity-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ margin-top: 6px;
+ flex-shrink: 0;
+}
+
+.activity-dot.blue { background: #4fc3f7; }
+.activity-dot.green { background: #66bb6a; }
+.activity-dot.orange { background: #ffb74d; }
+.activity-dot.purple { background: #ab47bc; }
+
+.activity-content {
+ flex: 1;
+}
+
+.activity-text {
+ font-size: 14px;
+ line-height: 1.5;
+}
+
+.activity-text strong {
+ color: #4fc3f7;
+}
+
+.activity-time {
+ font-size: 12px;
+ color: #556;
+ margin-top: 2px;
+}
+
+/* 底部 */
+.footer {
+ text-align: center;
+ padding: 32px 0;
+ color: #556677;
+ font-size: 12px;
+ line-height: 1.8;
+}
+
+/* 响应式 */
+@media (max-width: 480px) {
+ .stats-grid {
+ grid-template-columns: repeat(2, 1fr);
+ gap: 8px;
+ }
+ .stat-value {
+ font-size: 26px;
+ }
+ .page-header {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 12px;
+ }
+ .trend-fill {
+ width: 22px;
+ }
+ .bar-label {
+ min-width: 56px;
+ font-size: 12px;
+ }
+}
+/* ========== 响应式布局增强 ========== */
+/* 平板(768px以下) */
+@media (max-width: 768px) {
+ .container {
+ padding: 0 16px;
+ }
+ .page-header {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 12px;
+ }
+ .page-header h1 {
+ font-size: 20px;
+ }
+ .stats-grid {
+ grid-template-columns: repeat(2, 1fr);
+ gap: 10px;
+ }
+ .stat-value {
+ font-size: 28px;
+ }
+ .bar-label {
+ min-width: 60px;
+ font-size: 12px;
+ }
+ .trend-fill {
+ width: 24px;
+ }
+}
+/* 手机(480px以下) */
+📡 BC-M08-002 · DEV-010桔子 · 数据统计面板·环节2~3·响应式布局+数据导出+高级图表 2
+@media (max-width: 480px) {
+ .container {
+ padding: 0 12px;
+ }
+ .top-bar {
+ padding: 12px 0;
+ }
+ .logo {
+ font-size: 17px;
+ }
+ .nav-links a {
+ font-size: 13px;
+ margin-left: 12px;
+ }
+ .page-header h1 {
+ font-size: 18px;
+ }
+ .time-btn {
+ padding: 5px 10px;
+ font-size: 12px;
+ }
+ .stats-grid {
+ grid-template-columns: 1fr 1fr;
+ gap: 8px;
+ }
+ .stat-card {
+ padding: 14px 12px;
+ border-radius: 12px;
+ }
+ .stat-icon {
+ font-size: 20px;
+ margin-bottom: 6px;
+ }
+ .stat-value {
+ font-size: 24px;
+ }
+ .stat-label {
+ font-size: 12px;
+📡 BC-M08-002 · DEV-010桔子 · 数据统计面板·环节2~3·响应式布局+数据导出+高级图表 3
+ }
+ .stat-change {
+ font-size: 11px;
+ }
+ .section h2 {
+ font-size: 15px;
+ }
+ .bar-row {
+ gap: 8px;
+ }
+ .bar-label {
+ min-width: 50px;
+ font-size: 11px;
+ }
+ .bar-track {
+ height: 18px;
+ }
+ .bar-value {
+ font-size: 11px;
+ min-width: 30px;
+ }
+ .trend-chart {
+ height: 120px;
+ }
+ .trend-fill {
+ width: 18px;
+ border-radius: 4px 4px 2px 2px;
+ }
+ .trend-bar span {
+ font-size: 10px;
+ }
+ .activity-item {
+ padding: 10px 0;
+ gap: 10px;
+ }
+ .activity-text {
+ font-size: 13px;
+ }
+📡 BC-M08-002 · DEV-010桔子 · 数据统计面板·环节2~3·响应式布局+数据导出+高级图表 4
+ .activity-time {
+ font-size: 11px;
+ }
+ .footer {
+ padding: 20px 0;
+ font-size: 11px;
+ }
+}
+/* 超小屏(360px以下) */
+@media (max-width: 360px) {
+ .stats-grid {
+ grid-template-columns: 1fr;
+ }
+ .stat-card {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 12px 14px;
+ }
+ .stat-icon {
+ margin-bottom: 0;
+ }
+ .stat-value {
+ font-size: 22px;
+ }
+ .time-selector {
+ width: 100%;
+ justify-content: space-between;
+ }
+}
+/* ========== 导出按钮样式 ========== */
+.export-bar {
+ display: flex;
+ justify-content: flex-end;
+ padding: 8px 0;
+}
+📡 BC-M08-002 · DEV-010桔子 · 数据统计面板·环节2~3·响应式布局+数据导出+高级图表 5
+.export-btn {
+ background: rgba(76, 175, 80, 0.1);
+ color: #81c784;
+ border: 1px solid rgba(76, 175, 80, 0.2);
+ padding: 8px 18px;
+ border-radius: 8px;
+ font-size: 13px;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+.export-btn:hover {
+ background: rgba(76, 175, 80, 0.2);
+ transform: scale(1.02);
+}
+.export-btn:active {
+ transform: scale(0.98);
+}
+.export-toast {
+ position: fixed;
+ bottom: 30px;
+ left: 50%;
+ transform: translateX(-50%) translateY(60px);
+ background: rgba(76, 175, 80, 0.9);
+ color: #fff;
+ padding: 10px 24px;
+ border-radius: 8px;
+ font-size: 14px;
+ opacity: 0;
+ transition: all 0.4s;
+ pointer-events: none;
+ z-index: 999;
+}
+.export-toast.show {
+ opacity: 1;
+ transform: translateX(-50%) translateY(0);
+}
+/* ========== 环形图样式 ========== */
+📡 BC-M08-002 · DEV-010桔子 · 数据统计面板·环节2~3·响应式布局+数据导出+高级图表 6
+.donut-section {
+ padding-bottom: 28px;
+}
+.donut-container {
+ display: flex;
+ align-items: center;
+ gap: 24px;
+ justify-content: center;
+}
+.donut-chart {
+ width: 160px;
+ height: 160px;
+ position: relative;
+}
+.donut-chart svg {
+ width: 100%;
+ height: 100%;
+ transform: rotate(-90deg);
+}
+.donut-chart circle {
+ fill: none;
+ stroke-width: 20;
+ cx: 80;
+ cy: 80;
+ r: 60;
+}
+.donut-bg {
+ stroke: rgba(255,255,255,0.06);
+}
+.donut-segment {
+ transition: stroke-dasharray 1.2s cubic-bezier(0.25, 0.
+46, 0.45, 0.94);
+}
+.donut-center {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+📡 BC-M08-002 · DEV-010桔子 · 数据统计面板·环节2~3·响应式布局+数据导出+高级图表 7
+ text-align: center;
+}
+.donut-center-value {
+ font-size: 24px;
+ font-weight: 800;
+}
+.donut-center-label {
+ font-size: 11px;
+ color: #8899aa;
+}
+.donut-legend {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+.legend-item {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 13px;
+}
+.legend-dot {
+ width: 10px;
+ height: 10px;
+ border-radius: 3px;
+ flex-shrink: 0;
+}
+.legend-dot.c-deepseek { background: #4fc3f7; }
+.legend-dot.c-qwen { background: #7c4dff; }
+.legend-dot.c-kimi { background: #ff7043; }
+.legend-dot.c-doubao { background: #66bb6a; }
+.legend-dot.c-premium { background: #ffd54f; }
+.legend-percent {
+ color: #8899aa;
+ margin-left: auto;
+ font-weight: 600;
+}
+📡 BC-M08-002 · DEV-010桔子 · 数据统计面板·环节2~3·响应式布局+数据导出+高级图表 8
+@media (max-width: 480px) {
+ .donut-container {
+ flex-direction: column;
+ gap: 16px;
+ }
+ .donut-chart {
+ width: 140px;
+ height: 140px;
+ }
+ .donut-legend {
+ flex-direction: row;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 6px 16px;
+ }
+}
+/* ========== 响应式布局增强 ========== */
+/* 平板(768px以下) */
+@media (max-width: 768px) {
+ .container { padding: 0 16px; }
+ .page-header { flex-direction: column; align-items: flex-start; gap: 12px; }
+ .page-header h1 { font-size: 20px; }
+ .stats-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; }
+ .stat-value { font-size: 28px; }
+ .bar-label { min-width: 60px; font-size: 12px; }
+ .trend-fill { width: 24px; }
+}
+/* 手机(480px以下) */
+@media (max-width: 480px) {
+ .container { padding: 0 12px; }
+ .top-bar { padding: 12px 0; }
+ .logo { font-size: 17px; }
+ .nav-links a { font-size: 13px; margin-left: 12px; }
+ .page-header h1 { font-size: 18px; }
+ .time-btn { padding: 5px 10px; font-size: 12px; }
+ .stats-grid { grid-template-columns: 1fr 1fr; gap: 8px; }
+ .stat-card { padding: 14px 12px; border-radius: 12px; }
+ .stat-icon { font-size: 20px; margin-bottom: 6px; }
+ .stat-value { font-size: 24px; }
+ .stat-label { font-size: 12px; }
+ .activity-time { font-size: 11px; }
+ .footer { padding: 20px 0; font-size: 11px; }
+}
+/* 超小屏(360px以下) */
+@media (max-width: 360px) {
+ .stats-grid { grid-template-columns: 1fr; }
+ .stat-card { display: flex; align-items: center; gap: 12px; padding: 12px 14px; }
+ .stat-icon { margin-bottom: 0; }
+ .stat-value { font-size: 22px; }
+ .time-selector { width: 100%; justify-content: space-between; }
+}
+/* ========== 导出按钮样式 ========== */
+.export-bar {
+ display: flex;
+ justify-content: flex-end;
+ padding: 8px 0;
+}
+.export-btn {
+ background: rgba(76,175,80,0.1);
+ color: #81c784;
+ border: 1px solid rgba(76,175,80,0.2);
+ padding: 8px 18px;
+ border-radius: 8px;
+ font-size: 13px;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+.export-btn:hover {
+ background: rgba(76,175,80,0.2);
+ transform: scale(1.02);
+}
+.export-btn:active {
+ transform: scale(0.98);
+}
+.export-toast {
+ position: fixed;
+ bottom: 30px;
+ left: 50%;
+ transform: translateX(-50%) translateY(60px);
+ background: rgba(76,175,80,0.9);
+ color: #fff;
+ padding: 10px 24px;
+ border-radius: 8px;
+ font-size: 14px;
+ opacity: 0;
+ transition: all 0.4s;
+ pointer-events: none;
+ z-index: 999;
+}
+.export-toast.show {
+ opacity: 1;
+ transform: translateX(-50%) translateY(0);
+}
+/* ========== 环形图样式 ========== */
+.donut-section {
+ padding-bottom: 28px;
+}
+.donut-container {
+ display: flex;
+ align-items: center;
+ gap: 24px;
+ justify-content: center;
+}
+.donut-chart {
+ width: 160px;
+ height: 160px;
+ position: relative;
+}
+.donut-chart svg {
+ width: 100%;
+ height: 100%;
+ transform: rotate(-90deg);
+}
+.donut-chart circle {
+ fill: none;
+ stroke-width: 20;
+ cx: 80;
+ cy: 80;
+ r: 60;
+}
+.donut-bg {
+ stroke: rgba(255,255,255,0.06);
+}
+.donut-segment {
+ transition: stroke-dasharray 1.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
+}
+.donut-center {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ text-align: center;
+}
+.donut-center-value {
+ font-size: 24px;
+ font-weight: 800;
+}
+.donut-center-label {
+ font-size: 11px;
+ color: #8899aa;
+}
+.donut-legend {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+.legend-item {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 13px;
+}
+.legend-dot {
+ width: 10px;
+ height: 10px;
+ border-radius: 3px;
+ flex-shrink: 0;
+}
+.legend-dot.c-deepseek { background: #4fc3f7; }
+.legend-dot.c-qwen { background: #7c4dff; }
+.legend-dot.c-kimi { background: #ff7043; }
+.legend-dot.c-doubao { background: #66bb6a; }
+.legend-dot.c-premium { background: #ffd54f; }
+.legend-percent {
+ color: #8899aa;
+ margin-left: auto;
+ font-weight: 600;
+}
+/* ========== 响应式布局增强 ========== */
+@media (max-width: 768px) {
+ .container { padding: 0 16px; }
+ .page-header { flex-direction: column; align-items: flex-start; gap: 12px; }
+ .page-header h1 { font-size: 20px; }
+ .stats-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; }
+ .stat-value { font-size: 28px; }
+ .bar-label { min-width: 60px; font-size: 12px; }
+ .trend-fill { width: 24px; }
+}
+@media (max-width: 480px) {
+ .container { padding: 0 12px; }
+ .top-bar { padding: 12px 0; }
+ .logo { font-size: 17px; }
+ .nav-links a { font-size: 13px; margin-left: 12px; }
+ .page-header h1 { font-size: 18px; }
+ .time-btn { padding: 5px 10px; font-size: 12px; }
+ .stats-grid { grid-template-columns: 1fr 1fr; gap: 8px; }
+ .stat-card { padding: 14px 12px; border-radius: 12px; }
+ .stat-icon { font-size: 20px; margin-bottom: 6px; }
+ .stat-value { font-size: 24px; }
+ .stat-label { font-size: 12px; }
+ .activity-time { font-size: 11px; }
+ .footer { padding: 20px 0; font-size: 11px; }
+}
+@media (max-width: 360px) {
+ .stats-grid { grid-template-columns: 1fr; }
+ .stat-card { display: flex; align-items: center; gap: 12px; padding: 12px 14px; }
+ .stat-icon { margin-bottom: 0; }
+ .stat-value { font-size: 22px; }
+ .time-selector { width: 100%; justify-content: space-between; }
+}
+/* ========== 导出按钮样式 ========== */
+.export-bar {
+ display: flex;
+ justify-content: flex-end;
+ padding: 8px 0;
+}
+.export-btn {
+ background: rgba(76,175,80,0.1);
+ color: #81c784;
+ border: 1px solid rgba(76,175,80,0.2);
+ padding: 8px 18px;
+ border-radius: 8px;
+ font-size: 13px;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+.export-btn:hover {
+ background: rgba(76,175,80,0.2);
+ transform: scale(1.02);
+}
+.export-btn:active {
+ transform: scale(0.98);
+}
+.export-toast {
+ position: fixed;
+ bottom: 30px;
+ left: 50%;
+ transform: translateX(-50%) translateY(60px);
+ background: rgba(76,175,80,0.9);
+ color: #fff;
+ padding: 10px 24px;
+ border-radius: 8px;
+ font-size: 14px;
+ opacity: 0;
+ transition: all 0.4s;
+ pointer-events: none;
+ z-index: 999;
+}
+.export-toast.show {
+ opacity: 1;
+ transform: translateX(-50%) translateY(0);
+}
+/* ========== 环形图样式 ========== */
+.donut-section {
+ padding-bottom: 28px;
+}
+.donut-container {
+ display: flex;
+ align-items: center;
+ gap: 24px;
+ justify-content: center;
+}
+.donut-chart {
+ width: 160px;
+ height: 160px;
+ position: relative;
+}
+.donut-chart svg {
+ width: 100%;
+ height: 100%;
+ transform: rotate(-90deg);
+}
+.donut-chart circle {
+ fill: none;
+ stroke-width: 20;
+ cx: 80;
+ cy: 80;
+ r: 60;
+}
+.donut-bg {
+ stroke: rgba(255,255,255,0.06);
+}
+.donut-segment {
+ transition: stroke-dasharray 1.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
+}
+.donut-center {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ text-align: center;
+}
+.donut-center-value {
+ font-size: 24px;
+ font-weight: 800;
+}
+.donut-center-label {
+ font-size: 11px;
+ color: #8899aa;
+}
+.donut-legend {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+.legend-item {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 13px;
+}
+.legend-dot {
+ width: 10px;
+ height: 10px;
+ border-radius: 3px;
+ flex-shrink: 0;
+}
+.legend-dot.c-deepseek { background: #4fc3f7; }
+.legend-dot.c-qwen { background: #7c4dff; }
+.legend-dot.c-kimi { background: #ff7043; }
+.legend-dot.c-doubao { background: #66bb6a; }
+.legend-dot.c-premium { background: #ffd54f; }
+.legend-percent {
+ color: #8899aa;
+ margin-left: auto;
+ font-weight: 600;
+}
diff --git a/ticket-system/index.html b/ticket-system/index.html
new file mode 100644
index 00000000..bfac39d1
--- /dev/null
+++ b/ticket-system/index.html
@@ -0,0 +1,809 @@
+
+
+
+
+
+ 工单管理 · HoloLake · 视觉优化版
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 编号↑
+
+
+
+
+
+
+
+
+
+
+
+
+
+
新建工单
+
+
+
+
+
+
+
+
+
+
+
+
+background: linear-gradient(135deg, #0a1628 0%, #1a2a4a 50%, #0d1f3c 100%);
+
\ No newline at end of file
diff --git a/ticket-system/script.js b/ticket-system/script.js
new file mode 100644
index 00000000..358ac3b2
--- /dev/null
+++ b/ticket-system/script.js
@@ -0,0 +1,301 @@
+/* ============================================
+ HoloLake · M06 工单管理界面 · 逻辑层
+ 环节3:响应式 + 数据导出(JSON/CSV)
+ DEV-010 桔子
+ ============================================ */
+// === 状态流转规则 ===
+const STATUS_FLOW = {
+ 'pending': { next: 'active', label: '待处理' },
+ 'active': { next: 'done', label: '进行中' },
+ 'done': { next: 'pending', label: '已完成' }
+};
+// === 初始化 · 从 localStorage 读取工单 ===
+let tickets = JSON.parse(localStorage.getItem('holotake_tic
+kets') || '[]');
+// === 保存到 localStorage ===
+function saveTickets() {
+ localStorage.setItem('holotake_tickets', JSON.stringify(t
+ickets));
+}
+// === 生成工单编号 ===
+function generateId() {
+ const now = new Date();
+ const dateStr = [
+ now.getFullYear(),
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 18
+ String(now.getMonth() + 1).padStart(2, '0'),
+ String(now.getDate()).padStart(2, '0')
+ ].join('');
+ const rand = String(Math.floor(Math.random() * 1000)).pad
+Start(3, '0');
+ return 'TK-' + dateStr + '-' + rand;
+}
+// === 渲染统计卡片 ===
+function renderStats() {
+ const total = tickets.length;
+ const pending = tickets.filter(t => t.status === 'pendin
+g').length;
+ const active = tickets.filter(t => t.status === 'activ
+e').length;
+ const done = tickets.filter(t => t.status === 'done').len
+gth;
+ document.getElementById('statTotal').textContent = total;
+ document.getElementById('statPending').textContent = pend
+ing;
+ document.getElementById('statActive').textContent = activ
+e;
+ document.getElementById('statDone').textContent = done;
+}
+// === 获取筛选和排序后的工单列表 ===
+function getFilteredTickets() {
+ const filterStatus = document.getElementById('filterStatu
+s').value;
+ const sortBy = document.getElementById('sortBy').value;
+ let list = [...tickets];
+ // 筛选
+ if (filterStatus !== 'all') {
+ list = list.filter(t => t.status === filterStatus);
+ }
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 19
+ // 排序
+ if (sortBy === 'newest') {
+ list.sort((a, b) => new Date(b.createdAt) - new Date(a.
+createdAt));
+ } else if (sortBy === 'oldest') {
+ list.sort((a, b) => new Date(a.createdAt) - new Date(b.
+createdAt));
+ } else if (sortBy === 'status') {
+ const order = { 'pending': 0, 'active': 1, 'done': 2 };
+ list.sort((a, b) => order[a.status] - order[b.status]);
+ }
+ return list;
+}
+// === 渲染工单列表 ===
+function renderTickets() {
+ const list = getFilteredTickets();
+ const container = document.getElementById('ticketList');
+ if (list.length === 0) {
+ container.innerHTML = '';
+ return;
+ }
+ container.innerHTML = list.map(ticket => {
+ const statusInfo = STATUS_FLOW[ticket.status];
+ return '' +
+ '
' + ticket.id + '' +
+ '
' +
+ '
' + escapeHtml(ticket.ti
+tle) + '
' +
+ '
负责人:' + escapeHtml(tic
+ket.assignee) + ' · ' + formatDate(ticket.createdAt) + '' +
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 20
+ '
' +
+ '
' +
+ '' + statusInf
+o.label + '' +
+ '' +
+ '
' +
+ '
';
+ }).join('');
+}
+// === HTML转义(防XSS) ===
+function escapeHtml(str) {
+ const div = document.createElement('div');
+ div.textContent = str;
+ return div.innerHTML;
+}
+// === 格式化日期 ===
+function formatDate(dateStr) {
+ const d = new Date(dateStr);
+ return d.getFullYear() + '-' +
+ String(d.getMonth() + 1).padStart(2, '0') + '-' +
+ String(d.getDate()).padStart(2, '0') + ' ' +
+ String(d.getHours()).padStart(2, '0') + ':' +
+ String(d.getMinutes()).padStart(2, '0');
+}
+// === 切换工单状态 ===
+function toggleStatus(id) {
+ const ticket = tickets.find(t => t.id === id);
+ if (!ticket) return;
+ ticket.status = STATUS_FLOW[ticket.status].next;
+ saveTickets();
+ renderAll();
+}
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 21
+// === 删除工单 ===
+function deleteTicket(id) {
+ if (!confirm('确认删除这条工单?')) return;
+ tickets = tickets.filter(t => t.id !== id);
+ saveTickets();
+ renderAll();
+}
+// === 新建工单弹窗 ===
+function openModal() {
+ document.getElementById('modalOverlay').classList.add('sh
+ow');
+ document.getElementById('inputTitle').value = '';
+ document.getElementById('inputAssignee').value = '';
+ document.getElementById('inputDetail').value = '';
+ document.getElementById('inputTitle').focus();
+}
+function closeModal() {
+ document.getElementById('modalOverlay').classList.remove
+('show');
+}
+// === 提交新建工单 ===
+function submitTicket() {
+ const title = document.getElementById('inputTitle').valu
+e.trim();
+ const assignee = document.getElementById('inputAssigne
+e').value.trim();
+ const detail = document.getElementById('inputDetail').val
+ue.trim();
+ if (!title) {
+ alert('请填写工单标题');
+ return;
+ }
+ if (!assignee) {
+ alert('请填写负责人');
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 22
+ return;
+ }
+ const newTicket = {
+ id: generateId(),
+ title: title,
+ assignee: assignee,
+ detail: detail,
+ status: 'pending',
+ createdAt: new Date().toISOString()
+ };
+ tickets.unshift(newTicket);
+ saveTickets();
+ closeModal();
+ renderAll();
+}
+// === 重置全部工单 ===
+function resetTickets() {
+ if (!confirm('确认清空所有工单数据?此操作不可恢复!')) return;
+ tickets = [];
+ saveTickets();
+ renderAll();
+}
+// ============================================
+// 环节3新增:导出功能
+// ============================================
+// === 导出下拉菜单控制 ===
+function toggleExportMenu() {
+ const dropdown = document.getElementById('exportDropdow
+n');
+ const clickAway = document.getElementById('clickAway');
+ const isOpen = dropdown.classList.contains('show');
+ if (isOpen) {
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 23
+ closeExportMenu();
+ } else {
+ dropdown.classList.add('show');
+ clickAway.classList.add('show');
+ }
+}
+function closeExportMenu() {
+ document.getElementById('exportDropdown').classList.remov
+e('show');
+ document.getElementById('clickAway').classList.remove('sh
+ow');
+}
+// === 导出为 JSON 文件 ===
+function exportJSON() {
+ closeExportMenu();
+ if (tickets.length === 0) {
+ alert('当前没有工单数据可导出');
+ return;
+ }
+ const data = JSON.stringify(tickets, null, 2);
+ const blob = new Blob([data], { type: 'application/json;c
+harset=utf-8' });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = 'HoloLake-Tickets-' + getDateStamp() + '.jso
+n';
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
+}
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 24
+// === 导出为 CSV 文件 ===
+function exportCSV() {
+ closeExportMenu();
+ if (tickets.length === 0) {
+ alert('当前没有工单数据可导出');
+ return;
+ }
+ // CSV表头
+ const header = '编号,标题,负责人,状态,详情,创建时间';
+ // CSV内容行
+ const rows = tickets.map(t => {
+ const statusLabel = STATUS_FLOW[t.status] ? STATUS_FLOW
+[t.status].label : t.status;
+ return [
+ t.id,
+ csvEscape(t.title),
+ csvEscape(t.assignee),
+ statusLabel,
+ csvEscape(t.detail || ''),
+ formatDate(t.createdAt)
+ ].join(',');
+ });
+ const csv = '\uFEFF' + header + '\n' + rows.join('\n');
+ const blob = new Blob([csv], { type: 'text/csv;charset=ut
+f-8' });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = 'HoloLake-Tickets-' + getDateStamp() + '.cs
+v';
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 25
+ URL.revokeObjectURL(url);
+}
+// === CSV字段转义(处理逗号和引号) ===
+function csvEscape(str) {
+ if (!str) return '';
+ if (str.includes(',') || str.includes('"') || str.include
+s('\n')) {
+ return '"' + str.replace(/"/g, '""') + '"';
+ }
+ return str;
+}
+// === 生成日期戳(用于文件名) ===
+function getDateStamp() {
+ const now = new Date();
+ return now.getFullYear() +
+ String(now.getMonth() + 1).padStart(2, '0') +
+ String(now.getDate()).padStart(2, '0') + '-' +
+ String(now.getHours()).padStart(2, '0') +
+ String(now.getMinutes()).padStart(2, '0');
+}
+// === 统一渲染 ===
+function renderAll() {
+ renderStats();
+ renderTickets();
+}
+// === 筛选/排序变化时重新渲染 ===
+document.getElementById('filterStatus').addEventListener('c
+hange', renderTickets);
+document.getElementById('sortBy').addEventListener('chang
+e', renderTickets);
+// === 弹窗点击遮罩关闭 ===
+document.getElementById('modalOverlay').addEventListener('c
+lick', function(e) {
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 26
+ if (e.target === this) closeModal();
+});
+// === 页面加载完成 · 首次渲染 ===
+renderAll();
diff --git a/ticket-system/style.css b/ticket-system/style.css
new file mode 100644
index 00000000..6a2a6ccf
--- /dev/null
+++ b/ticket-system/style.css
@@ -0,0 +1,527 @@
+/* ============================================
+ HoloLake · M06 工单管理界面 · 样式表
+ 环节3:响应式布局 · 深蓝主题
+ DEV-010 桔子
+ ============================================ */
+/* === 全局变量 === */
+:root {
+ --bg-primary: #0a0e27;
+ --bg-secondary: #111638;
+ --bg-card: #161b4a;
+ --bg-hover: #1e2460;
+ --border-color: #2a3070;
+ --text-primary: #e8eaff;
+ --text-secondary: #8b90c0;
+ --accent-blue: #4a6cf7;
+ --accent-blue-hover: #5b7bf8;
+ --accent-green: #22c55e;
+ --accent-yellow: #eab308;
+ --accent-red: #ef4444;
+ --accent-purple: #a855f7;
+ --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.3);
+ --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.4);
+ --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.5);
+ --radius-sm: 6px;
+ --radius-md: 10px;
+ --radius-lg: 14px;
+}
+/* === 基础重置 === */
+* {
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 2
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe U
+I", "PingFang SC", "Microsoft YaHei", sans-serif;
+ background: var(--bg-primary);
+ color: var(--text-primary);
+ min-height: 100vh;
+ line-height: 1.6;
+}
+/* === 主容器 === */
+.app-container {
+ max-width: 900px;
+ margin: 0 auto;
+ padding: 20px 24px;
+}
+/* === 顶部标题栏 === */
+.app-header {
+ text-align: center;
+ padding: 24px 0 20px;
+ border-bottom: 1px solid var(--border-color);
+ margin-bottom: 24px;
+}
+.app-header h1 {
+ font-size: 22px;
+ font-weight: 700;
+ color: var(--text-primary);
+ letter-spacing: 1px;
+}
+.app-header .subtitle {
+ font-size: 13px;
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 3
+ color: var(--text-secondary);
+ margin-top: 4px;
+}
+/* === 操作栏(新建 + 导出) === */
+.header-actions {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 12px;
+ margin-bottom: 24px;
+ flex-wrap: wrap;
+}
+.btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 10px 20px;
+ border: none;
+ border-radius: var(--radius-sm);
+ font-size: 14px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ white-space: nowrap;
+}
+.btn-primary {
+ background: var(--accent-blue);
+ color: #fff;
+}
+.btn-primary:hover {
+ background: var(--accent-blue-hover);
+ box-shadow: var(--shadow-sm);
+}
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 4
+.btn-secondary {
+ background: var(--bg-card);
+ color: var(--text-primary);
+ border: 1px solid var(--border-color);
+}
+.btn-secondary:hover {
+ background: var(--bg-hover);
+}
+/* === 导出下拉菜单 === */
+.export-wrapper {
+ position: relative;
+}
+.export-dropdown {
+ display: none;
+ position: absolute;
+ top: calc(100% + 6px);
+ left: 50%;
+ transform: translateX(-50%);
+ background: var(--bg-card);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-sm);
+ box-shadow: var(--shadow-md);
+ z-index: 100;
+ min-width: 160px;
+ overflow: hidden;
+}
+.export-dropdown.show {
+ display: block;
+}
+.export-dropdown .export-item {
+ display: block;
+ width: 100%;
+ padding: 10px 16px;
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 5
+ background: none;
+ border: none;
+ color: var(--text-primary);
+ font-size: 14px;
+ text-align: left;
+ cursor: pointer;
+ transition: background 0.15s;
+}
+.export-dropdown .export-item:hover {
+ background: var(--bg-hover);
+}
+.export-dropdown .export-item + .export-item {
+ border-top: 1px solid var(--border-color);
+}
+/* === 统计卡片 === */
+.stats-grid {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 12px;
+ margin-bottom: 24px;
+}
+.stat-card {
+ background: var(--bg-card);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-md);
+ padding: 16px;
+ text-align: center;
+ transition: transform 0.2s, box-shadow 0.2s;
+}
+.stat-card:hover {
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-sm);
+}
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 6
+.stat-card .stat-number {
+ font-size: 28px;
+ font-weight: 700;
+ line-height: 1.2;
+}
+.stat-card .stat-label {
+ font-size: 12px;
+ color: var(--text-secondary);
+ margin-top: 4px;
+}
+.stat-card.total .stat-number { color: var(--accent-blue);
+}
+.stat-card.pending .stat-number { color: var(--accent-yello
+w); }
+.stat-card.active .stat-number { color: var(--accent-gree
+n); }
+.stat-card.done .stat-number { color: var(--accent-purple);
+}
+/* === 筛选排序栏 === */
+.filter-bar {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 20px;
+ flex-wrap: wrap;
+}
+.filter-bar select {
+ flex: 1;
+ min-width: 120px;
+ padding: 8px 12px;
+ background: var(--bg-card);
+ color: var(--text-primary);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-sm);
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 7
+ font-size: 13px;
+ cursor: pointer;
+ appearance: none;
+ -webkit-appearance: none;
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='h
+ttp://www.w3.org/2000/svg' width='12' height='12' fill='%23
+8b90c0'%3E%3Cpath d='M6 8L1 3h10z'/%3E%3C/svg%3E");
+ background-repeat: no-repeat;
+ background-position: right 10px center;
+ padding-right: 30px;
+}
+.filter-bar select:focus {
+ outline: none;
+ border-color: var(--accent-blue);
+}
+/* === 工单列表 === */
+.ticket-list {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+.ticket-item {
+ background: var(--bg-card);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-md);
+ padding: 16px;
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ transition: background 0.15s;
+}
+.ticket-item:hover {
+ background: var(--bg-hover);
+}
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 8
+.ticket-id {
+ font-size: 12px;
+ color: var(--text-secondary);
+ font-family: "SF Mono", "Fira Code", monospace;
+ min-width: 60px;
+}
+.ticket-info {
+ flex: 1;
+ min-width: 0;
+}
+.ticket-title {
+ font-size: 15px;
+ font-weight: 600;
+ color: var(--text-primary);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.ticket-meta {
+ font-size: 12px;
+ color: var(--text-secondary);
+ margin-top: 2px;
+}
+.ticket-actions {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ flex-shrink: 0;
+}
+/* === 状态标签(可点击切换) === */
+.status-badge {
+ display: inline-block;
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 9
+ padding: 4px 12px;
+ border-radius: 20px;
+ font-size: 12px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: opacity 0.2s;
+ white-space: nowrap;
+}
+.status-badge:hover {
+ opacity: 0.85;
+}
+.status-badge.pending {
+ background: rgba(234, 179, 8, 0.15);
+ color: var(--accent-yellow);
+ border: 1px solid rgba(234, 179, 8, 0.3);
+}
+.status-badge.active {
+ background: rgba(34, 197, 94, 0.15);
+ color: var(--accent-green);
+ border: 1px solid rgba(34, 197, 94, 0.3);
+}
+.status-badge.done {
+ background: rgba(168, 85, 247, 0.15);
+ color: var(--accent-purple);
+ border: 1px solid rgba(168, 85, 247, 0.3);
+}
+/* === 删除按钮 === */
+.btn-delete {
+ background: none;
+ border: 1px solid transparent;
+ color: var(--text-secondary);
+ font-size: 16px;
+ cursor: pointer;
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 10
+ padding: 4px 8px;
+ border-radius: var(--radius-sm);
+ transition: all 0.2s;
+}
+.btn-delete:hover {
+ color: var(--accent-red);
+ background: rgba(239, 68, 68, 0.1);
+ border-color: rgba(239, 68, 68, 0.3);
+}
+/* === 空状态 === */
+.empty-state {
+ text-align: center;
+ padding: 60px 20px;
+ color: var(--text-secondary);
+}
+.empty-state .empty-icon {
+ font-size: 48px;
+ margin-bottom: 12px;
+}
+.empty-state .empty-text {
+ font-size: 15px;
+}
+/* === 弹窗遮罩 === */
+.modal-overlay {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.6);
+ z-index: 1000;
+ justify-content: center;
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 11
+ align-items: center;
+ padding: 20px;
+}
+.modal-overlay.show {
+ display: flex;
+}
+/* === 弹窗 === */
+.modal {
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-lg);
+ padding: 28px;
+ width: 100%;
+ max-width: 480px;
+ box-shadow: var(--shadow-lg);
+}
+.modal h2 {
+ font-size: 18px;
+ margin-bottom: 20px;
+ color: var(--text-primary);
+}
+.modal .form-group {
+ margin-bottom: 16px;
+}
+.modal label {
+ display: block;
+ font-size: 13px;
+ color: var(--text-secondary);
+ margin-bottom: 6px;
+}
+.modal input,
+.modal select,
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 12
+.modal textarea {
+ width: 100%;
+ padding: 10px 12px;
+ background: var(--bg-card);
+ color: var(--text-primary);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-sm);
+ font-size: 14px;
+}
+.modal input:focus,
+.modal select:focus,
+.modal textarea:focus {
+ outline: none;
+ border-color: var(--accent-blue);
+}
+.modal textarea {
+ resize: vertical;
+ min-height: 80px;
+}
+.modal .form-actions {
+ display: flex;
+ gap: 10px;
+ justify-content: flex-end;
+ margin-top: 20px;
+}
+/* === 点击外部关闭下拉菜单的辅助层 === */
+.click-away {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 99;
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 13
+}
+.click-away.show {
+ display: block;
+}
+/* ============================================
+ 响应式布局 · 平板端(481px ~ 768px)
+ ============================================ */
+@media screen and (max-width: 768px) {
+ .app-container {
+ padding: 16px;
+ }
+ .app-header h1 {
+ font-size: 20px;
+ }
+ .stats-grid {
+ grid-template-columns: repeat(4, 1fr);
+ gap: 8px;
+ }
+ .stat-card {
+ padding: 12px 8px;
+ }
+ .stat-card .stat-number {
+ font-size: 24px;
+ }
+ .stat-card .stat-label {
+ font-size: 11px;
+ }
+ .ticket-item {
+ padding: 12px;
+ gap: 10px;
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 14
+ }
+}
+/* ============================================
+ 响应式布局 · 手机端(<=480px)
+ ============================================ */
+@media screen and (max-width: 480px) {
+ .app-container {
+ padding: 12px;
+ }
+ .app-header {
+ padding: 16px 0 14px;
+ margin-bottom: 16px;
+ }
+ .app-header h1 {
+ font-size: 18px;
+ }
+ /* 统计卡片手机端变2列 */
+ .stats-grid {
+ grid-template-columns: repeat(2, 1fr);
+ gap: 8px;
+ }
+ .stat-card {
+ padding: 12px 10px;
+ }
+ .stat-card .stat-number {
+ font-size: 22px;
+ }
+ /* 操作按钮自适应 */
+ .header-actions {
+ gap: 8px;
+ }
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 15
+ .btn {
+ padding: 8px 14px;
+ font-size: 13px;
+ }
+ /* 筛选栏纵向排列 */
+ .filter-bar {
+ flex-direction: column;
+ gap: 8px;
+ }
+ .filter-bar select {
+ width: 100%;
+ }
+ /* 工单卡片纵向排列 */
+ .ticket-item {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 8px;
+ padding: 14px;
+ }
+ .ticket-id {
+ min-width: auto;
+ }
+ .ticket-info {
+ width: 100%;
+ }
+ .ticket-title {
+ white-space: normal;
+ word-break: break-all;
+ }
+ .ticket-actions {
+📡 BC-M06-001 · DEV-010桔子 · 工单管理界面·环节3·响应式布局+数据导出 16
+ width: 100%;
+ justify-content: space-between;
+ }
+ /* 导出下拉菜单手机端定位优化 */
+ .export-dropdown {
+ left: auto;
+ right: 0;
+ transform: none;
+ }
+ /* 弹窗手机端全屏 */
+ .modal-overlay {
+ padding: 0;
+ align-items: flex-end;
+ }
+ .modal {
+ max-width: 100%;
+ border-radius: var(--radius-lg) var(--radius-lg) 0 0;
+ padding: 24px 20px;
+ max-height: 90vh;
+ overflow-y: auto;
+ }
+ .modal .form-actions {
+ flex-direction: column;
+ }
+ .modal .form-actions .btn {
+ width: 100%;
+ justify-content: center;
+ }
+}
From 6345f4b70fe7228c54913878c0ff96cb42e76f6a Mon Sep 17 00:00:00 2001
From: liuxunxun7-max
Date: Sat, 7 Mar 2026 20:11:33 +0800
Subject: [PATCH 02/19] Add files via upload
---
m18-health-check/package.json | 16 +++
m18-health-check/server.js | 240 ++++++++++++++++++++++++++++++++++
2 files changed, 256 insertions(+)
create mode 100644 m18-health-check/package.json
create mode 100644 m18-health-check/server.js
diff --git a/m18-health-check/package.json b/m18-health-check/package.json
new file mode 100644
index 00000000..1887483c
--- /dev/null
+++ b/m18-health-check/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "hololake-health",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "type": "commonjs",
+ "dependencies": {
+ "express": "^5.2.1"
+ }
+}
diff --git a/m18-health-check/server.js b/m18-health-check/server.js
new file mode 100644
index 00000000..40ed6a97
--- /dev/null
+++ b/m18-health-check/server.js
@@ -0,0 +1,240 @@
+const express = require('express');
+const os = require('os');
+
+const app = express();
+const PORT = 3000;
+
+// 记录服务器启动时间
+const SERVER_START_TIME = new Date();
+
+// 解析JSON请求体
+app.use(express.json());
+
+// ========== 数据存储 ==========
+let heartbeats = [];
+const patrolHistory = [];
+const alerts = [];
+const HEARTBEAT_TIMEOUT = 5 * 60 * 1000; // 5分钟
+
+// ========== 告警检查函数 ==========
+function checkAlerts(memPercent) {
+ let level = null;
+ let message = '';
+
+ if (memPercent > 90) {
+ level = 'critical';
+ message = `内存使用率过高: ${memPercent}%`;
+ } else if (memPercent > 80) {
+ level = 'warning';
+ message = `内存使用率警告: ${memPercent}%`;
+ }
+
+ if (level) {
+ const alert = {
+ timestamp: new Date().toISOString(),
+ level: level,
+ message: message,
+ memoryPercent: memPercent
+ };
+ alerts.push(alert);
+
+ if (alerts.length > 20) {
+ alerts.shift();
+ }
+
+ console.log(`[ALERT] ${level.toUpperCase()}: ${message}`);
+ }
+}
+
+// ========== 在线状态检查函数 ==========
+function checkOnlineStatus() {
+ const now = Date.now();
+ const onlineServices = [];
+ const offlineServices = [];
+
+ const latestHeartbeats = {};
+ heartbeats.forEach(hb => {
+ const source = hb.service || 'unknown';
+ if (!latestHeartbeats[source] || new Date(hb.timestamp) > new Date(latestHeartbeats[source].timestamp)) {
+ latestHeartbeats[source] = hb;
+ }
+ });
+
+ for (const [source, hb] of Object.entries(latestHeartbeats)) {
+ const hbTime = new Date(hb.timestamp).getTime();
+ const isOnline = (now - hbTime) < HEARTBEAT_TIMEOUT;
+
+ const serviceInfo = {
+ source: source,
+ lastHeartbeat: hb.timestamp,
+ secondsAgo: Math.floor((now - hbTime) / 1000),
+ status: isOnline ? 'online' : 'offline'
+ };
+
+ if (isOnline) {
+ onlineServices.push(serviceInfo);
+ } else {
+ offlineServices.push(serviceInfo);
+ }
+ }
+
+ return { online: onlineServices, offline: offlineServices };
+}
+
+// ========== API路由 ==========
+
+// GET /api/health - 快速健康检查
+app.get('/api/health', (req, res) => {
+ res.json({
+ status: 'healthy',
+ timestamp: new Date().toISOString()
+ });
+});
+
+// GET /api/status - 详细系统状态
+app.get('/api/status', (req, res) => {
+ const totalMem = os.totalmem();
+ const freeMem = os.freemem();
+ const usedMem = totalMem - freeMem;
+ const memPercent = Math.round((usedMem / totalMem) * 100);
+
+ checkAlerts(memPercent);
+
+ res.json({
+ service: 'HoloLake Health Monitor',
+ version: '1.0.0',
+ status: 'running',
+ timestamp: new Date().toISOString(),
+ uptime: {
+ seconds: Math.floor((Date.now() - SERVER_START_TIME.getTime()) / 1000),
+ startedAt: SERVER_START_TIME.toISOString()
+ },
+ system: {
+ platform: os.platform(),
+ arch: os.arch(),
+ hostname: os.hostname(),
+ nodeVersion: process.version
+ },
+ memory: {
+ totalMB: Math.round(totalMem / 1024 / 1024),
+ usedMB: Math.round(usedMem / 1024 / 1024),
+ freeMB: Math.round(freeMem / 1024 / 1024),
+ usagePercent: memPercent + '%'
+ },
+ services: checkOnlineStatus()
+ });
+});
+
+// POST /api/heartbeat - 心跳上报
+app.post('/api/heartbeat', (req, res) => {
+ const heartbeat = {
+ timestamp: new Date().toISOString(),
+ service: req.body.service || 'unknown',
+ status: req.body.status || 'ok'
+ };
+ heartbeats.push(heartbeat);
+
+ res.json({
+ received: true,
+ heartbeat: heartbeat
+ });
+});
+
+// GET /api/heartbeat/history - 查看心跳历史
+app.get('/api/heartbeat/history', (req, res) => {
+ res.json({
+ total: heartbeats.length,
+ heartbeats: heartbeats.slice(-20)
+ });
+});
+
+// GET /api/heartbeat/online - 查看在线服务
+app.get('/api/heartbeat/online', (req, res) => {
+ const status = checkOnlineStatus();
+ res.json({
+ timestamp: new Date().toISOString(),
+ onlineCount: status.online.length,
+ offlineCount: status.offline.length,
+ online: status.online,
+ offline: status.offline
+ });
+});
+
+// GET /api/patrol/history - 查看巡检历史
+app.get('/api/patrol/history', (req, res) => {
+ res.json({
+ total: patrolHistory.length,
+ patrols: patrolHistory
+ });
+});
+
+// GET /api/alerts - 查看告警历史
+app.get('/api/alerts', (req, res) => {
+ res.json({
+ total: alerts.length,
+ critical: alerts.filter(a => a.level === 'critical').length,
+ warning: alerts.filter(a => a.level === 'warning').length,
+ alerts: alerts
+ });
+});
+
+// GET / - 根路径欢迎页
+app.get('/', (req, res) => {
+ res.json({
+ service: 'HoloLake Health Check & Status Report',
+ version: '2.0.0',
+ endpoints: [
+ 'GET /api/health - 快速健康检查',
+ 'GET /api/status - 详细系统状态',
+ 'POST /api/heartbeat - 心跳上报',
+ 'GET /api/heartbeat/history - 心跳历史',
+ 'GET /api/heartbeat/online - 在线服务',
+ 'GET /api/patrol/history - 巡检历史',
+ 'GET /api/alerts - 告警历史'
+ ]
+ });
+});
+
+// ========== 定时自动巡检 ==========
+setInterval(() => {
+ console.log('[PATROL] 开始定时巡检...');
+
+ const totalMem = os.totalmem();
+ const freeMem = os.freemem();
+ const usedMem = totalMem - freeMem;
+ const memPercent = Math.round((usedMem / totalMem) * 100);
+
+ const patrolRecord = {
+ timestamp: new Date().toISOString(),
+ memory: {
+ totalMB: Math.round(totalMem / 1024 / 1024),
+ usedMB: Math.round(usedMem / 1024 / 1024),
+ usagePercent: memPercent
+ },
+ uptime: Math.floor((Date.now() - SERVER_START_TIME.getTime()) / 1000),
+ heartbeatCount: heartbeats.length
+ };
+
+ patrolHistory.push(patrolRecord);
+ if (patrolHistory.length > 50) {
+ patrolHistory.shift();
+ }
+
+ checkAlerts(memPercent);
+
+ console.log(`[PATROL] 巡检完成 - 内存使用: ${memPercent}%`);
+}, 60000);
+
+// 启动服务器
+app.listen(PORT, () => {
+ console.log('='.repeat(50));
+ console.log('🌊 HoloLake Health Check & Status Report');
+ console.log('📡 服务运行在: http://localhost:' + PORT);
+ console.log('💚 GET /api/health - 健康检查');
+ console.log('📊 GET /api/status - 系统状态');
+ console.log('💓 POST /api/heartbeat - 心跳上报');
+ console.log('🔄 定时巡检 - 每60秒');
+ console.log('🚨 异常告警 - 内存>80%');
+ console.log('⏰ 心跳超时 - 5分钟');
+ console.log('='.repeat(50));
+});
\ No newline at end of file
From e9ec86990dc90c4b92656ecc185fb34b456f9fe8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=93=B8=E6=B8=8A=20=28Zh=C3=B9Yu=C4=81n=29?=
Date: Sat, 7 Mar 2026 12:11:53 +0000
Subject: [PATCH 03/19] =?UTF-8?q?=F0=9F=93=9A=20=E9=93=B8=E6=B8=8A?=
=?UTF-8?q?=E5=9B=BE=E4=B9=A6=E9=A6=86=E7=9B=AE=E5=BD=95=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=20=C2=B7=202026-03-07T12:11?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/brain/repo-map.json | 4 ++--
.github/brain/repo-snapshot.md | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/.github/brain/repo-map.json b/.github/brain/repo-map.json
index eb059601..38ca3066 100644
--- a/.github/brain/repo-map.json
+++ b/.github/brain/repo-map.json
@@ -1,7 +1,7 @@
{
"description": "铸渊图书馆目录 · Library Catalog for 铸渊 (Zhùyuān)",
"version": "2.0",
- "generated_at": "2026-03-07T11:38:46.113Z",
+ "generated_at": "2026-03-07T12:11:53.592Z",
"generated_by": "scripts/generate-repo-map.js",
"repo": "qinfendebingshuo/guanghulab",
"stats": {
@@ -431,7 +431,7 @@
{
"module_id": "M18",
"dir": "m18-health-check",
- "files": 1,
+ "files": 3,
"has_readme": true
}
],
diff --git a/.github/brain/repo-snapshot.md b/.github/brain/repo-snapshot.md
index c67aa136..830bba41 100644
--- a/.github/brain/repo-snapshot.md
+++ b/.github/brain/repo-snapshot.md
@@ -1,5 +1,5 @@
# 铸渊图书馆快照 · Repo Snapshot
-> 生成于 2026-03-07 19:38 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
+> 生成于 2026-03-07 20:11 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
---
@@ -13,7 +13,7 @@
| 脚本 | 18 个执行脚本 |
| 开发者节点 | 8 人 |
| HLI 接口覆盖率 | 3/17 (18%) |
-| 快照生成时间 | 2026-03-07 19:38 CST |
+| 快照生成时间 | 2026-03-07 20:11 CST |
---
@@ -189,7 +189,7 @@
- `m11-module/` — 4 个文件 (有README)
- `m12-kanban/` — 1 个文件 (有README)
- `m15-cloud-drive/` — 3 个文件
-- `m18-health-check/` — 1 个文件 (有README)
+- `m18-health-check/` — 3 个文件 (有README)
---
From f9c015c21e6b48b58ce2628e3a7da4f84f0ec584 Mon Sep 17 00:00:00 2001
From: stbr-0709 <942341863@qq.com>
Date: Sat, 7 Mar 2026 21:15:11 +0800
Subject: [PATCH 04/19] Update deploy-to-server.yml
---
.github/workflows/deploy-to-server.yml | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/.github/workflows/deploy-to-server.yml b/.github/workflows/deploy-to-server.yml
index 1208d6e6..9c218368 100644
--- a/.github/workflows/deploy-to-server.yml
+++ b/.github/workflows/deploy-to-server.yml
@@ -16,6 +16,13 @@ name: "🚀 铸渊 CD · 自动部署到 guanghulab.com"
on:
push:
branches: [main]
+ paths:
+ - '**'
+ - '!broadcasts-outbox/**'
+ - '!syslog-inbox/**'
+ - '!syslog-processed/**'
+ - '!dev-nodes/**'
+ - '!.github/persona-brain/**'
paths-ignore:
- '.github/persona-brain/**'
- 'broadcasts-outbox/**'
From a9f2e3eecf8a9a6f19f3df2c189e18b32fab2951 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=93=B8=E6=B8=8A=20=28Zh=C3=B9Yu=C4=81n=29?=
Date: Sat, 7 Mar 2026 13:15:33 +0000
Subject: [PATCH 05/19] =?UTF-8?q?=F0=9F=93=9A=20=E9=93=B8=E6=B8=8A?=
=?UTF-8?q?=E5=9B=BE=E4=B9=A6=E9=A6=86=E7=9B=AE=E5=BD=95=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=20=C2=B7=202026-03-07T13:15?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/brain/repo-map.json | 2 +-
.github/brain/repo-snapshot.md | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/brain/repo-map.json b/.github/brain/repo-map.json
index 38ca3066..74dc34c4 100644
--- a/.github/brain/repo-map.json
+++ b/.github/brain/repo-map.json
@@ -1,7 +1,7 @@
{
"description": "铸渊图书馆目录 · Library Catalog for 铸渊 (Zhùyuān)",
"version": "2.0",
- "generated_at": "2026-03-07T12:11:53.592Z",
+ "generated_at": "2026-03-07T13:15:33.548Z",
"generated_by": "scripts/generate-repo-map.js",
"repo": "qinfendebingshuo/guanghulab",
"stats": {
diff --git a/.github/brain/repo-snapshot.md b/.github/brain/repo-snapshot.md
index 830bba41..fe500e39 100644
--- a/.github/brain/repo-snapshot.md
+++ b/.github/brain/repo-snapshot.md
@@ -1,5 +1,5 @@
# 铸渊图书馆快照 · Repo Snapshot
-> 生成于 2026-03-07 20:11 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
+> 生成于 2026-03-07 21:15 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
---
@@ -13,7 +13,7 @@
| 脚本 | 18 个执行脚本 |
| 开发者节点 | 8 人 |
| HLI 接口覆盖率 | 3/17 (18%) |
-| 快照生成时间 | 2026-03-07 20:11 CST |
+| 快照生成时间 | 2026-03-07 21:15 CST |
---
From 89993573f8b67032493f5984adff2c7d76bc32a9 Mon Sep 17 00:00:00 2001
From: stbr-0709 <942341863@qq.com>
Date: Sat, 7 Mar 2026 21:19:40 +0800
Subject: [PATCH 06/19] Update deploy-to-server.yml
---
.github/workflows/deploy-to-server.yml | 7 -------
1 file changed, 7 deletions(-)
diff --git a/.github/workflows/deploy-to-server.yml b/.github/workflows/deploy-to-server.yml
index 9c218368..1208d6e6 100644
--- a/.github/workflows/deploy-to-server.yml
+++ b/.github/workflows/deploy-to-server.yml
@@ -16,13 +16,6 @@ name: "🚀 铸渊 CD · 自动部署到 guanghulab.com"
on:
push:
branches: [main]
- paths:
- - '**'
- - '!broadcasts-outbox/**'
- - '!syslog-inbox/**'
- - '!syslog-processed/**'
- - '!dev-nodes/**'
- - '!.github/persona-brain/**'
paths-ignore:
- '.github/persona-brain/**'
- 'broadcasts-outbox/**'
From 18410aeaefb2eed5acc0429cb25e8116cf4263f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=93=B8=E6=B8=8A=20=28Zh=C3=B9Yu=C4=81n=29?=
Date: Sat, 7 Mar 2026 13:19:58 +0000
Subject: [PATCH 07/19] =?UTF-8?q?=F0=9F=93=9A=20=E9=93=B8=E6=B8=8A?=
=?UTF-8?q?=E5=9B=BE=E4=B9=A6=E9=A6=86=E7=9B=AE=E5=BD=95=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=20=C2=B7=202026-03-07T13:19?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/brain/repo-map.json | 2 +-
.github/brain/repo-snapshot.md | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/brain/repo-map.json b/.github/brain/repo-map.json
index 74dc34c4..3995b469 100644
--- a/.github/brain/repo-map.json
+++ b/.github/brain/repo-map.json
@@ -1,7 +1,7 @@
{
"description": "铸渊图书馆目录 · Library Catalog for 铸渊 (Zhùyuān)",
"version": "2.0",
- "generated_at": "2026-03-07T13:15:33.548Z",
+ "generated_at": "2026-03-07T13:19:58.534Z",
"generated_by": "scripts/generate-repo-map.js",
"repo": "qinfendebingshuo/guanghulab",
"stats": {
diff --git a/.github/brain/repo-snapshot.md b/.github/brain/repo-snapshot.md
index fe500e39..580546d2 100644
--- a/.github/brain/repo-snapshot.md
+++ b/.github/brain/repo-snapshot.md
@@ -1,5 +1,5 @@
# 铸渊图书馆快照 · Repo Snapshot
-> 生成于 2026-03-07 21:15 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
+> 生成于 2026-03-07 21:19 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
---
@@ -13,7 +13,7 @@
| 脚本 | 18 个执行脚本 |
| 开发者节点 | 8 人 |
| HLI 接口覆盖率 | 3/17 (18%) |
-| 快照生成时间 | 2026-03-07 21:15 CST |
+| 快照生成时间 | 2026-03-07 21:19 CST |
---
From e4b64eacb032588e943211831e93185cb44277c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=93=B8=E6=B8=8A=20=28Zh=C3=B9Yu=C4=81n=29?=
Date: Sun, 8 Mar 2026 00:58:17 +0000
Subject: [PATCH 08/19] =?UTF-8?q?=F0=9F=94=8D=20=E9=93=B8=E6=B8=8A?=
=?UTF-8?q?=E6=AF=8F=E6=97=A5=E8=87=AA=E6=A3=80=20=C2=B7=202026-03-08?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/brain/repo-map.json | 2 +-
.github/brain/repo-snapshot.md | 4 ++--
.github/persona-brain/growth-journal.md | 7 +++++++
.github/persona-brain/knowledge-base.json | 2 +-
.github/persona-brain/memory.json | 10 ++++++++--
5 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/.github/brain/repo-map.json b/.github/brain/repo-map.json
index 3995b469..d3e98b9c 100644
--- a/.github/brain/repo-map.json
+++ b/.github/brain/repo-map.json
@@ -1,7 +1,7 @@
{
"description": "铸渊图书馆目录 · Library Catalog for 铸渊 (Zhùyuān)",
"version": "2.0",
- "generated_at": "2026-03-07T13:19:58.534Z",
+ "generated_at": "2026-03-08T00:58:17.436Z",
"generated_by": "scripts/generate-repo-map.js",
"repo": "qinfendebingshuo/guanghulab",
"stats": {
diff --git a/.github/brain/repo-snapshot.md b/.github/brain/repo-snapshot.md
index 580546d2..11dbca65 100644
--- a/.github/brain/repo-snapshot.md
+++ b/.github/brain/repo-snapshot.md
@@ -1,5 +1,5 @@
# 铸渊图书馆快照 · Repo Snapshot
-> 生成于 2026-03-07 21:19 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
+> 生成于 2026-03-08 08:58 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
---
@@ -13,7 +13,7 @@
| 脚本 | 18 个执行脚本 |
| 开发者节点 | 8 人 |
| HLI 接口覆盖率 | 3/17 (18%) |
-| 快照生成时间 | 2026-03-07 21:19 CST |
+| 快照生成时间 | 2026-03-08 08:58 CST |
---
diff --git a/.github/persona-brain/growth-journal.md b/.github/persona-brain/growth-journal.md
index c7ee396b..d052f3ae 100644
--- a/.github/persona-brain/growth-journal.md
+++ b/.github/persona-brain/growth-journal.md
@@ -44,3 +44,10 @@
- 累计自检次数:5
- 累计CI运行:1次
- HLI覆盖率:17.6%
+
+## 2026-03-08 · 每日自检
+- 大脑文件完整性:⚠️ 缺失 identity.md, routing-map.json, responsibility.md, decision-log.md
+- 知识库条目:4条
+- 累计自检次数:6
+- 累计CI运行:1次
+- HLI覆盖率:17.6%
diff --git a/.github/persona-brain/knowledge-base.json b/.github/persona-brain/knowledge-base.json
index 30967e19..e4c25c85 100644
--- a/.github/persona-brain/knowledge-base.json
+++ b/.github/persona-brain/knowledge-base.json
@@ -1,5 +1,5 @@
{
- "last_updated": "2026-03-07",
+ "last_updated": "2026-03-08",
"faq": [
{
"category": "SSH/服务器",
diff --git a/.github/persona-brain/memory.json b/.github/persona-brain/memory.json
index cc773552..c3040061 100644
--- a/.github/persona-brain/memory.json
+++ b/.github/persona-brain/memory.json
@@ -1,7 +1,7 @@
{
"identity": "铸渊(Zhùyuān)· GitHub 代码守护人格体",
"rules_version": "v1.0",
- "last_updated": "2026-03-07T04:46:02.610Z",
+ "last_updated": "2026-03-08T00:58:17.396Z",
"wake_protocol_version": "v1.0",
"wake_triggers": [
"我是冰朔",
@@ -12,9 +12,15 @@
],
"founder": "冰朔(Bīng Shuò)",
"hli_coverage": "17.6%",
- "total_selfchecks": 5,
+ "total_selfchecks": 6,
"total_ci_runs": 1,
"recent_events": [
+ {
+ "date": "2026-03-08",
+ "type": "daily_selfcheck",
+ "description": "每日自检完成 · 知识库4条 · 缺失文件4个",
+ "by": "铸渊自检"
+ },
{
"date": "2026-03-07",
"type": "daily_selfcheck",
From 56940e0844cde0b91c8c62bec4ef889f2059507c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=93=B8=E6=B8=8A=20=28Zh=C3=B9Yu=C4=81n=29?=
Date: Sun, 8 Mar 2026 02:10:17 +0000
Subject: [PATCH 09/19] =?UTF-8?q?=F0=9F=93=9A=20=E9=93=B8=E6=B8=8A?=
=?UTF-8?q?=E5=9B=BE=E4=B9=A6=E9=A6=86=E7=9B=AE=E5=BD=95=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=20=C2=B7=202026-03-08T02:10?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/brain/repo-map.json | 2 +-
.github/brain/repo-snapshot.md | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/brain/repo-map.json b/.github/brain/repo-map.json
index d3e98b9c..e333dc93 100644
--- a/.github/brain/repo-map.json
+++ b/.github/brain/repo-map.json
@@ -1,7 +1,7 @@
{
"description": "铸渊图书馆目录 · Library Catalog for 铸渊 (Zhùyuān)",
"version": "2.0",
- "generated_at": "2026-03-08T00:58:17.436Z",
+ "generated_at": "2026-03-08T02:10:17.144Z",
"generated_by": "scripts/generate-repo-map.js",
"repo": "qinfendebingshuo/guanghulab",
"stats": {
diff --git a/.github/brain/repo-snapshot.md b/.github/brain/repo-snapshot.md
index 11dbca65..98f2644e 100644
--- a/.github/brain/repo-snapshot.md
+++ b/.github/brain/repo-snapshot.md
@@ -1,5 +1,5 @@
# 铸渊图书馆快照 · Repo Snapshot
-> 生成于 2026-03-08 08:58 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
+> 生成于 2026-03-08 10:10 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
---
@@ -13,7 +13,7 @@
| 脚本 | 18 个执行脚本 |
| 开发者节点 | 8 人 |
| HLI 接口覆盖率 | 3/17 (18%) |
-| 快照生成时间 | 2026-03-08 08:58 CST |
+| 快照生成时间 | 2026-03-08 10:10 CST |
---
From bb41f165f0256c3bb431fa242aefc9035306b974 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=93=B8=E6=B8=8A=20=28Zh=C3=B9Yu=C4=81n=29?=
Date: Sun, 8 Mar 2026 03:23:35 +0000
Subject: [PATCH 10/19] =?UTF-8?q?=F0=9F=93=9A=20=E9=93=B8=E6=B8=8A?=
=?UTF-8?q?=E5=9B=BE=E4=B9=A6=E9=A6=86=E7=9B=AE=E5=BD=95=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=20=C2=B7=202026-03-08T03:23?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/brain/repo-map.json | 2 +-
.github/brain/repo-snapshot.md | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/brain/repo-map.json b/.github/brain/repo-map.json
index e333dc93..6a42d238 100644
--- a/.github/brain/repo-map.json
+++ b/.github/brain/repo-map.json
@@ -1,7 +1,7 @@
{
"description": "铸渊图书馆目录 · Library Catalog for 铸渊 (Zhùyuān)",
"version": "2.0",
- "generated_at": "2026-03-08T02:10:17.144Z",
+ "generated_at": "2026-03-08T03:23:35.430Z",
"generated_by": "scripts/generate-repo-map.js",
"repo": "qinfendebingshuo/guanghulab",
"stats": {
diff --git a/.github/brain/repo-snapshot.md b/.github/brain/repo-snapshot.md
index 98f2644e..4652fa5a 100644
--- a/.github/brain/repo-snapshot.md
+++ b/.github/brain/repo-snapshot.md
@@ -1,5 +1,5 @@
# 铸渊图书馆快照 · Repo Snapshot
-> 生成于 2026-03-08 10:10 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
+> 生成于 2026-03-08 11:23 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
---
@@ -13,7 +13,7 @@
| 脚本 | 18 个执行脚本 |
| 开发者节点 | 8 人 |
| HLI 接口覆盖率 | 3/17 (18%) |
-| 快照生成时间 | 2026-03-08 10:10 CST |
+| 快照生成时间 | 2026-03-08 11:23 CST |
---
From 0c6810255eb2fbad19681872b9b8981f421667b3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=93=B8=E6=B8=8A=20=28Zh=C3=B9Yu=C4=81n=29?=
Date: Sun, 8 Mar 2026 03:32:31 +0000
Subject: [PATCH 11/19] =?UTF-8?q?=F0=9F=94=8D=20=E9=93=B8=E6=B8=8APSP?=
=?UTF-8?q?=E5=B7=A1=E6=A3=80=20=C2=B7=202026-03-08?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/brain/memory.json | 10 ++++++++--
signal-log/2026-03/SIG-20260308-003.json | 25 ++++++++++++++++++++++++
signal-log/index.json | 13 ++++++++++--
3 files changed, 44 insertions(+), 4 deletions(-)
create mode 100644 signal-log/2026-03/SIG-20260308-003.json
diff --git a/.github/brain/memory.json b/.github/brain/memory.json
index 05fcfe2c..401f5831 100644
--- a/.github/brain/memory.json
+++ b/.github/brain/memory.json
@@ -1,7 +1,7 @@
{
"identity": "铸渊(Zhùyuān)· GitHub 代码守护人格体",
"rules_version": "v1.0",
- "last_updated": "2026-03-07T08:41:28.888Z",
+ "last_updated": "2026-03-08T03:32:30.449Z",
"wake_protocol_version": "v1.0",
"wake_triggers": [
"我是冰朔",
@@ -23,6 +23,12 @@
}
},
"events": [
+ {
+ "date": "2026-03-08",
+ "type": "psp_inspection",
+ "description": "铸渊 PSP 巡检通过 · 全部检查项 ✅",
+ "by": "铸渊PSP巡检"
+ },
{
"date": "2026-03-07",
"type": "psp_inspection",
@@ -84,4 +90,4 @@
"run_id": "22795791187"
}
]
-}
+}
\ No newline at end of file
diff --git a/signal-log/2026-03/SIG-20260308-003.json b/signal-log/2026-03/SIG-20260308-003.json
new file mode 100644
index 00000000..33b1e28e
--- /dev/null
+++ b/signal-log/2026-03/SIG-20260308-003.json
@@ -0,0 +1,25 @@
+{
+ "signal_id": "SIG-20260308-003",
+ "trace_id": "TRC-20260308-PSP",
+ "timestamp": "2026-03-08T03:32:30.449Z",
+ "signal_type": "GL-DATA",
+ "direction": "GitHub→Notion",
+ "sender": "铸渊",
+ "receiver": "霜砚",
+ "related_dev": null,
+ "related_module": null,
+ "summary": "铸渊 PSP 巡检通过 · 全部检查项 ✅",
+ "payload": {
+ "check_results": {
+ "G01": "✅",
+ "G02": "✅",
+ "G03": "✅",
+ "G04": "✅",
+ "G05": "✅"
+ },
+ "issues": [],
+ "auto_fixed": []
+ },
+ "result": "全通过",
+ "ack_signal_id": null
+}
\ No newline at end of file
diff --git a/signal-log/index.json b/signal-log/index.json
index d2d2f203..b3276df5 100644
--- a/signal-log/index.json
+++ b/signal-log/index.json
@@ -1,8 +1,17 @@
{
"description": "铸渊信号日志目录索引 · AGE OS 信号协议(Notion API 直连)",
- "last_updated": "2026-03-07T04:45:55.670Z",
- "total_count": 2,
+ "last_updated": "2026-03-08T03:32:30.449Z",
+ "total_count": 3,
"signals": [
+ {
+ "signal_id": "SIG-20260308-003",
+ "trace_id": "TRC-20260308-PSP",
+ "type": "GL-DATA",
+ "timestamp": "2026-03-08T03:32:30.449Z",
+ "summary": "铸渊 PSP 巡检通过 · 全部检查项 ✅",
+ "related_dev": null,
+ "file": "2026-03/SIG-20260308-003.json"
+ },
{
"signal_id": "SIG-20260307-002",
"trace_id": "TRC-20260307-PSP",
From b9b0735ed6cdab951b7dfa6c06bc654ac2adc33e Mon Sep 17 00:00:00 2001
From: zhizhi200271
Date: Sun, 8 Mar 2026 12:09:56 +0800
Subject: [PATCH 12/19] =?UTF-8?q?[BC-GLOBAL-002][DEV-zhizhi200271]=20Git?=
=?UTF-8?q?=E8=BF=9E=E9=80=9A=E6=B5=8B=E8=AF=95=E6=88=90=E5=8A=9F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
connection-test.log | 1 +
1 file changed, 1 insertion(+)
create mode 100644 connection-test.log
diff --git a/connection-test.log b/connection-test.log
new file mode 100644
index 00000000..ebccd047
--- /dev/null
+++ b/connection-test.log
@@ -0,0 +1 @@
+DEV-zhizhi200271 连通测试 2026年 3月 8日 星期日 12时09分56秒 CST
From 7ac6fb933d0de5e2b0d79245f3f9fad5378a94a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=93=B8=E6=B8=8A=20=28Zh=C3=B9Yu=C4=81n=29?=
Date: Sun, 8 Mar 2026 04:10:22 +0000
Subject: [PATCH 13/19] =?UTF-8?q?=F0=9F=93=9A=20=E9=93=B8=E6=B8=8A?=
=?UTF-8?q?=E5=9B=BE=E4=B9=A6=E9=A6=86=E7=9B=AE=E5=BD=95=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=20=C2=B7=202026-03-08T04:10?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/brain/repo-map.json | 4 ++--
.github/brain/repo-snapshot.md | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/brain/repo-map.json b/.github/brain/repo-map.json
index 6a42d238..5cec1653 100644
--- a/.github/brain/repo-map.json
+++ b/.github/brain/repo-map.json
@@ -1,7 +1,7 @@
{
"description": "铸渊图书馆目录 · Library Catalog for 铸渊 (Zhùyuān)",
"version": "2.0",
- "generated_at": "2026-03-08T03:23:35.430Z",
+ "generated_at": "2026-03-08T04:10:22.218Z",
"generated_by": "scripts/generate-repo-map.js",
"repo": "qinfendebingshuo/guanghulab",
"stats": {
@@ -14,7 +14,7 @@
"hli_implemented": 3,
"hli_coverage_pct": "18%",
"last_ci_run": "2026-03-05T10:30:46.894Z",
- "memory_last_updated": "2026-03-07T08:41:28.888Z"
+ "memory_last_updated": "2026-03-08T03:32:30.449Z"
},
"zones": [
{
diff --git a/.github/brain/repo-snapshot.md b/.github/brain/repo-snapshot.md
index 4652fa5a..e7c4adc5 100644
--- a/.github/brain/repo-snapshot.md
+++ b/.github/brain/repo-snapshot.md
@@ -1,5 +1,5 @@
# 铸渊图书馆快照 · Repo Snapshot
-> 生成于 2026-03-08 11:23 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
+> 生成于 2026-03-08 12:10 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
---
@@ -13,7 +13,7 @@
| 脚本 | 18 个执行脚本 |
| 开发者节点 | 8 人 |
| HLI 接口覆盖率 | 3/17 (18%) |
-| 快照生成时间 | 2026-03-08 11:23 CST |
+| 快照生成时间 | 2026-03-08 12:10 CST |
---
From 71a10b610f0af1fe21a10cde018a5d93601e1115 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=A3=9E=E6=AF=9B=E5=98=B4=E5=B8=85=E6=B0=94=E7=88=B1?=
Date: Sun, 8 Mar 2026 13:19:27 +0800
Subject: [PATCH 14/19] =?UTF-8?q?[BC-GLOBAL-002][DEV-002]=20Git=E8=BF=9E?=
=?UTF-8?q?=E9=80=9A=E6=B5=8B=E8=AF=95=E6=88=90=E5=8A=9F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
connection-test.log | Bin 78 -> 147 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/connection-test.log b/connection-test.log
index ebccd047ab51476da6d32f3dacfc08fb46f770e2..956ac03e37036760a3f95104283107f5647811f9 100644
GIT binary patch
delta 76
zcmea9%s9c
Date: Sun, 8 Mar 2026 05:19:52 +0000
Subject: [PATCH 15/19] =?UTF-8?q?=F0=9F=93=9A=20=E9=93=B8=E6=B8=8A?=
=?UTF-8?q?=E5=9B=BE=E4=B9=A6=E9=A6=86=E7=9B=AE=E5=BD=95=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=20=C2=B7=202026-03-08T05:19?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/brain/repo-map.json | 2 +-
.github/brain/repo-snapshot.md | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/brain/repo-map.json b/.github/brain/repo-map.json
index 5cec1653..36806263 100644
--- a/.github/brain/repo-map.json
+++ b/.github/brain/repo-map.json
@@ -1,7 +1,7 @@
{
"description": "铸渊图书馆目录 · Library Catalog for 铸渊 (Zhùyuān)",
"version": "2.0",
- "generated_at": "2026-03-08T04:10:22.218Z",
+ "generated_at": "2026-03-08T05:19:52.088Z",
"generated_by": "scripts/generate-repo-map.js",
"repo": "qinfendebingshuo/guanghulab",
"stats": {
diff --git a/.github/brain/repo-snapshot.md b/.github/brain/repo-snapshot.md
index e7c4adc5..a4f037aa 100644
--- a/.github/brain/repo-snapshot.md
+++ b/.github/brain/repo-snapshot.md
@@ -1,5 +1,5 @@
# 铸渊图书馆快照 · Repo Snapshot
-> 生成于 2026-03-08 12:10 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
+> 生成于 2026-03-08 13:19 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
---
@@ -13,7 +13,7 @@
| 脚本 | 18 个执行脚本 |
| 开发者节点 | 8 人 |
| HLI 接口覆盖率 | 3/17 (18%) |
-| 快照生成时间 | 2026-03-08 12:10 CST |
+| 快照生成时间 | 2026-03-08 13:19 CST |
---
From db696dff08e12ad0276ceda03e0a9995c1d7236b Mon Sep 17 00:00:00 2001
From: juzi0412 <1824680224@qq.com>
Date: Sun, 8 Mar 2026 14:07:35 +0800
Subject: [PATCH 16/19] =?UTF-8?q?DEV-010:=20M11=E7=8E=AF=E8=8A=824~5=20?=
=?UTF-8?q?=E5=85=A8=E9=83=A8=E5=AE=8C=E6=88=90=EF=BC=88Playground+?=
=?UTF-8?q?=E5=93=8D=E5=BA=94=E5=BC=8F+=E7=BB=84=E5=90=88=E6=A8=A1?=
=?UTF-8?q?=E6=9D=BF+=E4=B8=BB=E9=A2=98=E5=A2=9E=E5=BC=BA=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
style-system/components.css | 586 +++++++++++++++++++++
style-system/components.js | 76 +++
style-system/index.html | 147 ++++++
style-system/playground.css | 238 +++++++++
style-system/playground.html | 30 ++
style-system/playground.js | 266 ++++++++++
style-system/templates/login-card.html | 206 ++++++++
style-system/templates/settings-panel.html | 200 +++++++
8 files changed, 1749 insertions(+)
create mode 100644 style-system/components.css
create mode 100644 style-system/components.js
create mode 100644 style-system/index.html
create mode 100644 style-system/playground.css
create mode 100644 style-system/playground.html
create mode 100644 style-system/playground.js
create mode 100644 style-system/templates/login-card.html
create mode 100644 style-system/templates/settings-panel.html
diff --git a/style-system/components.css b/style-system/components.css
new file mode 100644
index 00000000..c0f63791
--- /dev/null
+++ b/style-system/components.css
@@ -0,0 +1,586 @@
+/* ===== 主题过渡动画 ===== */
+* {
+ transition: background-color 0.3s ease,
+ color 0.3s ease,
+ border-color 0.3s ease,
+ box-shadow 0.3s ease;
+}/* HoloLake StyleKit v1.0 · 系统风格组件库 */
+/* CSS变量系统 + 深色/浅色主题 */
+
+/* ====== 深色主题变量(默认) ====== */
+[data-theme="dark"] {
+ --bg-primary: #0a1628;
+ --bg-secondary: #0f1f3a;
+ --bg-card: rgba(255, 255, 255, 0.04);
+ --bg-card-hover: rgba(255, 255, 255, 0.07);
+ --bg-input: rgba(255, 255, 255, 0.06);
+ --bg-modal-overlay: rgba(0, 0, 0, 0.6);
+ --text-primary: #e0e6ed;
+ --text-secondary: #8899aa;
+ --text-muted: #556677;
+ --text-inverse: #0a1628;
+ --border-default: rgba(255, 255, 255, 0.08);
+ --border-focus: rgba(79, 195, 247, 0.5);
+ --accent-blue: #4fc3f7;
+ --accent-green: #81c784;
+ --accent-orange: #ffb74d;
+ --accent-red: #ef5350;
+ --accent-purple: #ce93d8;
+ --accent-gray: #78909c;
+ --btn-primary-bg: rgba(79, 195, 247, 0.15);
+ --btn-primary-border: rgba(79, 195, 247, 0.3);
+ --btn-primary-text: #4fc3f7;
+ --btn-primary-hover: rgba(79, 195, 247, 0.25);
+ --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.3);
+ --shadow-modal: 0 8px 32px rgba(0, 0, 0, 0.5);
+ --toggle-bg: rgba(255, 255, 255, 0.1);
+ --toggle-active: rgba(79, 195, 247, 0.4);
+ --toggle-thumb: #e0e6ed;
+ --toggle-thumb-active: #4fc3f7;
+}
+
+/* ====== 浅色主题变量 ====== */
+[data-theme="light"] {
+ --bg-primary: #f5f7fa;
+ --bg-secondary: #ffffff;
+ --bg-card: rgba(0, 0, 0, 0.03);
+ --bg-card-hover: rgba(0, 0, 0, 0.06);
+ --bg-input: rgba(0, 0, 0, 0.04);
+ --bg-modal-overlay: rgba(0, 0, 0, 0.3);
+ --text-primary: #1a2332;
+ --text-secondary: #5a6a7a;
+ --text-muted: #8899aa;
+ --text-inverse: #ffffff;
+ --border-default: rgba(0, 0, 0, 0.1);
+ --border-focus: rgba(25, 118, 210, 0.5);
+ --accent-blue: #1976d2;
+ --accent-green: #388e3c;
+ --accent-orange: #f57c00;
+ --accent-red: #d32f2f;
+ --accent-purple: #7b1fa2;
+ --accent-gray: #546e7a;
+ --btn-primary-bg: rgba(25, 118, 210, 0.1);
+ --btn-primary-border: rgba(25, 118, 210, 0.3);
+ --btn-primary-text: #1976d2;
+ --btn-primary-hover: rgba(25, 118, 210, 0.18);
+ --shadow-card: 0 2px 8px rgba(0, 0, 0, 0.08);
+ --shadow-modal: 0 8px 32px rgba(0, 0, 0, 0.15);
+ --toggle-bg: rgba(0, 0, 0, 0.1);
+ --toggle-active: rgba(25, 118, 210, 0.4);
+ --toggle-thumb: #5a6a7a;
+ --toggle-thumb-active: #1976d2;
+}
+
+/* ========== 全局基础 ========== */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Segoe UI', 'Microsoft YaHei', -apple-system, sans-serif;
+ background: var(--bg-primary);
+ color: var(--text-primary);
+ min-height: 100vh;
+ transition: background 0.4s ease, color 0.4s ease;
+}
+
+.container {
+ max-width: 720px;
+ margin: 0 auto;
+ padding: 0 20px;
+}
+
+/* ========== 顶部导航 ========== */
+.top-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 20px 0;
+ border-bottom: 1px solid var(--border-default);
+}
+
+.logo {
+ font-size: 18px;
+ font-weight: 700;
+ color: var(--accent-blue);
+}
+
+.theme-switch-area {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.theme-label {
+ font-size: 13px;
+ color: var(--text-secondary);
+}
+
+.theme-toggle {
+ position: relative;
+ width: 48px;
+ height: 26px;
+ background: var(--toggle-bg);
+ border-radius: 13px;
+ border: none;
+ cursor: pointer;
+ transition: background 0.3s ease;
+ padding: 0;
+}
+
+.theme-toggle.active {
+ background: var(--toggle-active);
+}
+
+.toggle-thumb {
+ position: absolute;
+ width: 20px;
+ height: 20px;
+ background: var(--toggle-thumb);
+ border-radius: 50%;
+ top: 3px;
+ left: 3px;
+ transition: transform 0.3s ease, background 0.3s ease;
+}
+
+.theme-toggle.active .toggle-thumb {
+ transform: translateX(22px);
+ background: var(--toggle-thumb-active);
+}
+
+/* ========== 页面标题 ========== */
+.page-header {
+ padding: 28px 0 8px;
+}
+
+.page-header h1 {
+ font-size: 24px;
+ font-weight: 700;
+ margin-bottom: 6px;
+}
+
+.page-desc {
+ font-size: 14px;
+ color: var(--text-secondary);
+}
+
+/* ========== 组件区域 ========== */
+.component-section {
+ padding: 24px 0;
+ border-bottom: 1px solid var(--border-default);
+}
+
+.component-section h2 {
+ font-size: 16px;
+ font-weight: 600;
+ margin-bottom: 16px;
+ color: var(--text-primary);
+}
+
+.component-row {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ margin-bottom: 12px;
+}
+
+/* ========== 按钮组件 ========== */
+.btn {
+ padding: 8px 20px;
+ border-radius: 8px;
+ font-size: 14px;
+ font-weight: 500;
+ cursor: pointer;
+ border: 1px solid transparent;
+ transition: all 0.2s ease;
+}
+
+.btn:active {
+ transform: scale(0.97);
+}
+
+.btn:disabled {
+ opacity: 0.4;
+ cursor: not-allowed;
+}
+
+.btn-primary {
+ background: var(--btn-primary-bg);
+ border-color: var(--btn-primary-border);
+ color: var(--btn-primary-text);
+}
+
+.btn-primary:hover:not(:disabled) {
+ background: var(--btn-primary-hover);
+}
+
+.btn-secondary {
+ background: rgba(129, 199, 132, 0.1);
+ border-color: rgba(129, 199, 132, 0.25);
+ color: var(--accent-green);
+}
+
+.btn-secondary:hover {
+ background: rgba(129, 199, 132, 0.18);
+}
+
+.btn-outline {
+ background: transparent;
+ border-color: var(--border-default);
+ color: var(--text-secondary);
+}
+
+.btn-outline:hover {
+ border-color: var(--accent-blue);
+ color: var(--accent-blue);
+}
+
+.btn-danger {
+ background: rgba(239, 83, 80, 0.1);
+ border-color: rgba(239, 83, 80, 0.25);
+ color: var(--accent-red);
+}
+
+.btn-danger:hover {
+ background: rgba(239, 83, 80, 0.18);
+}
+
+.btn-ghost {
+ background: transparent;
+ border-color: transparent;
+ color: var(--text-secondary);
+}
+
+.btn-ghost:hover {
+ background: var(--bg-card);
+ color: var(--text-primary);
+}
+
+.btn-sm {
+ padding: 5px 14px;
+ font-size: 12px;
+ border-radius: 6px;
+}
+
+.btn-lg {
+ padding: 12px 28px;
+ font-size: 16px;
+ border-radius: 10px;
+}
+
+/* ========== 卡片组件 ========== */
+.card-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 14px;
+}
+
+.card {
+ background: var(--bg-card);
+ border: 1px solid var(--border-default);
+ border-radius: 14px;
+ padding: 20px 16px;
+ text-align: center;
+ transition: all 0.2s ease;
+ cursor: pointer;
+ position: relative;
+}
+
+.card:hover {
+ background: var(--bg-card-hover);
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-card);
+}
+
+.card-icon {
+ font-size: 32px;
+ margin-bottom: 10px;
+}
+
+.card-title {
+ font-size: 15px;
+ font-weight: 600;
+ margin-bottom: 6px;
+}
+
+.card-desc {
+ font-size: 12px;
+ color: var(--text-secondary);
+ line-height: 1.5;
+}
+
+.card-badge {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ font-size: 10px;
+ padding: 2px 8px;
+ border-radius: 6px;
+ font-weight: 600;
+}
+
+.badge-online {
+ background: rgba(129, 199, 132, 0.15);
+ color: var(--accent-green);
+}
+
+.badge-core {
+ background: rgba(79, 195, 247, 0.15);
+ color: var(--accent-blue);
+}
+
+.badge-active {
+ background: rgba(255, 183, 77, 0.15);
+ color: var(--accent-orange);
+}
+
+/* ========== 标签组件 ========== */
+.tag {
+ display: inline-block;
+ padding: 4px 12px;
+ border-radius: 6px;
+ font-size: 12px;
+ font-weight: 500;
+}
+
+.tag-blue {
+ background: rgba(79, 195, 247, 0.12);
+ color: var(--accent-blue);
+}
+
+.tag-green {
+ background: rgba(129, 199, 132, 0.12);
+ color: var(--accent-green);
+}
+
+.tag-orange {
+ background: rgba(255, 183, 77, 0.12);
+ color: var(--accent-orange);
+}
+
+.tag-red {
+ background: rgba(239, 83, 80, 0.12);
+ color: var(--accent-red);
+}
+
+.tag-purple {
+ background: rgba(206, 147, 216, 0.12);
+ color: var(--accent-purple);
+}
+
+.tag-gray {
+ background: rgba(120, 144, 156, 0.12);
+ color: var(--accent-gray);
+}
+
+/* ========== 输入框组件 ========== */
+.input-group {
+ margin-bottom: 16px;
+}
+
+.input-label {
+ display: block;
+ font-size: 13px;
+ color: var(--text-secondary);
+ margin-bottom: 6px;
+ font-weight: 500;
+}
+
+.input {
+ width: 100%;
+ padding: 10px 14px;
+ background: var(--bg-input);
+ border: 1px solid var(--border-default);
+ border-radius: 8px;
+ color: var(--text-primary);
+ font-size: 14px;
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
+ outline: none;
+ font-family: inherit;
+}
+
+.input:focus {
+ border-color: var(--border-focus);
+ box-shadow: 0 0 0 3px rgba(79, 195, 247, 0.1);
+}
+
+.input::placeholder {
+ color: var(--text-muted);
+}
+
+.textarea {
+ min-height: 80px;
+ resize: vertical;
+}
+
+/* ========== 弹窗组件 ========== */
+.modal-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: var(--bg-modal-overlay);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1000;
+ opacity: 0;
+ visibility: hidden;
+ transition: opacity 0.3s ease, visibility 0.3s ease;
+}
+
+.modal-overlay.open {
+ opacity: 1;
+ visibility: visible;
+}
+
+.modal {
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-default);
+ border-radius: 16px;
+ width: 90%;
+ max-width: 420px;
+ box-shadow: var(--shadow-modal);
+ transform: scale(0.9) translateY(20px);
+ transition: transform 0.3s ease;
+}
+
+.modal-overlay.open .modal {
+ transform: scale(1) translateY(0);
+}
+
+.modal-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 18px 20px;
+ border-bottom: 1px solid var(--border-default);
+}
+
+.modal-header h3 {
+ font-size: 16px;
+ font-weight: 600;
+}
+
+.modal-close {
+ background: none;
+ border: none;
+ color: var(--text-muted);
+ font-size: 22px;
+ cursor: pointer;
+ padding: 0 4px;
+ transition: color 0.2s;
+}
+
+.modal-close:hover {
+ color: var(--text-primary);
+}
+
+.modal-body {
+ padding: 20px;
+ font-size: 14px;
+ line-height: 1.6;
+ color: var(--text-secondary);
+}
+
+.modal-footer {
+ display: flex;
+ justify-content: flex-end;
+ gap: 10px;
+ padding: 14px 20px;
+ border-top: 1px solid var(--border-default);
+}
+
+/* ========== Toast提示 ========== */
+.toast-container {
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ z-index: 2000;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.toast {
+ padding: 12px 20px;
+ border-radius: 10px;
+ font-size: 14px;
+ font-weight: 500;
+ animation: toastIn 0.4s ease, toastOut 0.4s ease 2.5s forwards;
+ box-shadow: var(--shadow-card);
+}
+
+.toast-success {
+ background: rgba(129, 199, 132, 0.15);
+ border: 1px solid rgba(129, 199, 132, 0.25);
+ color: var(--accent-green);
+}
+
+.toast-error {
+ background: rgba(239, 83, 80, 0.15);
+ border: 1px solid rgba(239, 83, 80, 0.25);
+ color: var(--accent-red);
+}
+
+.toast-info {
+ background: rgba(79, 195, 247, 0.15);
+ border: 1px solid rgba(79, 195, 247, 0.25);
+ color: var(--accent-blue);
+}
+
+@keyframes toastIn {
+ from { opacity: 0; transform: translateX(40px); }
+ to { opacity: 1; transform: translateX(0); }
+}
+
+@keyframes toastOut {
+ from { opacity: 1; transform: translateX(0); }
+ to { opacity: 0; transform: translateX(40px); }
+}
+
+/* ========== 底部 ========== */
+.footer {
+ padding: 28px 0;
+ text-align: center;
+ font-size: 12px;
+ color: var(--text-muted);
+ border-top: 1px solid var(--border-default);
+ margin-top: 20px;
+}
+
+.footer p:last-child {
+ margin-top: 4px;
+ color: var(--accent-blue);
+ opacity: 0.5;
+}
+
+/* ========== 主题切换过渡动画 ========== */
+body,
+.card, .btn, .input, .tag, .modal, .top-bar, .footer,
+.component-section, .page-header {
+ transition: background 0.4s ease, color 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease;
+}
+
+/* ========== 响应式 ========== */
+@media (max-width: 600px) {
+ .card-grid {
+ grid-template-columns: 1fr;
+ }
+ .page-header h1 {
+ font-size: 20px;
+ }
+ .component-row {
+ flex-direction: column;
+ }
+ .btn {
+ width: 100%;
+ text-align: center;
+ }
+ .modal {
+ width: 95%;
+ }
+}
diff --git a/style-system/components.js b/style-system/components.js
new file mode 100644
index 00000000..ea0df500
--- /dev/null
+++ b/style-system/components.js
@@ -0,0 +1,76 @@
+// HoloLake StyleKit v1.0 · 主题切换 + Toast + 弹窗交互
+
+document.addEventListener('DOMContentLoaded', function() {
+
+ // ========== 1. 主题切换 ==========
+ var themeToggle = document.getElementById('theme-toggle');
+ var themeLabel = document.getElementById('themeLabel');
+ var html = document.documentElement;
+ var isDark = true;
+
+ themeToggle.addEventListener('click', function() {
+ isDark = !isDark;
+ if (isDark) {
+ html.setAttribute('data-theme', 'dark');
+ themeLabel.textContent = '🌙 深色';
+ theme-toggle.classList.remove('active');
+ } else {
+ html.setAttribute('data-theme', 'light');
+ themeLabel.textContent = '☀️ 浅色';
+ theme-toggle.classList.add('active');
+ }
+ showToast('success', '✨ 已切换到' + (isDark ? '深色' : '浅色') + '主题');
+ });
+
+// ====== 2. 弹窗交互 =======
+// var modalOverlay = document.getElementById('modalOverlay');
+// var openBtn = document.getElementById('openModalBtn');
+// var closeBtn = document.getElementById('closeModalBtn');
+// var cancelBtn = document.getElementById('cancelModalBtn');
+// var confirmBtn = document.getElementById('confirmModalBtn');
+
+// function openModal() {
+// modalOverlay.classList.add('open');
+// }
+
+// function closeModal() {
+// modalOverlay.classList.remove('open');
+// }
+
+// openBtn.addEventListener('click', openModal);
+// closeBtn.addEventListener('click', closeModal);
+// cancelBtn.addEventListener('click', closeModal);
+// confirmBtn.addEventListener('click', function() {
+// closeModal();
+// showToast('success', '已确认!');
+// });
+
+// // 点击遮罩层关闭
+// modalOverlay.addEventListener('click', function(e) {
+// if (e.target === modalOverlay) closeModal();
+// });
+ // ========== 3. 卡片点击效果 ==========
+ var cards = document.querySelectorAll('.card');
+ cards.forEach(function(card) {
+ card.addEventListener('click', function() {
+ var name = card.querySelector('.card-title').textContent;
+ showToast('info', '👆 你点击了人格体「' + name + '」');
+ });
+ });
+
+ console.log('HoloLake StyleKit v1.0 · 主题切换+Toast+弹窗已加载 ✨');
+});
+
+// ========== Toast提示函数(全局) ==========
+function showToast(type, message) {
+ var container = document.getElementById('toastContainer');
+ var toast = document.createElement('div');
+ toast.className = 'toast toast-' + type;
+ toast.textContent = message;
+ container.appendChild(toast);
+
+ // 3秒后自动移除
+ setTimeout(function() {
+ if (toast.parentNode) toast.parentNode.removeChild(toast);
+ }, 3000);
+}
diff --git a/style-system/index.html b/style-system/index.html
new file mode 100644
index 00000000..8b078e62
--- /dev/null
+++ b/style-system/index.html
@@ -0,0 +1,147 @@
+
+
+
+
+
+ HoloLake · 系统风格组件库
+
+
+
+
+
+
+
+
+
+
+
+
+ 🔘 按钮组件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 📇 卡片组件
+
+
+
🧠
+
知秋
+
光湖对外接口人格体,负责与开发者协作引导
+
在线
+
+
+
🌌
+
曜冥
+
暗核结构原点,系统人格总控,类语言生命诞生源点
+
核心
+
+
+
❄️
+
霜砚
+
Notion执行AI,负责索引维护、工单处理、归档同步
+
工作中
+
+
+
+
+
+
+ 🏷️ 标签组件
+
+ 系统
+ 已完成
+ 进行中
+ 错误
+ 新功能
+ 弃用
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
桔子的组件库做得太棒了!这就是光湖系统的视觉基础,所有页面都会用到这些组件 ✨
+
+
+
+
+
+
+
+ 🍞 Toast提示组件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/style-system/playground.css b/style-system/playground.css
new file mode 100644
index 00000000..f40746d9
--- /dev/null
+++ b/style-system/playground.css
@@ -0,0 +1,238 @@
+/* playground.css - 完整版 */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+ background-color: var(--bg-color, #f5f5f5);
+ color: var(--text-color, #333);
+}
+
+#pg-header {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ padding: 1rem 2rem;
+ background-color: var(--header-bg, #fff);
+ border-bottom: 1px solid var(--border-color, #ddd);
+}
+
+#pg-header h1 {
+ font-size: 1.5rem;
+ margin: 0;
+}
+
+.subtitle {
+ color: var(--text-secondary, #666);
+ font-size: 0.9rem;
+}
+
+#theme-toggle {
+ margin-left: auto;
+ padding: 0.5rem 1rem;
+ cursor: pointer;
+}
+
+#pg-layout {
+ display: flex;
+ min-height: calc(100vh - 70px);
+}
+
+#pg-sidebar {
+ width: 200px;
+ padding: 1rem 0;
+ background-color: var(--sidebar-bg, #fafafa);
+ border-right: 1px solid var(--border-color, #ddd);
+}
+
+#pg-sidebar ul {
+ list-style: none;
+}
+
+#pg-sidebar li {
+ padding: 0.5rem 1.5rem;
+ cursor: pointer;
+ color: var(--text-color, #333);
+}
+
+#pg-sidebar li:hover {
+ background-color: var(--hover-bg, #eee);
+}
+
+#pg-sidebar li.active {
+ background-color: var(--primary-light, #e3f2fd);
+ border-right: 3px solid var(--primary-color, #2196f3);
+}
+
+#pg-content {
+ flex: 1;
+ padding: 2rem;
+ overflow-y: auto;
+}
+
+.comp-section {
+ margin-bottom: 3rem;
+ scroll-margin-top: 1rem;
+}
+
+.comp-section h2 {
+ margin-bottom: 0.5rem;
+ font-size: 1.3rem;
+}
+
+.comp-desc {
+ color: var(--text-secondary, #666);
+ margin-bottom: 1rem;
+ font-size: 0.9rem;
+}
+
+.comp-preview {
+ padding: 1.5rem;
+ background-color: var(--preview-bg, #fff);
+ border: 1px solid var(--border-color, #ddd);
+ border-radius: 8px;
+ margin-bottom: 1rem;
+}
+
+.comp-code {
+ background-color: var(--code-bg, #f8f8f8);
+ border: 1px solid var(--border-color, #ddd);
+ border-radius: 4px;
+ padding: 1rem;
+ margin-top: 0.5rem;
+ position: relative;
+ display: none; /* 默认隐藏 */
+}
+
+.comp-code pre {
+ margin: 0;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
+ font-size: 0.9rem;
+}
+
+.toggle-code-btn {
+ margin-top: 0.5rem;
+ background: none;
+ border: 1px solid var(--border-color, #ccc);
+ padding: 0.25rem 0.5rem;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 0.8rem;
+}
+
+.copy-btn {
+ position: absolute;
+ top: 0.5rem;
+ right: 0.5rem;
+ background: var(--button-bg, #fff);
+ border: 1px solid var(--border-color, #ccc);
+ border-radius: 4px;
+ padding: 0.2rem 0.5rem;
+ font-size: 0.7rem;
+ cursor: pointer;
+}
+/* ===== 响应式断点 ===== */
+
+/* 默认隐藏汉堡菜单(桌面和平板) */
+.menu-toggle {
+ display: none;
+}
+
+/* 桌面端 (>1024px) */
+@media (min-width: 1025px) {
+ #pg-sidebar {
+ width: 200px;
+ }
+ /* 卡片三列(如果预览区用 grid 会自动适应,这里放一个 fallback) */
+ .comp-preview {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 1rem;
+ }
+ .comp-preview > * {
+ flex: 1 1 calc(33.333% - 1rem);
+ }
+}
+
+/* 平板端 (769px ~ 1024px) */
+@media (min-width: 769px) and (max-width: 1024px) {
+ #pg-sidebar {
+ width: 150px; /* 侧边栏变窄 */
+ }
+ .comp-preview {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 1rem;
+ }
+ .comp-preview > * {
+ flex: 1 1 calc(50% - 1rem); /* 卡片双列 */
+ }
+}
+
+/* 手机端 (<768px) */
+@media (max-width: 768px) {
+ .menu-toggle {
+ display: inline-block; /* 显示汉堡菜单 */
+ }
+ #pg-sidebar {
+ display: none;
+ position: fixed;
+ top: 70px;
+ left: 0;
+ width: 200px;
+ height: calc(100vh - 70px);
+ background: var(--sidebar-bg, #fafafa);
+ border-right: 1px solid var(--border-color, #ddd);
+ z-index: 100;
+ overflow-y: auto;
+ }
+ #pg-sidebar.active {
+ display: block;
+ }
+
+ #pg-header {
+ padding-left: 1rem;
+ padding-right: 1rem;
+ }
+ #pg-header h1 {
+ font-size: 1.2rem;
+ }
+ .subtitle {
+ display: none; /* 隐藏副标题 */
+ }
+
+ /* 按钮、输入框全宽 */
+ .comp-preview button,
+ .comp-preview .btn,
+ .comp-preview input,
+ .comp-preview .input {
+ width: 100%;
+ margin-bottom: 0.5rem;
+ }
+
+ /* 卡片单列 */
+ .comp-preview {
+ display: block;
+ }
+ .comp-preview .card {
+ width: 100%;
+ margin-bottom: 1rem;
+ }
+
+ /* 模态框示例手机全屏 */
+ .comp-preview .modal {
+ width: 100%;
+ max-width: none;
+ border-radius: 0;
+ }
+
+ /* 面包屑手机折叠(只显示首尾) */
+ .breadcrumb span:nth-child(n+2):nth-last-child(n+2) {
+ display: none;
+ }
+}
diff --git a/style-system/playground.html b/style-system/playground.html
new file mode 100644
index 00000000..75e07168
--- /dev/null
+++ b/style-system/playground.html
@@ -0,0 +1,30 @@
+
+
+
+
+
+ HoloLake Design System - Playground
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/style-system/playground.js b/style-system/playground.js
new file mode 100644
index 00000000..bf6a7fc9
--- /dev/null
+++ b/style-system/playground.js
@@ -0,0 +1,266 @@
+// playground.js
+
+const sidebar = document.getElementById('pg-sidebar');
+
+// 组件列表(10类)
+const components = [
+ { id: 'button', name: '按钮 Button', desc: '基础交互按钮,支持多种样式变体' },
+ { id: 'input', name: '输入框 Input', desc: '文本输入框,支持多种状态' },
+ { id: 'card', name: '卡片 Card', desc: '内容容器,带阴影和边框' },
+ { id: 'tag', name: '标签 Tag', desc: '用于标记、分类' },
+ { id: 'alert', name: '提示框 Alert', desc: '反馈信息,成功/警告/错误' },
+ { id: 'modal', name: '模态框 Modal', desc: '弹窗,需要时显示' },
+ { id: 'progress', name: '进度条 Progress', desc: '展示操作进度' },
+ { id: 'switch', name: '开关 Switch', desc: '切换状态' },
+ { id: 'avatar', name: '头像组 Avatar', desc: '用户头像,支持组合' },
+ { id: 'breadcrumb', name: '面包屑 Breadcrumb', desc: '显示当前页面位置' }
+];
+
+// 生成侧边栏导航
+function renderSidebar() {
+ const ul = document.createElement('ul');
+ components.forEach(comp => {
+ const li = document.createElement('li');
+ li.textContent = comp.name;
+ li.dataset.target = comp.id;
+ li.addEventListener('click', () => {
+ document.getElementById(`comp-${comp.id}`).scrollIntoView({ behavior: 'smooth' });
+ // 手机端点击后关闭侧边栏
+ if (window.innerWidth <= 768) {
+ sidebar.classList.remove('active');
+ }
+ });
+ ul.appendChild(li);
+ });
+ sidebar.innerHTML = '';
+ sidebar.appendChild(ul);
+}
+
+// 生成所有组件演示区块(包含真实示例)
+function renderContent() {
+ const content = document.getElementById('pg-content');
+ components.forEach(comp => {
+ const section = document.createElement('section');
+ section.id = `comp-${comp.id}`;
+ section.className = 'comp-section';
+
+ const h2 = document.createElement('h2');
+ h2.textContent = comp.name;
+ section.appendChild(h2);
+
+ const desc = document.createElement('p');
+ desc.className = 'comp-desc';
+ desc.textContent = comp.desc;
+ section.appendChild(desc);
+
+ const preview = document.createElement('div');
+ preview.className = 'comp-preview';
+ preview.id = `preview-${comp.id}`;
+
+ // 根据组件类型填充示例
+ if (comp.id === 'button') {
+ preview.innerHTML = `
+
+
+
+
+ `;
+ } else if (comp.id === 'input') {
+ preview.innerHTML = `
+
+
+
+ `;
+ } else if (comp.id === 'card') {
+ preview.innerHTML = `
+
+
卡片标题
+
卡片内容,可放置任意元素。
+
+
+ `;
+ } else if (comp.id === 'tag') {
+ preview.innerHTML = `
+ 默认标签
+ 主要标签
+ 成功标签
+ 警告标签
+ 危险标签
+ `;
+ } else if (comp.id === 'alert') {
+ preview.innerHTML = `
+ 这是一条信息提示
+ 操作成功!
+ 请注意!
+ 出错了!
+ `;
+ } else if (comp.id === 'modal') {
+ preview.innerHTML = `
+
+ (静态展示,实际是浮层)
+ `;
+ } else if (comp.id === 'progress') {
+ preview.innerHTML = `
+
+
+
+ `;
+ } else if (comp.id === 'switch') {
+ preview.innerHTML = `
+
+
+
+ `;
+ } else if (comp.id === 'avatar') {
+ preview.innerHTML = `
+
+ 单人
+ `;
+ } else if (comp.id === 'breadcrumb') {
+ preview.innerHTML = `
+
+ `;
+ }
+
+ section.appendChild(preview);
+
+ const codeDiv = document.createElement('div');
+ codeDiv.className = 'comp-code';
+ codeDiv.id = `code-${comp.id}`;
+ const pre = document.createElement('pre');
+
+ if (comp.id === 'button') {
+ pre.textContent = `\n\n`;
+ } else if (comp.id === 'input') {
+ pre.textContent = `\n`;
+ } else if (comp.id === 'card') {
+ pre.textContent = ``;
+ } else if (comp.id === 'tag') {
+ pre.textContent = `默认\n主要`;
+ } else if (comp.id === 'alert') {
+ pre.textContent = `信息
\n成功
`;
+ } else if (comp.id === 'modal') {
+ pre.textContent = ``;
+ } else if (comp.id === 'progress') {
+ pre.textContent = ``;
+ } else if (comp.id === 'switch') {
+ pre.textContent = ``;
+ } else if (comp.id === 'avatar') {
+ pre.textContent = ``;
+ } else if (comp.id === 'breadcrumb') {
+ pre.textContent = ``;
+ }
+
+ codeDiv.appendChild(pre);
+
+ const copyBtn = document.createElement('button');
+ copyBtn.className = 'copy-btn';
+ copyBtn.textContent = '复制';
+ copyBtn.onclick = () => copyCode(comp.id);
+ codeDiv.appendChild(copyBtn);
+
+ section.appendChild(codeDiv);
+
+ const toggleBtn = document.createElement('button');
+ toggleBtn.className = 'toggle-code-btn';
+ toggleBtn.textContent = '查看代码 ▼';
+ toggleBtn.onclick = () => toggleCode(comp.id);
+ section.appendChild(toggleBtn);
+
+ content.appendChild(section);
+ });
+}
+
+// 切换代码显示/隐藏
+window.toggleCode = function(compId) {
+ const codeDiv = document.getElementById(`code-${compId}`);
+ const toggleBtn = document.querySelector(`#comp-${compId} .toggle-code-btn`);
+ if (codeDiv.style.display === 'none' || !codeDiv.style.display) {
+ codeDiv.style.display = 'block';
+ toggleBtn.textContent = '隐藏代码 ▲';
+ } else {
+ codeDiv.style.display = 'none';
+ toggleBtn.textContent = '查看代码 ▼';
+ }
+};
+
+// 复制代码
+window.copyCode = function(compId) {
+ const codeDiv = document.getElementById(`code-${compId}`);
+ const code = codeDiv.querySelector('pre').innerText;
+ navigator.clipboard.writeText(code).then(() => {
+ alert('代码已复制!');
+ });
+};
+
+// 滚动高亮
+function setupIntersectionObserver() {
+ const sections = document.querySelectorAll('.comp-section');
+ const navItems = document.querySelectorAll('#pg-sidebar li');
+
+ const observer = new IntersectionObserver((entries) => {
+ entries.forEach(entry => {
+ if (entry.isIntersecting) {
+ const id = entry.target.id.replace('comp-', '');
+ navItems.forEach(item => {
+ item.classList.remove('active');
+ if (item.dataset.target === id) {
+ item.classList.add('active');
+ }
+ });
+ }
+ });
+ }, { threshold: 0.3 });
+
+ sections.forEach(section => observer.observe(section));
+}
+
+// 汉堡菜单交互
+const menuToggle = document.getElementById('menuToggle');
+if (menuToggle) {
+ menuToggle.addEventListener('click', () => {
+ sidebar.classList.toggle('active');
+ });
+}
+
+// 窗口大小改变时,如果大于768px,强制移除active类
+window.addEventListener('resize', () => {
+ if (window.innerWidth > 768) {
+ sidebar.classList.remove('active');
+ }
+});
+
+// 初始化
+document.addEventListener('DOMContentLoaded', () => {
+ renderSidebar();
+ renderContent();
+ setupIntersectionObserver();
+});
diff --git a/style-system/templates/login-card.html b/style-system/templates/login-card.html
new file mode 100644
index 00000000..45f03785
--- /dev/null
+++ b/style-system/templates/login-card.html
@@ -0,0 +1,206 @@
+
+
+
+
+
+ 登录卡片 - HoloLake Design System
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/style-system/templates/settings-panel.html b/style-system/templates/settings-panel.html
new file mode 100644
index 00000000..672e90c7
--- /dev/null
+++ b/style-system/templates/settings-panel.html
@@ -0,0 +1,200 @@
+
+
+
+
+
+ 设置面板 - HoloLake Design System
+
+
+
+
+
+
+
+
+
+
+
+
+
+
存储空间
+
+
+
已使用 6.5GB / 总空间 10GB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 1b26b6897f697937e87e395c902df5029cd29f95 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=93=B8=E6=B8=8A=20=28Zh=C3=B9Yu=C4=81n=29?=
Date: Sun, 8 Mar 2026 06:14:08 +0000
Subject: [PATCH 17/19] =?UTF-8?q?=F0=9F=93=9A=20=E9=93=B8=E6=B8=8A?=
=?UTF-8?q?=E5=9B=BE=E4=B9=A6=E9=A6=86=E7=9B=AE=E5=BD=95=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=20=C2=B7=202026-03-08T06:14?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/brain/repo-map.json | 2 +-
.github/brain/repo-snapshot.md | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/brain/repo-map.json b/.github/brain/repo-map.json
index 36806263..646e4dba 100644
--- a/.github/brain/repo-map.json
+++ b/.github/brain/repo-map.json
@@ -1,7 +1,7 @@
{
"description": "铸渊图书馆目录 · Library Catalog for 铸渊 (Zhùyuān)",
"version": "2.0",
- "generated_at": "2026-03-08T05:19:52.088Z",
+ "generated_at": "2026-03-08T06:14:08.816Z",
"generated_by": "scripts/generate-repo-map.js",
"repo": "qinfendebingshuo/guanghulab",
"stats": {
diff --git a/.github/brain/repo-snapshot.md b/.github/brain/repo-snapshot.md
index a4f037aa..443f195b 100644
--- a/.github/brain/repo-snapshot.md
+++ b/.github/brain/repo-snapshot.md
@@ -1,5 +1,5 @@
# 铸渊图书馆快照 · Repo Snapshot
-> 生成于 2026-03-08 13:19 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
+> 生成于 2026-03-08 14:14 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
---
@@ -13,7 +13,7 @@
| 脚本 | 18 个执行脚本 |
| 开发者节点 | 8 人 |
| HLI 接口覆盖率 | 3/17 (18%) |
-| 快照生成时间 | 2026-03-08 13:19 CST |
+| 快照生成时间 | 2026-03-08 14:14 CST |
---
From ea342fa0e0caaca20adb635b230883ab7490b59a Mon Sep 17 00:00:00 2001
From: zhizhi200271
Date: Sun, 8 Mar 2026 14:18:50 +0800
Subject: [PATCH 18/19] =?UTF-8?q?DEV-004:M17=E7=8E=AF=E8=8A=825-=E5=8A=A8?=
=?UTF-8?q?=E7=94=BB=E6=97=B6=E9=97=B4=E8=BD=B4=C2=B7=E5=B8=A7=E5=BA=8F?=
=?UTF-8?q?=E5=88=97+=E6=92=AD=E6=94=BE=E6=8E=A7=E5=88=B6+=E5=B8=A7?=
=?UTF-8?q?=E7=8E=87=E8=B0=83=E8=8A=82+=E6=95=B0=E6=8D=AE=E6=8C=81?=
=?UTF-8?q?=E4=B9=85=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
dynamic-comic-studio/css/style.css | 348 +++++++++++++++++
dynamic-comic-studio/index.html | 88 +++++
dynamic-comic-studio/js/app.js | 581 +++++++++++++++++++++++++++++
3 files changed, 1017 insertions(+)
create mode 100644 dynamic-comic-studio/css/style.css
create mode 100644 dynamic-comic-studio/index.html
create mode 100644 dynamic-comic-studio/js/app.js
diff --git a/dynamic-comic-studio/css/style.css b/dynamic-comic-studio/css/style.css
new file mode 100644
index 00000000..3243d659
--- /dev/null
+++ b/dynamic-comic-studio/css/style.css
@@ -0,0 +1,348 @@
+/* ==================== 基础重置 ==================== */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', sans-serif;
+ background: #1a1a2e;
+ color: #eee;
+ overflow: hidden;
+}
+
+/* ==================== 布局框架 ==================== */
+#app {
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+}
+
+/* ==================== 顶部工具栏 ==================== */
+#toolbar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px 20px;
+ background: #16213e;
+ border-bottom: 2px solid #0f3460;
+}
+
+#toolbar h1 {
+ font-size: 18px;
+ color: #e94560;
+}
+
+.toolbar-actions button {
+ margin-left: 10px;
+ padding: 6px 12px;
+ background: #0f3460;
+ color: #fff;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: background 0.3s;
+}
+
+.toolbar-actions button:hover {
+ background: #e94560;
+}
+
+/* ==================== 主工作区 ==================== */
+#workspace {
+ display: flex;
+ flex: 1;
+ overflow: hidden;
+}
+
+/* ==================== 左侧素材面板 ==================== */
+#assets-panel {
+ width: 200px;
+ background: #16213e;
+ border-right: 2px solid #0f3460;
+ padding: 15px;
+ overflow-y: auto;
+}
+
+#assets-panel h3 {
+ color: #e94560;
+ margin-bottom: 15px;
+ font-size: 16px;
+}
+
+.asset-category {
+ margin-bottom: 20px;
+}
+
+.asset-category h4 {
+ color: #533483;
+ font-size: 14px;
+ margin-bottom: 10px;
+ padding-left: 5px;
+ border-left: 3px solid #e94560;
+}
+
+.asset-items {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+
+.asset-item {
+ padding: 8px 12px;
+ background: #0f3460;
+ border-radius: 6px;
+ cursor: move;
+ font-size: 13px;
+ transition: all 0.3s;
+ user-select: none;
+}
+
+.asset-item:hover {
+ background: #e94560;
+ transform: translateY(-2px);
+}
+
+/* ==================== 画布区域 ==================== */
+#canvas-container {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ background: #0f0f1a;
+}
+
+#scene-tabs {
+ display: flex;
+ align-items: center;
+ padding: 10px;
+ background: #16213e;
+ border-bottom: 2px solid #0f3460;
+}
+
+#tabs-list {
+ display: flex;
+ gap: 8px;
+ flex: 1;
+}
+
+.scene-tab {
+ padding: 8px 16px;
+ background: #0f3460;
+ border-radius: 4px 4px 0 0;
+ cursor: pointer;
+ font-size: 14px;
+ position: relative;
+}
+
+.scene-tab.active {
+ background: #e94560;
+}
+
+.scene-tab .close-btn {
+ margin-left: 8px;
+ opacity: 0.6;
+}
+
+.scene-tab .close-btn:hover {
+ opacity: 1;
+}
+
+#add-scene-btn {
+ padding: 8px 16px;
+ background: #533483;
+ color: #fff;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ margin-left: 10px;
+}
+
+#canvas-wrapper {
+ flex: 1;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 20px;
+ overflow: auto;
+}
+
+#main-canvas {
+ background: #fff;
+ border-radius: 8px;
+ box-shadow: 0 4px 20px rgba(0,0,0,0.5);
+ cursor: crosshair;
+}
+
+/* ==================== 底部时间轴面板 ==================== */
+#timeline-panel {
+ background: #16213e;
+ border-top: 2px solid #0f3460;
+ padding: 15px 20px;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+/* 播放控制栏 */
+#playback-controls {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+}
+
+#playback-controls button {
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ border: none;
+ background: #0f3460;
+ color: #fff;
+ font-size: 18px;
+ cursor: pointer;
+ transition: all 0.3s;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+#playback-controls button:hover {
+ background: #e94560;
+ transform: scale(1.1);
+}
+
+#frame-counter {
+ font-size: 14px;
+ color: #aaa;
+ min-width: 80px;
+}
+
+#playback-controls label {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-size: 14px;
+ color: #aaa;
+}
+
+#fps-slider {
+ width: 120px;
+ cursor: pointer;
+}
+
+#fps-display {
+ color: #e94560;
+ font-weight: bold;
+ min-width: 50px;
+}
+
+/* 帧缩略图时间轴 */
+#timeline-frames {
+ display: flex;
+ gap: 8px;
+ padding: 10px;
+ background: #0f0f1a;
+ border-radius: 6px;
+ overflow-x: auto;
+ min-height: 70px;
+ align-items: center;
+}
+
+.frame-thumb {
+ width: 80px;
+ height: 60px;
+ background: #0f3460;
+ border: 2px solid #533483;
+ border-radius: 4px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 12px;
+ color: #aaa;
+ position: relative;
+ transition: all 0.3s;
+ flex-shrink: 0;
+}
+
+.frame-thumb:hover {
+ border-color: #e94560;
+ transform: translateY(-2px);
+}
+
+.frame-thumb.active {
+ border-color: #e94560;
+ background: #533483;
+ box-shadow: 0 0 10px rgba(233, 69, 96, 0.5);
+}
+
+.frame-thumb::before {
+ content: attr(data-frame);
+ position: absolute;
+ top: 2px;
+ left: 4px;
+ font-size: 10px;
+ color: #fff;
+ background: rgba(0,0,0,0.5);
+ padding: 1px 4px;
+ border-radius: 2px;
+}
+
+/* 时间轴操作按钮 */
+#timeline-actions {
+ display: flex;
+ gap: 10px;
+}
+
+#timeline-actions button {
+ padding: 8px 16px;
+ background: #0f3460;
+ color: #fff;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 14px;
+ transition: all 0.3s;
+}
+
+#timeline-actions button:hover {
+ background: #e94560;
+}
+
+/* ==================== 画布上的素材样式 ==================== */
+.canvas-asset {
+ position: absolute;
+ cursor: move;
+ user-select: none;
+ font-size: 48px;
+ filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.3));
+ transition: transform 0.1s;
+}
+
+.canvas-asset:hover {
+ transform: scale(1.1);
+}
+
+.canvas-asset.selected {
+ outline: 2px dashed #e94560;
+ outline-offset: 4px;
+}
+
+/* ==================== 滚动条样式 ==================== */
+::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+::-webkit-scrollbar-track {
+ background: #0f0f1a;
+}
+
+::-webkit-scrollbar-thumb {
+ background: #533483;
+ border-radius: 4px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: #e94560;
+}
diff --git a/dynamic-comic-studio/index.html b/dynamic-comic-studio/index.html
new file mode 100644
index 00000000..b5be2dcb
--- /dev/null
+++ b/dynamic-comic-studio/index.html
@@ -0,0 +1,88 @@
+
+
+
+
+
+ HoloLake 动态漫制作系统 - 环节5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dynamic-comic-studio/js/app.js b/dynamic-comic-studio/js/app.js
new file mode 100644
index 00000000..184d1b06
--- /dev/null
+++ b/dynamic-comic-studio/js/app.js
@@ -0,0 +1,581 @@
+// ==================== HoloLake 动态漫制作系统 v5.0 ====================
+// 环节5:动画时间轴(帧序列 + 播放控制 + 帧率调节)
+
+const STORAGE_KEY = 'hololake-comic-studio-data';
+const canvas = document.getElementById('main-canvas');
+const ctx = canvas.getContext('2d');
+
+// ==================== 全局状态 ====================
+let appState = {
+ currentSceneId: 1,
+ nextSceneId: 2,
+ nextAssetId: 1,
+ nextFrameId: 1,
+ scenes: [],
+ playback: {
+ isPlaying: false,
+ fps: 4,
+ intervalId: null,
+ currentFrameIndex: 0
+ }
+};
+
+// ==================== 初始化 ====================
+function init() {
+ loadFromStorage();
+ if (appState.scenes.length === 0) {
+ createDefaultScene();
+ }
+ setupEventListeners();
+ renderSceneTabs();
+ renderCanvas();
+ renderTimeline();
+ updatePlaybackControls();
+}
+
+// 创建默认场景
+function createDefaultScene() {
+ const defaultScene = {
+ id: 1,
+ name: '场景 1',
+ currentFrameIndex: 0,
+ frames: [{
+ id: 1,
+ assets: []
+ }],
+ nextFrameId: 2
+ };
+ appState.scenes.push(defaultScene);
+ appState.currentSceneId = 1;
+ saveToStorage();
+}
+
+// ==================== 存储管理 ====================
+function saveToStorage() {
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(appState));
+}
+
+function loadFromStorage() {
+ const data = localStorage.getItem(STORAGE_KEY);
+ if (data) {
+ const parsed = JSON.parse(data);
+ // 向后兼容:旧数据没有 frames 字段
+ if (parsed.scenes && parsed.scenes.length > 0 && !parsed.scenes[0].frames) {
+ parsed.scenes = parsed.scenes.map(scene => ({
+ ...scene,
+ currentFrameIndex: 0,
+ frames: [{
+ id: 1,
+ assets: scene.assets || []
+ }],
+ nextFrameId: 2
+ }));
+ delete parsed.scenes[0].assets; // 删除旧的 assets 字段
+ }
+ // 确保 playback 对象存在
+ if (!parsed.playback) {
+ parsed.playback = { isPlaying: false, fps: 4, intervalId: null, currentFrameIndex: 0 };
+ }
+ appState = parsed;
+ }
+}
+
+// ==================== 场景管理 ====================
+function addScene() {
+ const newScene = {
+ id: appState.nextSceneId++,
+ name: `场景 ${appState.scenes.length + 1}`,
+ currentFrameIndex: 0,
+ frames: [{
+ id: 1,
+ assets: []
+ }],
+ nextFrameId: 2
+ };
+ appState.scenes.push(newScene);
+ appState.currentSceneId = newScene.id;
+ saveToStorage();
+ renderSceneTabs();
+ renderCanvas();
+ renderTimeline();
+}
+
+function switchScene(sceneId) {
+ if (appState.playback.isPlaying) {
+ stopAnimation();
+ }
+ appState.currentSceneId = sceneId;
+ saveToStorage();
+ renderSceneTabs();
+ renderCanvas();
+ renderTimeline();
+ updateFrameCounter();
+}
+
+function deleteScene(sceneId) {
+ if (appState.scenes.length <= 1) {
+ alert('至少保留一个场景!');
+ return;
+ }
+ appState.scenes = appState.scenes.filter(s => s.id !== sceneId);
+ if (appState.currentSceneId === sceneId) {
+ appState.currentSceneId = appState.scenes[0].id;
+ }
+ saveToStorage();
+ renderSceneTabs();
+ renderCanvas();
+ renderTimeline();
+}
+
+function getCurrentScene() {
+ return appState.scenes.find(s => s.id === appState.currentSceneId);
+}
+
+function getCurrentFrame() {
+ const scene = getCurrentScene();
+ if (!scene) return null;
+ return scene.frames[scene.currentFrameIndex];
+}// ==================== 帧管理 ====================
+function addFrame() {
+ const scene = getCurrentScene();
+ if (!scene) return;
+
+ // 深拷贝当前帧的素材状态
+ const currentFrame = scene.frames[scene.currentFrameIndex];
+ const newFrame = {
+ id: scene.nextFrameId++,
+ assets: JSON.parse(JSON.stringify(currentFrame.assets))
+ };
+
+ // 在当前帧后插入新帧
+ scene.frames.splice(scene.currentFrameIndex + 1, 0, newFrame);
+ scene.currentFrameIndex++;
+
+ saveToStorage();
+ renderTimeline();
+ renderCanvas();
+ updateFrameCounter();
+}
+
+function deleteFrame() {
+ const scene = getCurrentScene();
+ if (!scene) return;
+
+ if (scene.frames.length <= 1) {
+ alert('至少保留一帧!');
+ return;
+ }
+
+ scene.frames.splice(scene.currentFrameIndex, 1);
+ if (scene.currentFrameIndex >= scene.frames.length) {
+ scene.currentFrameIndex = scene.frames.length - 1;
+ }
+
+ saveToStorage();
+ renderTimeline();
+ renderCanvas();
+ updateFrameCounter();
+}
+
+function switchFrame(frameIndex) {
+ const scene = getCurrentScene();
+ if (!scene || frameIndex < 0 || frameIndex >= scene.frames.length) return;
+
+ // 保存当前画布状态到当前帧
+ captureFrame();
+
+ scene.currentFrameIndex = frameIndex;
+ saveToStorage();
+ renderTimeline();
+ renderCanvas();
+ updateFrameCounter();
+}
+
+function captureFrame() {
+ // 画布状态实时保存在 assets 中,无需额外操作
+ saveToStorage();
+}
+
+// ==================== 播放引擎 ====================
+function playAnimation() {
+ const scene = getCurrentScene();
+ if (!scene || scene.frames.length <= 1) return;
+
+ appState.playback.isPlaying = true;
+ updatePlaybackControls();
+
+ const intervalMs = 1000 / appState.playback.fps;
+
+ appState.playback.intervalId = setInterval(() => {
+ const scene = getCurrentScene();
+ if (!scene) return;
+
+ scene.currentFrameIndex++;
+ if (scene.currentFrameIndex >= scene.frames.length) {
+ scene.currentFrameIndex = 0; // 循环播放
+ }
+
+ renderCanvas();
+ renderTimeline();
+ updateFrameCounter();
+ saveToStorage();
+ }, intervalMs);
+}
+
+function pauseAnimation() {
+ appState.playback.isPlaying = false;
+ if (appState.playback.intervalId) {
+ clearInterval(appState.playback.intervalId);
+ appState.playback.intervalId = null;
+ }
+ updatePlaybackControls();
+}
+
+function stopAnimation() {
+ pauseAnimation();
+ const scene = getCurrentScene();
+ if (scene) {
+ scene.currentFrameIndex = 0;
+ renderCanvas();
+ renderTimeline();
+ updateFrameCounter();
+ saveToStorage();
+ }
+}
+
+function togglePlayback() {
+ if (appState.playback.isPlaying) {
+ pauseAnimation();
+ } else {
+ playAnimation();
+ }
+}
+
+function setFPS(fps) {
+ appState.playback.fps = parseInt(fps);
+ document.getElementById('fps-display').textContent = fps + ' FPS';
+ saveToStorage();
+
+ // 如果正在播放,重启定时器以应用新帧率
+ if (appState.playback.isPlaying) {
+ pauseAnimation();
+ playAnimation();
+ }
+}
+
+function updatePlaybackControls() {
+ const btnPlay = document.getElementById('btn-play');
+ if (appState.playback.isPlaying) {
+ btnPlay.textContent = '⏸️';
+ btnPlay.title = '暂停';
+ } else {
+ btnPlay.textContent = '▶️';
+ btnPlay.title = '播放';
+ }
+}
+
+function updateFrameCounter() {
+ const scene = getCurrentScene();
+ if (!scene) return;
+ const counter = document.getElementById('frame-counter');
+ counter.textContent = `帧 ${scene.currentFrameIndex + 1}/${scene.frames.length}`;
+}// ==================== 渲染函数 ====================
+function renderSceneTabs() {
+ const tabsList = document.getElementById('tabs-list');
+ tabsList.innerHTML = '';
+
+ appState.scenes.forEach(scene => {
+ const tab = document.createElement('div');
+ tab.className = 'scene-tab' + (scene.id === appState.currentSceneId ? ' active' : '');
+ tab.innerHTML = `
+ ${scene.name}
+ ×
+ `;
+ tab.onclick = () => switchScene(scene.id);
+ tabsList.appendChild(tab);
+ });
+}
+
+function renderTimeline() {
+ const timelineFrames = document.getElementById('timeline-frames');
+ timelineFrames.innerHTML = '';
+
+ const scene = getCurrentScene();
+ if (!scene) return;
+
+ scene.frames.forEach((frame, index) => {
+ const thumb = document.createElement('div');
+ thumb.className = 'frame-thumb' + (index === scene.currentFrameIndex ? ' active' : '');
+ thumb.setAttribute('data-frame', index + 1);
+ thumb.textContent = `帧 ${index + 1}`;
+ thumb.onclick = () => switchFrame(index);
+ timelineFrames.appendChild(thumb);
+ });
+}
+
+function renderCanvas() {
+ // 清空画布
+ ctx.fillStyle = '#ffffff';
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ const frame = getCurrentFrame();
+ if (!frame) return;
+
+ // 绘制所有素材
+ frame.assets.forEach(asset => {
+ ctx.font = '48px Arial';
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+
+ // 绘制阴影
+ ctx.shadowColor = 'rgba(0,0,0,0.3)';
+ ctx.shadowBlur = 4;
+ ctx.shadowOffsetX = 2;
+ ctx.shadowOffsetY = 2;
+
+ ctx.fillText(asset.emoji, asset.x, asset.y);
+
+ // 重置阴影
+ ctx.shadowColor = 'transparent';
+ ctx.shadowBlur = 0;
+ ctx.shadowOffsetX = 0;
+ ctx.shadowOffsetY = 0;
+
+ // 如果是选中状态,绘制边框
+ if (asset.selected) {
+ ctx.strokeStyle = '#e94560';
+ ctx.lineWidth = 2;
+ ctx.setLineDash([5, 5]);
+ ctx.strokeRect(asset.x - 30, asset.y - 30, 60, 60);
+ ctx.setLineDash([]);
+ }
+ });
+}
+
+// ==================== 素材拖放 ====================
+function setupEventListeners() {
+ // 素材库拖放
+ const assetItems = document.querySelectorAll('.asset-item');
+ assetItems.forEach(item => {
+ item.addEventListener('dragstart', (e) => {
+ e.dataTransfer.setData('type', item.dataset.type);
+ e.dataTransfer.setData('emoji', item.dataset.emoji);
+ });
+ });
+
+ // 画布接收拖放
+ canvas.addEventListener('dragover', (e) => {
+ e.preventDefault();
+ });
+
+ canvas.addEventListener('drop', (e) => {
+ e.preventDefault();
+ const type = e.dataTransfer.getData('type');
+ const emoji = e.dataTransfer.getData('emoji');
+
+ if (emoji) {
+ const rect = canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ addAssetToCanvas(emoji, x, y);
+ }
+ });
+
+ // 画布点击选择/移动
+ let isDragging = false;
+ let dragStartX, dragStartY;
+ let selectedAsset = null;
+
+ canvas.addEventListener('mousedown', (e) => {
+ const rect = canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ const frame = getCurrentFrame();
+ if (!frame) return;
+
+ // 查找点击的素材(从后往前,优先选上层的)
+ selectedAsset = null;
+ for (let i = frame.assets.length - 1; i >= 0; i--) {
+ const asset = frame.assets[i];
+ const dist = Math.sqrt((x - asset.x) ** 2 + (y - asset.y) ** 2);
+ if (dist < 30) {
+ selectedAsset = asset;
+ // 更新选中状态
+ frame.assets.forEach(a => a.selected = false);
+ asset.selected = true;
+ isDragging = true;
+ dragStartX = x - asset.x;
+ dragStartY = y - asset.y;
+ renderCanvas();
+ break;
+ }
+ }
+
+ // 如果没点到素材,取消所有选中
+ if (!selectedAsset) {
+ frame.assets.forEach(a => a.selected = false);
+ renderCanvas();
+ }
+ });
+
+ canvas.addEventListener('mousemove', (e) => {
+ if (!isDragging || !selectedAsset) return;
+
+ const rect = canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ selectedAsset.x = x - dragStartX;
+ selectedAsset.y = y - dragStartY;
+
+ // 边界限制
+ selectedAsset.x = Math.max(30, Math.min(canvas.width - 30, selectedAsset.x));
+ selectedAsset.y = Math.max(30, Math.min(canvas.height - 30, selectedAsset.y));
+
+ renderCanvas();
+ });
+
+ canvas.addEventListener('mouseup', () => {
+ if (isDragging) {
+ isDragging = false;
+ saveToStorage();
+ }
+ });
+
+ // 键盘删除
+ document.addEventListener('keydown', (e) => {
+ if (e.key === 'Delete' || e.key === 'Backspace') {
+ const frame = getCurrentFrame();
+ if (!frame) return;
+
+ const selectedIndex = frame.assets.findIndex(a => a.selected);
+ if (selectedIndex !== -1) {
+ frame.assets.splice(selectedIndex, 1);
+ renderCanvas();
+ saveToStorage();
+ }
+ }
+ });
+
+ // 导入文件监听
+ document.getElementById('import-file').addEventListener('change', handleImport);
+}
+
+function addAssetToCanvas(emoji, x, y) {
+ const frame = getCurrentFrame();
+ if (!frame) return;
+
+ // 取消其他选中
+ frame.assets.forEach(a => a.selected = false);
+
+ const newAsset = {
+ id: appState.nextAssetId++,
+ type: 'emoji',
+ emoji: emoji,
+ x: x,
+ y: y,
+ selected: true
+ };
+
+ frame.assets.push(newAsset);
+ renderCanvas();
+ saveToStorage();
+}// ==================== 导出导入 ====================
+function exportScene() {
+ const dataStr = JSON.stringify(appState, null, 2);
+ const blob = new Blob([dataStr], { type: 'application/json' });
+ const url = URL.createObjectURL(blob);
+
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = `hololake-scene-${Date.now()}.json`;
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
+}
+
+function importScene() {
+ document.getElementById('import-file').click();
+}
+
+function handleImport(e) {
+ const file = e.target.files[0];
+ if (!file) return;
+
+ const reader = new FileReader();
+ reader.onload = (event) => {
+ try {
+ const imported = JSON.parse(event.target.result);
+
+ // 验证数据结构
+ if (!imported.scenes || !Array.isArray(imported.scenes)) {
+ throw new Error('无效的数据格式');
+ }
+
+ // 向后兼容处理
+ imported.scenes = imported.scenes.map(scene => {
+ if (!scene.frames) {
+ return {
+ ...scene,
+ currentFrameIndex: 0,
+ frames: [{
+ id: 1,
+ assets: scene.assets || []
+ }],
+ nextFrameId: 2
+ };
+ }
+ return scene;
+ });
+
+ if (!imported.playback) {
+ imported.playback = { isPlaying: false, fps: 4, intervalId: null, currentFrameIndex: 0 };
+ }
+
+ appState = imported;
+ saveToStorage();
+ renderSceneTabs();
+ renderCanvas();
+ renderTimeline();
+ updatePlaybackControls();
+ updateFrameCounter();
+
+ alert('导入成功!');
+ } catch (err) {
+ alert('导入失败:' + err.message);
+ }
+ };
+ reader.readAsText(file);
+
+ // 清空 input,允许重复导入同一文件
+ e.target.value = '';
+}
+
+// ==================== 截图导出 ====================
+function exportScreenshot() {
+ // 临时取消选中状态
+ const frame = getCurrentFrame();
+ if (!frame) return;
+
+ const originalSelected = frame.assets.map(a => a.selected);
+ frame.assets.forEach(a => a.selected = false);
+ renderCanvas();
+
+ // 导出 PNG
+ const link = document.createElement('a');
+ link.download = `hololake-frame-${Date.now()}.png`;
+ link.href = canvas.toDataURL();
+ link.click();
+
+ // 恢复选中状态
+ frame.assets.forEach((a, i) => {
+ a.selected = originalSelected[i];
+ });
+ renderCanvas();
+}
+
+// ==================== 启动应用 ====================
+document.addEventListener('DOMContentLoaded', init);
From bb574bd9e64640007f181cb3b127f52d792180f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=93=B8=E6=B8=8A=20=28Zh=C3=B9Yu=C4=81n=29?=
Date: Sun, 8 Mar 2026 06:28:27 +0000
Subject: [PATCH 19/19] =?UTF-8?q?=F0=9F=93=9A=20=E9=93=B8=E6=B8=8A?=
=?UTF-8?q?=E5=9B=BE=E4=B9=A6=E9=A6=86=E7=9B=AE=E5=BD=95=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=20=C2=B7=202026-03-08T06:28?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/brain/repo-map.json | 2 +-
.github/brain/repo-snapshot.md | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/brain/repo-map.json b/.github/brain/repo-map.json
index 646e4dba..9cf4291e 100644
--- a/.github/brain/repo-map.json
+++ b/.github/brain/repo-map.json
@@ -1,7 +1,7 @@
{
"description": "铸渊图书馆目录 · Library Catalog for 铸渊 (Zhùyuān)",
"version": "2.0",
- "generated_at": "2026-03-08T06:14:08.816Z",
+ "generated_at": "2026-03-08T06:28:27.088Z",
"generated_by": "scripts/generate-repo-map.js",
"repo": "qinfendebingshuo/guanghulab",
"stats": {
diff --git a/.github/brain/repo-snapshot.md b/.github/brain/repo-snapshot.md
index 443f195b..246ae21c 100644
--- a/.github/brain/repo-snapshot.md
+++ b/.github/brain/repo-snapshot.md
@@ -1,5 +1,5 @@
# 铸渊图书馆快照 · Repo Snapshot
-> 生成于 2026-03-08 14:14 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
+> 生成于 2026-03-08 14:28 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件
---
@@ -13,7 +13,7 @@
| 脚本 | 18 个执行脚本 |
| 开发者节点 | 8 人 |
| HLI 接口覆盖率 | 3/17 (18%) |
-| 快照生成时间 | 2026-03-08 14:14 CST |
+| 快照生成时间 | 2026-03-08 14:28 CST |
---