<!DOCTYPE html>
|
<html lang="zh-CN">
|
<head>
|
<meta charset="utf-8">
|
<title>设备日志</title>
|
<meta name="renderer" content="webkit">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<!-- CSS -->
|
<link rel="stylesheet" href="../../static/vue/element/element.css">
|
<link rel="stylesheet" href="../../static/css/common.css">
|
<style>
|
body { margin: 0; padding: 0; background-color: #f0f2f5; height: 100vh; overflow: hidden; }
|
#app { height: 100%; padding: 10px; box-sizing: border-box; display: flex; flex-direction: column; }
|
.main-container { flex: 1; display: flex; overflow: hidden; }
|
.sidebar { width: 260px; margin-right: 10px; display: flex; flex-direction: column; }
|
.content { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
|
|
.box-card { height: 100%; display: flex; flex-direction: column; border: none; box-shadow: 0 1px 4px rgba(0,21,41,.08); }
|
.box-card .el-card__header { padding: 10px 15px; border-bottom: 1px solid #ebeef5; background: #fff; font-weight: bold; font-size: 15px; }
|
.box-card .el-card__body { flex: 1; overflow: auto; padding: 15px; }
|
|
.device-item { margin-bottom: 10px; }
|
.device-card { background-color: #fff; border: 1px solid #e6ebf5; border-radius: 4px; transition: all .3s; }
|
.device-card:hover { box-shadow: 0 2px 12px 0 rgba(0,0,0,.1); }
|
.device-info { display: flex; justify-content: space-between; align-items: center; padding: 15px; }
|
.device-info .info-text { font-size: 14px; color: #606266; }
|
.device-info .info-text b { color: #303133; margin-right: 5px; }
|
.device-info .tag-group { margin-left: 15px; }
|
|
.control-bar { margin-bottom: 15px; padding: 15px; background: #fff; border-radius: 4px; box-shadow: 0 1px 4px rgba(0,21,41,.08); }
|
|
/* Visualization styles */
|
.vis-control-panel { margin-bottom: 10px; display: flex; align-items: center; background: #f5f7fa; padding: 10px; border-radius: 4px; }
|
.vis-container { border: 1px solid #ebeef5; padding: 10px; border-radius: 4px; min-height: 400px; height: calc(80vh - 100px); overflow-y: auto; }
|
</style>
|
</head>
|
<body>
|
|
<div id="app" v-cloak>
|
<div class="main-container">
|
<!-- Sidebar: Date Tree -->
|
<div class="sidebar">
|
<el-card class="box-card" :body-style="{padding: '10px'}">
|
<div slot="header">日期选择</div>
|
<el-tree
|
ref="dateTree"
|
:data="dateTreeData"
|
:props="defaultProps"
|
node-key="id"
|
:default-expanded-keys="defaultExpandedKeys"
|
@node-click="handleNodeClick"
|
highlight-current
|
accordion>
|
<span class="custom-tree-node" slot-scope="{ node, data }">
|
<i v-if="data.children" class="el-icon-folder"></i>
|
<i v-else class="el-icon-document"></i>
|
<span style="margin-left: 5px;">{{ node.label }}</span>
|
</span>
|
</el-tree>
|
</el-card>
|
</div>
|
|
<!-- Main Content -->
|
<div class="content">
|
<!-- Search Bar -->
|
<div class="control-bar">
|
<el-form :inline="true" :model="searchForm" size="small" style="margin-bottom: -18px;">
|
<el-form-item label="选中日期">
|
<el-input v-model="searchForm.day" placeholder="yyyyMMdd" readonly style="width: 120px;" disabled></el-input>
|
</el-form-item>
|
<el-form-item label="设备类型">
|
<el-select v-model="searchForm.type" placeholder="全部" clearable style="width: 100px;">
|
<el-option label="Crn" value="Crn"></el-option>
|
<el-option label="Devp" value="Devp"></el-option>
|
<el-option label="Rgv" value="Rgv"></el-option>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="设备编号">
|
<el-input v-model="searchForm.deviceNo" placeholder="请输入编号" style="width: 120px;" clearable></el-input>
|
</el-form-item>
|
<el-form-item label="起始序号">
|
<el-input-number v-model="searchForm.offset" :min="0" controls-position="right" style="width: 100px;"></el-input-number>
|
</el-form-item>
|
<el-form-item label="最大文件">
|
<el-input-number v-model="searchForm.limit" :min="1" :max="1000" controls-position="right" style="width: 100px;"></el-input-number>
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" icon="el-icon-download" @click="handleBatchDownload" :disabled="!canDownload">下载</el-button>
|
</el-form-item>
|
</el-form>
|
</div>
|
|
<!-- Device List -->
|
<el-card class="box-card">
|
<div slot="header" class="clearfix">
|
<span>设备列表</span>
|
<span style="float: right; color: #909399; font-size: 12px;">共 {{ filteredDeviceList.length }} 个设备</span>
|
</div>
|
|
<div v-if="loading" style="text-align: center; padding: 20px;">
|
<i class="el-icon-loading" style="font-size: 24px;"></i>
|
</div>
|
<div v-else-if="filteredDeviceList.length === 0" style="text-align: center; color: #909399; padding: 50px;">
|
<i class="el-icon-info" style="margin-right: 5px;"></i>暂无数据,请先选择日期
|
</div>
|
<div v-else>
|
<div v-for="(item, index) in filteredDeviceList" :key="index" class="device-item">
|
<div class="device-card">
|
<div class="device-info">
|
<div>
|
<span class="info-text"><b>设备编号:</b> {{ item.deviceNo }}</span>
|
<span class="info-text tag-group"><b>类型:</b> {{ item.types.join(', ') }}</span>
|
<span class="info-text tag-group"><b>文件数:</b> {{ item.fileCount }}</span>
|
</div>
|
<div>
|
<template v-for="t in item.types">
|
<el-button size="mini" icon="el-icon-download" @click="downloadLog(item.deviceNo, t)">下载({{t}})</el-button>
|
<el-button size="mini" type="success" icon="el-icon-view" @click="visualizeLog(item.deviceNo, t)">可视化({{t}})</el-button>
|
</template>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</el-card>
|
</div>
|
</div>
|
|
<!-- Visualization Dialog -->
|
<el-dialog
|
:title="visualizationTitle"
|
:visible.sync="visualizationVisible"
|
width="90%"
|
top="5vh"
|
:close-on-click-modal="false"
|
@close="handleVisualizationClose">
|
|
<div class="vis-control-panel">
|
<el-button-group>
|
<el-button type="primary" icon="el-icon-video-play" @click="play" v-if="!isPlaying" size="small">播放</el-button>
|
<el-button type="primary" icon="el-icon-video-pause" @click="pause" v-else size="small">暂停</el-button>
|
<el-button type="warning" icon="el-icon-refresh-left" @click="reset" size="small">重置</el-button>
|
</el-button-group>
|
<div style="margin-left: 20px; flex: 1; padding-right: 20px;">
|
<el-slider v-model="sliderValue" :max="maxSliderValue" @change="sliderChange" @input="sliderInput" :format-tooltip="formatTooltip"></el-slider>
|
</div>
|
<div style="width: 210px; font-size: 14px; font-weight: bold; font-family: monospace; display: flex; align-items: center;">
|
{{ currentTimeStr }}
|
<el-popover
|
placement="bottom"
|
width="200"
|
trigger="click"
|
v-model="jumpVisible"
|
@show="initJumpTime">
|
<div style="text-align: center;">
|
<el-time-picker
|
v-model="jumpTime"
|
size="small"
|
placeholder="选择时间"
|
style="width: 100%; margin-bottom: 10px;"
|
:picker-options="{ selectableRange: '00:00:00 - 23:59:59' }">
|
</el-time-picker>
|
<el-button type="primary" size="mini" @click="confirmJump" style="width: 100%;">跳转</el-button>
|
</div>
|
<el-button type="text" slot="reference" icon="el-icon-edit" style="margin-left: 5px; padding: 0;" title="跳转时间"></el-button>
|
</el-popover>
|
</div>
|
<div style="margin-left: 10px;">
|
<el-select v-model="playbackSpeed" style="width: 100px;" size="small" placeholder="倍速">
|
<el-option :value="1" label="1x"></el-option>
|
<el-option :value="5" label="5x"></el-option>
|
<el-option :value="10" label="10x"></el-option>
|
<el-option :value="50" label="50x"></el-option>
|
<el-option :value="100" label="100x"></el-option>
|
<el-option :value="200" label="200x"></el-option>
|
<el-option :value="500" label="500x"></el-option>
|
<el-option :value="1000" label="1000x"></el-option>
|
</el-select>
|
</div>
|
</div>
|
|
<div class="vis-container">
|
<watch-crn-card v-if="visDeviceType === 'Crn'" ref="card" :auto-refresh="false" :read-only="true"></watch-crn-card>
|
<watch-rgv-card v-else-if="visDeviceType === 'Rgv'" ref="card" :auto-refresh="false" :read-only="true"></watch-rgv-card>
|
<watch-dual-crn-card v-else-if="visDeviceType === 'DualCrn'" ref="card" :auto-refresh="false" :read-only="true"></watch-dual-crn-card>
|
<devp-card v-else-if="visDeviceType === 'Devp'" ref="card" :auto-refresh="false" :read-only="true"></devp-card>
|
<div v-else style="text-align: center; padding: 50px; color: #909399;">
|
未知设备类型: {{ visDeviceType }}
|
</div>
|
</div>
|
</el-dialog>
|
|
<!-- Download Progress Dialog -->
|
<el-dialog title="文件下载中" :visible.sync="downloadDialogVisible" width="400px" :close-on-click-modal="false" :show-close="false">
|
<div style="padding: 10px;">
|
<div style="margin-bottom: 5px; font-size: 14px;">压缩生成进度</div>
|
<el-progress :percentage="buildProgress" :text-inside="true" :stroke-width="18"></el-progress>
|
<div style="margin: 20px 0 5px; font-size: 14px;">下载接收进度</div>
|
<el-progress :percentage="receiveProgress" :text-inside="true" :stroke-width="18" status="success"></el-progress>
|
</div>
|
</el-dialog>
|
</div>
|
|
<script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
|
<script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script>
|
<script src="../../static/vue/js/vue.min.js"></script>
|
<script src="../../static/vue/element/element.js"></script>
|
<script src="../../components/WatchCrnCard.js"></script>
|
<script src="../../components/WatchRgvCard.js"></script>
|
<script src="../../components/WatchDualCrnCard.js"></script>
|
<script src="../../components/DevpCard.js"></script>
|
<script type="text/javascript" src="../../static/js/deviceLogs/deviceLogs.js" charset="utf-8"></script>
|
</body>
|
</html>
|