通用数据分析看板生成器(可筛选+手动刷新) - 从数据文件自动生成交互式HTML看板
dashboard-builder v4.3是一项面向实际任务的技能,主要用于从Excel/CSV数据文件生成单文件交互式HTML看板,支持全局多维筛选 + 手动数据刷新按钮;唯一外部依赖:Chart.js 4.x CDN;
日期列 → 含日期/时间信息,作为趋势分析时间轴;数值列 → 含数值,候选核心指标;分类列 →。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。
实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。该技能适合用于一次性任务,也可以接入自动化工作流,与其他技能或上层代理配合完成更完整的业务链路;在组合使用时,应明确每一步的输入输出关系,并避免不同步骤之间出现参数冲突。
从Excel/CSV数据文件生成单文件交互式HTML看板,支持全局多维筛选 + 手动数据刷新按钮。唯一外部依赖:Chart.js 4.x CDN。
核心指标(3-5个):从数值列选取最具业务含义的原始聚合值。按日期聚合(求和/平均/计数)。
计算指标(5-8个):基于核心指标派生,必须覆盖以下类别:
维度(2-4个):从分类列中选取
漏斗链路:给出最全的漏斗转化链路
在开始分析前,快速向用户确认以下参数
data.json)生成两个交付物:
dashboard.html — 主看板文件,内嵌全部CSS/JS,初始数据以JS对象嵌入dashboard_data.json — 伴生数据文件,包含完整 DATA 对象(raw/daily/city/category/funnel/dimValues/generatedAt),供HTML刷新使用⚠️ DATA嵌入铁律:先用Python json.dumps(data, ensure_ascii=False, separators=(',', ':')) 生成紧凑JSON字符串,再整体替换HTML中 const DATA = ...; 块。禁止手动逐行拼接JSON——多行嵌套对象极易出现括号不匹配(如daily对象后多余})导致JS语法错误。
⚠️ data.json 生成铁律:同样用 json.dumps(data, ensure_ascii=False) 生成,写入独立文件。data 对象必须包含 generatedAt 字段(ISO 8601时间戳,如 "2026-06-30T09:35:48"),供HTML端判断数据是否有更新。
⚠️ 全局筛选数据要求:DATA.raw 必须嵌入所有原始明细行(对象数组),供全局筛选后重新聚合。DATA.dimValues 存储各筛选维度的distinct值列表(如 { city: [...], category: [...] })。DATA.daily/DATA.city/DATA.category/DATA.funnel 在Python阶段基于全量数据预聚合,同时作为初始状态(全选"全部"时的展示数据);全局筛选变更后,由前端JS基于 DATA.raw 重新聚合生成 WORKING_DATA。
header.global-filter-bar(44px高,全宽,粘性顶部)
│ └── 筛选器组(左)+ 刷新按钮组(右)
└── body → flex布局
├── aside.sidebar(280px,可折叠)
│ ├── 配色方案 → 13套色块选择器(点击切换)
│ ├── 核心指标 → 复选框列表(默认全选)
│ ├── 计算指标 → 复选框列表(默认全选)
│ └── 重点维度 → 复选框列表(默认全选)
└── main.dashboard → 12板块纵向排列
位于看板最顶部(body之上),全宽横向排列,粘性定位(position: sticky; top: 0; z-index: 100),包含各维度的下拉筛选器。左右分区:左侧为筛选器组,右侧为刷新控件组。
结构:
下拉框,选项 = ["全部"] + 该维度在 DATA.dimValues 中的所有distinct值gap: 12px样式:
var(--bg-primary),底部 1px solid var(--bg-card) 分隔线bg = var(--bg-card), color = var(--text-primary), border: 1px solid rgba(255,255,255,0.1), border-radius: 4pxpadding: 8px 16px,字体 Calibri 11ptcolor = var(--text-secondary),margin-right: 6pxbg = transparent, border: 1px solid var(--accent-1), color = var(--accent-1), border-radius: 4px, cursor: pointer, hover时 bg = var(--accent-1), color = #fffborder: 1px solid var(--accent-2), color = var(--accent-2)),hover时 bg = var(--accent-2), color = #fff;按钮内显示刷新图标文字("↻ 刷新数据"),刷新进行中时显示旋转动画 + "刷新中…"var(--accent-2))= 数据最新/空闲;黄色(#F39C12)= 刷新进行中;红色(var(--accent-3))= 上次刷新失败display: none。样式:border: 1px solid var(--accent-3); color: var(--accent-3),hover 时 bg = var(--accent-3); color = #fff。点击后清除 localStorage 并 location.reload()margin-left: auto 分隔,确保刷新控件固定在右侧行为:
filterRawData(filters) → reaggregateAll(filteredRows) → refreshAllPanels(workingData)reaggregateAll() 重新生成 WORKING_DATA.daily、WORKING_DATA.city、WORKING_DATA.category、WORKING_DATA.funnelrefreshAllPanels() 更新所有卡片数值 + destroyAllCharts + recreateAllCharts + 刷新表格 + 重写结论文本看板仅支持手动刷新,initRefresh() 根据浏览器协议和能力自动选择最佳方式:
| 协议 | 浏览器 | 刷新方式 | 说明 |
|---|---|---|---|
file:// |
Chrome/Edge 86+ | File System Access API | showOpenFilePicker() 获取句柄存 IndexedDB,后续直接读取无需重复选择 |
file:// |
Safari/Firefox | |
每次需重新选择文件 |
http:// |
任意 | fetch('/api/data') |
比较 generatedAt 时间戳,相同则跳过;失败则提示 |
核心流程:用户点「↻ 刷新数据」→ 状态灯变黄 → 按协议读取数据 → applyNewData(fresh):
applyNewData(): DATA = fresh(let 声明,允许重新赋值) buildFilters() → resetFilters() 全量刷新所有12板块(卡片+图表+表格+结论) 状态灯 → 绿色 显示「恢复默认」按钮(display: inline-block) 保存到 localStorage(key: 'dashboard_data',value: JSON.stringify(DATA))
文件解析(FSA / 文件上传共用):parseExcelFile(file) 用 SheetJS (XLSX.read) 解析 Excel → 标准化行数据(日期→YYYY-MM-DD)→ 构建 {raw, daily, city, category, funnel, dimValues, generatedAt} → 调用 applyNewData()。
可选服务器:dashboard_server.py 提供 GET /api/data 端点,实时 pd.read_excel() 返回最新数据。启动方式:python dashboard_server.py 9090。
上传文件后的数据在浏览器内存中生效,但刷新页面会丢失(HTML 中的内嵌数据不可自修改)。通过 localStorage 持久化解决:
applyNewData() 中:聚合 + 刷新完成后,执行 localStorage.setItem('dashboard_data', JSON.stringify(DATA)) 保存完整 DATA 对象。
init() 初始化时:页面加载后先检查 localStorage:
var saved = null;
try { saved = localStorage.getItem('dashboard_data'); } catch(e) {}
if (saved) {
try {
var parsed = JSON.parse(saved);
if (parsed && parsed.raw && Array.isArray(parsed.raw) && parsed.raw.length > 0) {
DATA = parsed;
document.getElementById('restoreDefault').style.display = 'inline-block';
}
} catch(e) { console.warn('localStorage data corrupt, using embedded data'); }
}
有持久化数据时用持久化数据,没有则用内嵌初始数据。
「恢复默认」按钮:位于刷新按钮右侧,初始 display: none,localStorage 有数据时显示。样式:border: 1px solid var(--accent-3); color: var(--accent-3)(红色边框,与重置/刷新区分)。点击后:
function restoreDefaultData() {
try { localStorage.removeItem('dashboard_data'); } catch(e) {}
location.reload();
}
基于用户确认的核心指标、计算指标、分析维度,按照如下方式展示。所有板块均受全局筛选控制:
| # | 板块 | 图表类型 | 交互方式 | 全局筛选响应 | 数据刷新响应 |
|---|---|---|---|---|---|
| 1 | 核心指标卡片 | 数值卡片(32px高)+环比色标 | 左侧勾选切换显隐 | 数值基于筛选后数据重新计算 | 数值基于新DATA重新计算 |
| 2 | 计算指标卡片 | 数值卡片(32px高)+环比色标 | 左侧勾选切换显隐 | 数值基于筛选后数据重新计算 | 数值基于新DATA重新计算 |
| 3 | 核心指标趋势 | 折线图(渐变填充) | 下拉框选指标 | 折线数据基于筛选后daily重绘 | 折线数据基于新DATA.daily重绘 |
| 4 | 比率指标趋势 | 折线图(渐变填充) | 下拉框选指标 | 折线数据基于筛选后daily重绘 | 折线数据基于新DATA.daily重绘 |
| 5 | 同环比指标趋势 | 柱形图(正向绿色,负向红色) | 下拉框选指标 | 折线数据基于筛选后daily重绘 | 折线数据基于新DATA.daily重绘 |
| 6 | 核心指标分维度 | 柱状图(渐变填充) | 2个下拉框分别选核心指标、分析维度 | 柱状图数据基于筛选后维度聚合重绘 | 柱状图数据基于新DATA维度聚合重绘 |
| 7 | 计算指标分维度 | 柱状图(渐变填充) | 2个下拉框分别选核心指标、分析维度 | 柱状图数据基于筛选后维度聚合重绘 | 柱状图数据基于新DATA维度聚合重绘 |
| 8 | 漏斗分析 | 横向递减柱状图 | 无漏斗数据→留空+提示文字 | 各阶段计数基于筛选后数据重算 | 各阶段计数基于新DATA.funnel重算 |
| 9 | 漏斗分析 | 各步骤转化的格式化表格(各步数量级、转化率) | 无漏斗数据→留空+提示文字 | 各阶段计数基于筛选后数据重算 | 各阶段计数基于新DATA.funnel重算 |
| 10 | 城市排名 | 条形图(渐变填充) | 1个下拉框,用来筛选指标(核心指标+计算指标) | 排名基于筛选后数据重算 | 排名基于新DATA重算 |
| 11 | 品类排名 | 条形图(渐变填充) | 1个下拉框,用来筛选指标(核心指标+计算指标) | 排名基于筛选后数据重算 | 排名基于新DATA重算 |
| 12 | 多维交叉分析 | 格式化表格 | 3个下拉框分别选指标(核心指标+计算指标)、横向维度、纵向维度 | 表格数据基于筛选后数据重算 | 表格数据基于新DATA重算 |
| 13 | 文字分析结论 | 格式化文本 | 基于数据自动生成 | 结论基于筛选后数据重新生成 | 结论基于新DATA重新生成 |
6、7并列展示;8、9并列展示;10、11并列展示
字体与尺寸:
Chart.js图表必选项:
折线图: pointRadius=4, pointHoverRadius=6, tension=0.3, fill=true, borderWidth=3, 渐变backgroundColor 柱状图: borderRadius=6, barPercentage=0.7, 渐变backgroundColor 条形图: borderRadius=6, barPercentage=0.7, 渐变backgroundColor 环形图: cutout='60%', 数据标签在外圈, 渐变backgroundColor 渐变创建: ctx=createLinearGradient(0,0,0,220), addColorStop(0,主色0.8透明), addColorStop(1,主色0.5透明)
卡片三层结构(⚠️ 强制规范):
结构: ┌─ .kpi-card (.bc1~.bc8) ──────────────┐ │ .kpi-label 图标+名称 9pt 灰色 │ │ .kpi-value 主数值 18pt 白色粗体 │ │ .kpi-meta 辅助信息 8.5pt 暗色 │ └──── 4px 左边框颜色条 ─────────────────┘
第二层 .kpi-value 计算规则:
| 卡片类型 | 第二层显示 | 说明 |
|---|---|---|
| 核心指标 | ¥34.4万/2896 | 取最近一天的对应指标之和 |
| 计算指标-isMom 类 | 环比 ▲ 3.2% | 计算该指标最近一天的实际值 |
| 计算指标-比率类 | 25% | 计算该指标最近一天的实际值 |
第三层 .kpi-meta 内容规则(根据业务语义差异化):
| 卡片类型 | 第三层显示 | 说明 |
|---|---|---|
| 核心指标 | 环比 ▲ 3.2% | 取 daily 最后一行对应的 _mom 字段 |
| 计算指标-isMom 类 | 最近一天 | 主数值已是环比%,第三层只标注数据来源 |
| 计算指标-比率类 | 环比 ▲ 3.2% | 利润率/客单价/转化率/复购率 |
⚠️ 环比色标分场景规则(卡片 vs 图表,方向相反):
| 场景 | 涨(正增长) | 跌(负增长) | 逻辑 |
|---|---|---|---|
| 卡片环比文字 | 绿色 ▲ | 红色 ▼ | 增长=好事=绿,下跌=警报=红 |
| 同环比趋势图 | 绿色柱 | 红色柱 | 增长=好事=绿,下跌=警报=红 |
⚠️ 维度数据KPI过滤铁律:DATA.city/DATA.category 中没有环比类指标(如 sales_mom, orders_mom 等),它们只存在于 DATA.daily。初始化维度图表下拉和排名下拉时,必须用 k in DATA.city 过滤,否则 ds[calcKpi] 取到 undefined → data.map() 崩溃 → 后续漏斗/交叉表/排名/结论全部挂掉。数据刷新后重新赋值 DATA 对象时,同样必须重新执行此过滤逻辑。
表格规范
美化要素:
.kpi-card 样式,仅左边框颜色和底部提示文字颜色不同border-radius: 50%,带 box-shadow: 0 0 6px 同色发光效果切换方案时更新:root的CSS变量,同时destroy所有chart并用新配色recreate。
| 方案名 | --bg-primary | --bg-card | --accent-1 | --accent-2 | --accent-3 |
|---|---|---|---|---|---|
| dark_tech★ | #1A252F | #2C3E50 | #3498DB | #27AE60 | #E74C3C |
| business_blue | #0D1B2A | #1B2838 | #3A86FF | #4895EF | #4CC9F0 |
| dark_purple | #1A1A2E | #16213E | #7B2CBF | #9D4EDD | #C77DFF |
| dark_forest | #1B2A1B | #2D4A2D | #2D6A4F | #40916C | #52B788 |
| warm_copper | #2C1810 | #3E2723 | #BF6900 | #D4880F | #E8A838 |
| slate_modern | #0F172A | #1E293B | #38BDF8 | #818CF8 | #F472B6 |
| ocean_dream | #0C1B33 | #132A47 | #00A8FF | #00D2FF | #77E4D4 |
| sunset_embers | #1E0A1F | #2D122C | #FF6B6B | #FF9F43 | #FECA57 |
| teal_mystic | #0A1F1A | #12332A | #20B2AA | #48C9B0 | #7DDFC2 |
| crimson_royal | #1E1018 | #2D1A24 | #E63946 | #D90429 | #FFADAD |
| midnight_lavender | #10101A | #1C1C2E | #B980F0 | #8B5CF6 | #C4B5FD |
| coffee_night | #1E1512 | #2C211D | #D97A3C | #E69A59 | #F4B97A |
| aurora_green | #0A1C12 | #0F2B1A | #00C49A | #4ADE80 | #BBF7D0 |
多指标/多维度的图表配色:在accent-1/2/3基础上生成渐变色系(同色系不同透明度/亮度)。
filterRawData() → reaggregateAll() → refreshAllPanels()(⚠️ 全量刷新,不可遗漏任何板块)refreshAllPanels()(⚠️ 全量刷新,与筛选变更相同管线)⛔ 本节是硬关卡。Phase 4 完成后,必须逐项输出检查结果(
PASS或FAIL + 原因),全部 PASS 后才能进入 Phase 6 交付。严禁跳过任何一项。 如果某项 FAIL,立即修复后重新运行全部自检。
自检输出格式:编号 + 项目 + [PASS] / [FAIL: 原因],每项一行。
存在 存在handleRefresh() 已实现且非空壳 — 函数体内包含实际的 Excel 解析逻辑,不能是 DATA.raw = DATA.raw 或 setTimeout(()=>{},500) 这类 no-optypeof window.showOpenFilePicker === 'function' 检测 + showOpenFilePicker() 调用hiddenFileInput.click()parseExcelFile(file) 已实现 — 使用 XLSX.read() + XLSX.utils.sheet_to_json(),中文列名→英文映射applyNewData(rows) 已实现 — 替换 DATA.raw → 重建 dimValues → 重建筛选下拉框 → resetFilters → refreshAllrebuildFilterDropdowns() 已实现 — 刷新后筛选下拉框选项随新数据更新loadWD() 使用过滤后的数据 — 调用 filterRaw(DATA.raw) 而非 直接 DATA.raw(f.city==='all'||r.city===f.city) && (f.cat==='all'||r.category===f.cat)let DATA 声明(非 const DATA)— 允许刷新后重新赋值 DATA.raw#F39C12)/红(失败, var(--accent-3))applyNewData() 保存 DATA 到 localStorage;init() 中优先读取 localStorage;「恢复默认」按钮存在且功能正常new Function(script) 验证,禁止跳过)k in DATA.city 过滤)HTML 代码编写必须按以下顺序,先功能→后视觉,严禁先调渐变再补刷新:
__DATA_JSON__ 占位符⛔ 防偷懒铁律:如果第3步(核心功能)未完成,禁止进入第5步(视觉美化)。
handleRefresh()写成空壳就去做渐变调色 = 违规。
以下为旧版完整清单,保留供详细对照,但执行时以 Phase 5 强制自检为准。
new vm.Script(script) 验证,禁止跳过)DATA.city/DATA.category 中存在的KPI(不含环比类)DATA.raw 不受影响(每次筛选均从原始全量数据重新过滤+聚合)let DATA 声明(非 const DATA),允许刷新后重新赋值typeof showOpenFilePicker==='function',使用 handleRefreshWithFSA) 文件选择框)handleRefresh(),http:// 协议,服务器运行时)parseExcelFile(),所有浏览器,SheetJS 解析 Excel)applyNewData() 正确执行:DATA 赋值 → buildFilters() → resetFilters() → 全量刷新12板块setInterval 和倒计时)generatedAt 变化检测:API 刷新时比较时间戳,相同则跳过把下面两个链接都交付给我:
相关专题
热门下载
相关下载
精品课程
共6课时 | 54.7万人学习
共89课时 | 134.1万人学习
共49课时 | 82.6万人学习
最新文章