233 lines
4.4 KiB
Vue
233 lines
4.4 KiB
Vue
<template>
|
|
<div class="rewards-punishments-container">
|
|
<!-- 标题栏 -->
|
|
<div class="rewards-header">
|
|
<span class="header-title">近期奖惩</span>
|
|
<div class="filter-tabs">
|
|
<div
|
|
v-for="tab in filterTabs"
|
|
:key="tab.value"
|
|
class="filter-tab"
|
|
:class="{ active: activeFilter === tab.value }"
|
|
@click="activeFilter = tab.value"
|
|
>
|
|
{{ tab.label }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 时间线列表 -->
|
|
<div class="timeline-container">
|
|
<div class="timeline-content">
|
|
<div class="timeline-line"></div>
|
|
<div class="timeline-items">
|
|
<div v-for="(item, index) in filteredList" :key="index" class="timeline-item">
|
|
<div class="timeline-dot" :class="item.type"></div>
|
|
<div class="timeline-card">
|
|
<div class="card-type" :class="item.type">{{ item.typeText }}</div>
|
|
<div class="card-description">{{ item.content }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed, watch } from 'vue'
|
|
|
|
defineOptions({ name: 'RecentRewardsPunishments' })
|
|
|
|
interface RewardPunishmentItem {
|
|
date?: string // 日期(可选)
|
|
type: 'reward' | 'danger'
|
|
typeText: string // 类型文本(表扬奖励/警告等)
|
|
content: string // 内容
|
|
}
|
|
|
|
// 过滤标签
|
|
const filterTabs = [
|
|
{ label: '全部', value: 'all' },
|
|
{ label: '奖励记录', value: 'reward' },
|
|
{ label: '惩罚记录', value: 'punishment' }
|
|
]
|
|
|
|
const activeFilter = ref<string>('all')
|
|
|
|
// 数据列表 - 使用 ref 存储
|
|
const listData = ref<RewardPunishmentItem[]>([])
|
|
|
|
// 过滤后的列表
|
|
const filteredList = computed(() => {
|
|
if (activeFilter.value === 'all') {
|
|
return listData.value
|
|
} else if (activeFilter.value === 'reward') {
|
|
return listData.value.filter((item) => item.type === 'reward')
|
|
} else {
|
|
return listData.value.filter((item) => item.type === 'danger')
|
|
}
|
|
})
|
|
|
|
// 可以通过 props 接收外部数据
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
data?: RewardPunishmentItem[]
|
|
}>(),
|
|
{
|
|
data: () => []
|
|
}
|
|
)
|
|
|
|
// 监听 props 数据变化
|
|
watch(
|
|
() => props.data,
|
|
(newData) => {
|
|
if (newData && newData.length > 0) {
|
|
listData.value = newData
|
|
}
|
|
},
|
|
{ immediate: true, deep: true }
|
|
)
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.rewards-punishments-container {
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
border: 1px solid rgba(56, 102, 141, 0.5);
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
}
|
|
|
|
// 标题栏
|
|
.rewards-header {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 14px;
|
|
}
|
|
|
|
.header-title {
|
|
font-size: 2vh;
|
|
font-weight: bold;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.filter-tabs {
|
|
display: flex;
|
|
gap: 8px;
|
|
}
|
|
|
|
.filter-tab {
|
|
padding: 6px 12px;
|
|
font-size: 12px;
|
|
color: rgba(255, 255, 255, 0.85);
|
|
background: rgba(56, 102, 141, 0.2);
|
|
border-radius: 4px;
|
|
|
|
&.active {
|
|
background: #37599d;
|
|
color: #ffffff;
|
|
}
|
|
}
|
|
|
|
// 时间线容器
|
|
.timeline-container {
|
|
flex: 1 1 0;
|
|
min-height: 0;
|
|
overflow-y: auto;
|
|
padding-left: 10px;
|
|
|
|
&::-webkit-scrollbar {
|
|
width: 0px;
|
|
}
|
|
}
|
|
|
|
.timeline-content {
|
|
position: relative;
|
|
padding-bottom: 8px;
|
|
}
|
|
|
|
// 时间线
|
|
.timeline-line {
|
|
position: absolute;
|
|
left: -2px;
|
|
top: 0;
|
|
bottom: 0;
|
|
width: 2px;
|
|
background: #5e7fef;
|
|
}
|
|
|
|
.timeline-items {
|
|
position: relative;
|
|
margin-left: 2px;
|
|
}
|
|
|
|
// 时间线项
|
|
.timeline-item {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: flex-start;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
// 时间线标记点
|
|
.timeline-dot {
|
|
position: absolute;
|
|
left: -8px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: 50%;
|
|
background: rgba(3, 173, 252, 0.8);
|
|
z-index: 1;
|
|
|
|
&.reward {
|
|
background: #10b981;
|
|
border-color: #10b981;
|
|
}
|
|
|
|
&.punishment {
|
|
background: #ff0000;
|
|
border-color: #ff0000;
|
|
}
|
|
}
|
|
|
|
// 事件卡片
|
|
.timeline-card {
|
|
flex: 1;
|
|
background: rgba(56, 102, 141, 0.15);
|
|
border: 1px solid rgba(56, 102, 141, 0.3);
|
|
border-radius: 4px;
|
|
padding: 8px 12px;
|
|
margin-left: 1px;
|
|
}
|
|
|
|
.card-type {
|
|
font-size: 1.8vh;
|
|
font-weight: 500;
|
|
margin-bottom: 4px;
|
|
color: rgba(255, 255, 255, 0.9);
|
|
|
|
&.reward {
|
|
color: #10b981;
|
|
}
|
|
|
|
&.punishment {
|
|
color: #ff0000;
|
|
}
|
|
}
|
|
|
|
.card-description {
|
|
font-size: 1.4vh;
|
|
color: rgba(255, 255, 255, 0.7);
|
|
line-height: 1.5;
|
|
}
|
|
</style>
|