返回 Skill 列表
extension
分类: 数据与分析无需 API Key

动态看板

通用数据分析看板生成器(可筛选+手动刷新) - 从数据文件自动生成交互式HTML看板

person作者: user_d82a8f08hubcommunity

dashboard-builder v4.3

从Excel/CSV数据文件生成单文件交互式HTML看板,支持全局多维筛选 + 手动数据刷新按钮。唯一外部依赖:Chart.js 4.x CDN。

执行流程

Phase 1: 数据读取与分类

  1. 读取用户提供的数据文件(Excel/CSV)
  2. 自动分类所有列:
    • 日期列 → 含日期/时间信息,作为趋势分析时间轴
    • 数值列 → 含数值,候选核心指标
    • 分类列 → 含有限离散值,候选维度
  3. 向用户展示分类结果并确认

Phase 2: 指标体系构建

核心指标(3-5个):从数值列选取最具业务含义的原始聚合值。按日期聚合(求和/平均/计数)。

  • 销售场景:销售额、订单量、利润、客户数
  • 财务场景:收入、成本、毛利、净利润
  • HR场景:在职人数、入职数、离职数、薪酬总额

计算指标(5-8个):基于核心指标派生,必须覆盖以下类别:

  • 环比增长率:(当期-上期)/上期(每个核心指标配一个环比)
  • 同比增长率:需多年数据,否则跳过
  • 比率指标:利润率、客单价、人效等(根据业务场景推断2-3个)

维度(2-4个):从分类列中选取

  • 优先选择值域≤15的分类列,排除ID/编号等无意义列

漏斗链路:给出最全的漏斗转化链路

Phase 3: 参数确认

在开始分析前,快速向用户确认以下参数

  1. 核心指标 — 给出选项让用户自己选择确认
  2. 计算指标 — 给出选项让用户自己选择确认
  3. 分析维度 — 给出选项让用户自己选择确认
  4. 漏斗链路 — 给出选项让用户自己选择确认
  5. 全局筛选维度 — 从分析维度中选择尽量全面的维度作为顶部全局筛选器;这些筛选器控制整个看板的数据范围,选择"全部"时该维度不筛选
  6. 数据刷新 — 确认数据源路径(原始Excel/CSV文件的绝对路径,用于生成伴生 data.json

Phase 4: HTML生成

生成两个交付物:

  1. dashboard.html — 主看板文件,内嵌全部CSS/JS,初始数据以JS对象嵌入
  2. 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),包含各维度的下拉筛选器。左右分区:左侧为筛选器组,右侧为刷新控件组。

结构

  • 每个筛选维度一个 <select> 下拉框,选项 = ["全部"] + 该维度在 DATA.dimValues 中的所有distinct值
  • 所有筛选器横向排列,gap: 12px
  • 筛选器右侧放置"重置"按钮(点击恢复所有筛选为"全部")
  • 刷新按钮组(右对齐):手动刷新按钮 + 「恢复默认」按钮 + 刷新状态指示灯
  • 筛选器标签(维度名)前置,与下拉框同行展示

