数据可视化:php+echarts实现数据可视化

发布于:2025-05-07 ⋅ 阅读:(27) ⋅ 点赞:(0)

 一、实现效果

实现动态时间,多列柱状图,单列柱状图,普通表格,表格动画等效果

二、实现

1、动态时间显示

通过php获取当前时间

设置计时器来动态显示时间秒数

<!-- 时间动画 -->
<script>
    // 动态更新时间中的秒数
    function updateTime() {
        const now = new Date();
        const hours = String(now.getHours()).padStart(2, '0');
        const minutes = String(now.getMinutes()).padStart(2, '0');
        const seconds = String(now.getSeconds()).padStart(2, '0');
        const formattedTime = `${hours}:${minutes}:${seconds}`;

        // 更新时间显示
        document.getElementById('current-time').textContent = formattedTime;
    }
    // 每秒更新一次时间
    setInterval(updateTime, 1000);
    // 页面加载时立即更新时间
    updateTime();
</script>

2、非图表数据获取

第一行的标题,第二行的第一列,第二列,第三行的第三列均使用普通数据

①主页面展示框架

例如,线别的获取,写入div框架,内部的内容由ajax获取

②ajax请求

请求数据同时设置刷新时间,保证数据的及时更新

function fetchData() {
    fetch('echarts/get_base_data.php')
        .then(response => response.json())
        .then(data => {
            console.log(data);
            // 线别
            const lineTitle = document.querySelector('.line1_title');
            if (lineTitle && data.linebody && data.linebody.linebody) {
                lineTitle.textContent = data.linebody.linebody;
            }
            // 清空旧工单信息
            const wipContainer = document.querySelector('.line2_item1');
            if (wipContainer) {
                wipContainer.innerHTML = ''; // 清空之前的内容
                if (data.wip) {
                    const wipHtml = `
                        <div class="line2_1_block flex flex-between">
                            <div class="line2_1_title">工单号</div>
                            <div class="line2_1_content">${data.wip.wip_entity_name || ''}</div>
                        </div>
                        <div class="line2_1_block flex flex-between">
                            <div class="line2_1_title">机种料号</div>
                            <div class="line2_1_content">${data.wip.item_no || ''}</div>
                        </div>
                        <div class="line2_1_block flex flex-between">
                            <div class="line2_1_title">机种名称</div>
                            <div class="line2_1_content">${data.wip.item_name || ''}</div>
                        </div>
                        <div class="line2_1_block flex flex-between">
                            <div class="line2_1_title">规格型号</div>
                            <div class="line2_1_content">${data.wip.item_desc || ''}</div>
                        </div>
                        <div class="line2_1_block flex flex-between">
                            <div class="line2_1_title">在岗人数</div>
                            <div class="line2_1_content">${data.linebody.atwork_qty || ''}</div>
                        </div>
                        <div class="line2_1_block flex flex-between">
                            <div class="line2_1_title">加工面别</div>
                            <div class="line2_1_content">${data.linebody.surface || ''}</div>
                        </div>
                    `;
                    wipContainer.innerHTML = wipHtml;
                } else {
                    wipContainer.innerHTML = '<div class="no-data flex flex-center">暂未查到线别对应工单信息</div>';
                }
            }
            .....
        })
        .catch(error => console.error('Error fetching data:', error));
}
// 每隔一定时间自动刷新数据(例如每1秒刷新一次)
setInterval(fetchData, 5000);
// 页面加载后立即加载一次
document.addEventListener("DOMContentLoaded", fetchData);

③php获取基本数据

根据php去获取基本数据,并返回

<?php
header('Content-Type: application/json');
require_once '../get_db_conn.php';
$conn = db_connect();
mysqli_set_charset($conn, 'utf8');

// 查询线别信息
$sql_linebody = "SELECT * FROM linebody_board_front WHERE 1=1";
$result_linebody = mysqli_query($conn, $sql_linebody);
$linebody_data = [];

if ($result_linebody && mysqli_num_rows($result_linebody) > 0) {
    while ($row = mysqli_fetch_assoc($result_linebody)) {
        $linebody_data[] = $row;
    }
}

