1
zhang
5 天以前 e5e76412f1a20e8aed95614cbd7bf2b638cda2cc
1
1个文件已删除
4个文件已修改
6个文件已添加
1181 ■■■■■ 已修改文件
zy-acs-cv/src/main/webapp/views/pipeline.html 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-hex/dashboard.html 392 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-hex/pom.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-hex/src/main/java/com/zy/acs/hex/HexApplication.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-hex/src/main/java/com/zy/acs/hex/config/WebMvcConfig.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-hex/src/main/java/com/zy/acs/hex/controller/DeviceLogController.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-hex/src/main/java/com/zy/acs/hex/controller/RouterController.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-hex/src/main/resources/application.yml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-hex/src/main/webapp/views/dashboard.html 354 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-hex/src/main/webapp/views/index.html 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-hex/src/main/webapp/views/login.html 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-cv/src/main/webapp/views/pipeline.html
@@ -841,6 +841,7 @@
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-primary" id="save">保存</button>
                    <button type="button" class="btn btn-secondary" id="clear">清除</button>
                    <button type="button" class="btn btn-secondary" id="cancel">取消</button>
                </div>
            </div>
@@ -1090,6 +1091,12 @@
            });
        });
        // 清除任务号和目标站点
        $(document).on('click', '#clear', function () {
            $('#workNo').val(0);
            $('#staNo').val(0);
        });
        // 取消站点信息修改
        $(document).on('click', '#cancel', function () {
            closeModal();
zy-acs-hex/dashboard.html
New file
@@ -0,0 +1,392 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>机器人数据监控</title>
    <!-- 引入 layui-vue 样式 -->
    <link href="https://cdn.jsdelivr.net/npm/layui-vue@2.1.0/dist/index.css" rel="stylesheet">
    <!-- 引入 Vue 3 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@3.3.4/dist/vue.global.min.js"></script>
    <!-- 引入 layui-vue -->
    <script src="https://cdn.jsdelivr.net/npm/layui-vue@2.1.0/dist/index.js"></script>
    <!-- 引入 Chart.js -->
    <script src="/static/js/chart.umd.min.js"></script>
    <!-- 引入 Font Awesome -->
    <link href="/static/css/font-awesome.min.css" rel="stylesheet">
    <style>
        body {
            font-family: 'Inter', sans-serif;
            background-color: #f5f7fa;
        }
        .layui-card {
            margin-bottom: 16px;
        }
        .layui-card-header {
            font-weight: 600;
        }
        .status-online {
            color: #10b981;
        }
        .status-offline {
            color: #ef4444;
        }
        .chart-container {
            height: 300px;
        }
        .realtime-container {
            height: 160px;
            overflow-y: auto;
        }
    </style>
</head>
<body>
    <div id="app">
        <!-- 顶部导航栏 -->
        <lay-header height="60px" bg-color="#fff" shadow>
            <template #left>
                <div class="flex items-center space-x-2">
                    <i class="fa fa-android text-2xl" style="color: #3b82f6"></i>
                    <h1 class="text-xl font-bold" style="color: #1e293b">机器人数据监控</h1>
                </div>
            </template>
            <template #right>
                <div class="flex items-center space-x-4">
                    <lay-input placeholder="搜索机器人..." prefix-icon="search" style="width: 200px"></lay-input>
                    <lay-button type="primary" @click="refreshData">
                        <i class="fa fa-refresh mr-1"></i> 刷新
                    </lay-button>
                </div>
            </template>
        </lay-header>
        <!-- 主内容区 -->
        <lay-container style="padding: 20px">
            <!-- 状态概览 -->
            <lay-row :gutter="16">
                <lay-col :span="6">
                    <lay-card shadow>
                        <div class="flex items-center justify-between">
                            <div>
                                <p style="color: #64748b; font-size: 14px">总机器人数</p>
                                <h3 style="font-size: 24px; font-weight: bold; color: #1e293b">24</h3>
                            </div>
                            <div style="width: 48px; height: 48px; border-radius: 50%; background-color: #dbeafe; display: flex; align-items: center; justify-content: center">
                                <i class="fa fa-microchip text-xl" style="color: #3b82f6"></i>
                            </div>
                        </div>
                    </lay-card>
                </lay-col>
                <lay-col :span="6">
                    <lay-card shadow>
                        <div class="flex items-center justify-between">
                            <div>
                                <p style="color: #64748b; font-size: 14px">在线机器人</p>
                                <h3 style="font-size: 24px; font-weight: bold; color: #10b981">18</h3>
                            </div>
                            <div style="width: 48px; height: 48px; border-radius: 50%; background-color: #d1fae5; display: flex; align-items: center; justify-content: center">
                                <i class="fa fa-check-circle text-xl" style="color: #10b981"></i>
                            </div>
                        </div>
                    </lay-card>
                </lay-col>
                <lay-col :span="6">
                    <lay-card shadow>
                        <div class="flex items-center justify-between">
                            <div>
                                <p style="color: #64748b; font-size: 14px">离线机器人</p>
                                <h3 style="font-size: 24px; font-weight: bold; color: #ef4444">6</h3>
                            </div>
                            <div style="width: 48px; height: 48px; border-radius: 50%; background-color: #fee2e2; display: flex; align-items: center; justify-content: center">
                                <i class="fa fa-exclamation-circle text-xl" style="color: #ef4444"></i>
                            </div>
                        </div>
                    </lay-card>
                </lay-col>
                <lay-col :span="6">
                    <lay-card shadow>
                        <div class="flex items-center justify-between">
                            <div>
                                <p style="color: #64748b; font-size: 14px">今日数据量</p>
                                <h3 style="font-size: 24px; font-weight: bold; color: #f59e0b">1.2k</h3>
                            </div>
                            <div style="width: 48px; height: 48px; border-radius: 50%; background-color: #fef3c7; display: flex; align-items: center; justify-content: center">
                                <i class="fa fa-database text-xl" style="color: #f59e0b"></i>
                            </div>
                        </div>
                    </lay-card>
                </lay-col>
            </lay-row>
            <!-- 数据图表 -->
            <lay-row :gutter="16" style="margin-top: 16px">
                <lay-col :span="12">
                    <lay-card shadow>
                        <template #header>
                            <div class="flex justify-between items-center">
                                <h2 style="font-size: 16px; font-weight: 600; color: #1e293b">上行数据趋势</h2>
                                <div class="flex space-x-2">
                                    <lay-button size="sm" type="primary">小时</lay-button>
                                    <lay-button size="sm">天</lay-button>
                                    <lay-button size="sm">周</lay-button>
                                </div>
                            </div>
                        </template>
                        <div class="chart-container">
                            <canvas ref="upDataChart"></canvas>
                        </div>
                    </lay-card>
                </lay-col>
                <lay-col :span="12">
                    <lay-card shadow>
                        <template #header>
                            <div class="flex justify-between items-center">
                                <h2 style="font-size: 16px; font-weight: 600; color: #1e293b">下行数据趋势</h2>
                                <div class="flex space-x-2">
                                    <lay-button size="sm" type="primary">小时</lay-button>
                                    <lay-button size="sm">天</lay-button>
                                    <lay-button size="sm">周</lay-button>
                                </div>
                            </div>
                        </template>
                        <div class="chart-container">
                            <canvas ref="downDataChart"></canvas>
                        </div>
                    </lay-card>
                </lay-col>
            </lay-row>
            <!-- 设备数据表格 -->
            <lay-card shadow style="margin-top: 16px">
                <template #header>
                    <div class="flex justify-between items-center">
                        <h2 style="font-size: 16px; font-weight: 600; color: #1e293b">机器人数据列表</h2>
                        <div class="flex space-x-2">
                            <lay-button size="sm">
                                <i class="fa fa-filter mr-1"></i> 筛选
                            </lay-button>
                            <lay-button size="sm">
                                <i class="fa fa-download mr-1"></i> 导出
                            </lay-button>
                        </div>
                    </div>
                </template>
                <lay-table :data="devices" :height="400">
                    <lay-table-column prop="id" label="设备ID" width="120"></lay-table-column>
                    <lay-table-column prop="name" label="设备名称" width="150"></lay-table-column>
                    <lay-table-column prop="status" label="状态" width="100">
                        <template #default="{ row }">
                            <lay-badge v-if="row.status === 'online'" type="success">在线</lay-badge>
                            <lay-badge v-else type="danger">离线</lay-badge>
                        </template>
                    </lay-table-column>
                    <lay-table-column prop="upData" label="上行数据" width="120"></lay-table-column>
                    <lay-table-column prop="downData" label="下行数据" width="120"></lay-table-column>
                    <lay-table-column prop="lastComm" label="最后通信" width="150"></lay-table-column>
                    <lay-table-column label="操作" width="150">
                        <template #default="{ row }">
                            <lay-button size="sm" type="primary" style="margin-right: 8px">
                                <i class="fa fa-eye"></i>
                            </lay-button>
                            <lay-button size="sm" type="warning" style="margin-right: 8px">
                                <i class="fa fa-edit"></i>
                            </lay-button>
                            <lay-button size="sm" type="danger">
                                <i class="fa fa-trash"></i>
                            </lay-button>
                        </template>
                    </lay-table-column>
                </lay-table>
                <div class="flex justify-between items-center mt-4">
                    <p style="color: #64748b; font-size: 14px">显示 1-10 条,共 24 条</p>
                    <lay-pagination
                        v-model:current="currentPage"
                        v-model:limit="pageSize"
                        :total="total"
                        :limits="[10, 20, 50, 100]"
                        layout="prev, pager, next, jumper, sizes, total"
                    ></lay-pagination>
                </div>
            </lay-card>
            <!-- 实时数据更新 -->
            <lay-card shadow style="margin-top: 16px">
                <template #header>
                    <h2 style="font-size: 16px; font-weight: 600; color: #1e293b">实时数据更新</h2>
                </template>
                <div class="realtime-container p-2 border border-gray-200 rounded-lg">
                    <div v-for="(item, index) in realtimeData" :key="index" class="py-1 border-b border-gray-100">
                        <span style="color: #64748b; font-size: 12px">{{ item.timestamp }}</span>
                        <span style="color: #1e293b; margin-left: 10px">{{ item.message }}</span>
                    </div>
                </div>
            </lay-card>
        </lay-container>
        <!-- 页脚 -->
        <lay-footer height="60px" bg-color="#fff" shadow>
            <div class="text-center" style="color: #64748b; font-size: 14px">
                © 2026 机器人数据监控系统 | 版本 1.0.0
            </div>
        </lay-footer>
    </div>
    <script>
        const { createApp, ref, onMounted } = Vue;
        const app = createApp({
            components: {
                LayHeader: layui.LayHeader,
                LayContainer: layui.LayContainer,
                LayRow: layui.LayRow,
                LayCol: layui.LayCol,
                LayCard: layui.LayCard,
                LayInput: layui.LayInput,
                LayButton: layui.LayButton,
                LayTable: layui.LayTable,
                LayTableColumn: layui.LayTableColumn,
                LayBadge: layui.LayBadge,
                LayPagination: layui.LayPagination,
                LayFooter: layui.LayFooter
            },
            setup() {
                // 模拟机器人数据
                const devices = ref([
                    { id: 'ROB-001', name: '配送机器人1号', status: 'online', upData: '2.4KB', downData: '0.8KB', lastComm: '2分钟前' },
                    { id: 'ROB-002', name: '配送机器人2号', status: 'online', upData: '1.8KB', downData: '0.5KB', lastComm: '5分钟前' },
                    { id: 'ROB-003', name: '巡检机器人1号', status: 'offline', upData: '0KB', downData: '0KB', lastComm: '2小时前' },
                    { id: 'ROB-004', name: '配送机器人3号', status: 'online', upData: '3.2KB', downData: '1.2KB', lastComm: '1分钟前' },
                    { id: 'ROB-005', name: '巡检机器人2号', status: 'online', upData: '1.5KB', downData: '0.6KB', lastComm: '3分钟前' },
                    { id: 'ROB-006', name: '配送机器人4号', status: 'offline', upData: '0KB', downData: '0KB', lastComm: '5小时前' },
                    { id: 'ROB-007', name: '巡检机器人3号', status: 'online', upData: '2.1KB', downData: '0.9KB', lastComm: '4分钟前' },
                    { id: 'ROB-008', name: '配送机器人5号', status: 'online', upData: '2.8KB', downData: '1.1KB', lastComm: '2分钟前' },
                    { id: 'ROB-009', name: '巡检机器人4号', status: 'offline', upData: '0KB', downData: '0KB', lastComm: '1天前' },
                    { id: 'ROB-010', name: '配送机器人6号', status: 'online', upData: '1.9KB', downData: '0.7KB', lastComm: '6分钟前' }
                ]);
                // 分页数据
                const currentPage = ref(1);
                const pageSize = ref(10);
                const total = ref(24);
                // 实时数据
                const realtimeData = ref([]);
                // 图表引用
                const upDataChart = ref(null);
                const downDataChart = ref(null);
                // 刷新数据
                const refreshData = () => {
                    console.log('刷新数据');
                    // 这里可以添加实际的刷新逻辑
                };
                // 初始化图表
                const initCharts = () => {
                    // 上行数据图表
                    const upCtx = upDataChart.value.getContext('2d');
                    new Chart(upCtx, {
                        type: 'line',
                        data: {
                            labels: ['00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00'],
                            datasets: [{
                                label: '上行数据 (KB)',
                                data: [12, 19, 15, 25, 22, 30, 28, 35],
                                borderColor: '#3b82f6',
                                backgroundColor: 'rgba(59, 130, 246, 0.1)',
                                tension: 0.4,
                                fill: true
                            }]
                        },
                        options: {
                            responsive: true,
                            maintainAspectRatio: false,
                            plugins: {
                                legend: {
                                    display: false
                                }
                            },
                            scales: {
                                y: {
                                    beginAtZero: true
                                }
                            }
                        }
                    });
                    // 下行数据图表
                    const downCtx = downDataChart.value.getContext('2d');
                    new Chart(downCtx, {
                        type: 'line',
                        data: {
                            labels: ['00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00'],
                            datasets: [{
                                label: '下行数据 (KB)',
                                data: [5, 8, 6, 12, 10, 15, 13, 18],
                                borderColor: '#10b981',
                                backgroundColor: 'rgba(16, 185, 129, 0.1)',
                                tension: 0.4,
                                fill: true
                            }]
                        },
                        options: {
                            responsive: true,
                            maintainAspectRatio: false,
                            plugins: {
                                legend: {
                                    display: false
                                }
                            },
                            scales: {
                                y: {
                                    beginAtZero: true
                                }
                            }
                        }
                    });
                };
                // 模拟实时数据更新
                const simulateRealtimeData = () => {
                    const messages = [
                        'ROB-001 配送机器人1号: 运行中,位置: A1区',
                        'ROB-002 配送机器人2号: 待机中,位置: B2区',
                        'ROB-004 配送机器人3号: 充电中,电量: 85%',
                        'ROB-005 巡检机器人2号: 巡检中,已完成3/5任务',
                        'ROB-007 巡检机器人3号: 待机中,位置: C3区',
                        'ROB-008 配送机器人5号: 运行中,位置: D4区'
                    ];
                    setInterval(() => {
                        const message = messages[Math.floor(Math.random() * messages.length)];
                        const timestamp = new Date().toLocaleTimeString();
                        realtimeData.value.unshift({ timestamp, message });
                        // 限制显示条数
                        if (realtimeData.value.length > 20) {
                            realtimeData.value.pop();
                        }
                    }, 2000);
                };
                // 页面加载完成后初始化
                onMounted(() => {
                    initCharts();
                    simulateRealtimeData();
                });
                return {
                    devices,
                    currentPage,
                    pageSize,
                    total,
                    realtimeData,
                    upDataChart,
                    downDataChart,
                    refreshData
                };
            }
        });
        app.mount('#app');
    </script>
</body>
</html>
zy-acs-hex/pom.xml
@@ -10,6 +10,8 @@
    </parent>
    <artifactId>zy-acs-hex</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
zy-acs-hex/src/main/java/com/zy/acs/hex/HexApplication.java
@@ -3,16 +3,19 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling
@ComponentScan(basePackages = {"com.zy.component", "com.zy.acs"})
@SpringBootApplication
public class HexApplication {
public class HexApplication extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(HexApplication.class, args);
    }
}
zy-acs-hex/src/main/java/com/zy/acs/hex/config/WebMvcConfig.java
New file
@@ -0,0 +1,69 @@
package com.zy.acs.hex.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * WebMvc配置, 拦截器、资源映射等都在此配置
 *
 * @author vincent
 * @since 2019-06-12 10:11:16
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    /**
     * token通过header传递的名称
     */
    public static final String TOKEN_HEADER_NAME = "Authorization";
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getAsyncHandlerInterceptor())
                .addPathPatterns("/**")
        ;
    }
    @Bean
    public AsyncHandlerInterceptor getAsyncHandlerInterceptor() {
        return new AsyncHandlerInterceptor(){
            @Override
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
               cors(response);
                return true;
            }
        };
    }
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 配置静态资源处理器
        registry.addResourceHandler("/static/**")
                .addResourceLocations("/static/");
        // 配置视图文件处理器
        registry.addResourceHandler("/views/**")
                .addResourceLocations("/views/");
    }
    public static void cors(HttpServletResponse response){
        // 跨域设置
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Expose-Headers", TOKEN_HEADER_NAME);
    }
}
zy-acs-hex/src/main/java/com/zy/acs/hex/controller/DeviceLogController.java
New file
@@ -0,0 +1,37 @@
package com.zy.acs.hex.controller;
import com.zy.acs.common.domain.mq.DeviceMessage;
import com.zy.acs.framework.common.R;
import com.zy.component.influxdb.service.InfluxDBService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@Slf4j
@RequestMapping(value = "/deviceLog")
public class DeviceLogController {
    @Autowired
    private InfluxDBService influxDBService;
    /**
     * 查询最新的十条数据
     *
     * @return
     */
    @GetMapping(value = "/query")
    @ResponseBody
    public R query() {
        List<DeviceMessage> deviceMessages = influxDBService.queryPoints("select * from device order by time desc limit 10", DeviceMessage.class);
        return R.ok(deviceMessages);
    }
}
zy-acs-hex/src/main/java/com/zy/acs/hex/controller/RouterController.java
New file
@@ -0,0 +1,37 @@
package com.zy.acs.hex.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletResponse;
/**
 * Created by vincent on 2019-07-30
 */
