前途科技前途科技
  • 洞察
  • 服务
  • 关于
  • AI 资讯
    • 快讯
    • 产品
    • 技术
    • 商业
    • 政策
    • 初创
  • 洞察
  • 资源中心
    • 深度研究
      • AI 前沿
      • 案例研究
      • AI 知识库
    • 行业报告
      • 白皮书
      • 行业报告
      • 研究报告
      • 技术分享
      • 专题报告
    • 精选案例
      • 金融行业
      • 医疗行业
      • 教育行业
      • 零售行业
      • 制造行业
  • 服务
  • 关于
联系我们

使用HTML、CSS和JavaScript构建交互式数据看板:一份无框架指南

教程2025年10月4日· 5 分钟阅读5 阅读

为客户、合作伙伴或团队成员构建数据看板,已成为软件开发者、数据科学家、机器学习工程师以及数据工程师必备的关键技 […]

为客户、合作伙伴或团队成员构建数据看板,已成为软件开发者、数据科学家、机器学习工程师以及数据工程师必备的关键技能之一。即使主要从事后端数据处理,所处理的数据通常也需要在某个阶段以直观的方式呈现给用户。幸运的话,组织内可能设有专门的前端团队来处理这些工作;然而,更多时候,这项任务会落在工程师自身肩上。

如今,单纯作为一名不具备HTML、JavaScript等前端经验的Python开发者已不再是借口,因为过去几年中涌现了许多强大的Python库,例如Streamlit和Gradio,它们极大地简化了前端界面的开发。

然而,本文并非探讨这些Python库。相反,它将深入探索如何通过学习新技能,利用前端开发领域经久不衰的基石技术——HTML、JavaScript和CSS——来构建一个数据看板,特别适合那些希望拓展技能边界的Python开发者。

本数据看板的数据将来源于一个本地的SQLite数据库。为演示目的,文中创建了一个名为“sales_data”的SQLite表,其中包含了模拟的销售数据。以下是该数据的表格形式展示。

销售数据表格

下方提供了一段代码,读者可以依此自行创建SQLite数据库及表,并填充所示的示例数据,以便跟随教程进行实践。

文中仅向数据库插入少量记录,这并非代码无法处理大规模数据量。其主要目的是为了将注意力集中于数据看板的功能实现上,避免被复杂的数据处理所分散。读者可以根据下方提供的脚本,根据需要自行向输入数据集添加更多记录。

因此,在进入前端开发之前,首先将继续在Python环境中,通过编程方式设置SQLite数据库。

import sqlite3

Define the database name

DATABASE_NAME = "C:Users homaprojectsmy-dashboardsales_data.db"

Connect to SQLite database

conn = sqlite3.connect(DATABASE_NAME)

Create a cursor object

cursor = conn.cursor()

SQL to create the 'sales' table

create_table_query = '''
CREATE TABLE IF NOT EXISTS sales (
order_id INTEGER PRIMARY KEY,
order_date TEXT,
customer_id INTEGER,
customer_name TEXT,
product_id INTEGER,
product_names TEXT,
categories TEXT,
quantity INTEGER,
price REAL,
total REAL
);
'''

Execute the query to create the table

cursor.execute(create_table_query)

Sample data to insert into the 'sales' table

sample_data = [
(1, "2022-08-01", 245, "Customer_884", 201, "Smartphone", "Electronics", 3, 90.02, 270.06),
(2, "2022-02-19", 701, "Customer_1672", 205, "Printer", "Electronics", 6, 12.74, 76.44),
(3, "2017-01-01", 184, "Customer_21720", 208, "Notebook", "Stationery", 8, 48.35, 386.80),
(4, "2013-03-09", 275, "Customer_23770", 200, "Laptop", "Electronics", 3, 74.85, 224.55),
(5, "2022-04-23", 960, "Customer_23790", 210, "Cabinet", "Office", 6, 53.77, 322.62),
(6, "2019-07-10", 197, "Customer_25587", 202, "Desk", "Office", 3, 47.17, 141.51),
(7, "2014-11-12", 510, "Customer_6912", 204, "Monitor", "Electronics", 5, 22.5, 112.5),
(8, "2016-07-12", 150, "Customer_17761", 200, "Laptop", "Electronics", 9, 49.33, 443.97)
]