// 查询工单机种信息
$wip_data = [];
if (!empty($linebody_data)) {
    $linebody = $linebody_data[0]['linebody'];
    $sql_wip = "
        SELECT 
            wc.wip_entity_name AS wip_entity_name,
            wj.primary_item AS item_no,
            si.item_desc AS item_desc,
            si.item_name AS item_name
        FROM 
            wip_capacity wc
        LEFT JOIN 
            wip_jobs_all wj ON wc.wip_entity_name = wj.wip_entity_name
        LEFT JOIN 
            sf_item_no si ON wj.primary_item = si.item_no
        WHERE 
            wc.linebody = '" . mysqli_real_escape_string($conn, $linebody) . "'
        ORDER BY 
            wc.creation_date ASC
        LIMIT 1
    ";
    $result_wip = mysqli_query($conn, $sql_wip);
    if ($result_wip) {
        while ($row = mysqli_fetch_assoc($result_wip)) {
            $wip_data[] = $row;
        }
    }
}
.....

// 返回 JSON 数据
echo json_encode([
    'linebody' => !empty($linebody_data) ? $linebody_data[0] : null,
    'wip' => !empty($wip_data) ? $wip_data[0] : null,
    'line_post' => $line_post_data,
    'abnormal' => $abnormal_data
]);

?>

3、图表数据获取

①引入方法

引入使用jquery和echarts图表

引入写入linebody.js方法(封装的图表js)

②主页面写入图表的框架

③写入图表样式

根据echarts官网示例,引入echarts模板,再写入ajax去获取动态的数据,并且设置数据刷新

document.addEventListener("DOMContentLoaded", function () {
    // 全局刷新间隔时间(毫秒)
    const REFRESH_INTERVAL = 3000;
    let refreshTimer = null;

    // ============ 计划产能与实际达成 图表 ====================
    function initCapacityChart() {
        const chartDom = document.getElementById("capacity");
        if (!chartDom) {
            console.error("未找到 ID 为 capacity 的图表容器");
            return;
        }
        // 创建提示信息的 DOM 元素
        const noDataText = document.createElement('div');
        noDataText.innerText = '暂无计划产能与实际达成数据';
        noDataText.style.color = '#ffffff';
        noDataText.style.fontSize = '16px';
        noDataText.style.textAlign = 'center';
        noDataText.style.marginTop = '20px';
        noDataText.style.display = 'none';
        chartDom.parentNode.appendChild(noDataText);
        const myChart = echarts.init(chartDom);
        let autoPlayInterval = null;
        let currentIndex = -1;
        // 默认配置
        const option = {
            title: {
                text: '计划产能与实际达成',
                left: 'center',
                textStyle: { color: '#ffffff', fontSize: 16 }
            },
            tooltip: {
                trigger: 'axis',
                axisPointer: { type: 'shadow' },
                show: true,
                textStyle: { color: 'black' }
            },
            legend: {
                data: ['计划量', '实际产出'],
                bottom: '0',
                textStyle: { color: '#ffffff' }
            },
            xAxis: {
                type: 'category',
                data: [],
                axisLabel: { color: '#ffffff' },
                axisLine: { lineStyle: { color: '#ffffff' } }
            },
            yAxis: {
                type: 'value',
                name: '',
                axisLabel: { color: '#ffffff' },
                axisLine: { lineStyle: { color: '#ffffff' } }
            },
            series: [
                {
                    name: '计划量',
                    type: 'bar',
                    data: [],
                    itemStyle: { color: '#ff6d00' },
                    label: {
                        show: true,
                        position: 'top',
                        valueAnimation: true,
                        formatter: '{c}',
                        color: '#fff'
                    }
                },
                {
                    name: '实际产出',
                    type: 'bar',
                    data: [],
                    itemStyle: { color: '#00ddfd' },
                    label: {
                        show: true,
                        position: 'top',
                        valueAnimation: true,
                        formatter: '{c}',
                        color: '#fff'
                    }
                }
            ]
        };
        // 获取数据并更新图表
        function fetchData() {
            fetch("echarts/get_data.php?type=capacity")
                .then(response => response.json())
                .then(jsonData => {
                    if (!jsonData || jsonData.length === 0) {
                        chartDom.style.display = 'none';
                        noDataText.style.display = 'block';
                        return;
                    }
                    chartDom.style.display = 'block';
                    noDataText.style.display = 'none';

                    // 提取数据
                    const xAxisData = jsonData.map(item => item.time_slot);
                    const planValues = jsonData.map(item => item.plan_qty);
                    const actualValues = jsonData.map(item => item.real_qty);

                    // 更新配置项
                    option.xAxis.data = xAxisData;
                    option.series[0].data = planValues;
                    option.series[1].data = actualValues;

                    // 渲染图表
                    myChart.setOption(option);
                    // 启动自动提示
                    startAutoShowTooltip(myChart, xAxisData.length);
                })
                .catch(error => {
                    console.error("加载数据失败:", error);
                    chartDom.style.display = 'none';
                    noDataText.innerText = '加载数据失败,请检查网络或后端接口';
                    noDataText.style.display = 'block';
                });
        }
        // 初始加载数据
        fetchData();
        // 动态展示提示信息
        function startAutoShowTooltip(myChart, dataLength) {
            stopAutoShowTooltip(); // 防止重复启动
            autoPlayInterval = setInterval(() => {
                if (dataLength === 0) return;
                currentIndex = (currentIndex + 1) % dataLength;
                myChart.dispatchAction({
                    type: 'highlight',
                    dataIndex: currentIndex,
                    seriesIndex: 0
                });
                myChart.dispatchAction({
                    type: 'showTip',
                    seriesIndex: 0,
                    dataIndex: currentIndex
                });
            }, 2000);
        }
        // 停止动画
        function stopAutoShowTooltip() {
            if (autoPlayInterval) clearInterval(autoPlayInterval);
        }
        // 鼠标悬停/离开控制自动播放
        myChart.on('mouseover', () => stopAutoShowTooltip());
        myChart.on('mouseout', () => startAutoShowTooltip(myChart, option.xAxis.data.length));
        // 返回fetchData函数以便全局刷新调用
        return fetchData;
    }
    // 初始化图表并获取各自的刷新函数
    const refreshFunctions = [];
    const capacityRefresh = initCapacityChart();
    if (capacityRefresh) refreshFunctions.push(capacityRefresh);

    // 设置全局定时刷新
    function startAutoRefresh() {
        stopAutoRefresh(); // 防止重复启动
        refreshTimer = setInterval(() => {
            refreshFunctions.forEach(fn => fn());
        }, REFRESH_INTERVAL);
    }
    function stopAutoRefresh() {
        if (refreshTimer) clearInterval(refreshTimer);
    }
    // 启动自动刷新
    startAutoRefresh();
    // 当页面失去焦点时停止刷新,获得焦点时重新开始
    document.addEventListener('visibilitychange', function () {
        if (document.hidden) {
            stopAutoRefresh();
        } else {
            startAutoRefresh();
        }
    });
});

