HazardInspectUI/src/components/hazard_inspect/timeline/timeline.vue

148 lines
4.3 KiB
Vue

<script setup lang="ts">
import type { Arrayable } from '@vueuse/core'
import type { TimelineEmits, TimelineProps } from './timeline'
import { InfoFilled } from '@element-plus/icons-vue'
import { ElScrollbar, ElSlider } from 'element-plus'
import { onMounted, onUnmounted } from 'vue'
import { useTimeline } from './timeline'
import './timeline.css'
const props = defineProps<TimelineProps>()
const emit = defineEmits<TimelineEmits>()
const {
timelineContainer,
trackWidth,
timeTicks,
secondTicks,
playheadPos,
trackRows,
pxPerFrame,
minPxPerFrame,
maxPxPerFrame,
setZoom,
getHazardStyle,
handleHazardClick,
handleMouseMove,
handleMouseUp,
handlePlayheadMouseDown,
handleRulerClick,
initMounted,
openMessageBox,
initUnmounted,
} = useTimeline(props, emit)
onMounted(() => {
initMounted()
})
onUnmounted(() => {
initUnmounted()
})
</script>
<template>
<div class="timeline-wrapper">
<div class="timeline-toolbar">
<div class="timeline-title-container">
<span class="timeline-title">隐患时间线 ( {{ Object.keys(hazardRanges).length }} 个隐患)</span>
<el-button
type="info" dashed :icon="InfoFilled" size="small"
@click="openMessageBox(
'拖动播放头 控制播放进度。滚轮/拖动 时间轴前后移动。点击隐患编号跳转对应隐患。shift键+鼠标滚轮 缩放时间轴。缩放默认以播放头位置为中心,如果播放头不在可视范围内,会以时间轴中心缩放。',
'操作说明',
)"
>
操作说明
</el-button>
</div>
<div class="timeline-zoom-controls">
<div class="timeline-zoom-label">
<el-text type="info" size="small">
缩放
</el-text>
</div>
<ElSlider
:model-value="pxPerFrame"
:min="minPxPerFrame"
:max="maxPxPerFrame"
:step="0.1"
:show-tooltip="true"
:format-tooltip="(val: number) => `缩放: ${val.toFixed(2)}`"
class="zoom-slider"
@update:model-value="(val: Arrayable<number>) => setZoom(Array.isArray(val) ? val[0] : val)"
/>
</div>
</div>
<div
ref="timelineContainer"
class="timeline-container"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@mouseleave="handleMouseUp"
>
<div
id="playhead"
class="playhead"
:style="{ left: `${playheadPos}px` }"
@mousedown="handlePlayheadMouseDown"
>
<div class="playhead-indicator" />
</div>
<div class="timeline-content" :style="{ width: trackWidth }">
<div class="timeline-ruler">
<div
v-for="tick in secondTicks"
:key="tick.second"
class="time-tick"
:style="{ left: `${tick.position}px` }"
>
<div class="tick-mark minor" />
</div>
<div
v-for="tick in timeTicks"
:key="tick.second"
class="time-tick"
:style="{ left: `${tick.position}px` }"
>
<div class="tick-mark major" />
<span class="tick-label">{{ tick.label }}</span>
</div>
<div
class="timeline-ruler-click-area"
@click="handleRulerClick"
/>
</div>
<ElScrollbar :style="{ height: '100%' }">
<div id="tracks-list" class="tracks-list">
<div
v-for="(row, rowIndex) in trackRows"
:key="rowIndex"
class="track-row"
>
<div
v-for="hazard in row"
:key="hazard.id"
class="hazard-block"
:class="{ primary: hazard.level === 0, danger: hazard.level === 1 }"
:style="getHazardStyle(hazard.start, hazard.end)"
@click="handleHazardClick(hazard.id)"
>
<el-tooltip :content="hazard.tip" placement="top">
<div style="width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;">
{{ parseInt(hazard.id) + 1 }}
</div>
</el-tooltip>
</div>
</div>
</div>
</ElScrollbar>
</div>
</div>
</div>
</template>