SQL to insert data into the 'sales' table

insert_data_query = '''
INSERT INTO sales (order_id, order_date, customer_id, customer_name, product_id, product_names, categories, quantity, price, total)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
'''

Insert the sample data

cursor.executemany(insert_data_query, sample_data)

Commit the transaction

conn.commit()

Close the connection

conn.close()

print(f"Database '{DATABASE_NAME}' has been created and populated successfully.")

数据看板功能概览

本数据看板将具备以下功能:

  • 关键指标。 总收入、总订单数、平均订单价值、最畅销类别
  • 不同图表类型。 随时间变化的收入(折线图)、按类别划分的收入(柱状图)、按收入排名的热门产品(水平柱状图)
  • 筛选。 按日期和类别进行筛选
  • 数据表。 以分页和可搜索的网格形式显示数据记录。

环境配置

接下来,将通过一系列步骤来配置开发环境。

1/ 安装 Node.js。

Node.js 是一个运行时环境,允许在浏览器外部运行 JavaScript,从而能够使用 JavaScript 构建快速且可扩展的服务器端应用程序。

因此,请确保系统已安装 Node.js,以便运行本地服务器和管理软件包。可以从Node.js 官方网站下载。

2/ 创建主项目文件夹和子文件夹

打开命令终端并运行以下命令。文中使用了Windows系统上的Ubuntu环境进行演示,但读者可以根据自己偏好的命令行工具和系统进行调整。

$ mkdir my-dashboard
$ cd my-dashboard
$ mkdir client
% mkdir server

3/ 初始化 Node 项目

$ npm init -y

此命令会自动在项目目录中创建一个默认的 package.json 文件,无需用户输入。

-y 标志表示对所有提示回答“是”,使用以下字段的默认值:

  • name
  • version
  • description
  • main
  • scripts
  • author
  • license

以下是生成的 package.json 文件示例:

{
  "name": "my-dashboard",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "express": "^4.21.2",
    "sqlite3": "^5.1.7"
  }
}

4/ 安装 Express 和 SQLite

SQLite 是一个轻量级、基于文件的关系型数据库引擎,它将所有数据存储在一个单一、便携的文件中,无需独立的服务器。

Express 是一个用于 Node.js 的极简、灵活的 Web 应用程序框架,通过路由和中间件简化了 API 和 Web 服务器的构建。

可以使用以下命令安装两者:

$ npm install express sqlite3

现在,可以开始开发代码了。本项目将需要四个代码文件:一个 index.html 文件、一个 server.js 文件、一个 client.js 文件和一个 script.js 文件。

接下来,将逐步介绍每个文件。

1) client/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
    <link rel="stylesheet" href="style.css">
    <title>Sales Performance Dashboard</title>
