新增:对话列表高亮显示当前对话

- 修改:对话添加hover样式
This commit is contained in:
yueliuli 2026-05-08 10:12:04 +08:00
parent 1559524338
commit 14bc8ffbf7
2 changed files with 67 additions and 6 deletions

View File

@ -1,9 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { CaretRight, Location } from '@element-plus/icons-vue' import { CaretRight, Location } from '@element-plus/icons-vue'
/** import { ref, shallowRef, watch } from 'vue'
* 项目列表展示组件
* 接收两个参数title字符串和data字符串数组
*/
const props = defineProps({ const props = defineProps({
title: { title: {
type: String, type: String,
@ -13,6 +11,10 @@ const props = defineProps({
type: Array, type: Array,
default: () => [], default: () => [],
}, },
currentTime: {
type: Number,
default: 0,
},
}) })
const emit = defineEmits(['click', 'play']) const emit = defineEmits(['click', 'play'])
@ -25,6 +27,49 @@ function handlePlayClick(e: Event, item: any[], index: number) {
e.stopPropagation() e.stopPropagation()
emit('play', item, index) emit('play', item, index)
} }
const dataCache = shallowRef<[number, string, string, string][]>([])
const indexMap = ref(new Map<number, number[]>())
const sortedTimes = ref<number[]>([])
watch(() => props.data, (newData) => {
const arr = newData as [number, string, string, string][]
dataCache.value = arr
const map = new Map<number, number[]>()
const times: number[] = []
for (let i = 0; i < arr.length; i++) {
const t = (arr[i][0] * 10) | 0
if (!map.has(t)) {
map.set(t, [])
times.push(t)
}
map.get(t)!.push(i)
}
times.sort((a, b) => a - b)
indexMap.value = map
sortedTimes.value = times
}, { immediate: true })
const currentHighlight = ref(-1)
watch(() => props.currentTime, (t) => {
const time = (t * 10) | 0
const indices = indexMap.value.get(time)
if (indices && indices.length > 0) {
currentHighlight.value = indices[0]
return
}
const times = sortedTimes.value
let prev = times[times.length - 1] || 0
for (let i = 0; i < times.length; i++) {
if (times[i] > time) {
prev = times[i - 1] ?? prev
break
}
}
const prevIndices = indexMap.value.get(prev)
currentHighlight.value = prevIndices?.[0] ?? 0
}, { immediate: true })
</script> </script>
<template> <template>
@ -40,7 +85,7 @@ function handlePlayClick(e: Event, item: any[], index: number) {
<!-- 滚动列表区域 --> <!-- 滚动列表区域 -->
<el-row style="flex: 1; overflow-y: auto;"> <el-row style="flex: 1; overflow-y: auto;">
<el-col> <el-col>
<el-row v-for="(item, index) in props.data" :key="index" class="message-item"> <el-row v-for="(item, index) in props.data" :key="index" class="message-item" :class="{ highlighted: currentHighlight === index }">
<div class="message-content" @click="handleItemClick(item as any[], index)"> <div class="message-content" @click="handleItemClick(item as any[], index)">
<div class="flex flex-col items-start"> <div class="flex flex-col items-start">
<div class="flex flex-row gap-2"> <div class="flex flex-row gap-2">
@ -97,6 +142,14 @@ function handlePlayClick(e: Event, item: any[], index: number) {
padding: 4px 0.75rem; padding: 4px 0.75rem;
} }
.message-item:hover {
background-color: var(--ep-bg-color-page);
}
.message-item.highlighted {
background-color: var(--ep-color-primary-light-8) !important;
}
.message-content { .message-content {
flex: 1; flex: 1;
cursor: pointer; cursor: pointer;

View File

@ -113,6 +113,10 @@ const data = ref<DataFormat>({
const selectedHazard = ref(-1) const selectedHazard = ref(-1)
const currentFrame = ref(0) const currentFrame = ref(0)
const videoCurrentTime = computed(() => {
return currentFrame.value / 30
})
const videoDuration = ref(0) const videoDuration = ref(0)
const FPS = 30 const FPS = 30
const totalFrames = computed(() => { const totalFrames = computed(() => {
@ -143,7 +147,8 @@ function updateCurrentFrame() {
const videoEl = videoRef.value const videoEl = videoRef.value
if (!videoEl) if (!videoEl)
return return
currentFrame.value = Math.floor(videoEl.currentTime * 30) const newFrame = Math.floor(videoEl.currentTime * 30)
currentFrame.value = newFrame
} }
function handleVideoLoadedMetadata() { function handleVideoLoadedMetadata() {
@ -229,6 +234,7 @@ function handleJumpToTimePoint(seconds: number) {
// currentTime // currentTime
videoEl.currentTime = seconds videoEl.currentTime = seconds
currentFrame.value = Math.floor(seconds * 30)
// //
videoEl.pause() videoEl.pause()
@ -244,6 +250,7 @@ function handlePlayAndSeek(item: any[]) {
return return
videoEl.currentTime = seconds videoEl.currentTime = seconds
currentFrame.value = Math.floor(seconds * 30)
videoEl.play() videoEl.play()
} }
@ -461,6 +468,7 @@ onMounted(() => {
<SubtitleList <SubtitleList
title="对话" title="对话"
:data="data.对话列表" :data="data.对话列表"
:current-time="videoCurrentTime"
@click="(item: any[]) => handleJumpToTimePoint(Number(item[0]))" @click="(item: any[]) => handleJumpToTimePoint(Number(item[0]))"
@play="(item: any[]) => handlePlayAndSeek(item)" @play="(item: any[]) => handlePlayAndSeek(item)"
/> />