sgj
昨天 ce819cce8e411e78e188e31645b0d7c8c2382784
巡更轨迹查看修改
已修改4个文件
865 ■■■■■ 文件已修改
fzzy-igdss-web/src/main/java/com/fzzy/sys/controller/security/PatrolRecordController.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/static/security/patrol/patrolRecord-style.css 259 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/static/security/patrol/patrolRecord.js 412 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/templates/security/patrol/patrolRecord/patrolRecord.html 156 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/java/com/fzzy/sys/controller/security/PatrolRecordController.java
@@ -35,31 +35,25 @@
    @GetMapping("/{patrolId}")
    public String getPatrolRecordById(@PathVariable("patrolId") String patrolId, Model model) {
        IgdsBaseParam param = new IgdsBaseParam();
        param.setPage(1);
        param.setLimit(6);
        param.setKey(patrolId);
        Page<PatrolRecord> records = patrolRecordManager.pageData(param);
        model.addAttribute("patrolRecordList", records.getRecords());
        model.addAttribute("currentPage", records.getCurrent());
        model.addAttribute("totalItems", records.getTotal());
        model.addAttribute("pageSize", records.getSize());
        model.addAttribute("patrolId", patrolId);
        return prefix + "/patrolRecord";
    }
    /**
     * 获取轨迹图页面
     */
    @GetMapping("trajectoryMap/{patrolId}")
    public String showTrajectoryMap(@PathVariable("patrolId") String patrolId, Model model) {
        IgdsBaseParam param = new IgdsBaseParam();
        param.setKey(patrolId);
        List<PatrolRecord> trackPoints = patrolRecordManager.listAll(param);
        model.addAttribute("trackPoints", trackPoints);
        return prefix + "/trajectoryMap";
        model.addAttribute("patrolRecordList", trackPoints);
        return prefix + "/patrolRecord";
    }