</head>
<body>
    <div class="container">
        <!-- Centered Heading -->
        <h1 class="text-center">Sales Performance Dashboard</h1>
    &lt;!-- Filter Section --&gt;
    &lt;div class="filters row my-4"&gt;
        &lt;div class="col-md-4"&gt;
            &lt;label for="start-date"&gt;Start Date&lt;/label&gt;
            &lt;input type="text" id="start-date" class="form-control" placeholder="Start Date"&gt;
        &lt;/div&gt;
        &lt;div class="col-md-4"&gt;
            &lt;label for="end-date"&gt;End Date&lt;/label&gt;
            &lt;input type="text" id="end-date" class="form-control" placeholder="End Date"&gt;
        &lt;/div&gt;
        &lt;div class="col-md-4"&gt;
            &lt;label for="category-filter"&gt;Category&lt;/label&gt;
            &lt;select id="category-filter" class="form-control"&gt;
                &lt;option value="all"&gt;All Categories&lt;/option&gt;
                &lt;!-- Options will be populated dynamically --&gt;
            &lt;/select&gt;
        &lt;/div&gt;
    &lt;/div&gt;

    &lt;!-- Key Metrics Section --&gt;
    &lt;h2 class="mt-5"&gt;Key Metrics&lt;/h2&gt; &lt;!-- Added heading for Key Metrics --&gt;
    &lt;div id="key-metrics" class="row text-center my-4"&gt;
        &lt;div class="col-md-3"&gt;
            &lt;h4&gt;Total Revenue&lt;/h4&gt;
            &lt;p id="total-revenue"&gt;$0&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class="col-md-3"&gt;
            &lt;h4&gt;Total Orders&lt;/h4&gt;
            &lt;p id="total-orders"&gt;0&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class="col-md-3"&gt;
            &lt;h4&gt;Average Order Value&lt;/h4&gt;
            &lt;p id="average-order-value"&gt;$0&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class="col-md-3"&gt;
            &lt;h4&gt;Top Category&lt;/h4&gt;
            &lt;p id="top-category"&gt;None&lt;/p&gt;
        &lt;/div&gt;
    &lt;/div&gt;

    &lt;!-- Chart Section --&gt;
    &lt;div class="chart-section my-4"&gt;
        &lt;label for="chart-type-selector"&gt;Select Chart:&lt;/label&gt;
        &lt;select id="chart-type-selector" class="form-control mb-3"&gt;
            &lt;option value="revenueOverTime"&gt;Revenue Over Time&lt;/option&gt;
            &lt;option value="revenueByCategory"&gt;Revenue By Category&lt;/option&gt;
            &lt;option value="topProducts"&gt;Top Products by Revenue&lt;/option&gt;
        &lt;/select&gt;
        &lt;canvas id="chart-canvas"&gt;&lt;/canvas&gt;
    &lt;/div&gt;

    &lt;!-- Raw Data Table Section --&gt;
    &lt;div id="raw-data" class="my-4"&gt;
        &lt;h3&gt;Raw Data&lt;/h3&gt;
        &lt;table id="data-table" class="table table-striped table-bordered"&gt;&lt;/table&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;!-- Required JS Libraries --&gt;
&lt;script src="https://code.jquery.com/jquery-3.5.1.min.js"&gt;&lt;/script&gt;
&lt;script src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"&gt;&lt;/script&gt;
&lt;script src="https://cdn.jsdelivr.net/npm/chart.js"&gt;&lt;/script&gt;
&lt;script src="https://cdn.jsdelivr.net/npm/flatpickr"&gt;&lt;/script&gt;
&lt;script src="script.js"&gt;&lt;/script&gt;

</body>
</html>

此 HTML 文件构建了销售业绩看板的基本视觉元素,包括用于日期和类别的交互式筛选器、显示关键销售指标的区域、用于选择图表类型的下拉菜单以及原始数据表。

它使用了 Bootstrap 进行样式设计,Flatpickr 处理日期输入,Chart.js 用于数据可视化,而 DataTables 则负责表格数据的展示。所有的交互逻辑由外部的 script.js 文件处理,该文件将在稍后进行详细介绍。

Bootstrap 是一个流行的前端框架,最初由 Twitter 开发,可帮助开发者更轻松、快速地构建响应式且视觉一致的网页界面。

DataTables 是一个基于 jQuery 的插件,它增强了标准的 HTML <table> 元素,将其转换为功能丰富、完全交互式的表格。

Flatpickr 是一个轻量级、可定制的 JavaScript 日期和时间选择器。它允许用户从简洁的弹出日历中选择日期(以及可选的时间),而无需手动输入。

Chart.js 是一个简单而强大的 JavaScript 库,用于在 Web 应用程序中利用 <canvas> 元素创建交互式、动画化的图表。

2) client/style.css

/* client/style.css */
body {
    background-color: #f8f9fa;
    font-family: 'Arial', sans-serif;
}

h1 {
text-align: center; /* Center the heading /
margin-top: 20px; /
Add spacing above the heading /
margin-bottom: 40px; /
Add spacing below the heading */
}

.container .filters {
margin-top: 20px;
margin-bottom: 60px !important; /* Ensure larger spacing between filters and Key Metrics */
}

.container #key-metrics {
margin-top: 40px !important; /* Additional spacing above the Key Metrics section /
margin-bottom: 20px; /
Optional spacing below */
}

.key-metrics div {
margin: 10px 0;
padding: 10px;
background-color: #f4f4f4;
border: 1px solid #ccc;
border-radius: 4px;
}