样式

  • 高度44px,背景色 = 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: 4px
  • padding: 8px 16px,字体 Calibri 11pt
  • 筛选标签:字体 Calibri 10pt,color = var(--text-secondary)margin-right: 6px
  • "重置"按钮:bg = transparent, border: 1px solid var(--accent-1), color = var(--accent-1), border-radius: 4px, cursor: pointer, hover时 bg = var(--accent-1), color = #fff
  • "刷新"按钮:与"重置"按钮同一套样式(border: 1px solid var(--accent-2), color = var(--accent-2)),hover时 bg = var(--accent-2), color = #fff;按钮内显示刷新图标文字("↻ 刷新数据"),刷新进行中时显示旋转动画 + "刷新中…"
  • 刷新状态指示灯:8px圆点,位于刷新按钮左侧。绿色(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 分隔,确保刷新控件固定在右侧

行为

  • 任何维度筛选变更 → 即时重新计算全看板数据 → 刷新所有12板块(无需Apply按钮)
  • 多维度筛选:AND逻辑(同时满足所有选定筛选条件)
  • 选择"全部" → 该维度不过滤(等效于移除该维度筛选)
  • 刷新流程:filterRawData(filters)reaggregateAll(filteredRows)refreshAllPanels(workingData)
  • reaggregateAll() 重新生成 WORKING_DATA.dailyWORKING_DATA.cityWORKING_DATA.categoryWORKING_DATA.funnel
  • refreshAllPanels() 更新所有卡片数值 + destroyAllCharts + recreateAllCharts + 刷新表格 + 重写结论文本

数据刷新机制(v4.2 更新:协议感知 + File System Access API)

看板仅支持手动刷新,initRefresh() 根据浏览器协议和能力自动选择最佳方式:

| 协议 | 浏览器 | 刷新方式 | 说明 | |---|---|---|---| | file:// | Chrome/Edge 86+ | File System Access API | showOpenFilePicker() 获取句柄存 IndexedDB,后续直接读取无需重复选择 | | file:// | Safari/Firefox | <input type="file"> | 每次需重新选择文件 | | 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

localStorage 数据持久化(v4.3 新增)

上传文件后的数据在浏览器内存中生效,但刷新页面会丢失(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();
}

13大板块

基于用户确认的核心指标、计算指标、分析维度,按照如下方式展示。所有板块均受全局筛选控制

| # | 板块 | 图表类型 | 交互方式 | 全局筛选响应 | 数据刷新响应 | |---|------|----------|----------|-------------|-------------| | 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并列展示

视觉规范

字体与尺寸

  • 全篇使用统一字体Calibri
  • 字号:
  • 图表轴标签10pt、不显示图例
  • 图表标题:11.5pt
  • 卡片内容高度32px,图表容器高度220px,宽度均100%自适应
  • 表格字号:10pt,对齐方式为靠左
  • 结论页标题:11.5pt、结论页内容:10pt
  • 删除所有背景网格线(grid display:false)
  • 图表横坐标轴的文字都横排显示,如果太拥挤就扩大两个文本之间的间隔数量

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] 取到 undefineddata.map() 崩溃 → 后续漏斗/交叉表/排名/结论全部挂掉。数据刷新后重新赋值 DATA 对象时,同样必须重新执行此过滤逻辑。

表格规范

  • 找出该行的最大值和最小值,最大值 → 🔴 红色加粗(ct-high,--accent-2),最小值 → 🟢 绿色(ct-low,--accent-2)

美化要素

  • 每个图表标题前加一个适合的小图标
  • 卡片:左侧4px色条+渐变背景+box-shadow:0 4px 15px rgba(0,0,0,0.3)
    • 每个卡片分配一个不同的颜色
    • ⚠️ 核心指标卡片与计算指标卡片样式必须完全一致(同一套CSS class,禁止两套不同样式)
    • 计算指标卡片沿用 .kpi-card 样式,仅左边框颜色和底部提示文字颜色不同
  • 图表容器:圆角8px+阴影+微渐变边框,注:卡片不要容器
  • 每个柱形图、条形图采用同一种色系,不要彩色的,柱子不要边框
  • 折线点标记:白色描边1.5px+主题色填充
  • 板块间间距20px,板块标题带图标
  • 第9大板块的漏斗转化表格:配色联动,每行左边框 + 渐变底色与漏斗图同色(蓝→绿→红→橙);且文字表格平铺满整个区域,文字靠左对其
  • 第8大板块的漏斗图:图表居中,标签只保留指标名称且放到最左侧,转化率及每步的数值去掉
  • 状态指示灯:border-radius: 50%,带 box-shadow: 0 0 6px 同色发光效果

13套配色方案(CSS变量驱动)

切换方案时更新: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基础上生成渐变色系(同色系不同透明度/亮度)。

交互逻辑

  • 左侧任何变更 → 右侧看板即时刷新(无需Apply按钮)
  • Chart实例管理:全局Map存储,切换时先chart.destroy()再new Chart()
  • 配色切换 → 更新CSS变量 + destroyAll + recreateAll
  • 勾选切换 → 对应板块显隐 + 图表destroy/recreate
  • 指标下拉切换 → 仅更新对应图表数据
  • 全局筛选变更 → filterRawData()reaggregateAll()refreshAllPanels()(⚠️ 全量刷新,不可遗漏任何板块)
  • 数据刷新(手动)→ 检测 generatedAt 变化 → 替换 DATA → 重置筛选 → refreshAllPanels()(⚠️ 全量刷新,与筛选变更相同管线)

