sgj
3 天以前 1e0b151f8e1fab091fbc24051baefc33fa677052
电子巡更,巡更详情,巡更轨迹图添加
已修改6个文件
已添加7个文件
921 ■■■■■ 文件已修改
fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/PatrolRecord.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/igds/service/PatrolRecordService.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/java/com/fzzy/sys/controller/security/PatrolRecordController.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/java/com/fzzy/sys/manager/security/PatrolRecordManager.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/static/security/eventInfo/eventInfo.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/static/security/patrol/patrolRecord-style.css 203 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/static/security/patrol/patrolRecord.js 281 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/static/security/snap/snapRecord.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/templates/security/eventInfo/eventInfo.html 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/templates/security/patrol/patrol.html 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/templates/security/patrol/patrolRecord/patrolRecord.html 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/templates/security/patrol/patrolRecord/trajectoryMap.html 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/templates/security/snap/snapRecord/snapRecord.html 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/igds/domain/PatrolRecord.java
@@ -42,11 +42,6 @@
    @TableField("point_name")
    private String pointName;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @Column(name = "create_time", columnDefinition = "datetime COMMENT '巡逻时间'")
    @TableField("create_time")
    private Date createTime;
    @Column(name = "longitude", columnDefinition = "decimal(20,6) COMMENT '经度'")
    @TableField("longitude")
    private String longitude;