@Controller
public class RouterController {
    @RequestMapping("/")
    public void index(HttpServletResponse response) {
        try {
            response.sendRedirect(  "/views/index.html");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    @RequestMapping("/login")
    public void login(HttpServletResponse response) {
        try {
            response.sendRedirect(  "/views/login.html");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
zy-acs-hex/src/main/resources/application.yml
@@ -5,7 +5,7 @@
    name: rcs-hex
  # RabbitMQ配置
  rabbitmq:
    host: 192.168.133.173
    host: localhost
    port: 5672
    username: root
    password: xltys1995
@@ -26,9 +26,10 @@
#  --add-opens java.base/java.nio=ALL-UNNAMED
influxdb3:
  enabled: true
  url: http://192.168.133.173:8181
  #token: apiv3_Jx1SvmBMV_kikGhc4eZJQbeGmNYN7KX1GdpoR9MClkKzMxSJ0MPKM_O2Xt3o1hVyRikMmlxZ_h9zfy6ybC5Idg
  url: http://localhost:8181
  token: apiv3_Jx1SvmBMV_kikGhc4eZJQbeGmNYN7KX1GdpoR9MClkKzMxSJ0MPKM_O2Xt3o1hVyRikMmlxZ_h9zfy6ybC5Idg
  database: rcs
  token: apiv3_116RKycNhxbf62Nys4zthC05aRD-aidzhEpEpLtsFuedhJTaCtVklNrzHs9LHxBWMuzDclBHVgToGoQuWGiIIA
  # 虚拟机的token
  #token: apiv3_116RKycNhxbf62Nys4zthC05aRD-aidzhEpEpLtsFuedhJTaCtVklNrzHs9LHxBWMuzDclBHVgToGoQuWGiIIA
  retention-period: 30d
  createDatabaseUrl: ${influxdb3.url}/api/v3/configure/database
zy-acs-hex/src/main/webapp/views/dashboard.html
File was deleted
zy-acs-hex/src/main/webapp/views/index.html
New file
@@ -0,0 +1,165 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>机器人日志系统</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: Arial, sans-serif;
            background-color: #f0f2f5;
        }
        .header {
            background-color: #1890ff;
            color: white;
            padding: 15px 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .header h1 {
            font-size: 20px;
        }
        .header button {
            background-color: transparent;
            color: white;
            border: 1px solid white;
            padding: 5px 15px;
            border-radius: 4px;
            cursor: pointer;
        }
        .header button:hover {
            background-color: rgba(255,255,255,0.1);
        }
        .container {
            padding: 20px;
        }
        .refresh-btn {
            background-color: #1890ff;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 4px;
            cursor: pointer;
            margin-bottom: 20px;
        }
        .refresh-btn:hover {
            background-color: #40a9ff;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            background-color: white;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        th, td {
            padding: 12px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }
        th {
            background-color: #f5f5f5;
            font-weight: bold;
        }
        tr:hover {
            background-color: #f5f5f5;
        }
        .loading {
            text-align: center;
            padding: 20px;
            color: #666;
        }
        .error {
            text-align: center;
            padding: 20px;
            color: red;
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>机器人上下行日志</h1>
        <button id="logoutBtn">登出</button>
    </div>
    <div class="container">
        <button class="refresh-btn" id="refreshBtn">刷新数据</button>
        <div id="loading" class="loading">加载中...</div>
        <div id="error" class="error" style="display: none;"></div>
        <table id="logTable" style="display: none;">
            <thead>
                <tr>
                    <th>时间</th>
                    <th>设备ID</th>
                    <th>消息类型</th>
                    <th>消息内容</th>
                </tr>
            </thead>
            <tbody id="logTableBody">
            </tbody>
        </table>
    </div>
    <script>
        // 检查登录状态
        function checkLogin() {
            if (!localStorage.getItem('loggedIn')) {
                window.location.href = '/login';
            }
        }
        // 登出功能
        document.getElementById('logoutBtn').addEventListener('click', function() {
            localStorage.removeItem('loggedIn');
            window.location.href = '/login';
        });
        // 加载日志数据
        function loadLogData() {
            document.getElementById('loading').style.display = 'block';
            document.getElementById('error').style.display = 'none';
            document.getElementById('logTable').style.display = 'none';
            fetch('/deviceLog/query')
                .then(response => response.json())
                .then(data => {
                    document.getElementById('loading').style.display = 'none';
                    if (data && data.length > 0) {
                        document.getElementById('logTable').style.display = 'table';
                        const tbody = document.getElementById('logTableBody');
                        tbody.innerHTML = '';
                        data.forEach(item => {
                            const row = document.createElement('tr');
                            row.innerHTML = `
                                <td>${item.time || '-'}</td>
                                <td>${item.deviceId || '-'}</td>
                                <td>${item.messageType || '-'}</td>
                                <td>${item.messageContent || '-'}</td>
                            `;
                            tbody.appendChild(row);
                        });
                    } else {
                        document.getElementById('error').textContent = '暂无日志数据';
                        document.getElementById('error').style.display = 'block';
                    }
                })
                .catch(error => {
                    document.getElementById('loading').style.display = 'none';
                    document.getElementById('error').textContent = '加载数据失败: ' + error.message;
                    document.getElementById('error').style.display = 'block';
                });
        }
        // 刷新按钮点击事件
        document.getElementById('refreshBtn').addEventListener('click', loadLogData);
        // 页面加载时检查登录状态并加载数据
        checkLogin();
        loadLogData();
    </script>
</body>
</html>
zy-acs-hex/src/main/webapp/views/login.html
New file
@@ -0,0 +1,104 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录 - 机器人日志系统</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: Arial, sans-serif;
            background-color: #f0f2f5;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
        .login-container {
            background-color: white;
            padding: 40px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            width: 100%;
            max-width: 400px;
        }
        h2 {
            text-align: center;
            margin-bottom: 30px;
            color: #333;
        }
        .form-group {
            margin-bottom: 20px;
        }
        label {
            display: block;
            margin-bottom: 8px;
            color: #666;
        }
        input {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 16px;
        }
        button {
            width: 100%;
            padding: 12px;
            background-color: #1890ff;
            color: white;
            border: none;
            border-radius: 4px;
            font-size: 16px;
            cursor: pointer;
            margin-top: 10px;
        }
        button:hover {
            background-color: #40a9ff;
        }
        .error-message {
            color: red;
            margin-top: 10px;
            text-align: center;
        }
    </style>
</head>
<body>
    <div class="login-container">
        <h2>机器人日志系统</h2>
        <form id="loginForm">
            <div class="form-group">
                <label for="username">用户名</label>
                <input type="text" id="username" name="username" required>
            </div>
            <div class="form-group">
                <label for="password">密码</label>
                <input type="password" id="password" name="password" required>
            </div>
            <button type="submit">登录</button>
            <div id="errorMessage" class="error-message"></div>
        </form>
    </div>
    <script>
        document.getElementById('loginForm').addEventListener('submit', function(e) {
            e.preventDefault();
            const username = document.getElementById('username').value;
            const password = document.getElementById('password').value;
            // 简单的登录验证(实际项目中应该调用后端API)
            if (username === 'admin' && password === 'admin123') {
                // 存储登录状态
                localStorage.setItem('loggedIn', 'true');
                // 跳转到主页面
                window.location.href = '/';
            } else {
                document.getElementById('errorMessage').textContent = '用户名或密码错误';
            }
        });
    </script>
</body>
</html>