/* Fix for DataTables Pagination Spacing */
.dataTables_wrapper .dataTables_paginate {
text-align: center;
margin-top: 10px;
}

.dataTables_wrapper .dataTables_paginate .paginate_button {
margin: 0 12px;
padding: 5px 10px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #f9f9f9;
color: #007bff;
text-decoration: none;
display: inline-block;
}

.dataTables_wrapper .dataTables_paginate .paginate_button:hover {
background-color: #007bff;
color: #fff;
border: 1px solid #007bff;
}

.dataTables_wrapper .dataTables_paginate .paginate_button.current {
font-weight: bold;
color: #fff;
background-color: #007bff;
border-color: #007bff;
}

本项目的级联样式表 (CSS) 文件用于定义看板的基本视觉组件样式,例如按钮和文本颜色、元素间距等。

style.css 文件赋予了看板整体的外观和风格,呈现出简洁、明亮的主题,并进行了充足的间距和布局调整,以确保清晰度和可读性。此外,style.css 文件还自定义了 DataTables 分页按钮的外观,使其更具用户友好性,并与 Bootstrap 的设计风格保持一致。

3) server/server.js

const express = require('express');
const sqlite3 = require('sqlite3').verbose();
const path = require('path');
const app = express();
const PORT = 3000;

// Full path to your SQLite database
const DB_PATH = "C:Users homaprojectsmy-dashboardsales_data.db";

// Serve static files from the client directory
app.use(express.static(path.join(__dirname, '..', 'client')));

// Route to fetch data from SQLite database
app.get('/data', (req, res) => {
const db = new sqlite3.Database(DB_PATH, sqlite3.OPEN_READONLY, (err) => {
if (err) {
console.error("Error connecting to database:", err.message);
res.status(500).json({ error: "Database connection failed" });
return;
}
});

// Query the database
const query = "SELECT * FROM sales;"; // Replace 'sales' with your table name
db.all(query, [], (err, rows) =&gt; {
    if (err) {
        console.error("Error running query:", err.message);
        res.status(500).json({ error: "Query failed" });
    } else {
        res.json(rows); // Send the query result as JSON
    }
});

db.close((err) =&gt; {
    if (err) {
        console.error("Error closing database:", err.message);
    }
});

});

// Catch-all route to serve the main HTML file
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '..', 'client', 'index.html'));
});

// Start the server
app.listen(PORT, () => {
console.log(Server running at http://localhost:${PORT});
});

这个 Node.js 脚本包含了设置支持销售业绩看板的基本 Express 服务器的 JavaScript 代码。它主要执行两项任务:

  1. 从客户端(client)子文件夹提供静态文件(如 HTML、CSS 和 JS),以便前端在浏览器中加载。
  2. 提供一个 /data API 接口,该接口从本地 SQLite 数据库 (sales_data.db) 读取数据,并以 JSON 格式返回整个销售表,从而在前端实现动态数据可视化和表格展示。

4) client/script.js

let chartInstance = null; // Global variable to store the current Chart.js instance

// Wait until the DOM is fully loaded
document.addEventListener('DOMContentLoaded', function () {
// Fetch sales data from the backend API
fetch('/data')
.then((response) => response.json())
.then((data) => {
// Handle case where no data is returned
if (!data || data.length === 0) {
const app = document.getElementById('app');
if (app) {
app.innerHTML = "<p>No data available.</p>";
}
return;
}

        // Initialize filters and dashboard content
        setupFilters(data);
        initializeDashboard(data);

        // Re-render charts when chart type changes
        document.getElementById('chart-type-selector').onchange = () =&gt; filterAndRenderData(data);
    })
    .catch((error) =&gt; {
        // Handle fetch error
        console.error('Error fetching data:', error);
        const app = document.getElementById('app');
        if (app) {
            app.innerHTML = "&lt;p&gt;Failed to fetch data.&lt;/p&gt;";
        }
    });

});

