269 lines
6.4 KiB
Vue
269 lines
6.4 KiB
Vue
<template>
|
||
<div class="postList-component">
|
||
<img
|
||
src="@/assets/images/head/ContextoftheincidentTitle.png"
|
||
alt=""
|
||
style="margin-top: -17px; margin-left: -11px"
|
||
/>
|
||
<div
|
||
class="post-list-wrapper"
|
||
ref="listRef"
|
||
@mouseenter="pauseScroll"
|
||
@mouseleave="resumeScroll"
|
||
>
|
||
<div class="scrolling-content">
|
||
<div
|
||
class="post-item"
|
||
v-for="(post, index) in posts"
|
||
:key="index"
|
||
:class="{ highlighted: post.highlighted }"
|
||
@click="handleLeaderPost(post)"
|
||
>
|
||
<div class="post-type">
|
||
<svg
|
||
width="20"
|
||
height="20"
|
||
viewBox="0 0 20 20"
|
||
fill="none"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
class="icon"
|
||
>
|
||
<rect opacity="0.1" width="20" height="20" rx="2" fill="#2B88DD" />
|
||
<path d="M5 4V7C5 7.55228 5.44772 8 6 8H7" stroke="#8EFBFF" />
|
||
<path d="M15 4V7C15 7.55228 14.5523 8 14 8H13" stroke="#8EFBFF" />
|
||
<path d="M5 16V13C5 12.4477 5.44772 12 6 12H7" stroke="#8EFBFF" />
|
||
<path d="M15 16V13C15 12.4477 14.5523 12 14 12H13" stroke="#8EFBFF" />
|
||
</svg>
|
||
<span class="post-type-text">帖文</span>
|
||
</div>
|
||
<span class="timestamp">{{ post.timestamp }}</span>
|
||
<span class="author">【{{ post.author }}】发布了帖文</span>
|
||
<div class="influence-section">
|
||
<div class="influence-label">互动: {{ post.influence }}</div>
|
||
<div class="influence-bar">
|
||
<div class="bar-track"></div>
|
||
<div class="bar-fill" :style="{ width: getInfluenceWidth(post.influence) }"></div>
|
||
<div class="bar-handle-wrapper" :style="{ left: getInfluenceWidth(post.influence) }">
|
||
<div class="bar-handle"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, defineProps, defineEmits, onMounted, onBeforeUnmount } from "vue";
|
||
const props = defineProps({
|
||
posts: {
|
||
type: Array,
|
||
default: () => []
|
||
}
|
||
});
|
||
|
||
const emit = defineEmits(["click:openDialog"]);
|
||
const animationDuration = computed(() => `${props.posts.length * 3}s`);
|
||
|
||
const maxInfluence = 10000;
|
||
|
||
const getInfluenceWidth = (influence) => {
|
||
const percentage = (influence / maxInfluence) * 100;
|
||
return `${Math.min(percentage, 100)}%`;
|
||
};
|
||
const handleLeaderPost = (item) => {
|
||
emit("click:openDialog", item);
|
||
console.log(item);
|
||
};
|
||
|
||
const listRef = ref(null);
|
||
let scrollTimer = null;
|
||
let direction = 1; // 1: 向下, -1: 向上
|
||
const scrollStep = 1; // 每步像素
|
||
const scrollInterval = 80; // 每40ms滚动一次,越大越慢
|
||
|
||
function startScroll() {
|
||
if (scrollTimer) return;
|
||
scrollTimer = setInterval(() => {
|
||
const el = listRef.value;
|
||
if (!el) return;
|
||
el.scrollTop += direction * scrollStep;
|
||
// 到底部
|
||
if (el.scrollTop + el.clientHeight >= el.scrollHeight) {
|
||
direction = -1;
|
||
}
|
||
// 到顶部
|
||
if (el.scrollTop <= 0) {
|
||
direction = 1;
|
||
}
|
||
}, scrollInterval);
|
||
}
|
||
|
||
function pauseScroll() {
|
||
if (scrollTimer) {
|
||
clearInterval(scrollTimer);
|
||
scrollTimer = null;
|
||
}
|
||
}
|
||
function resumeScroll() {
|
||
startScroll();
|
||
}
|
||
|
||
onMounted(() => {
|
||
startScroll();
|
||
});
|
||
onBeforeUnmount(() => {
|
||
pauseScroll();
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.postList-component {
|
||
width: 100%;
|
||
height: 100%;
|
||
.post-list-wrapper {
|
||
width: 100%;
|
||
height: 80%;
|
||
overflow: auto;
|
||
}
|
||
/* 滚动条整体样式 - WebKit浏览器 */
|
||
.post-list-wrapper::-webkit-scrollbar {
|
||
width: 3px; /* 垂直滚动条宽度 */
|
||
height: 5px; /* 水平滚动条高度 */
|
||
}
|
||
|
||
/* 滚动条滑块 */
|
||
.post-list-wrapper::-webkit-scrollbar-thumb {
|
||
background: rgba(147, 210, 255, 0.3); /* 蓝色半透明滑块 */
|
||
border-radius: 4px;
|
||
}
|
||
|
||
/* 鼠标悬停在滑块上的效果 */
|
||
.post-list-wrapper::-webkit-scrollbar-thumb:hover {
|
||
background: rgba(147, 210, 255, 0.5); /* 更明显的蓝色 */
|
||
}
|
||
.scrolling-content {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1px;
|
||
animation-name: scroll-up;
|
||
animation-timing-function: linear;
|
||
animation-iteration-count: infinite;
|
||
}
|
||
|
||
.post-list-wrapper:hover .scrolling-content {
|
||
animation-play-state: paused;
|
||
}
|
||
|
||
.post-item {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 36px;
|
||
padding: 0 16px;
|
||
background: linear-gradient(90deg, rgba(63, 169, 245, 0.16) 0%, rgba(0, 84, 187, 0) 100%);
|
||
border-left: 2px solid #3fa9f5;
|
||
color: white;
|
||
font-size: 14px;
|
||
gap: 12px;
|
||
flex-shrink: 0;
|
||
cursor: pointer;
|
||
margin: 8px 0;
|
||
}
|
||
|
||
.post-item.highlighted {
|
||
background: linear-gradient(90deg, rgba(63, 169, 245, 0.4) 0%, rgba(0, 84, 187, 0) 100%);
|
||
}
|
||
|
||
.post-type {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.post-type-text {
|
||
color: #8efbff;
|
||
font-size: 14px;
|
||
font-weight: 400;
|
||
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.25);
|
||
}
|
||
|
||
.timestamp {
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.author {
|
||
flex-grow: 1;
|
||
text-align: left;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.influence-section {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
flex-shrink: 0;
|
||
}
|
||
.influence-label {
|
||
width: 90px;
|
||
display: flex;
|
||
justify-content: flex-start;
|
||
}
|
||
.influence-bar {
|
||
width: 200px;
|
||
height: 10px;
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.bar-track {
|
||
width: 100%;
|
||
height: 2px;
|
||
background-color: rgba(208, 222, 238, 0.1);
|
||
position: absolute;
|
||
}
|
||
|
||
.bar-fill {
|
||
position: absolute;
|
||
height: 2px;
|
||
background: linear-gradient(270deg, #00f3ff 0%, #00527d 100%);
|
||
}
|
||
|
||
.bar-handle-wrapper {
|
||
position: absolute;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
height: 16px;
|
||
width: 16px;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.bar-handle {
|
||
width: 10px;
|
||
height: 10px;
|
||
border-radius: 50%;
|
||
background-color: #e0f1ff;
|
||
position: relative;
|
||
box-shadow: 0 0 6px 0 rgba(13, 97, 255, 0.8);
|
||
}
|
||
|
||
.bar-handle::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 16px;
|
||
height: 16px;
|
||
border-radius: 50%;
|
||
border: 1px solid rgba(21, 154, 255, 0.3);
|
||
}
|
||
}
|
||
</style>
|