④图表数据获取

直接使用php查询需要获取的数据,并返回,使用switch case进行条件查询,满足多个图表查询数据问题

<?php
// 设置响应头为 JSON 格式
header("Content-Type: application/json");

// 引入数据库连接函数
require_once '../get_db_conn.php';
$conn = db_connect();
mysqli_set_charset($conn, 'utf8');
date_default_timezone_set('Asia/Shanghai');

// 获取请求类型参数
$type = isset($_GET['type']) ? $_GET['type'] : '';
//获取当前页面的线别
$linebody_sql = "select linebody from linebody_board_front where id = 1";
$linebody_result = mysqli_query($conn, $linebody_sql);
while ($row = mysqli_fetch_assoc($linebody_result)) {
    $linebody = $row['linebody'];
}
//查找当前的工单
$sql_wip = "
    SELECT 
        wc.wip_entity_name AS wip_entity_name
    FROM 
        wip_capacity wc
    WHERE 
        wc.linebody = '" . $linebody . "'
    ORDER BY 
        wc.creation_date ASC
    limit 1
";
$result_wip = mysqli_query($conn, $sql_wip);
if ($row = mysqli_fetch_assoc($result_wip)) {
    $wip_entity_name = $row['wip_entity_name'];
} else {
    $wip_entity_name = '';
}
// 获取今天的开始和结束时间戳(查询的是开始时间在今天内的数据)
$todayStart = strtotime(date("Y-m-d")); // 今天 00:00:00 的时间戳(不包含时区)
$todayEnd   = $todayStart + 86400;       // 明天 00:00:00 的时间戳(不包含)
switch ($type) {
    case 'capacity': // 计划产能与实际达成
        $sql = "SELECT * FROM wip_capacity WHERE linebody = '" . $linebody . "' AND startTime >= '" . $todayStart . "' AND startTime < '" . $todayEnd . "' order by startTime ASC";
        $result = mysqli_query($conn, $sql);
        $data = [];
        // echo json_encode(['sql' =>  $sql]);
        if ($result && mysqli_num_rows($result) > 0) {
            while ($row = mysqli_fetch_assoc($result)) {
                $data[] = [
                    'time_slot' => date("H", $row['startTime']) . '-' . date("H", $row['endTime']),
                    'plan_qty' => (int)$row['plan_qty'],
                    'real_qty' => (int)$row['real_qty']
                ];
            }
        }
        echo json_encode($data);
        break;
    ......       
    default:
        echo json_encode(['error' => '未知的请求类型']);
}
$conn->close();


网站公告

今日签到

点亮在社区的每一天
去签到