// Initialize Flatpickr date pickers and category filter
function setupFilters(data) {
// Convert date strings to JS Date objects
const dates = data.map((item) => new Date(item.order_date.split('/').reverse().join('-')));
const minDate = new Date(Math.min(...dates));
const maxDate = new Date(Math.max(...dates));

// Configure start date picker
flatpickr("#start-date", {
    defaultDate: minDate.toISOString().slice(0, 10),
    dateFormat: "Y-m-d",
    altInput: true,
    altFormat: "F j, Y",
    onChange: function () {
        filterAndRenderData(data);
    },
});

// Configure end date picker
flatpickr("#end-date", {
    defaultDate: maxDate.toISOString().slice(0, 10),
    dateFormat: "Y-m-d",
    altInput: true,
    altFormat: "F j, Y",
    onChange: function () {
        filterAndRenderData(data);
    },
});

// Set up category dropdown change listener
const categoryFilter = document.getElementById('category-filter');
if (categoryFilter) {
    categoryFilter.onchange = () =&gt; filterAndRenderData(data);
}

}

// Initialize dashboard after filters are set
function initializeDashboard(data) {
populateCategoryFilter(data); // Populate category dropdown
filterAndRenderData(data); // Initial render with all data
}

// Apply filters and update key metrics, chart, and table
function filterAndRenderData(data) {
const chartType = document.getElementById('chart-type-selector').value;
const startDate = document.getElementById('start-date')._flatpickr.selectedDates[0];
const endDate = document.getElementById('end-date')._flatpickr.selectedDates[0];
const selectedCategory = document.getElementById('category-filter').value;

// Filter data by date and category
const filteredData = data.filter((item) =&gt; {
    const itemDate = new Date(item.order_date.split('/').reverse().join('-'));
    return (
        itemDate &gt;= startDate &amp;&amp;
        itemDate &lt;= endDate &amp;&amp;
        (selectedCategory === 'all' || item.categories === selectedCategory)
    );
});

updateKeyMetrics(filteredData);                   // Update metrics like revenue and orders
drawChart(filteredData, 'chart-canvas', chartType); // Render chart
populateDataTable(filteredData);                  // Update table

}

// Update dashboard metrics (total revenue, order count, etc.)
function updateKeyMetrics(data) {
const totalRevenue = data.reduce((acc, item) => acc + parseFloat(item.total), 0);
const totalOrders = data.length;
const averageOrderValue = totalOrders > 0 ? totalRevenue / totalOrders : 0;

// Calculate total revenue per category to find top category
const revenueByCategory = data.reduce((acc, item) =&gt; {
    const category = item.categories || "Uncategorized";
    acc[category] = (acc[category] || 0) + parseFloat(item.total);
    return acc;
}, {});

// Determine category with highest total revenue
const topCategory = Object.keys(revenueByCategory).reduce(
    (a, b) =&gt; (revenueByCategory[a] &gt; revenueByCategory[b] ? a : b),
    "None"
);

// Display metrics in the DOM
document.getElementById('total-revenue').textContent = `$${totalRevenue.toFixed(2)}`;
document.getElementById('total-orders').textContent = `${totalOrders}`;
document.getElementById('average-order-value').textContent = `$${averageOrderValue.toFixed(2)}`;
document.getElementById('top-category').textContent = topCategory || 'None';

}