//
//    /**
//     * 获取轨迹图页面
//     */
//    @GetMapping("trajectoryMap/{patrolId}")
//    public String showTrajectoryMap(@PathVariable("patrolId") String patrolId, Model model) {
//
//        IgdsBaseParam param = new IgdsBaseParam();
//        param.setKey(patrolId);
//        List<PatrolRecord> trackPoints = patrolRecordManager.listAll(param);
//        model.addAttribute("trackPoints", trackPoints);
//
//        return prefix + "/trajectoryMap";
//    }
    /**
     * 分页获取数据
fzzy-igdss-web/src/main/resources/static/security/patrol/patrolRecord-style.css
@@ -1,203 +1,96 @@
/* 图片预览层样式 */
.img-preview {
    display: none;
#map {
    width: 100vw;
    height: 100vh;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.9);
    z-index: 1000;
    justify-content: center;
    align-items: center;
    z-index: 1;
}
.preview-content {
    max-width: 90%;
    max-height: 90%;
    position: relative;
}
.preview-img {
    max-width: 100%;
    max-height: 90vh;
    border-radius: 4px;
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
.close-preview {
    position: absolute;
    top: -40px;
    right: -10px;
    color: white;
    font-size: 2rem;
    cursor: pointer;
    background: rgba(0, 0, 0, 0.5);
    width: 40px;
    height: 40px;
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
    transition: all 0.3s ease;
}
.close-preview:hover {
    background: rgba(255, 255, 255, 0.2);
    transform: scale(1.1);
}
/* 图片网格样式 */
.gallery-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
    gap: 20px;
    margin-bottom: 5px;
}
.gallery-item {
    background: white;
/* 右侧轨迹卡片悬浮层 */
.track-card-panel {
    position: fixed;
    top: 20px;
    right: 20px;
    bottom: 20px;
    width: 380px;
    background: #fff;
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
    transition: all 0.3s ease;
}
.gallery-item:hover {
    transform: translateY(-5px);
    box-shadow: 0 10px 20px rgba(0, 0, 0, 0.12);
}
.gallery-img {
    width: 100%;
    height: 240px;
    object-fit: cover;
    cursor: pointer;
    transition: all 0.3s ease;
}
.gallery-img:hover {
    opacity: 0.95;
}
.gallery-info {
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
    z-index: 10; /* 层级高于地图 */
    padding: 15px;
    overflow-y: auto; /* 纵向滚动 */
    overflow-x: hidden; /* 隐藏横向滚动 */
}
.gallery-header {
/* 卡片面板标题 */
.panel-title {
    font-size: 18px;
    font-weight: 600;
    color: #333;
    padding-bottom: 10px;
    border-bottom: 1px solid #e6e6e6;
    margin-bottom: 15px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 10px;
}
.gallery-title {
    font-size: 1.5rem;
    font-weight: 600;
.panel-title .count {
    font-size: 14px;
    color: #1890ff;
    font-weight: normal;
}
/* 单个轨迹卡片 */
.track-card {
    padding: 12px;
    border: 1px solid #f0f0f0;
    border-radius: 6px;
    margin-bottom: 10px;
    cursor: pointer;
    transition: all 0.2s ease;
}
.track-card:hover {
    border-color: #1890ff;
    background: #f5f8ff;
    transform: translateX(-2px);
}
.track-card.active {
    border-color: #1890ff;
    background: #e6f7ff;
}
/* 卡片内信息行 */
.card-row {
    display: flex;
    margin-bottom: 6px;
    font-size: 14px;
    line-height: 1.5;
}
.card-row:last-child {
    margin-bottom: 0;
}
.card-row .label {
    width: 80px;
    color: #666;
    flex-shrink: 0;
}
.card-row .value {
    color: #333;
    margin: 0;
    flex: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.gallery-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
/* 滚动条美化 */
.track-card-panel::-webkit-scrollbar {
    width: 6px;
}
.meta-item {
    display: flex;
    align-items: center;
    font-size: 1.3rem;
    color: #666;
.track-card-panel::-webkit-scrollbar-track {
    background: #f5f5f5;
    border-radius: 3px;
}
.meta-item i {
    width: 16px;
    margin-right: 6px;
    color: #999;
    font-size: 1.25rem;
.track-card-panel::-webkit-scrollbar-thumb {
    background: #d9d9d9;
    border-radius: 3px;
}
.gallery-filename i {
    margin-right: 5px;
    font-size: 0.7rem;
}
/* 标签样式 */
.gallery-tags {
    display: flex;
    flex-wrap: wrap;
    margin-left: auto;
    gap: 3px;
    /*margin: 12px 0;*/
}
/* 分页样式 */
.pagination-container {
    display: flex;
    justify-content: flex-end;
    width: 100%;
    /*margin-top: 40px;*/
}
/* 空状态样式 */
.empty-state {
    grid-column: 1 / -1;
    text-align: center;
    padding: 60px 20px;
    color: #999;
}
.empty-state i {
    font-size: 4rem;
    margin-bottom: 20px;
    color: #ddd;
}
.empty-state h3 {
    font-size: 1.5rem;
    margin-bottom: 10px;
    color: #666;
}
/* 响应式设计 */
@media (max-width: 992px) {
    .gallery-grid {
        grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
        gap: 25px;
    }
}
@media (max-width: 768px) {
    .main-nav li {
        margin: 0 10px;
    }
    .gallery-grid {
        grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
        gap: 20px;
    }
    .gallery-img {
        height: 180px;
    }
}
@media (max-width: 576px) {
    .gallery-grid {
        grid-template-columns: 1fr;
    }
    .gallery-img {
        height: 200px;
    }
.track-card-panel::-webkit-scrollbar-thumb:hover {
    background: #1890ff;
}
fzzy-igdss-web/src/main/resources/static/security/patrol/patrolRecord.js
@@ -1,281 +1,169 @@
var layer;
var laypage;
$(function () {
    // 初始化分页
    layui.use(['laypage', 'layer'], function () {
$(document).ready(function () {
    layui.use(['layer'], function () {
        layer = layui.layer;
        laypage = layui.laypage;
        // 初始化分页组件
        initPagination();
    });
    // 初始化图片预览功能
    initImagePreview();
});
/**
 * 初始化分页组件
 */
function initPagination() {
    laypage.render({
        elem: 'pagination',
        count: typeof totalItems !== 'undefined' ? totalItems : 0,
        limit: typeof pageSize !== 'undefined' ? pageSize : 6,
        curr: typeof currentPage !== 'undefined' ? currentPage : 1,
        layout: ['prev', 'page', 'next', 'refresh', 'skip'],
        jump: function (obj, first) {
            if (!first) {
                searchRecord(obj.curr, obj.limit)
            }
        }
    });
}
/**
 * 重新初始化分页组件
 * @param {number} totalCount - 总记录数
 * @param {number} pageSize - 每页大小
 * @param {number} currentPage - 当前页码
 */
function reinitPagination(totalCount, pageSize, currentPage) {
    laypage.render({
        elem: 'pagination',
        count: totalCount,
        limit: pageSize,
        curr: currentPage,
        layout: ['prev', 'page', 'next', 'refresh', 'skip'],
        jump: function (obj, first) {
            if (!first) {
                searchRecord(obj.curr, obj.limit)
            }
        }
    });
}
/**
 * 获取巡检记录数据
 * @param {Object} params - 查询参数对象
 * @param {Function} callback - 回调函数
 */
function fetchPatrolRecordData(params, callback) {
    $.ajax({
        url: '../../patrol/patrolRecord/pageData',
        type: 'POST',
        dataType: "json",
        contentType: "application/json;charset=UTF-8",
        data: JSON.stringify(params),
        success: function (response) {
            if (response.code === '0000') {
                callback(null, response.data);
            } else {
                callback(new Error(response.msg || '数据加载失败'), null);
            }
        },
        error: function (xhr, status, error) {
            callback(new Error('请求失败,请稍后重试'), null);
        }
    });
}
/**
 * 构建查询参数
 * @param {number} page - 页码
 * @param {number} size - 每页大小
 * @returns {Object} 查询参数对象
 */
function buildQueryParams(page, size) {
    var params = {
        page: page,
        limit: size,
        key: patrolId  //主表id查询
    };
    // 添加表单查询条件
    var form = document.getElementById('patrolRecord-form');
    if (form) {
        var inputs = form.querySelectorAll('input[name], select[name]');
        inputs.forEach(function(input) {
            if (input.value) { // 只添加非空值
                params[input.name] = input.value;
            }
        });
    }
    return params;
}
/**
 * 更新巡检记录画廊内容
 * @param {Array} records - 巡检记录数据
 */
function updateGallery(records) {
    var container = document.getElementById('gallery-container');
    if (!container) return;
    // 清空现有内容
    container.innerHTML = '';
    if (!records || records.length === 0) {
        // 显示空状态
        container.innerHTML = `
            <div class="empty-state">
                <i class="fa-solid fa-clipboard-list"></i>
                <h3>暂无巡检记录</h3>
                <p>当前没有可展示的巡检记录数据</p>
            </div>
        `;
        // 隐藏分页
        $('.pagination-container').hide();
function initMap() {
    // 可删除代码开始
    // 检查百度地图API是否加载成功
    if (typeof BMapGL === 'undefined') {
        layer.msg("地图加载失败,请检查网络连接!", {icon: 2});
        return;
    }
    // 显示分页
    $('.pagination-container').show();
    // 检查容器是否存在
    var mapContainer = document.getElementById("map");
    if (!mapContainer) {
        layer.msg("地图容器未找到!", {icon: 2});
        return;
    }
    // 生成巡检记录卡片
    var html = '';
    records.forEach(function(record) {
        html += `
            <div class="gallery-item">
                <img src="${record.imgName || '/logo-sm.png'}" alt="${record.id}"
                     data-url="${record.imgName || '/logo-sm.png'}" data-id="${record.id}"
                     class="gallery-img" onclick="showPatrolRecordPreview(this.getAttribute('data-url'))">
                <div class="gallery-info">
                    <div class="gallery-header">
                        <h3 class="gallery-title">${record.pointName || record.id}</h3>
                    <!--
                        <div class="gallery-tags">
                            <span class="tag-person">
                                <i class="layui-icon layui-icon-user"></i>
                                <span>'未知'</span>
                            </span>
                        </div>
                         -->
                    </div>
                    <div class="gallery-meta">
                         <div style="display: flex; align-items: center; gap: 15px;width: 100%">
                             <div class="meta-item" style="width: 50%">
                                <i class="layui-icon layui-icon-location"></i>
                                <span>${record.longitude || ''}</span>
                            </div>
                            <div class="meta-item">
                                <i class="layui-icon layui-icon-location"></i>
                                <span>${record.latitude || ''}</span>
                            </div>
                         </div>
                        <div class="meta-item" style="width: 50%">
                                <i class="layui-icon layui-icon-date"></i>
                                <span>${formatDate(record.createTime)}</span>
                            </div>
                    </div>
    // 检查数据
    if (!patrolRecordList || patrolRecordList.length === 0) {
        layer.msg("暂无轨迹数据!", {icon: 2});
        var defaultPoint = new BMapGL.Point(116.404, 39.915);
        map.centerAndZoom(defaultPoint, 12);
        map.enableScrollWheelZoom(true);
        return;
    }
    //可删除代码结束
    // ========== 百度地图初始化与轨迹渲染 ==========
    // 1. 初始化地图
    var map = new BMapGL.Map("map");
    // 2. 获取轨迹点数据
    if (patrolRecordList.length === 0) {
        layer.msg("暂无轨迹数据!", {icon: 2});
        var defaultPoint = new BMapGL.Point(116.404, 39.915);
        map.centerAndZoom(defaultPoint, 14);
        map.enableScrollWheelZoom(true);
        return;
    }
    // 3. 构造轨迹点数组和标记点数组
    var points = [];       // 轨迹折线点
    var markers = [];      // 地图标记点
    var cardElements = document.querySelectorAll('.track-card'); // 所有卡片元素
    patrolRecordList.forEach(function (record, index) {
        var lng = record.longitude;
        var lat = record.latitude;
        var point = new BMapGL.Point(lng, lat);
        points.push(point);
        // 创建地图标记点
        var marker = new BMapGL.Marker(point);
        markers.push(marker);
        // 标记点弹窗信息
        var infoWindow = new BMapGL.InfoWindow(`
                <div style="font-size: 12px; line-height: 1.8;">
                    <p><strong>点位名称:</strong>${record.pointName}</p>
                    <p><strong>巡检人:</strong>${record.createBy}</p>
                    <p><strong>巡检时间:</strong>${new Date(record.createTime).toLocaleString()}</p>
                    <p><strong>经纬度:</strong>${lat}, ${lng}</p>
                    <p><strong>轨迹点ID:</strong>${record.id}</p>
                </div>
            </div>
        `;
            `);
        // 标记点点击事件:高亮对应卡片 + 显示弹窗
        marker.addEventListener("click", function () {
            // 移除所有卡片的active样式
            cardElements.forEach(el => el.classList.remove('active'));
            // 高亮当前卡片
            cardElements[index].classList.add('active');
            // 滚动到当前卡片
            cardElements[index].scrollIntoView({behavior: 'smooth', block: 'center'});
            // 显示弹窗
            this.openInfoWindow(infoWindow);
        });
        // 卡片点击事件:定位到对应标记点 + 高亮卡片
        cardElements[index].addEventListener("click", function () {
            // 移除所有卡片的active样式
            cardElements.forEach(el => el.classList.remove('active'));
            // 高亮当前卡片
            this.classList.add('active');
            // 地图中心定位到当前标记点
            map.centerAndZoom(point, 15);
            // 显示标记点弹窗
            marker.openInfoWindow(infoWindow);
            // 轻微动画效果
            marker.setAnimation(BMAP_ANIMATION_BOUNCE);
            setTimeout(() => marker.setAnimation(null), 1500);
        });
        map.addOverlay(marker);
    });
    container.innerHTML = html;
}
    // 寻找points中间的点位
    var midIndex = Math.floor(points.length / 2);
    const centerPoint = points[midIndex] || new BMapGL.Point(116.404, 39.915);
    map.centerAndZoom(centerPoint, 13); // 14为地图缩放级别
/**
 * 格式化日期
 * @param {string|number} date - 日期字符串或时间戳
 */
function formatDate(date) {
    if (!date) return '';
    var d = new Date(date);
    return d.getFullYear() + '-' +
        String(d.getMonth() + 1).padStart(2, '0') + '-' +
        String(d.getDate()).padStart(2, '0') + ' ' +
        String(d.getHours()).padStart(2, '0') + ':' +
        String(d.getMinutes()).padStart(2, '0') ;
}
/**
 * 初始化图片预览功能
 */
function initImagePreview() {
    var preview = document.getElementById('imgPreview');
    var previewImg = document.getElementById('previewImg');
    var closeBtn = document.getElementById('closePreview');
    // 如果预览元素不存在,则不初始化
    if (!preview || !previewImg) {
        return;
    }
    // 关闭按钮点击事件
    if (closeBtn) {
        closeBtn.addEventListener('click', closePreview);
    }
    // 点击预览区域外关闭
    preview.addEventListener('click', function (e) {
        if (e.target === preview) {
            closePreview();
        }
    // 4. 绘制轨迹折线
    var polyline = new BMapGL.Polyline(points, {
        strokeColor: "#1890ff", // 主色调:蓝色
        strokeWeight: 6,        // 折线宽度
        strokeOpacity: 0.8,     // 透明度
        strokeStyle: 'solid'    // 实线
    });
    map.addOverlay(polyline);
    // 键盘事件监听
    document.addEventListener('keydown', function (e) {
        if (e.key === 'Escape' && preview.style.display === 'flex') {
            closePreview();
        }
    });
    // // 5. 起点/终点特殊标记
    // // 起点标记
    // var startMarker = new BMapGL.Marker(points[0], {
    //     icon: new BMapGL.Icon("http://api.map.baidu.com/img/markers.png", new BMapGL.Size(25, 34), {
    //         offset: new BMapGL.Size(12, 34),
    //         imageOffset: new BMapGL.Size(0, 0) // 起点图标
    //     })
    // });
    // map.addOverlay(startMarker);
    // // startMarker.setLabel(new BMapGL.Label("起点:" + patrolRecordList[0].pointName, {
    // //     offset: new BMapGL.Size(30, -15),
    // //     styles: {fontSize: '12px', color: '#fff', background: '#52c41a', padding: '0px 14px', borderRadius: '3px'}
    // // }));
    // startMarker.setLabel(new BMapGL.Label("起点:" + patrolRecordList[0].pointName, {
    //     offset: new BMapGL.Size(30, -15),
    //     styles: {
    //         fontSize: '12px',
    //         color: '#fff',
    //         background: '#52c41a',
    //         padding: '8px 8px',  // 左右padding保持一致(14px),保证背景两侧空间对称
    //         borderRadius: '3px',
    //         textAlign: 'center'  // 新增:强制文字在背景内水平居中
    //     }
    // }));
    //
    // // 终点标记
    // var endMarker = new BMapGL.Marker(points[points.length - 1], {
    //     icon: new BMapGL.Icon("http://api.map.baidu.com/img/markers.png", new BMapGL.Size(25, 34), {
    //         offset: new BMapGL.Size(12, 34),
    //         imageOffset: new BMapGL.Size(-114, 0) // 终点图标
    //     })
    // });
    // map.addOverlay(endMarker);
    // endMarker.setLabel(new BMapGL.Label("终点:" + patrolRecordList[patrolRecordList.length - 1].pointName, {
    //     offset: new BMapGL.Size(30, -15),
    //     styles: {fontSize: '12px', color: '#fff', background: '#ff4d4f', padding: '0px 14px', borderRadius: '3px'}
    // }));
    // 关闭预览函数
    function closePreview() {
        preview.style.display = 'none';
        previewImg.src = '';
    }
}
    // 6. 地图自适应所有轨迹点
    map.enableScrollWheelZoom(true); // 开启滚轮缩放
    map.setViewport(points); // 适配所有轨迹点
/**
 * 显示图片预览
 * @param {string} imgUrl 图片URL
 */
function showPatrolRecordPreview(imgUrl) {
    var preview = document.getElementById('imgPreview');
    var previewImg = document.getElementById('previewImg');
    if (preview && previewImg) {
        previewImg.src = imgUrl;
        preview.style.display = 'flex';
    }
}
/**
 * 读取巡检记录
 */
function searchRecord(page , size) {
    var pageNumber = 1;
    var sizeNumber = 6;
    if (pageSize && pageSize > 0){
        size = pageSize;
    }
    if (size && size > 0){
        sizeNumber = size;
    }
    if (page && page > 0){
        pageNumber = page;
    }
    // 构造查询参数,从第一页开始
    var queryParams = buildQueryParams(pageNumber, sizeNumber);
    // 显示loading
    var loadingIndex = layer.load(1, {shade: [0.1, '#fff']});
    // 调用数据请求方法
    fetchPatrolRecordData(queryParams, function(error, data) {
        // 关闭loading
        layer.close(loadingIndex);
        if (error) {
            layer.msg(error.message);
            return;
        }
        // 更新页面数据
        updateGallery(data.records);
        // 重新初始化分页组件
        reinitPagination(data.total, data.size, data.current);
    // 7. 初始提示
    layer.msg("轨迹加载完成!点击卡片可定位到对应点位", {
        icon: 1,
        time: 3000,
        offset: ['20px', '20px']
    });
}
// 页面加载完成后初始化地图
window.onload = initMap;
fzzy-igdss-web/src/main/resources/templates/security/patrol/patrolRecord/patrolRecord.html
@@ -1,132 +1,64 @@
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="renderer" content="webkit">
    <meta charset="UTF-8">
    <title>巡检轨迹展示</title>
    <!-- Layui CSS(用于基础样式) -->
    <th:block th:include="include :: header('巡更记录')"/>
    <link rel="stylesheet" type="text/css" th:href="@{/ajax/libs/layui-ruoyi/css/layui.css}"/>
    <link rel="stylesheet" th:href="@{/security/patrol/patrolRecord-style.css}">
    <script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=R3FfyIEbBAWNckTqRSopHQktdkgp924F"></script>
</head>
<body class="gray-bg">
<body>
<div class="container-div">
    <div class="row">
        <div class="col-sm-12 search-collapse"
             style="display: flex; justify-content: space-between; align-items: center;">
            <form id="patrolRecord-form">
                <div class="select-list">
                    <ul>
                        <li>
                            巡更点:<input type="text" name="name"/>
                        </li>
                        <li>
                            <a class="btn btn-primary btn-rounded btn-sm" onclick="searchRecord()"><i
                                    class="fa fa-search"></i>&nbsp;搜索</a>
                            <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i
                                    class="fa fa-refresh"></i>&nbsp;重置</a>
                        </li>
                    </ul>
                </div>
            </form>
            <div class="btn-group-sm" role="group">
                <!-- 如果需要添加按钮可以放在这里 -->
                <a class="btn btn-success" onclick="openTrajectoryMap()" >
                    <i class="fa fa-search"></i> 轨迹图查看
                </a>
        <!-- 百度地图容器 -->
        <div id="map"></div>
        <!-- 右侧轨迹卡片悬浮层 -->
        <div class="track-card-panel">
            <div class="panel-title">
                巡检轨迹点
                <span class="count" th:text="'共 ' + ${#lists.size(patrolRecordList)} + ' 个点位'"></span>
            </div>
        </div>
        <div class="col-sm-12 " style="padding-top: 10px;">
            <!-- 巡检记录网格 -->
            <div class="gallery-grid" id="gallery-container">
                <!-- 记录为空时显示 -->
                <div th:if="${#lists.isEmpty(patrolRecordList)}" class="empty-state">
                    <i class="fa-solid fa-clipboard-list"></i>
                    <h3>暂无巡检记录</h3>
                    <p>当前没有可展示的巡检记录数据</p>
            <!-- 轨迹卡片列表(Thymeleaf循环渲染) -->
            <div th:each="record,stat : ${patrolRecordList}" class="track-card" data-index="${stat.index}">
                <div class="card-row">
                    <span class="label">序号:</span>
                    <span class="value" th:text="${stat.index + 1}"></span>
                </div>
                <!-- 记录卡片 -->
                <div th:each="patrolRecord : ${patrolRecordList}" class="gallery-item">
                    <img th:src="${patrolRecord.imgName ?: '/logo-sm.png'}" th:alt="${patrolRecord.id}"
                         th:data-url="${patrolRecord.imgName ?: '/logo-sm.png'}" th:data-id="${patrolRecord.id}"
                         class="gallery-img" onclick="showPatrolRecordPreview(this.getAttribute('data-url'))">
                    <div class="gallery-info">
                        <div class="gallery-header">
                            <h3 class="gallery-title" th:text="${patrolRecord.pointName ?: patrolRecord.id}"></h3>
                            <!-- 标签列表 -->
<!--                            <div class="gallery-tags">-->
<!--                                <span class="tag-person">-->
<!--                                    <i class="layui-icon layui-icon-user"></i>-->
<!--                                    <span th:text="'未知'"></span>-->
<!--                                </span>-->
<!--                            </div>-->
                        </div>
                        <div class="gallery-meta">
                            <div style="display: flex; align-items: center; gap: 15px;width: 100%">
                                <div class="meta-item" style="width: 50%">
                                    <i class="layui-icon layui-icon-location"></i>
                                    <span th:text="${patrolRecord.longitude ?: ''}"></span>
                                </div>
                                <div class="meta-item" style="width: 50%">
                                    <i class="layui-icon layui-icon-location"></i>
                                    <span th:text="${patrolRecord.latitude ?: ''}"></span>
                                </div>
                            </div>
                            <div class="meta-item" >
                                <i class="layui-icon layui-icon-date"></i>
                                <span th:text="${#dates.format(patrolRecord.createTime, 'yyyy-MM-dd HH:mm')}"></span>
                            </div>
                        </div>
                    </div>
                <div class="card-row">
                    <span class="label">点位名称:</span>
                    <span class="value" th:text="${record.pointName}"></span>
                </div>
            </div>
            <!-- 分页控件 -->
            <div class="pagination-container" th:if="${not #lists.isEmpty(patrolRecordList)}">
                <div id="pagination"></div>
            </div>
        </div>
    </div>
    <!-- 图片预览层 -->
    <div class="img-preview" id="imgPreview">
        <div class="preview-content">
            <img src="" alt="预览图片" class="preview-img" id="previewImg">
            <div class="close-preview" id="closePreview">
                <i class="layui-icon layui-icon-clear"></i>
                <div class="card-row">
                    <span class="label">巡检人:</span>
                    <span class="value" th:text="${record.createBy}"></span>
                </div>
                <div class="card-row">
                    <span class="label">巡检时间:</span>
                    <span class="value" th:text="${#dates.format(record.createTime, 'yyyy-MM-dd HH:mm:ss')}"></span>
                </div>
                <div class="card-row">
                    <span class="label">经纬度:</span>
                    <span class="value" th:text="${record.latitude} + ', ' + ${record.longitude}"></span>
                </div>
                <div class="card-row">
                    <span class="label">轨迹点ID:</span>
                    <span class="value" th:text="${record.id}"></span>
                </div>
            </div>
        </div>
    </div>
</div>
<!-- 引入Layui JS -->
<th:block th:include="include :: footer"/>
<script th:src="@{/ajax/libs/layui-ruoyi/layui.js}"></script>
<script th:src="@{/security/patrol/patrolRecord.js}"></script>
<script th:inline="javascript">
    var prefix = ctx + "security/patrol/patrolRecord";
    var currentPage = [[${currentPage}]];
    var totalItems = [[${totalItems}]];
    var pageSize = [[${pageSize}]];
    var patrolId = [[${patrolId}]];
    function openTrajectoryMap() {
        var url = prefix + '/trajectoryMap/'+patrolId ;
        var options = {
            title: "轨迹图",
            width: 500,
            height: 500,
            url: url,
            btn: 0,
            yes: function (index, layero) {
                $.modal.close(index);
            }
        };
        $.modal.openOptions(options);
    }
<script  th:inline="javascript">
    var patrolRecordList = [[${patrolRecordList}]];
</script>
</body>
</html>
</html>