@@ -68,6 +63,7 @@
    //巡更照片全路径
    @Transient
    @TableField(exist = false)
    private String imgPath;
}
fzzy-igdss-core/src/main/java/com/fzzy/igds/service/PatrolRecordService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,84 @@
package com.fzzy.igds.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fzzy.igds.data.BaseResp;
import com.fzzy.igds.data.IgdsBaseParam;
import com.fzzy.igds.domain.PatrolRecord;
import com.fzzy.igds.mapper.PatrolRecordMapper;
import com.fzzy.igds.utils.ContextUtil;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
@Slf4j
@Service
public class PatrolRecordService {
    @Resource
    private PatrolRecordMapper patrolRecordMapper;
    /**
     * åˆ†é¡µæŸ¥è¯¢æ•°æ®
     *
     * @param page
     * @param param
     */
    public void listPage(Page<PatrolRecord> page, IgdsBaseParam param) {
        QueryWrapper<PatrolRecord> queryWrapper = getQueryWrapper(param);
        patrolRecordMapper.selectPage(page, queryWrapper);
    }
    public List<PatrolRecord> listAll(IgdsBaseParam param) {
        QueryWrapper<PatrolRecord> queryWrapper = getQueryWrapper(param);
        return patrolRecordMapper.selectList(queryWrapper);
    }
    /**
     * å°è£…查询条件
     *
     * @param param
     */
    public QueryWrapper<PatrolRecord> getQueryWrapper(IgdsBaseParam param) {
        QueryWrapper<PatrolRecord> queryWrapper = new QueryWrapper<>();
        param.setCompanyId(ContextUtil.getCompanyId());
        queryWrapper.eq("company_id", param.getCompanyId());
        if (StringUtils.isNotBlank(param.getName())) {
            queryWrapper.eq("point_name", param.getName());
        }
        if (StringUtils.isNotBlank(param.getKey())) {
            queryWrapper.eq("patrol_id", param.getKey());
        }
        queryWrapper.orderByDesc("id");
        return queryWrapper;
    }
    public BaseResp addData(PatrolRecord patrolRecord) {
        patrolRecord.setId(ContextUtil.generateId());
        patrolRecord.setCompanyId(ContextUtil.getCompanyId());
        patrolRecord.setUpdateBy(ContextUtil.getLoginUserName());
        patrolRecord.setUpdateTime(new Date());
        patrolRecord.setCreateBy(ContextUtil.getLoginUserName());
        patrolRecord.setCreateTime(new Date());
        return patrolRecordMapper.insert(patrolRecord) > 0 ? BaseResp.success() : BaseResp.error("添加失败");
    }
    public BaseResp updateData(PatrolRecord patrolRecord) {
        patrolRecord.setUpdateBy(ContextUtil.getLoginUserName());
        patrolRecord.setUpdateTime(new Date());
        return patrolRecordMapper.updateById(patrolRecord) > 0 ? BaseResp.success() : BaseResp.error("更新失败");
    }
    public BaseResp deleteData(PatrolRecord patrolRecord) {
        return patrolRecordMapper.deleteById(patrolRecord) > 0 ? BaseResp.success() : BaseResp.error("删除失败");
    }
}
fzzy-igdss-web/src/main/java/com/fzzy/sys/controller/security/PatrolRecordController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,72 @@
package com.fzzy.sys.controller.security;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fzzy.igds.constant.RespCodeEnum;
import com.fzzy.igds.data.IgdsBaseParam;
import com.fzzy.igds.data.PageResponse;
import com.fzzy.igds.domain.PatrolRecord;
import com.fzzy.sys.manager.security.PatrolRecordManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@Slf4j
@Controller
@RequestMapping("/security/patrol/patrolRecord")
public class PatrolRecordController {
    private static final String prefix = "security/patrol/patrolRecord";
    @Resource
    private PatrolRecordManager patrolRecordManager;
    @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";
    }
    /**
     * åˆ†é¡µèŽ·å–æ•°æ®
     *
     * @param param
     * @return
     */
    @RequestMapping("/pageData")
    @ResponseBody
    public PageResponse<Page<PatrolRecord>> pageData(@RequestBody IgdsBaseParam param) {
        Page<PatrolRecord> patrolRecordPage = patrolRecordManager.pageData(param);
        if (null == patrolRecordPage.getRecords() || patrolRecordPage.getRecords().isEmpty()) {
            return new PageResponse<>(RespCodeEnum.CODE_2000.getCode(), "获取到数据信息为空");
        }
        return new PageResponse<>(RespCodeEnum.CODE_0000, patrolRecordPage);
    }
}
fzzy-igdss-web/src/main/java/com/fzzy/sys/manager/security/PatrolRecordManager.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
package com.fzzy.sys.manager.security;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fzzy.igds.data.IgdsBaseParam;
import com.fzzy.igds.domain.PatrolRecord;
import com.fzzy.igds.service.PatrolRecordService;
import com.fzzy.igds.utils.ContextUtil;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Component
public class PatrolRecordManager {
    @Resource
    private PatrolRecordService patrolRecordService;
    /**
     * åˆ†é¡µæŸ¥è¯¢æ•°æ®
     *
     * @param param
     * @return
     */
    public Page<PatrolRecord> pageData(IgdsBaseParam param) {
        if (StringUtils.isEmpty(param.getCompanyId())) {
            param.setCompanyId(ContextUtil.getCompanyId());
        }
        Page<PatrolRecord> corePage = new Page<>(param.getPage(), param.getLimit());
        patrolRecordService.listPage(corePage, param);
        if (null == corePage.getRecords() || corePage.getRecords().isEmpty()) {
            return corePage.setRecords(new ArrayList<>());
        }
        return corePage;
    }
    public List<PatrolRecord> listAll(IgdsBaseParam param) {
        if (StringUtils.isEmpty(param.getCompanyId())) {
            param.setCompanyId(ContextUtil.getCompanyId());
        }
        return patrolRecordService.listAll(param);
    }
}
fzzy-igdss-web/src/main/resources/static/security/eventInfo/eventInfo.js
@@ -195,8 +195,7 @@
        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') + ':' +
        String(d.getSeconds()).padStart(2, '0');
        String(d.getMinutes()).padStart(2, '0') ;
}
/**
fzzy-igdss-web/src/main/resources/static/security/patrol/patrolRecord-style.css
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,203 @@
/* å›¾ç‰‡é¢„览层样式 */
.img-preview {
    display: none;
    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;
}
.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;
    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 {
    padding: 15px;
}
.gallery-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 10px;
}
.gallery-title {
    font-size: 1.5rem;
    font-weight: 600;
    color: #333;
    margin: 0;
    flex: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.gallery-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.meta-item {
    display: flex;
    align-items: center;
    font-size: 1.3rem;
    color: #666;
}
.meta-item i {
    width: 16px;
    margin-right: 6px;
    color: #999;
    font-size: 1.25rem;
}
.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;
    }
}
fzzy-igdss-web/src/main/resources/static/security/patrol/patrolRecord.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,281 @@
var layer;
var laypage;
$(function () {
    // åˆå§‹åŒ–分页
    layui.use(['laypage', '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();
        return;
    }
    // æ˜¾ç¤ºåˆ†é¡µ
    $('.pagination-container').show();
    // ç”Ÿæˆå·¡æ£€è®°å½•卡片
    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>
                </div>
            </div>
        `;
    });
    container.innerHTML = html;
}
/**
 * æ ¼å¼åŒ–日期
 * @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();
        }
    });
    // é”®ç›˜äº‹ä»¶ç›‘听
    document.addEventListener('keydown', function (e) {
        if (e.key === 'Escape' && preview.style.display === 'flex') {
            closePreview();
        }
    });
    // å…³é—­é¢„览函数
    function closePreview() {
        preview.style.display = 'none';
        previewImg.src = '';
    }
}
/**
 * æ˜¾ç¤ºå›¾ç‰‡é¢„览
 * @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);
    });
}
fzzy-igdss-web/src/main/resources/static/security/snap/snapRecord.js
@@ -194,8 +194,9 @@
        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') + ':' +
        String(d.getSeconds()).padStart(2, '0');
        String(d.getMinutes()).padStart(2, '0')
        // + ':' +
        // String(d.getSeconds()).padStart(2, '0');
}
/**
fzzy-igdss-web/src/main/resources/templates/security/eventInfo/eventInfo.html
@@ -80,7 +80,7 @@
                                </div>
                                <div class="meta-item" style="width: 50%">
                                    <i class="layui-icon layui-icon-date"></i>
                                    <span th:text="${#dates.format(eventInfo.time, 'yyyy-MM-dd HH:mm:ss')}"></span>
                                    <span th:text="${#dates.format(eventInfo.time, 'yyyy-MM-dd HH:mm')}"></span>
                                </div>
                            </div>
                            <div class="meta-item">
fzzy-igdss-web/src/main/resources/templates/security/patrol/patrol.html
@@ -99,6 +99,7 @@
                        var actions = [];
                        actions.push('<a class="btn btn-success btn-xs '  + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.id + '\')"><i class="fa fa-edit"></i>编辑</a> ');
                        actions.push('<a class="btn btn-danger btn-xs '  + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.id + '\')"><i class="fa fa-remove"></i>删除</a>');
                        actions.push('<a class="btn btn-info btn-xs '  + '" href="javascript:void(0)" onclick="patrolDetail(\'' + row.id + '\')"><i class="fa fa-list-ul"></i>详情</a> ');
                        return actions.join('');
                    }
                }]
@@ -106,6 +107,12 @@
        $.table.init(options);
    });
    /*详情*/
    function patrolDetail(patrolId) {
        var url = prefix + '/patrolRecord/' + patrolId;
        $.modal.openTab("巡更详情", url);
    }
    function openPatrolConf() {
        var url = ctx + "security/patrol/patrolConf";
        $.modal.openTab("巡更配置", url);
fzzy-igdss-web/src/main/resources/templates/security/patrol/patrolRecord/patrolRecord.html
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,132 @@
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<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">
    <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}">
</head>
<body class="gray-bg">
<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>
        </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>
                </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>
            </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>
        </div>
    </div>
</div>
<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>
</body>
</html>
fzzy-igdss-web/src/main/resources/templates/security/patrol/patrolRecord/trajectoryMap.html
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,72 @@
<!DOCTYPE html>
<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">
    <th:block th:include="include :: header('轨迹图展示')"/>
    <!-- ç™¾åº¦åœ°å›¾API -->
    <script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&type=webgl&ak=R3FfyIEbBAWNckTqRSopHQktdkgp924F"></script>
</head>
<body>
<!-- åœ°å›¾å®¹å™¨ -->
<div class="container-div" id="map-container">
</div>
<th:block th:include="include :: footer"/>
<script th:inline="javascript">
    // 1. èŽ·å–åŽç«¯ä¼ é€’çš„è½¨è¿¹æ•°æ®
    const trackPoints = [[${trackPoints}]];
    // è½¬æ¢ä¸ºç™¾åº¦åœ°å›¾åæ ‡æ•°ç»„
    const path = trackPoints.map(point => new BMapGL.Point(point.longitude, point.latitude));
    // 2. åˆå§‹åŒ–地图
    function initMap() {
        // åˆ›å»ºåœ°å›¾å®žä¾‹ï¼Œä¸­å¿ƒç‚¹è®¾ä¸ºç¬¬ä¸€ä¸ªè½¨è¿¹ç‚¹
        const map = new BMapGL.Map("map-container");
        const centerPoint = path[0] || new BMapGL.Point(116.404, 39.915);
        map.centerAndZoom(centerPoint, 14); // 14为地图缩放级别
        map.enableScrollWheelZoom(true); // å¼€å¯é¼ æ ‡æ»šè½®ç¼©æ”¾
        // 3. æ·»åŠ è½¨è¿¹çº¿
        const polyline = new BMapGL.Polyline(path, {
            strokeColor: "#3388ff", // çº¿é¢œè‰²
            strokeWeight: 5, // çº¿å®½åº¦
            strokeOpacity: 0.8 // çº¿é€æ˜Žåº¦
        });
        map.addOverlay(polyline);
        // 4. ä¸ºæ¯ä¸ªè½¨è¿¹ç‚¹æ·»åŠ æ ‡è®°å’Œä¿¡æ¯çª—å£
        trackPoints.forEach((point, index) => {
            const markerPoint = new BMapGL.Point(point.longitude, point.latitude);
            // åˆ›å»ºæ ‡è®°
            const marker = new BMapGL.Marker(markerPoint);
            map.addOverlay(marker);
            // åˆ›å»ºä¿¡æ¯çª—口内容
            const infoWindow = new BMapGL.InfoWindow(`
                    <div style="font-size:14px;">
                        <p>序号:${index + 1}</p>
                        <p>经度:${point.longitude}</p>
                        <p>纬度:${point.latitude}</p>
                        <p>时间:${point.createTime}</p>
                    </div>
                `);
            // ç‚¹å‡»æ ‡è®°æ˜¾ç¤ºä¿¡æ¯çª—口
            marker.addEventListener("click", () => {
                map.openInfoWindow(infoWindow, markerPoint);
            });
        });
        // 5. è°ƒæ•´åœ°å›¾è§†é‡Žä»¥æ˜¾ç¤ºæ•´ä¸ªè½¨è¿¹
        if (path.length > 1) {
            map.setViewport(path); // è‡ªåŠ¨é€‚é…è½¨è¿¹èŒƒå›´
        }
    }
    // é¡µé¢åŠ è½½å®ŒæˆåŽåˆå§‹åŒ–åœ°å›¾
    window.onload = initMap;
</script>
</body>
</html>
fzzy-igdss-web/src/main/resources/templates/security/snap/snapRecord/snapRecord.html
@@ -30,7 +30,7 @@
                </div>
            </form>
            <div class="btn-group-sm" role="group">
                <a class="btn btn-success" onclick="openConf()" shiro:hasPermission="web:security:snap:snapRecord:view">
                <a class="btn btn-success" onclick="openConf()">
                    <i class="fa fa-plus"></i> æŠ“拍配置
                </a>
            </div>
@@ -79,7 +79,7 @@
                                </div>
                                <div class="meta-item" style="width: 50%">
                                    <i class="layui-icon layui-icon-date"></i>
                                    <span th:text="${#dates.format(snapRecord.snapTime, 'yyyy-MM-dd HH:mm:ss')}"></span>
                                    <span th:text="${#dates.format(snapRecord.snapTime, 'yyyy-MM-dd HH:mm')}"></span>
                                </div>
                            </div>
                            <div class="meta-item">