// Draw the selected chart type using Chart.js
function drawChart(data, elementId, chartType) {
const ctx = document.getElementById(elementId).getContext('2d');

// Destroy previous chart if one exists
if (chartInstance) {
    chartInstance.destroy();
}

switch (chartType) {
    case 'revenueOverTime':
        // Line chart showing revenue by order date
        chartInstance = new Chart(ctx, {
            type: 'line',
            data: {
                labels: data.map((item) =&gt; item.order_date),
                datasets: [{
                    label: 'Revenue Over Time',
                    data: data.map((item) =&gt; parseFloat(item.total)),
                    fill: false,
                    borderColor: 'rgb(75, 192, 192)',
                    tension: 0.1,
                }],
            },
            options: {
                scales: {
                    y: { beginAtZero: true },
                },
            },
        });
        break;

    case 'revenueByCategory':
        // Bar chart showing total revenue per category
        const categories = [...new Set(data.map((item) =&gt; item.categories))];
        const revenueByCategory = categories.map((category) =&gt; {
            return {
                category,
                revenue: data
                    .filter((item) =&gt; item.categories === category)
                    .reduce((acc, item) =&gt; acc + parseFloat(item.total), 0),
            };
        });
        chartInstance = new Chart(ctx, {
            type: 'bar',
            data: {
                labels: revenueByCategory.map((item) =&gt; item.category),
                datasets: [{
                    label: 'Revenue by Category',
                    data: revenueByCategory.map((item) =&gt; item.revenue),
                    backgroundColor: 'rgba(255, 99, 132, 0.2)',
                    borderColor: 'rgba(255, 99, 132, 1)',
                    borderWidth: 1,
                }],
            },
            options: {
                scales: {
                    y: { beginAtZero: true },
                },
            },
        });
        break;

    case 'topProducts':
        // Horizontal bar chart showing top 10 products by revenue
        const productRevenue = data.reduce((acc, item) =&gt; {
            const productName = item.product_names || 'Unknown Product';
            acc[productName] = (acc[productName] || 0) + parseFloat(item.total);
            return acc;
        }, {});

        const topProducts = Object.entries(productRevenue)
            .sort((a, b) =&gt; b[1] - a[1])
            .slice(0, 10);

        chartInstance = new Chart(ctx, {
            type: 'bar',
            data: {
                labels: topProducts.map((item) =&gt; item[0]), // Product names
                datasets: [{
                    label: 'Top Products by Revenue',
                    data: topProducts.map((item) =&gt; item[1]), // Revenue
                    backgroundColor: 'rgba(54, 162, 235, 0.8)',
                    borderColor: 'rgba(54, 162, 235, 1)',
                    borderWidth: 1,
                }],
            },
            options: {
                indexAxis: 'y', // Horizontal bars
                scales: {
                    x: { beginAtZero: true },
                },
            },
        });
        break;
}

}

// Display filtered data in a DataTable
function populateDataTable(data) {
const tableElement = $('#data-table');

// Destroy existing table if it exists
if ($.fn.DataTable.isDataTable(tableElement)) {
    tableElement.DataTable().clear().destroy();
}

// Create a new DataTable with relevant columns
tableElement.DataTable({
    data: data.map((item) =&gt; [
        item.order_id,
        item.order_date,
        item.customer_id,
        item.product_names,
        item.categories,
        `$${parseFloat(item.total).toFixed(2)}`,
    ]),
    columns: [
        { title: "Order ID" },
        { title: "Order Date" },
        { title: "Customer ID" },
        { title: "Product" },
        { title: "Category" },
        { title: "Total" },
    ],
});

}

// Populate the category filter dropdown with available categories
function populateCategoryFilter(data) {
const categoryFilter = document.getElementById('category-filter');
categoryFilter.innerHTML = '';
categoryFilter.appendChild(new Option('All Categories', 'all', true, true));

// Extract unique categories
const categories = new Set(data.map((item) =&gt; item.categories));
categories.forEach((category) =&gt; {
    categoryFilter.appendChild(new Option(category, category));
});

}

这是本项目中最复杂的代码文件,但它承担了大量关键任务。该 JavaScript 文件驱动着销售业绩看板的交互性和数据可视化功能。简而言之,它负责:

1/ 获取销售数据

  • 页面加载时(DOMContentLoaded 事件),它会调用后端 API 的 /data 接口。
  • 如果未返回数据,则显示“无可用数据”的消息。

2/ 设置筛选器

  • 使用 Flatpickr 日期选择器,根据数据集的最小/最大订单日期选择开始和结束日期。
  • 添加一个类别下拉菜单,允许用户按产品类别进行筛选。
  • 添加一个图表类型选择器,用于在不同的图表可视化之间切换。

3/ 初始化看板

  • 用可用的类别填充类别筛选器。
  • 使用完整数据集进行首次渲染。

4/ 应用筛选并重新渲染

  • 每次用户更改筛选条件(日期范围、类别或图表类型)时,它会:
    • 根据日期范围和类别筛选数据集。
    • 更新关键指标:总收入、订单数量、平均订单价值和最高收入类别。
    • 重新绘制所选的 Chart.js 图表。
    • 刷新数据表。

