SocialNetworks_duan/src/views/GroupEvolution/component/groupPost.vue
2025-07-22 16:40:46 +08:00

269 lines
6.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>