Phase 5: ⛔ 强制自检(不可跳过,必须在对话中逐项输出结果)

⛔ 本节是硬关卡。Phase 4 完成后,必须逐项输出检查结果PASSFAIL + 原因),全部 PASS 后才能进入 Phase 6 交付。严禁跳过任何一项。 如果某项 FAIL,立即修复后重新运行全部自检。

自检输出格式:编号 + 项目 + [PASS] / [FAIL: 原因],每项一行。

功能类(⛔ 最高优先级,先查这些)

  • [ ] F1: SheetJS CDN 已加载 — HTML 中 <script src="...xlsx.full.min.js"> 存在
  • [ ] F2: 隐藏 file input 已添加<input type="file" id="hiddenFileInput" accept=".xlsx,.xls,.csv" style="display:none"> 存在
  • [ ] F3: handleRefresh() 已实现且非空壳 — 函数体内包含实际的 Excel 解析逻辑,不能DATA.raw = DATA.rawsetTimeout(()=>{},500) 这类 no-op
  • [ ] F4: FSA 分支存在typeof window.showOpenFilePicker === 'function' 检测 + showOpenFilePicker() 调用
  • [ ] F5: file input 兜底分支存在 — FSA 不可用时触发 hiddenFileInput.click()
  • [ ] F6: parseExcelFile(file) 已实现 — 使用 XLSX.read() + XLSX.utils.sheet_to_json(),中文列名→英文映射
  • [ ] F7: applyNewData(rows) 已实现 — 替换 DATA.raw → 重建 dimValues → 重建筛选下拉框 → resetFilters → refreshAll
  • [ ] F8: rebuildFilterDropdowns() 已实现 — 刷新后筛选下拉框选项随新数据更新
  • [ ] F9: loadWD() 使用过滤后的数据 — 调用 filterRaw(DATA.raw) 而非 直接 DATA.raw
  • [ ] F10: 全局筛选变更后所有13板块更新 — onFilterChange → refreshAll → 12个板块全部刷新
  • [ ] F11: 多维度筛选为 AND 逻辑 — filterRaw 中 (f.city==='all'||r.city===f.city) && (f.cat==='all'||r.category===f.cat)
  • [ ] F12: "重置"按钮生效 — 恢复所有筛选为"全部"并触发 refreshAll
  • [ ] F13: let DATA 声明(非 const DATA)— 允许刷新后重新赋值 DATA.raw
  • [ ] F14: 刷新按钮状态管理 — 刷新中 disabled,完成后恢复
  • [ ] F15: 状态指示灯三态 — 绿(空闲)/黄(刷新中, #F39C12)/红(失败, var(--accent-3))
  • [ ] F16: localStorage 持久化applyNewData() 保存 DATA 到 localStorage;init() 中优先读取 localStorage;「恢复默认」按钮存在且功能正常

视觉类(功能通过后再查)

  • [ ] V1: 所有图表无网格线
  • [ ] V2: 折线图 pointRadius≥4,白色描边
  • [ ] V3: 图表容器高度统一220px
  • [ ] V4: 配色与选定方案一致
  • [ ] V5: 渐变填充生效(非纯色块,addColorStop(1) 透明度≥50%)
  • [ ] V6: 图表标题 11.5pt,轴标签 10pt,时间轴 9pt
  • [ ] V7: 卡片样式统一(kpi-card class,仅 border-left-color 不同)
  • [ ] V8: 环比涨跌红涨绿跌(A股惯例)
  • [ ] V9: 漏斗图+漏斗表严格递减,标签左对齐
  • [ ] V10: 13套配色全部包含 tp/ts 字段(文本色)

健壮性

  • [ ] R1: DATA JSON 语法有效(用 Node.js new Function(script) 验证,禁止跳过
  • [ ] R2: 维度下拉和排名下拉不含环比类 KPI(k in DATA.city 过滤)
  • [ ] R3: 无漏斗数据时留空+提示而非崩溃
  • [ ] R4: 刷新不影响当前配色方案选择
  • [ ] R5: 刷新不影响侧边栏勾选状态
  • [ ] R6: 上传数据后刷新页面 → localStorage 恢复 → 「恢复默认」按钮显示 → 数据与上传后一致

Phase 4 执行顺序(⛔ 强制,防偷懒)

HTML 代码编写必须按以下顺序,先功能→后视觉,严禁先调渐变再补刷新:

  1. 骨架:HTML 结构(header bar + sidebar + 12 panel 容器)
  2. 数据注入:Python json.dumps → 嵌入 __DATA_JSON__ 占位符
  3. 核心功能:全局筛选(filterRaw + onFilterChange + resetFilters)+ 数据刷新(handleRefresh + parseExcelFile + applyNewData + localStorage 持久化 + restoreDefaultData + SheetJS CDN + hidden file input + 「恢复默认」按钮)
  4. 12板块渲染:卡片→折线→柱状→漏斗→排名→交叉表→结论
  5. 视觉美化:渐变参数→图表样式→卡片样式→漏斗样式→表格条件格式
  6. 配色系统:13套 THEME + applyTheme + CSS变量联动
  7. Phase 5 全量自检:31项逐条 PASS/FAIL,FAIL 必须修复后重新全检

防偷懒铁律:如果第3步(核心功能)未完成,禁止进入第5步(视觉美化)。handleRefresh() 写成空壳就去做渐变调色 = 违规。

Phase 6: 原 Phase 5 质量检查清单(详细参考)

以下为旧版完整清单,保留供详细对照,但执行时以 Phase 5 强制自检为准。

  • [ ] 所有图表无网格线
  • [ ] 折线图pointRadius≥4,有白色描边
  • [ ] 图表容器高度统一220px
  • [ ] 配色与选定方案一致(非默认蓝色)
  • [ ] 图例不与坐标轴重叠(legend position:'top')
  • [ ] 渐变填充生效(非纯色块)
  • [ ] 左侧→右侧联动正常
  • [ ] chart先destroy再recreate(无canvas复用报错)
  • [ ] 无漏斗数据时留空+提示
  • [ ] DATA JSON语法有效(用Node.js new vm.Script(script) 验证,禁止跳过)
  • [ ] 数值格式化:大数用万/亿,百分比1位小数
  • [ ] 维度下拉和排名下拉仅包含 DATA.city/DATA.category 中存在的KPI(不含环比类)
  • [ ] 全局筛选初始值均为"全部",全看板展示完整数据
  • [ ] 全局筛选变更后所有12板块数据联动更新(卡片、图表、表格、结论无一遗漏)
  • [ ] 多维度筛选为AND逻辑,选择"全部"时该维度不参与过滤
  • [ ] 筛选后图表先destroy再recreate(无canvas残留或复用报错)
  • [ ] 筛选后 DATA.raw 不受影响(每次筛选均从原始全量数据重新过滤+聚合)
  • [ ] "重置"按钮一键恢复所有筛选为"全部"并刷新全看板
  • [ ] let DATA 声明(非 const DATA),允许刷新后重新赋值
  • [ ] FSA 检测生效(Chrome/Edge:typeof showOpenFilePicker==='function',使用 handleRefreshWithFSA
  • [ ] FSA 兜底生效(Safari/Firefox:回退到传统 <input type="file"> 文件选择框)
  • [ ] API 刷新生效handleRefresh()http:// 协议,服务器运行时)
  • [ ] 文件上传刷新生效parseExcelFile(),所有浏览器,SheetJS 解析 Excel)
  • [ ] applyNewData() 正确执行:DATA 赋值 → buildFilters() → resetFilters() → 全量刷新12板块
  • [ ] 刷新按钮状态管理:刷新中 disabled,完成后恢复
  • [ ] 状态指示灯:黄色(刷新中)→ 绿色(成功)/ 红色(失败)
  • [ ] 无自动轮询(已移除 setInterval 和倒计时)
  • [ ] generatedAt 变化检测:API 刷新时比较时间戳,相同则跳过
  • [ ] 文件 Banner 显示(file:// 协议下显示,提示用户选择 Excel 文件)
  • [ ] 刷新后所有12板块数据正确更新(卡片数值、图表、表格、结论)
  • [ ] 刷新后全局筛选器重置为"全部"
  • [ ] 刷新不影响配色方案选择(当前选中的配色在刷新后保持不变)
  • [ ] 刷新不影响侧边栏勾选状态(核心指标/计算指标/维度的选中状态保持)

Phase 7: 交付

把下面两个链接都交付给我:

  • 交付本地版本的看板链接
  • 把这个链接部署成可以对外分享的新链接