5/ 使用 Chart.js 绘制图表

  • 按时间线划分的收入 (Revenue Over Time) → 折线图,显示按日期划分的收入趋势。
  • 按类别划分的收入 (Revenue by Category) → 柱状图,汇总每个类别的总收入。
  • 热门产品 (Top Products) → 水平柱状图,显示按收入排名的前 10 种产品。

6/ 显示表格数据

  • 使用 DataTables (一个 jQuery 插件) 渲染过滤后的订单表格,包含订单ID、日期、客户ID、产品、类别和总金额等列。

7/ 保持用户界面同步

  • 当筛选条件改变时,销毁并重新创建图表/表格,以避免重复。
  • 保持指标、图表和表格与当前激活的筛选条件一致。

运行数据看板

现在,所有代码已准备就绪,是时候运行数据看板了。请进入 server 子文件夹并输入以下命令:

$ node server.js

执行上述命令后,将会收到类似如下的响应:

Server running at http://localhost:3000

在 Web 浏览器中打开 http://localhost:3000。应该能看到数据看板已通过 SQLite 数据库中的数据填充,如下图所示。

运行中的销售业绩看板

所有筛选器、图表选择等功能都应如预期般正常运行。

总结

本文详细介绍了如何使用核心 Web 技术——HTML、CSS、JavaScript、Node.js、Express 和本地 SQLite 数据库——来构建一个功能齐全、交互式的销售业绩看板。

文中探讨了技术栈和环境设置,具体包括:

  • 后端:Node.js、Express、SQLite
  • 前端:HTML、Bootstrap(用于布局)、Chart.js(用于图表)、Flatpickr(日期选择器)、DataTables(用于表格数据)
  • 项目文件夹结构如下所示:
my-dashboard/
├── client/
│   ├── index.html
│   ├── style.css
│   └── script.js
└── server/
    └── server.js

文章展示了如何通过代码创建和填充一个 SQLite 数据库,作为数据看板的数据源。同时,也讨论了环境设置以及前端和后端开发过程,并简要介绍了数据看板的功能。

最后,详细解释了所需的四个代码文件,并演示了如何在浏览器中运行此数据看板。

想了解 AI 如何助力您的企业?

免费获取企业 AI 成熟度诊断报告,发现转型机会

//

24小时热榜

阿联酋联手Colossal打造基因“诺亚方舟”
TOP1

阿联酋联手Colossal打造基因“诺亚方舟”

微软推出AI内容授权市场,为出版商与开发者搭建桥梁
TOP2

微软推出AI内容授权市场,为出版商与开发者搭建桥梁

3

欧盟发布AI法案高风险系统关键指南

13小时前
欧盟发布AI法案高风险系统关键指南
4

OpenAI 从 Anthropic 挖角安全专家,年薪超 55 万美元

16小时前
OpenAI 从 Anthropic 挖角安全专家,年薪超 55 万美元
5

亚马逊中东数据中心遭无人机袭击,云服务大规模中断

13小时前
亚马逊中东数据中心遭无人机袭击,云服务大规模中断
6

350家中国企业携机器人与AI技术亮相MWC 2026

13小时前
350家中国企业携机器人与AI技术亮相MWC 2026
7

伊朗黑客瞄准美国关键基础设施,网络战升级

15小时前
伊朗黑客瞄准美国关键基础设施,网络战升级
8

Cursor 收入三个月翻倍至 200 亿美元,成最快增长软件公司

17小时前
Cursor 收入三个月翻倍至 200 亿美元,成最快增长软件公司
热门标签
大模型AgentRAG微调私有化部署Prompt EngineeringChatGPTClaudeDeepSeek智能客服知识管理内容生成代码辅助数据分析金融零售制造医疗教育AI 战略数字化转型ROI 分析OpenAIAnthropicGoogle

关注公众号

前途科技微信公众号

扫码关注,获取最新 AI 资讯

免费获取 AI 落地指南

3 步完成企业诊断,获取专属转型建议

已有 200+ 企业完成诊断

前途科技前途科技
服务关于快讯技术商业报告
前途科技微信公众号

微信公众号

扫码关注

Copyright © 2026 AccessPath.com, 前途国际科技咨询(北京)有限公司,版权所有。|京ICP备17045010号-1|京公网安备 11010502033860号|隐私政策|服务条款