页面完成
|
|
@ -15,6 +15,7 @@
|
||||||
"element-plus": "^2.6.1",
|
"element-plus": "^2.6.1",
|
||||||
"hls.js": "^1.6.15",
|
"hls.js": "^1.6.15",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
|
"odometer": "^0.4.8",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"three": "^0.183.2",
|
"three": "^0.183.2",
|
||||||
"v3-scroll": "^1.0.4",
|
"v3-scroll": "^1.0.4",
|
||||||
|
|
@ -2037,6 +2038,12 @@
|
||||||
"integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==",
|
"integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/odometer": {
|
||||||
|
"version": "0.4.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/odometer/-/odometer-0.4.8.tgz",
|
||||||
|
"integrity": "sha512-bfKuAhWE/qMCiX9bwX90c5bTpt7MDVeq1e6YsOHQrYokNhv9jhS5JbR9kg6i+FeWmDgalf3VUtwNx1aVaZ8cgg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
"element-plus": "^2.6.1",
|
"element-plus": "^2.6.1",
|
||||||
"hls.js": "^1.6.15",
|
"hls.js": "^1.6.15",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
|
"odometer": "^0.4.8",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"three": "^0.183.2",
|
"three": "^0.183.2",
|
||||||
"v3-scroll": "^1.0.4",
|
"v3-scroll": "^1.0.4",
|
||||||
|
|
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 964 B |
|
After Width: | Height: | Size: 559 B |
|
After Width: | Height: | Size: 468 KiB |
|
After Width: | Height: | Size: 477 KiB |
|
After Width: | Height: | Size: 459 KiB |
|
After Width: | Height: | Size: 468 KiB |
|
|
@ -168,7 +168,7 @@ watch(stationOptions, options => {
|
||||||
|
|
||||||
:deep(.el-input__wrapper) {
|
:deep(.el-input__wrapper) {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border: 0;
|
border: none !important;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,29 @@
|
||||||
<template>
|
<template>
|
||||||
<section class="traffic-1">1</section>
|
<section class="traffic-1">
|
||||||
|
<div class="rank-list">
|
||||||
|
<TrafficRankRow v-for="item in rankList" :key="item.rank" :item="item" />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import TrafficRankRow from './TrafficRankRow.vue'
|
||||||
|
|
||||||
|
const rankList = ref([
|
||||||
|
{ rank: 1, lines: '1,3,7,15', station: '上海火车站', type: '进出站', today: '8.40', compare: '6.20', percent: 92 },
|
||||||
|
{ rank: 2, lines: '1,3,7,15', station: '上海体育场', type: '进出站', today: '8.20', compare: '5.20', percent: 80 },
|
||||||
|
{ rank: 3, lines: '1,3,7,15', station: '延安西路', type: '进出站', today: '6.40', compare: '3.20', percent: 70 },
|
||||||
|
{ rank: 4, lines: '1,3,7,15', station: '上大路', type: '进出站', today: '6.20', compare: '6.20', percent: 50 },
|
||||||
|
{ rank: 5, lines: '1,3,7,15', station: '上海体育馆', type: '进出站', today: '6.20', compare: '6.20', percent: 40 },
|
||||||
|
{ rank: 6, lines: '1,3,7,15', station: '上海南站', type: '进出站', today: '6.20', compare: '6.20', percent: 38 },
|
||||||
|
{ rank: 7, lines: '1,3,7,15', station: '大渡河路', type: '进出站', today: '6.20', compare: '6.20', percent: 38 },
|
||||||
|
{ rank: 8, lines: '1,3,7,15', station: '大渡河路', type: '进出站', today: '6.20', compare: '6.20', percent: 38 },
|
||||||
|
{ rank: 9, lines: '1,3,7,15', station: '红宝石路', type: '进出站', today: '6.20', compare: '6.20', percent: 38 },
|
||||||
|
{ rank: 10, lines: '1,3,7,15', station: '吴中路', type: '进出站', today: '6.20', compare: '6.20', percent: 10 }
|
||||||
|
])
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.traffic-1 {
|
.traffic-1 {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -17,5 +39,18 @@
|
||||||
background: url('/imgs/traffic/1-bg.png') no-repeat center center;
|
background: url('/imgs/traffic/1-bg.png') no-repeat center center;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
|
|
||||||
|
.rank-list {
|
||||||
|
position: absolute;
|
||||||
|
top: 140px;
|
||||||
|
right: 10px;
|
||||||
|
bottom: 30px;
|
||||||
|
left: 0px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,162 +1,26 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="traffic-2">
|
<div class="traffic-2">
|
||||||
<!-- <div class="module-title">模块四</div> -->
|
<div class="rank-list">
|
||||||
<div class="module-body">
|
<TrafficRankRow v-for="item in rankList" :key="item.rank" :item="item" />
|
||||||
<div class="scroll-wrapper">
|
|
||||||
<div class="scroll-list">
|
|
||||||
<div class="list-item" v-for="(item, index) in stationData" :key="item.id + '-' + index">
|
|
||||||
<div class="cell-bg">
|
|
||||||
<div class="progress-bar">
|
|
||||||
<div class="progress-fill" :style="{ width: item.progress + '%' }"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="rank" :class="'rank-' + ((index % stationData.length) + 1)">{{ String(item.rank).padStart(2,
|
|
||||||
'0')
|
|
||||||
}}</div>
|
|
||||||
<div class="line-numbers">
|
|
||||||
<span v-for="lineId in getLineIdList(item.lineId)" :key="lineId" class="line-number-badge"
|
|
||||||
:style="getLineNumberStyle(lineId)">
|
|
||||||
{{ lineId }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="station-name">{{ item.stationName }}</div>
|
|
||||||
<div class="action-type">{{ item.actionType }}</div>
|
|
||||||
<!-- <div class="progress-bar">
|
|
||||||
<div class="progress-fill" :style="{ width: item.progress + '%' }"></div>
|
|
||||||
</div> -->
|
|
||||||
<div class="in-count">
|
|
||||||
<span class="highlight">{{ item.inCount }}</span>
|
|
||||||
<span class="unit">人</span>
|
|
||||||
</div>
|
|
||||||
<div class="out-count">
|
|
||||||
<span :style="getOutCountColorStyle(item)">{{ getOutCountPercentage(item) }}</span>
|
|
||||||
<span class="unit">%</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
import { ref } from 'vue'
|
||||||
import server from '@/utils/service'
|
import TrafficRankRow from './TrafficRankRow.vue'
|
||||||
|
|
||||||
const stationData = ref([])
|
const rankList = ref([
|
||||||
|
{ rank: 1, lines: '1,3,7,15', station: '上海火车站', type: '进出站', today: '18.40', compare: '6.20', percent: 92 },
|
||||||
const fetchStationMaxList = async () => {
|
{ rank: 2, lines: '3,7', station: '上海体育场', type: '进出站', today: '18.20', compare: '5.20', percent: 80 },
|
||||||
try {
|
{ rank: 3, lines: '1,3,7,15', station: '延安西路', type: '进出站', today: '16.40', compare: '3.20', percent: 70 },
|
||||||
const response = await server.getStationMaxList()
|
{ rank: 4, lines: '1,3,7', station: '上大路', type: '进出站', today: '6.20', compare: '6.20', percent: 50 },
|
||||||
if (response.data.success) {
|
{ rank: 5, lines: '1,15', station: '上海体育馆', type: '进出站', today: '6.20', compare: '6.20', percent: 40 },
|
||||||
// console.log('原始最大客流列表:', response.data.data)
|
{ rank: 6, lines: '1,3,7,15', station: '上海南站', type: '进出站', today: '6.20', compare: '6.20', percent: 38 },
|
||||||
const maxTotal = Math.max(...response.data.data.map(item => parseFloat(item.total)))
|
{ rank: 7, lines: '1,3,15', station: '大渡河路', type: '进出站', today: '6.20', compare: '6.20', percent: 38 },
|
||||||
stationData.value = response.data.data.map((item, index) => ({
|
{ rank: 8, lines: '1,3,7,15', station: '大渡河路', type: '进出站', today: '6.20', compare: '6.20', percent: 38 },
|
||||||
id: item.stationId,
|
{ rank: 9, lines: '1,3', station: '红宝石路', type: '进出站', today: '6.20', compare: '6.20', percent: 38 },
|
||||||
rank: index + 1,
|
{ rank: 10, lines: '15', station: '吴中路', type: '进出站', today: '6.20', compare: '6.20', percent: 10 }
|
||||||
stationName: item.stationName,
|
])
|
||||||
actionType: '进出站',
|
|
||||||
progress: Math.round((parseFloat(item.total) / maxTotal) * 100),
|
|
||||||
inCount: item.total,
|
|
||||||
outCount: item.compareTotal,
|
|
||||||
lineId: item.lineId
|
|
||||||
}))
|
|
||||||
console.log('站点最大客流列表:', stationData.value)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取站点最大客流列表失败:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentIndex = ref(0)
|
|
||||||
const transitionState = ref(true)
|
|
||||||
let timer = null
|
|
||||||
const itemHeight = 70
|
|
||||||
const visibleCount = 3
|
|
||||||
|
|
||||||
const displayList = computed(() => {
|
|
||||||
return stationData.value
|
|
||||||
})
|
|
||||||
|
|
||||||
const getLineIdList = (lineId) => {
|
|
||||||
if (!lineId) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return String(lineId).split(',').map(id => id.trim())
|
|
||||||
}
|
|
||||||
|
|
||||||
const getLineNumberStyle = (lineId) => {
|
|
||||||
const lineNum = parseInt(lineId)
|
|
||||||
const colors = {
|
|
||||||
1: '#E6002A',
|
|
||||||
2: '#8CC220',
|
|
||||||
3: '#FBD61D',
|
|
||||||
4: '#451E83',
|
|
||||||
5: '#944D9A',
|
|
||||||
6: '#D40068',
|
|
||||||
7: '#ED7010',
|
|
||||||
8: '#0095D9',
|
|
||||||
9: '#87CAED',
|
|
||||||
10: '#C6AFD4',
|
|
||||||
11: '#871C2B',
|
|
||||||
12: '#007A60',
|
|
||||||
13: '#E999C0',
|
|
||||||
14: '#9A982F',
|
|
||||||
15: '#C4AF8C',
|
|
||||||
16: '#98D1C0',
|
|
||||||
17: '#B6766C',
|
|
||||||
18: '#C09453'
|
|
||||||
}
|
|
||||||
const textColors = {
|
|
||||||
4: '#ffffff'
|
|
||||||
}
|
|
||||||
const bgColor = colors[lineNum] || '#ffcc00'
|
|
||||||
const textColor = textColors[lineNum] || '#000000'
|
|
||||||
return {
|
|
||||||
backgroundColor: bgColor,
|
|
||||||
color: textColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getOutCountPercentage = (item) => {
|
|
||||||
if (!item.outCount || item.outCount === 0) {
|
|
||||||
return '0.00'
|
|
||||||
}
|
|
||||||
const percentage = ((item.inCount - item.outCount) / item.inCount) * 100
|
|
||||||
// return Math.abs(percentage).toFixed(2)
|
|
||||||
return percentage.toFixed(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
const getOutCountColorStyle = (item) => {
|
|
||||||
if (!item.outCount || item.outCount === 0) {
|
|
||||||
return { color: '#ffffff', fontWeight: 'bold' }
|
|
||||||
}
|
|
||||||
const percentage = (item.inCount - item.outCount) / item.inCount
|
|
||||||
if (percentage > 0) {
|
|
||||||
return { color: '#ff3333', fontWeight: 'bold' }
|
|
||||||
} else if (percentage < 0) {
|
|
||||||
return { color: '#00ff00', fontWeight: 'bold' }
|
|
||||||
} else {
|
|
||||||
return { color: '#ffffff', fontWeight: 'bold' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const startScroll = () => {
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleScrollEnd = (index) => {
|
|
||||||
console.log('滚动到第', index, '项')
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
fetchStationMaxList()
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
if (timer) {
|
|
||||||
clearInterval(timer)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
@ -174,256 +38,22 @@ onUnmounted(() => {
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
|
|
||||||
.module-title {
|
|
||||||
height: 40px;
|
:deep(.traffic-rank-row) {
|
||||||
line-height: 40px;
|
grid-template-columns: 66fr 110fr 210fr 120fr 150fr 140fr;
|
||||||
padding: 0 16px;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #00d4ff;
|
|
||||||
background: rgba(0, 212, 255, 0.1);
|
|
||||||
border-bottom: 1px solid rgba(0, 212, 255, 0.2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-body {
|
.rank-list {
|
||||||
flex: 1;
|
position: absolute;
|
||||||
padding: 20px;
|
top: 140px;
|
||||||
overflow: hidden;
|
right: 22px;
|
||||||
|
bottom: 30px;
|
||||||
|
left: 14px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
.scroll-wrapper {
|
|
||||||
overflow: visible;
|
|
||||||
margin-top: 100px;
|
|
||||||
// background: yellow;
|
|
||||||
|
|
||||||
.scroll-list {
|
|
||||||
.list-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 70px;
|
|
||||||
width: 100%;
|
|
||||||
position: relative;
|
|
||||||
background: transparent;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
|
|
||||||
.cell-bg {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
width: 742.6px;
|
|
||||||
height: 44px;
|
|
||||||
background: url('/imgs/cell.png') no-repeat center center;
|
|
||||||
background-size: 100% 100%;
|
|
||||||
z-index: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rank {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
width: 40px;
|
|
||||||
height: 28px;
|
|
||||||
line-height: 28px;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 22px;
|
|
||||||
font-weight: 600;
|
|
||||||
margin-right: 16px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-left: 8px;
|
|
||||||
|
|
||||||
// 10个等级
|
|
||||||
&.rank-1 {
|
|
||||||
background: linear-gradient(90deg, #00FFFF 0%, #00FFFF 100%);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
background-clip: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.rank-2 {
|
|
||||||
background: linear-gradient(90deg, #00FFFF 0%, #00FFFF 100%);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
background-clip: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.rank-3 {
|
|
||||||
background: linear-gradient(90deg, #00FFFF 0%, #00FFFF 100%);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
background-clip: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.rank-4 {
|
|
||||||
background: linear-gradient(90deg, #fff 0%, #fff 100%);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
background-clip: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.rank-5 {
|
|
||||||
background: linear-gradient(90deg, #fff 0%, #fff 100%);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
background-clip: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.rank-6 {
|
|
||||||
background: linear-gradient(90deg, #fff 0%, #fff 100%);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
background-clip: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.rank-7 {
|
|
||||||
background: linear-gradient(90deg, #fff 0%, #fff 100%);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
background-clip: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.rank-8 {
|
|
||||||
background: linear-gradient(90deg, #fff 0%, #fff 100%);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
background-clip: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.rank-9 {
|
|
||||||
background: linear-gradient(90deg, #fff 0%, #fff 100%);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
background-clip: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.rank-10 {
|
|
||||||
background: linear-gradient(90deg, #fff 0%, #fff 100%);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
background-clip: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.line-numbers {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 2px;
|
|
||||||
width: 70px;
|
|
||||||
// margin-left: 10px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
// background-color: yellow;
|
|
||||||
|
|
||||||
.line-number-badge {
|
|
||||||
width: 20px;
|
|
||||||
height: 30px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: 700;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.station-name {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
width: 140px;
|
|
||||||
font-size: 23px;
|
|
||||||
color: #fff;
|
|
||||||
flex-shrink: 0;
|
|
||||||
// margin-left: 20px;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-type {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
width: 90px;
|
|
||||||
font-size: 23px;
|
|
||||||
color: #fff;
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-left: 76px;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
flex: 1;
|
|
||||||
height: 6px;
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
border-radius: 3px;
|
|
||||||
margin-left: 60px;
|
|
||||||
margin-top: 37px;
|
|
||||||
overflow: hidden;
|
|
||||||
width: 500px;
|
|
||||||
|
|
||||||
.progress-fill {
|
|
||||||
height: 100%;
|
|
||||||
background: linear-gradient(270deg, #00FFFF 0%, rgba(0, 183, 255, 0.18) 100%);
|
|
||||||
border-radius: 3px;
|
|
||||||
transition: width 0.3s ease;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.in-count {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
width: 150px;
|
|
||||||
text-align: left;
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #47ffff;
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-left: 50px;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
// background-color: yellow;
|
|
||||||
|
|
||||||
.highlight {
|
|
||||||
color: #47ffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.unit {
|
|
||||||
font-size: 10px;
|
|
||||||
color: #47ffff;
|
|
||||||
margin-left: 2px;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.out-count {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
width: 120px;
|
|
||||||
text-align: left;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #FFFFFF;
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-left: 0px;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
|
|
||||||
.unit {
|
|
||||||
font-size: 10px;
|
|
||||||
color: #FFFFFF;
|
|
||||||
margin-left: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,453 @@
|
||||||
<template>
|
<template>
|
||||||
<section class="traffic-3">3</section>
|
<section class="traffic-3">
|
||||||
|
<div class="chart-legend">
|
||||||
|
<span class="legend-item legend-item--actual">实际</span>
|
||||||
|
<span class="legend-item legend-item--compare">对比日(2026-03-05)</span>
|
||||||
|
<span class="legend-item legend-item--history">历史峰值</span>
|
||||||
|
<span class="legend-unit">单位:万人次</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="line-chart-grid">
|
||||||
|
<article v-for="(item, index) in chartCards" :key="item.lineId" class="line-chart-card">
|
||||||
|
<div class="line-chart-header">
|
||||||
|
<span class="line-badge" :style="getLineStyle(item.lineId)">{{ item.lineId }}</span>
|
||||||
|
<span class="line-title">累计<br>客流</span>
|
||||||
|
<div class="total-digits">
|
||||||
|
<span v-for="(_, digitIndex) in targetTotals[index]" :key="`${item.lineId}-${digitIndex}`" class="digit-box">
|
||||||
|
<span
|
||||||
|
:ref="el => setDigitRef(el, index, digitIndex)"
|
||||||
|
class="digit-odometer"
|
||||||
|
>0</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<v-chart class="line-chart" :option="item.option" autoresize />
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<script setup>
|
||||||
.traffic-3 {
|
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
||||||
position: absolute;
|
import VChart from 'vue-echarts'
|
||||||
left: 1689px;
|
import * as echarts from 'echarts'
|
||||||
top: 128px;
|
import Odometer from 'odometer'
|
||||||
width: 1250px;
|
import 'odometer/themes/odometer-theme-default.css'
|
||||||
height: 895px;
|
import { METRO_LINES } from '@/utils/const'
|
||||||
background: url('/imgs/traffic/3-bg.png') no-repeat center center;
|
|
||||||
background-size: cover;
|
const hours = ['5', '7', '9', '11', '13', '15', '17', '19', '21', '23']
|
||||||
|
const pointGlowSymbol = 'image:///imgs/traffic/4-item.png'
|
||||||
|
|
||||||
|
const lineCards = ref([
|
||||||
|
{
|
||||||
|
lineId: 3,
|
||||||
|
total: '2746782',
|
||||||
|
actual: [2600, 4700, 2400, 3900, 2300, 4100, 2600, 3300, 1700, 2200],
|
||||||
|
compare: [4850, 4550, 4650, 4300, 4300, 4550, 4700, 3900, 3900, 3000],
|
||||||
|
history: [5000, 4600, 4700, 4200, 4200, 4450, 4600, 4300, 3900, 3600]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lineId: 4,
|
||||||
|
total: '2746782',
|
||||||
|
actual: [700, 950, 1550, 4200, 1700, 1350, 1600, 1550, 2500, 1400],
|
||||||
|
compare: [1150, 1450, 2200, 3900, 2500, 1550, 1700, 1650, 2950, 2050],
|
||||||
|
history: [1350, 2200, 3100, 4450, 3000, 2650, 2550, 2750, 4200, 4550]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lineId: 7,
|
||||||
|
total: '2746782',
|
||||||
|
actual: [2900, 3300, 5000, 2300, 2000, 1900, 2600, 4050, 1700, 1700],
|
||||||
|
compare: [3200, 3700, 5200, 2500, 2400, 2500, 3100, 4700, 2400, 2400],
|
||||||
|
history: [3300, 4100, 5300, 2700, 2650, 2900, 3500, 4950, 3300, 2700]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lineId: 15,
|
||||||
|
total: '2746782',
|
||||||
|
actual: [3000, 3600, 4550, 2400, 3900, 2200, 3400, 4050, 2800, 3300],
|
||||||
|
compare: [4700, 4300, 4500, 4100, 4100, 4300, 4400, 4550, 4000, 3900],
|
||||||
|
history: [4850, 4350, 4550, 4100, 4100, 4300, 4450, 4500, 3950, 3600]
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
lineCards.value[0].total = '8846081'
|
||||||
|
}, 8000);
|
||||||
|
|
||||||
|
const chartCards = computed(() => {
|
||||||
|
return lineCards.value.map(item => ({
|
||||||
|
...item,
|
||||||
|
option: createChartOption(item)
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
const targetTotals = computed(() => lineCards.value.map(item => item.total.split('')))
|
||||||
|
const digitEls = []
|
||||||
|
const odometerInstances = []
|
||||||
|
|
||||||
|
const setDigitRef = (el, cardIndex, digitIndex) => {
|
||||||
|
if (!el) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
digitEls[cardIndex] ||= []
|
||||||
|
digitEls[cardIndex][digitIndex] = el
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const initOdometers = () => {
|
||||||
|
targetTotals.value.forEach((digits, cardIndex) => {
|
||||||
|
odometerInstances[cardIndex] ||= []
|
||||||
|
|
||||||
|
digits.forEach((_, digitIndex) => {
|
||||||
|
const el = digitEls[cardIndex]?.[digitIndex]
|
||||||
|
|
||||||
|
if (!el || odometerInstances[cardIndex][digitIndex]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
odometerInstances[cardIndex][digitIndex] = new Odometer({
|
||||||
|
el,
|
||||||
|
value: 0,
|
||||||
|
format: 'd',
|
||||||
|
duration: 1200,
|
||||||
|
theme: 'default'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateOdometers = () => {
|
||||||
|
targetTotals.value.forEach((digits, cardIndex) => {
|
||||||
|
digits.forEach((digit, digitIndex) => {
|
||||||
|
odometerInstances[cardIndex]?.[digitIndex]?.update(Number(digit))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(targetTotals, async () => {
|
||||||
|
await nextTick()
|
||||||
|
initOdometers()
|
||||||
|
updateOdometers()
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await nextTick()
|
||||||
|
initOdometers()
|
||||||
|
requestAnimationFrame(updateOdometers)
|
||||||
|
})
|
||||||
|
|
||||||
|
const getLineStyle = lineId => {
|
||||||
|
const theme = METRO_LINES[lineId] || {
|
||||||
|
bg: '#2bd5ff',
|
||||||
|
color: '#00194a'
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
backgroundColor: theme.bg,
|
||||||
|
color: theme.color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createChartOption = item => ({
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
animationDuration: 900,
|
||||||
|
grid: {
|
||||||
|
left: 6,
|
||||||
|
right: 34,
|
||||||
|
top: 16,
|
||||||
|
bottom: 14,
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: hours,
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: 'rgba(167, 205, 255, 0.45)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: 'rgba(226, 239, 255, 0.96)',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: 600,
|
||||||
|
margin: 10
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
min: 0,
|
||||||
|
max: 5000,
|
||||||
|
interval: 1000,
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: 'rgba(226, 239, 255, 0.96)',
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: 600,
|
||||||
|
margin: 10
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: 'rgba(219, 235, 255, 0.32)',
|
||||||
|
type: 'dashed',
|
||||||
|
width: 1.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'scatter',
|
||||||
|
data: hours.map((hour, index) => [hour, item.actual[index]]),
|
||||||
|
symbol: pointGlowSymbol,
|
||||||
|
symbolSize: [38, 88],
|
||||||
|
symbolOffset: [3, 0],
|
||||||
|
symbolKeepAspect: false,
|
||||||
|
silent: true,
|
||||||
|
z: 3,
|
||||||
|
tooltip: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '实际',
|
||||||
|
type: 'line',
|
||||||
|
data: item.actual,
|
||||||
|
smooth: false,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 5,
|
||||||
|
z: 5,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#20cfff',
|
||||||
|
width: 3,
|
||||||
|
shadowBlur: 8,
|
||||||
|
shadowColor: 'rgba(32, 207, 255, 0.55)'
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#dffbff',
|
||||||
|
borderColor: '#20cfff',
|
||||||
|
borderWidth: 2
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
|
{ offset: 0, color: 'rgba(27, 218, 255, 0.86)' },
|
||||||
|
{ offset: 0.58, color: 'rgba(21, 144, 226, 0.48)' },
|
||||||
|
{ offset: 1, color: 'rgba(13, 74, 166, 0.16)' }
|
||||||
|
])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '对比日(2026-03-05)',
|
||||||
|
type: 'line',
|
||||||
|
data: item.compare,
|
||||||
|
smooth: false,
|
||||||
|
symbol: 'none',
|
||||||
|
z: 3,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#f5c400',
|
||||||
|
width: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '历史峰值',
|
||||||
|
type: 'line',
|
||||||
|
data: item.history,
|
||||||
|
smooth: false,
|
||||||
|
symbol: 'none',
|
||||||
|
z: 3,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#ff1d1d',
|
||||||
|
width: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
backgroundColor: 'rgba(0, 18, 55, 0.92)',
|
||||||
|
borderColor: 'rgba(31, 205, 255, 0.45)',
|
||||||
|
textStyle: {
|
||||||
|
color: '#ffffff',
|
||||||
|
fontSize: 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.traffic-3 {
|
||||||
|
position: absolute;
|
||||||
|
left: 1689px;
|
||||||
|
top: 128px;
|
||||||
|
width: 1250px;
|
||||||
|
height: 895px;
|
||||||
|
background: url('/imgs/traffic/3-bg.png') no-repeat center center;
|
||||||
|
background-size: cover;
|
||||||
|
|
||||||
|
.chart-legend {
|
||||||
|
position: absolute;
|
||||||
|
top: 64px;
|
||||||
|
left: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-item {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 18px;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 0;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--actual::before {
|
||||||
|
background: #20d8ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--compare::before {
|
||||||
|
background: #f5c400;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--history::before {
|
||||||
|
background: #ff1d1d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-unit {
|
||||||
|
margin-left: -12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-chart-grid {
|
||||||
|
position: absolute;
|
||||||
|
top: 96px;
|
||||||
|
right: 23px;
|
||||||
|
bottom: 22px;
|
||||||
|
left: 23px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
grid-template-rows: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 27px 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-chart-card {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background: rgba(27, 83, 165, 0.25);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-chart-header {
|
||||||
|
position: absolute;
|
||||||
|
top: 36px;
|
||||||
|
left: 20px;
|
||||||
|
right: 22px;
|
||||||
|
z-index: 2;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-badge {
|
||||||
|
width: 39px;
|
||||||
|
height: 39px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-title {
|
||||||
|
margin-left: 21px;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total-digits {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
margin-left: 47px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.digit-box {
|
||||||
|
width: 39px;
|
||||||
|
height: 44px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1;
|
||||||
|
background: url('/imgs/traffic/3-item.png') no-repeat center center;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.digit-odometer {
|
||||||
|
width: 39px;
|
||||||
|
height: 44px;
|
||||||
|
display: block;
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 44px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.digit-odometer :deep(.odometer-digit),
|
||||||
|
.digit-odometer :deep(.odometer-digit-spacer) {
|
||||||
|
width: 39px;
|
||||||
|
height: 44px;
|
||||||
|
line-height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.digit-odometer :deep(.odometer-digit-inner) {
|
||||||
|
width: 39px;
|
||||||
|
height: 44px;
|
||||||
|
line-height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.digit-odometer :deep(.odometer-value) {
|
||||||
|
width: 39px;
|
||||||
|
height: 44px;
|
||||||
|
line-height: 44px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-chart {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 14px;
|
||||||
|
left: 10px;
|
||||||
|
height: 238px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -159,8 +159,8 @@ const chartOption = computed(() => ({
|
||||||
symbol: pointGlowSymbol,
|
symbol: pointGlowSymbol,
|
||||||
symbolSize: [47, 109],
|
symbolSize: [47, 109],
|
||||||
symbolOffset: [4, 0],
|
symbolOffset: [4, 0],
|
||||||
symbolKeepAspect: true,
|
symbolKeepAspect: false,
|
||||||
silent: true,
|
silent: false,
|
||||||
z: 4,
|
z: 4,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
show: false
|
show: false
|
||||||
|
|
|
||||||
|
|
@ -167,12 +167,13 @@ const summaryCards = ref([
|
||||||
.rank-no {
|
.rank-no {
|
||||||
min-width: 74px;
|
min-width: 74px;
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
font-style: italic;
|
|
||||||
font-weight: 900;
|
font-family: YouSheBiaoTiHei;
|
||||||
line-height: 1;
|
font-size: 20px;
|
||||||
|
font-weight: normal;
|
||||||
|
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
text-shadow: 0 0 12px rgba(0, 210, 255, 0.15);
|
|
||||||
|
|
||||||
@each $rank, $color in $rank-colors {
|
@each $rank, $color in $rank-colors {
|
||||||
&--#{$rank} {
|
&--#{$rank} {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<section class="traffic-6">6</section>
|
<section class="traffic-6">
|
||||||
|
<div class="traffic-image-list">
|
||||||
|
<img
|
||||||
|
v-for="item in imageList"
|
||||||
|
:key="item"
|
||||||
|
class="traffic-image"
|
||||||
|
:src="`/imgs/traffic/${item}`"
|
||||||
|
alt=""
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const imageList = ['image1.png', 'image2.png', 'image3.png', 'image4.png']
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.traffic-6 {
|
.traffic-6 {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -10,8 +24,29 @@
|
||||||
width: 2923px;
|
width: 2923px;
|
||||||
height: 535px;
|
height: 535px;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
background: url('/imgs/traffic/6-bg.png') no-repeat center center;
|
background: url('/imgs/traffic/6-bg.png') no-repeat center center;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.traffic-image-list {
|
||||||
|
position: absolute;
|
||||||
|
top: 58px;
|
||||||
|
left: 24px;
|
||||||
|
right: 24px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 702px 689px 702px 702px;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.traffic-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 419px;
|
||||||
|
display: block;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 4px solid rgba(0, 102, 255, 0.72);
|
||||||
|
box-sizing: border-box;
|
||||||
|
box-shadow: inset 0 0 18px rgba(0, 180, 255, 0.36), 0 0 10px rgba(0, 90, 255, 0.32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,162 @@
|
||||||
<template>
|
<template>
|
||||||
<section class="traffic-8"></section>
|
<section class="traffic-8">
|
||||||
|
<div class="ranking-panel">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="ranking-list">
|
||||||
|
<article v-for="item in rankingList" :key="item.rank" class="ranking-item">
|
||||||
|
<span class="ranking-index" :class="'ranking-index--r' + item.rank">
|
||||||
|
NO.{{ item.rank }}
|
||||||
|
</span>
|
||||||
|
<span class="line-badge" :style="getLineStyle(item.lineId)">
|
||||||
|
<template v-if="getLineNameParts(item.lineId).isNumberLine">
|
||||||
|
<strong>{{ getLineNameParts(item.lineId).number }}</strong>
|
||||||
|
<small>{{ getLineNameParts(item.lineId).suffix }}</small>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{ getLineName(item.lineId) }}
|
||||||
|
</template>
|
||||||
|
</span>
|
||||||
|
<div>{{ item.count }}条</div>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="comment-panel">
|
||||||
|
|
||||||
|
|
||||||
|
<label class="search-box">
|
||||||
|
<input v-model="keyword" type="text" aria-label="鎼滅储璇勮" />
|
||||||
|
<span class="search-icon"></span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="comment-list">
|
||||||
|
<article v-for="comment in filteredComments" :key="comment.id" class="comment-card">
|
||||||
|
<header>
|
||||||
|
<span class="comment-user">
|
||||||
|
<i class="user-icon"></i>
|
||||||
|
{{ comment.user }}
|
||||||
|
</span>
|
||||||
|
<time>{{ comment.date }} {{ comment.time }}</time>
|
||||||
|
<i class="status-icon"></i>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<p>{{ comment.content }}</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { METRO_LINES } from '@/utils/const'
|
||||||
|
|
||||||
|
const keyword = ref('')
|
||||||
|
|
||||||
|
const rankingList = [
|
||||||
|
{ rank: 1, lineId: 3, count: 20 },
|
||||||
|
{ rank: 2, lineId: 4, count: 2 },
|
||||||
|
{ rank: 3, lineId: 7, count: 11 },
|
||||||
|
{ rank: 4, lineId: 41, count: 11 },
|
||||||
|
{ rank: 5, lineId: 51, count: 11 }
|
||||||
|
]
|
||||||
|
|
||||||
|
const getLineTheme = lineId => {
|
||||||
|
return METRO_LINES[Number(lineId)] || {
|
||||||
|
bg: '#2bd5ff',
|
||||||
|
color: '#00194a',
|
||||||
|
name: `${lineId}号线`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getLineName = lineId => getLineTheme(lineId).name
|
||||||
|
|
||||||
|
const getLineNameParts = lineId => {
|
||||||
|
const name = getLineName(lineId)
|
||||||
|
const match = String(name).match(/^(\d+)(.*)$/)
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
return {
|
||||||
|
isNumberLine: false,
|
||||||
|
text: name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isNumberLine: true,
|
||||||
|
number: match[1],
|
||||||
|
suffix: match[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getLineStyle = lineId => {
|
||||||
|
const theme = getLineTheme(lineId)
|
||||||
|
|
||||||
|
return {
|
||||||
|
color: theme.color,
|
||||||
|
backgroundColor: theme.bg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const comments = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
user: '莲花楼楼主_CC',
|
||||||
|
date: '03-28',
|
||||||
|
time: '16:21',
|
||||||
|
content: '把15号线,改为,青浦线,或者,华为专线,有这么难吗。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
user: '莲花楼楼主_CC',
|
||||||
|
date: '03-28',
|
||||||
|
time: '16:21',
|
||||||
|
content: '把15号线,改为,青浦线,或者,华为专线,有这么难吗。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
user: '莲花楼楼主_CC',
|
||||||
|
date: '03-28',
|
||||||
|
time: '16:21',
|
||||||
|
content: '把15号线,改为,青浦线,或者,华为专线,有这么难吗。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
user: '莲花楼楼主_CC',
|
||||||
|
date: '03-28',
|
||||||
|
time: '16:21',
|
||||||
|
content: '把15号线,改为,青浦线,或者,华为专线,有这么难吗。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
user: '莲花楼楼主_CC',
|
||||||
|
date: '03-28',
|
||||||
|
time: '16:21',
|
||||||
|
content: '把15号线,改为,青浦线,或者,华为专线,有这么难吗。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
user: '莲花楼楼主_CC',
|
||||||
|
date: '03-28',
|
||||||
|
time: '16:21',
|
||||||
|
content: '把15号线,改为,青浦线,或者,华为专线,有这么难吗。'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const filteredComments = computed(() => {
|
||||||
|
const text = keyword.value.trim()
|
||||||
|
|
||||||
|
if (!text) {
|
||||||
|
return comments
|
||||||
|
}
|
||||||
|
|
||||||
|
return comments.filter(item => {
|
||||||
|
return item.user.includes(text) || item.content.includes(text)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.traffic-8 {
|
.traffic-8 {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -13,5 +168,239 @@
|
||||||
|
|
||||||
background: url('/imgs/traffic/8-bg.png') no-repeat center center;
|
background: url('/imgs/traffic/8-bg.png') no-repeat center center;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
|
|
||||||
|
.ranking-panel,
|
||||||
|
.comment-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 120px;
|
||||||
|
bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ranking-panel {
|
||||||
|
left: 29px;
|
||||||
|
width: 426px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-panel {
|
||||||
|
right: 24px;
|
||||||
|
width: 430px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ranking-list {
|
||||||
|
height: calc(100% - 62px);
|
||||||
|
margin-top: 12px;
|
||||||
|
padding-right: 8px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ranking-item {
|
||||||
|
height: 81px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 112px 1fr 86px;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
padding: 0 25px 0 24px;
|
||||||
|
|
||||||
|
background: rgba(44, 121, 236, 0.25);
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
|
||||||
|
div {
|
||||||
|
font-family: YouSheBiaoTiHei;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 400;
|
||||||
|
text-align: end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ranking-index {
|
||||||
|
font-family: YouSheBiaoTiHei;
|
||||||
|
color: #2bd5ff;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
|
||||||
|
&--r1 {
|
||||||
|
color: #ff1010;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--r2 {
|
||||||
|
color: #EEB30F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-badge {
|
||||||
|
justify-self: center;
|
||||||
|
min-width: 72px;
|
||||||
|
height: 30px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1;
|
||||||
|
margin-right: 10px;
|
||||||
|
|
||||||
|
strong,
|
||||||
|
small {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
margin-left: 1px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 22px;
|
||||||
|
width: 385px;
|
||||||
|
height: 32px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 38px 0 14px;
|
||||||
|
border: 2px solid rgba(37, 216, 255, 0.76);
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(16, 65, 143, 0.38);
|
||||||
|
box-shadow: inset 0 0 12px rgba(31, 211, 255, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box input {
|
||||||
|
width: 100%;
|
||||||
|
border: 0;
|
||||||
|
outline: 0;
|
||||||
|
background: transparent;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
right: 13px;
|
||||||
|
width: 17px;
|
||||||
|
height: 17px;
|
||||||
|
border: 2px solid #28d9ff;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
right: -5px;
|
||||||
|
bottom: -4px;
|
||||||
|
width: 8px;
|
||||||
|
height: 2px;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
border-radius: 2px;
|
||||||
|
background: #28d9ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-list {
|
||||||
|
position: absolute;
|
||||||
|
top: 56px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 13px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-card {
|
||||||
|
min-height: 104px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 15px 16px 14px 16px;
|
||||||
|
|
||||||
|
background: rgba(44, 121, 236, 0.25);
|
||||||
|
color: #ffffff;
|
||||||
|
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
time {
|
||||||
|
margin-left: auto;
|
||||||
|
color: rgba(235, 248, 255, 0.92);
|
||||||
|
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 24px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 12px 19px 0 34px;
|
||||||
|
color: rgba(230, 230, 230, 1);
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 26px;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-user {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
max-width: 224px;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 24px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-icon,
|
||||||
|
.status-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: inline-block;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-icon {
|
||||||
|
width: 21px;
|
||||||
|
height: 21px;
|
||||||
|
margin-right: 9px;
|
||||||
|
background-image: url('/imgs/traffic/8-item.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
margin-left: 7px;
|
||||||
|
background-image: url('/imgs/traffic/8-item1.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,255 @@
|
||||||
|
<template>
|
||||||
|
<article class="traffic-rank-row" :class="`traffic-rank-row--${fillType}`">
|
||||||
|
<div class="row-fill" :style="{ width: `${item.percent}%` }"></div>
|
||||||
|
|
||||||
|
<div class="rank-hex" :class="{ 'rank-hex--highlight': item.rank < 4 }">{{ rankText }}</div>
|
||||||
|
|
||||||
|
<div class="tag-cell">
|
||||||
|
<div class="line-list">
|
||||||
|
<span v-for="lineId in lineIds" :key="lineId" class="line-tag" :style="getLineStyle(lineId)">
|
||||||
|
{{ lineId }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="station-cell">
|
||||||
|
<span class="station-name">{{ item.station }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="type-cell">{{ item.type }}</div>
|
||||||
|
|
||||||
|
<div class="flow-cell flow-cell--today" :class="{ 'flow-cell--highlight': item.rank < 4 }">
|
||||||
|
<strong>{{ item.today }}</strong>
|
||||||
|
<span>万人</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flow-cell flow-cell--compare">
|
||||||
|
<strong>{{ item.compare }}</strong>
|
||||||
|
<span>万人</span>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { METRO_LINES } from '@/utils/const'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const rankText = computed(() => String(props.item.rank).padStart(2, '0'))
|
||||||
|
|
||||||
|
const fillType = computed(() => {
|
||||||
|
const rank = Number(props.item.rank)
|
||||||
|
|
||||||
|
if (rank === 1) {
|
||||||
|
return 'first'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rank === 2) {
|
||||||
|
return 'second'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rank === 3) {
|
||||||
|
return 'third'
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'normal'
|
||||||
|
})
|
||||||
|
|
||||||
|
const lineIds = computed(() => {
|
||||||
|
return String(props.item.lines || '')
|
||||||
|
.split(',')
|
||||||
|
.map(item => item.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
})
|
||||||
|
|
||||||
|
const getLineStyle = lineId => {
|
||||||
|
const theme = METRO_LINES[Number(lineId)] || {
|
||||||
|
bg: '#2bd5ff',
|
||||||
|
color: '#00194a'
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
backgroundColor: theme.bg + 'aa',
|
||||||
|
border:`1px solid ${theme.bg}`,
|
||||||
|
color: theme.color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.traffic-rank-row {
|
||||||
|
position: relative;
|
||||||
|
height: 44px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 66px 120px 200px 130px 160px 146px;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #ffffff;
|
||||||
|
background: linear-gradient(90deg, #0085ff00 0%, #00a3ff32 7%, #00a3ff33 46%, #0075ff0a 100%);
|
||||||
|
|
||||||
|
&--first {
|
||||||
|
--fill-start: #0085ff00;
|
||||||
|
--fill-center1: #00ffff33;
|
||||||
|
--fill-center2: #00ffff33;
|
||||||
|
--fill-end: #0075ff14;
|
||||||
|
--bar-start: #00b7ff2e;
|
||||||
|
--bar-end: #00FFFF;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&--second {
|
||||||
|
--fill-start: #00d9ff00;
|
||||||
|
--fill-center1: #00ffdd33;
|
||||||
|
--fill-center2: #00ffdd33;
|
||||||
|
--fill-end: #00d9ff14;
|
||||||
|
--bar-start: #00b7ff2e;
|
||||||
|
--bar-end: #00ffdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--third {
|
||||||
|
--fill-start: #0085ff00;
|
||||||
|
--fill-center1: #0099ff52;
|
||||||
|
--fill-center2: #00b7ff52;
|
||||||
|
--fill-end: #0075ff14 ;
|
||||||
|
--bar-start: #00b7ff2e;
|
||||||
|
--bar-end: #00b7ff;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&--normal {
|
||||||
|
--fill-start: #ffffff00;
|
||||||
|
--fill-center1: #f5f5f533;
|
||||||
|
--fill-center2: #f1f1f133;
|
||||||
|
--fill-end: #ffffff14 ;
|
||||||
|
--bar-start: #c6c6c62e;
|
||||||
|
--bar-end: #ffffffcc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.row-fill {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 66px;
|
||||||
|
z-index: 0;
|
||||||
|
background: linear-gradient(90deg, var(--fill-start) 0%,var(--fill-center1) 42%,var(--fill-center2) 80%, var(--fill-end) 100%);
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 6px;
|
||||||
|
background: linear-gradient(90deg, var(--bar-start) 0%, var(--bar-end) 100%);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-hex,
|
||||||
|
.station-cell,
|
||||||
|
.tag-cell,
|
||||||
|
.type-cell,
|
||||||
|
.flow-cell {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.rank-hex {
|
||||||
|
justify-self: center;
|
||||||
|
width: 53px;
|
||||||
|
height: 43px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 400;
|
||||||
|
background: url('/imgs/traffic/1-item.png') no-repeat center center;
|
||||||
|
background-size: contain;
|
||||||
|
|
||||||
|
&--highlight {
|
||||||
|
color: #17f7ff;
|
||||||
|
text-shadow: 0 0 7px rgba(21, 247, 255, 0.6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.station-cell {
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-cell {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-list {
|
||||||
|
width: 93px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 3px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-tag {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 1px;
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 18px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.station-name,
|
||||||
|
.type-cell {
|
||||||
|
overflow: hidden;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 23px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-cell {
|
||||||
|
text-align: center;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-cell {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: center;
|
||||||
|
color: #ffffff;
|
||||||
|
margin-left: 20px;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1;
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-left: 2px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--highlight {
|
||||||
|
color: #12f8ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||