|
Before Width: | Height: | Size: 4.7 MiB After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 249 B |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
|
@ -7,6 +7,7 @@ import App from './App.vue'
|
|||
import router from './router'
|
||||
import { globalScale } from './utils/scale'
|
||||
import './styles/global.scss'
|
||||
import './styles/el-fomat.scss'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
|
|
@ -20,4 +21,4 @@ app.use(ElementPlus)
|
|||
|
||||
app.mount('#app')
|
||||
|
||||
globalScale()
|
||||
// globalScale()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
.traffic-filter-popper.el-popper {
|
||||
border: 1px solid rgba(40, 177, 255, 0.55) !important;
|
||||
background: rgba(7, 31, 78, 0.96) !important;
|
||||
}
|
||||
|
||||
.traffic-filter-popper.el-popper .el-popper__arrow::before {
|
||||
border-color: rgba(40, 177, 255, 0.55) !important;
|
||||
background: rgba(7, 31, 78, 0.96) !important;
|
||||
}
|
||||
|
||||
|
||||
.traffic-filter-popper .el-select-dropdown__item {
|
||||
color: #dcecff;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.traffic-filter-popper .el-select-dropdown__item.is-hovering,
|
||||
.traffic-filter-popper .el-select-dropdown__item.hover,
|
||||
.traffic-filter-popper .el-select-dropdown__item.is-selected {
|
||||
color: #ffffff;
|
||||
background: rgba(22, 119, 214, 0.68);
|
||||
}
|
||||
|
||||
|
||||
.traffic-month-popper .el-picker-panel,
|
||||
.traffic-month-popper .el-date-picker,
|
||||
.traffic-month-popper .el-date-picker__header,
|
||||
.traffic-month-popper .el-picker-panel__content {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.traffic-month-popper .el-date-picker__header-label,
|
||||
.traffic-month-popper .el-picker-panel__icon-btn {
|
||||
color: #dcecff;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.traffic-month-popper .el-date-table-cell__text {
|
||||
color: #dcecff !important;
|
||||
|
||||
}
|
||||
|
||||
.traffic-month-popper .el-month-table td.current:not(.disabled) .el-date-table-cell__text {
|
||||
color: #ffffff;
|
||||
background: rgba(22, 119, 214, 0.68);
|
||||
|
||||
}
|
||||
|
|
@ -14,6 +14,18 @@
|
|||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: BlackOpsOne;
|
||||
src: url('/fonts/BlackOpsOne-Regular.woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: YouSheBiaoTiHei;
|
||||
src: url('/fonts/YouSheBiaoTiHei.woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
|
|
@ -25,6 +37,7 @@ html, body, #app {
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
overflow: scroll;
|
||||
font-family: 'Alibaba PuHuiTi 3.0', 'Microsoft YaHei', 'PingFang SC', sans-serif;
|
||||
background: var(--bg-dark);
|
||||
color: var(--text-primary);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
/** @format */
|
||||
|
||||
export const METRO_LINES = {
|
||||
1: { bg: "#E20930", color: "#ffffff", name: "1号线" },
|
||||
2: { bg: "#80BD2A", color: "#000000", name: "2号线" },
|
||||
3: { bg: "#F9D600", color: "#000000", name: "3号线" },
|
||||
4: { bg: "#482284", color: "#ffffff", name: "4号线" },
|
||||
5: { bg: "#944D9A", color: "#ffffff", name: "5号线" },
|
||||
6: { bg: "#E10066", color: "#ffffff", name: "6号线" },
|
||||
7: { bg: "#ED6E00", color: "#000000", name: "7号线" },
|
||||
8: { bg: "#0094D6", color: "#ffffff", name: "8号线" },
|
||||
9: { bg: "#85C8EC", color: "#000000", name: "9号线" },
|
||||
10: { bg: "#C6ADD2", color: "#000000", name: "10号线" },
|
||||
11: { bg: "#86202E", color: "#ffffff", name: "11号线" },
|
||||
12: { bg: "#0C775F", color: "#ffffff", name: "12号线" },
|
||||
13: { bg: "#E698BF", color: "#000000", name: "13号线" },
|
||||
14: { bg: "#616025", color: "#ffffff", name: "14号线" },
|
||||
15: { bg: "#C9B38E", color: "#000000", name: "15号线" },
|
||||
16: { bg: "#97D0BF", color: "#000000", name: "16号线" },
|
||||
17: { bg: "#B97970", color: "#ffffff", name: "17号线" },
|
||||
18: { bg: "#C29750", color: "#000000", name: "18号线" },
|
||||
41: { bg: "#B4B5B4", color: "#FFFFFF", name: "浦江线" },
|
||||
51: { bg: "#898989", color: "#FFFFFF", name: "市域机场线" },
|
||||
};
|
||||
|
|
@ -113,12 +113,6 @@ onUnmounted(() => {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@font-face {
|
||||
font-family: BlackOpsOne;
|
||||
src: url('/fonts/BlackOpsOne-Regular.ttf') format('truetype');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.dashboard-header {
|
||||
width: 4800px;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import DashboardHeader from '@/views/home/components/DashboardHeader.vue'
|
|||
width: 4800px;
|
||||
height: 1620px;
|
||||
position: relative;
|
||||
background: url('/imgs/mainBg.png') no-repeat center center;
|
||||
background: url('/imgs/mainBg.webp') no-repeat center center;
|
||||
background-size: cover;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,203 @@
|
|||
<template>
|
||||
<div class="station-filter" :style="themeStyle">
|
||||
<div class="filter-item " :style="getFilterItemStyle(lineDisplayText, 'line')">
|
||||
<el-select v-model="selectedLine" popper-class="traffic-filter-popper" :teleported="true">
|
||||
<el-option v-for="item in lineOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
<span class="filter-arrow" aria-hidden="true"></span>
|
||||
</div>
|
||||
|
||||
<div class="filter-item" :style="getFilterItemStyle(stationDisplayText, 'station')">
|
||||
<el-select v-model="selectedStation" popper-class="traffic-filter-popper" :teleported="true">
|
||||
<el-option v-for="item in stationOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
<span class="filter-arrow" aria-hidden="true"></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, watch } from 'vue'
|
||||
import metroMenuData from '@/utils/lineStationList.json'
|
||||
import { METRO_LINES } from '@/utils/const'
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
line: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
station: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:line', 'update:station'])
|
||||
const lineStationList = metroMenuData.lineStationList || []
|
||||
|
||||
const selectedLine = computed({
|
||||
get: () => props.line,
|
||||
set: value => emit('update:line', value)
|
||||
})
|
||||
|
||||
const selectedStation = computed({
|
||||
get: () => props.station,
|
||||
set: value => emit('update:station', value)
|
||||
})
|
||||
|
||||
|
||||
|
||||
const lineOptions = computed(() => {
|
||||
return lineStationList.map(item => ({
|
||||
label: item.nameCn,
|
||||
value: item.lineId
|
||||
}))
|
||||
})
|
||||
|
||||
const stationOptions = computed(() => {
|
||||
const currentLine = lineStationList.find(item => item.lineId === selectedLine.value)
|
||||
const stationList = currentLine?.stationList || []
|
||||
|
||||
return stationList.map(item => ({
|
||||
label: item.nameCn,
|
||||
value: item.statId,
|
||||
line: item.line
|
||||
}))
|
||||
})
|
||||
|
||||
const lineDisplayText = computed(() => {
|
||||
const currentLine = lineOptions.value.find(item => item.value === props.line)
|
||||
return String(currentLine?.label || lineOptions.value[0]?.label || '')
|
||||
})
|
||||
|
||||
const stationDisplayText = computed(() => {
|
||||
const currentStation = stationOptions.value.find(item => item.value === props.station)
|
||||
return String(currentStation?.label || stationOptions.value[0]?.label || '')
|
||||
})
|
||||
|
||||
|
||||
|
||||
const lineTheme = computed(() => {
|
||||
return METRO_LINES[Number(selectedLine.value)] || {
|
||||
bg: '#ED6E00',
|
||||
color: '#000000'
|
||||
}
|
||||
})
|
||||
|
||||
const themeStyle = computed(() => ({
|
||||
'--metro-bg': lineTheme.value.bg,
|
||||
'--metro-text': lineTheme.value.color,
|
||||
}))
|
||||
|
||||
const getFilterItemStyle = (text, type) => {
|
||||
const contentLength = Array.from(String(text || '')).length
|
||||
const rules = {
|
||||
line: { padding: 18, charWidth: 20 },
|
||||
station: { padding: 18, charWidth: 20 },
|
||||
month: { padding: 44, charWidth: 12 }
|
||||
}
|
||||
const rule = rules[type]
|
||||
|
||||
return {
|
||||
width: `${Math.max(rule.padding + contentLength * rule.charWidth)}px`
|
||||
}
|
||||
}
|
||||
|
||||
watch(stationOptions, options => {
|
||||
if (!options.length) {
|
||||
emit('update:station', '')
|
||||
return
|
||||
}
|
||||
|
||||
const hasCurrentStation = options.some(item => item.value === props.station)
|
||||
if (!hasCurrentStation) {
|
||||
emit('update:station', options[0].value)
|
||||
}
|
||||
}, { immediate: true })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.station-filter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 26px;
|
||||
height: 33px;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
height: 33px;
|
||||
width: max-content;
|
||||
margin-right: 10px;
|
||||
|
||||
|
||||
:deep(.el-select__wrapper) {
|
||||
box-sizing: border-box;
|
||||
border: 0;
|
||||
border-radius: 6px;
|
||||
box-shadow: none;
|
||||
padding: 0 0 0 5px;
|
||||
background: var(--metro-bg);
|
||||
}
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
box-sizing: border-box;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
background: transparent !important;
|
||||
|
||||
}
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
font-size: 22px;
|
||||
font-family: BlackOpsOne;
|
||||
color: #c5dfff !important;
|
||||
font-weight: 400;
|
||||
|
||||
text-shadow: 2px 2px 2px #0051ec !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
:deep(.el-select__placeholder),
|
||||
:deep(.el-select__selected-item) {
|
||||
color: var(--metro-text);
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
text-shadow: none;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
|
||||
|
||||
:deep(.el-select__caret),
|
||||
:deep(.el-input__suffix),
|
||||
:deep(.el-input__prefix),
|
||||
:deep(.el-input__suffix-inner),
|
||||
:deep(.el-icon-circle-close) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.filter-arrow {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: -20px;
|
||||
width: 14px;
|
||||
height: 9px;
|
||||
background: url('/imgs/traffic/7-item.png') no-repeat center center;
|
||||
background-size: 14px 9px;
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
<template>
|
||||
<div class="station-time-filter" :style="themeStyle">
|
||||
<div class="filter-item " :style="getFilterItemStyle(lineDisplayText, 'line')">
|
||||
<el-select v-model="selectedLine" popper-class="traffic-filter-popper" :teleported="true">
|
||||
<el-option v-for="item in lineOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
<span class="filter-arrow" aria-hidden="true"></span>
|
||||
</div>
|
||||
|
||||
<div class="filter-item" :style="getFilterItemStyle(stationDisplayText, 'station')">
|
||||
<el-select v-model="selectedStation" popper-class="traffic-filter-popper" :teleported="true">
|
||||
<el-option v-for="item in stationOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
<span class="filter-arrow" aria-hidden="true"></span>
|
||||
</div>
|
||||
|
||||
<div class="filter-item item-month" :style="getFilterItemStyle(monthDisplayText, 'month')">
|
||||
<el-config-provider :locale="zhCn">
|
||||
<el-date-picker v-model="selectedMonth" type="month" format="YYYY-M" value-format="YYYY-M"
|
||||
popper-class="traffic-filter-popper traffic-month-popper" :clearable="false" :editable="false"
|
||||
:teleported="true" :prefix-icon="Calendar" />
|
||||
</el-config-provider>
|
||||
<span class="filter-arrow" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, watch } from 'vue'
|
||||
import { Calendar } from '@element-plus/icons-vue'
|
||||
import dayjs from 'dayjs'
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||
import metroMenuData from '@/utils/lineStationList.json'
|
||||
import { METRO_LINES } from '@/utils/const'
|
||||
|
||||
import 'dayjs/locale/zh-cn'
|
||||
|
||||
dayjs.locale('zh-cn')
|
||||
|
||||
const props = defineProps({
|
||||
line: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
station: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
month: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:line', 'update:station', 'update:month'])
|
||||
const lineStationList = metroMenuData.lineStationList || []
|
||||
|
||||
const selectedLine = computed({
|
||||
get: () => props.line,
|
||||
set: value => emit('update:line', value)
|
||||
})
|
||||
|
||||
const selectedStation = computed({
|
||||
get: () => props.station,
|
||||
set: value => emit('update:station', value)
|
||||
})
|
||||
|
||||
const selectedMonth = computed({
|
||||
get: () => props.month,
|
||||
set: value => emit('update:month', value)
|
||||
})
|
||||
|
||||
const lineOptions = computed(() => {
|
||||
return lineStationList.map(item => ({
|
||||
label: item.nameCn,
|
||||
value: item.lineId
|
||||
}))
|
||||
})
|
||||
|
||||
const stationOptions = computed(() => {
|
||||
const currentLine = lineStationList.find(item => item.lineId === selectedLine.value)
|
||||
const stationList = currentLine?.stationList || []
|
||||
|
||||
return stationList.map(item => ({
|
||||
label: item.nameCn,
|
||||
value: item.statId,
|
||||
line: item.line
|
||||
}))
|
||||
})
|
||||
|
||||
const lineDisplayText = computed(() => {
|
||||
const currentLine = lineOptions.value.find(item => item.value === props.line)
|
||||
return String(currentLine?.label || lineOptions.value[0]?.label || '')
|
||||
})
|
||||
|
||||
const stationDisplayText = computed(() => {
|
||||
const currentStation = stationOptions.value.find(item => item.value === props.station)
|
||||
return String(currentStation?.label || stationOptions.value[0]?.label || '')
|
||||
})
|
||||
|
||||
const monthDisplayText = computed(() => String(props.month || ''))
|
||||
|
||||
const lineTheme = computed(() => {
|
||||
return METRO_LINES[Number(selectedLine.value)] || {
|
||||
bg: '#ED6E00',
|
||||
color: '#000000'
|
||||
}
|
||||
})
|
||||
|
||||
const themeStyle = computed(() => ({
|
||||
'--metro-bg': lineTheme.value.bg,
|
||||
'--metro-text': lineTheme.value.color,
|
||||
}))
|
||||
|
||||
const getFilterItemStyle = (text, type) => {
|
||||
const contentLength = Array.from(String(text || '')).length
|
||||
const rules = {
|
||||
line: { padding: 18, charWidth: 20 },
|
||||
station: { padding: 18, charWidth: 20 },
|
||||
month: { padding: 44, charWidth: 12 }
|
||||
}
|
||||
const rule = rules[type]
|
||||
|
||||
return {
|
||||
width: `${Math.max(rule.padding + contentLength * rule.charWidth)}px`
|
||||
}
|
||||
}
|
||||
|
||||
watch(stationOptions, options => {
|
||||
if (!options.length) {
|
||||
emit('update:station', '')
|
||||
return
|
||||
}
|
||||
|
||||
const hasCurrentStation = options.some(item => item.value === props.station)
|
||||
if (!hasCurrentStation) {
|
||||
emit('update:station', options[0].value)
|
||||
}
|
||||
}, { immediate: true })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.station-time-filter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 26px;
|
||||
height: 33px;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
height: 33px;
|
||||
width: max-content;
|
||||
margin-right: 10px;
|
||||
|
||||
|
||||
:deep(.el-select__wrapper) {
|
||||
box-sizing: border-box;
|
||||
border: 0;
|
||||
border-radius: 6px;
|
||||
box-shadow: none;
|
||||
padding: 0 0 0 5px;
|
||||
background: var(--metro-bg);
|
||||
}
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
box-sizing: border-box;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
background: transparent !important;
|
||||
|
||||
}
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
font-size: 22px;
|
||||
font-family: BlackOpsOne;
|
||||
color: #c5dfff !important;
|
||||
font-weight: 400;
|
||||
|
||||
text-shadow: 2px 2px 2px #0051ec !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
:deep(.el-select__placeholder),
|
||||
:deep(.el-select__selected-item) {
|
||||
color: var(--metro-text);
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
text-shadow: none;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
|
||||
|
||||
:deep(.el-select__caret),
|
||||
:deep(.el-input__suffix),
|
||||
:deep(.el-input__prefix),
|
||||
:deep(.el-input__suffix-inner),
|
||||
:deep(.el-icon-circle-close) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.item-month {
|
||||
margin-right: 0;
|
||||
margin-left: -10px;
|
||||
|
||||
.filter-arrow {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-arrow {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: -20px;
|
||||
width: 14px;
|
||||
height: 9px;
|
||||
background: url('/imgs/traffic/7-item.png') no-repeat center center;
|
||||
background-size: 14px 9px;
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
<template>
|
||||
<section class="traffic-4">
|
||||
<StationFilter class="traffic-4__filter" v-model:line="selectedLine" v-model:station="selectedStation"
|
||||
/>
|
||||
<div class="chart-shell">
|
||||
<v-chart class="traffic-4__chart" :option="chartOption" autoresize />
|
||||
</div>
|
||||
|
|
@ -7,10 +9,18 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { computed ,ref} from 'vue'
|
||||
import StationFilter from './StationFilter.vue'
|
||||
import VChart from 'vue-echarts'
|
||||
import * as echarts from 'echarts'
|
||||
|
||||
|
||||
|
||||
const selectedLine = ref('3')
|
||||
const selectedStation = ref('0313')
|
||||
|
||||
|
||||
|
||||
const hours = ['5', '7', '9', '11', '13', '15', '17', '19', '21', '23']
|
||||
|
||||
const topActual = [800, 900, 2100, 4050, 1500, 1450, 1200, 2300, 900, 900]
|
||||
|
|
@ -19,6 +29,11 @@ const topCompare = [1400, 1800, 3400, 4500, 2950, 2600, 2800, 4300, 4300, 4850]
|
|||
const bottomActual = [4800, 4400, 3000, 1600, 3150, 3500, 3350, 1850, 1450, 1650]
|
||||
const bottomCompare = [5400, 5300, 4900, 2200, 4700, 5000, 3850, 4700, 5350, 5350 ]
|
||||
|
||||
const pointGlowSymbol = 'image:///imgs/traffic/4-item.png'
|
||||
const pointGlowSymbol1 = 'image:///imgs/traffic/4-item1.png'
|
||||
const topPointGlow = hours.map((hour, index) => [hour, topActual[index]])
|
||||
const bottomPointGlow = hours.map((hour, index) => [hour, bottomActual[index]])
|
||||
|
||||
|
||||
const chartOption = computed(() => ({
|
||||
backgroundColor: 'transparent',
|
||||
|
|
@ -136,6 +151,36 @@ const chartOption = computed(() => ({
|
|||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: 'scatter',
|
||||
xAxisIndex: 0,
|
||||
yAxisIndex: 0,
|
||||
data: topPointGlow,
|
||||
symbol: pointGlowSymbol,
|
||||
symbolSize: [47, 109],
|
||||
symbolOffset: [4, 0],
|
||||
symbolKeepAspect: true,
|
||||
silent: true,
|
||||
z: 4,
|
||||
tooltip: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'scatter',
|
||||
xAxisIndex: 1,
|
||||
yAxisIndex: 1,
|
||||
data: bottomPointGlow,
|
||||
symbol: pointGlowSymbol1,
|
||||
symbolSize: [47, 109],
|
||||
symbolOffset: [4,0],
|
||||
symbolKeepAspect: true,
|
||||
silent: true,
|
||||
z: 4,
|
||||
tooltip: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '进出站',
|
||||
type: 'line',
|
||||
|
|
@ -251,27 +296,35 @@ const chartOption = computed(() => ({
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.traffic-4 {
|
||||
position: absolute;
|
||||
left: 2948px;
|
||||
top: 128px;
|
||||
width: 892px;
|
||||
height: 564.59px;
|
||||
background: url('/imgs/traffic/4-bg.png') no-repeat center center;
|
||||
background-size: cover;
|
||||
|
||||
.chart-shell {
|
||||
.traffic-4 {
|
||||
position: absolute;
|
||||
left: 56px;
|
||||
right: 8px;
|
||||
top: 66px;
|
||||
bottom: 4px;
|
||||
background: #041a4b;
|
||||
}
|
||||
left: 2948px;
|
||||
top: 128px;
|
||||
width: 892px;
|
||||
height: 564.59px;
|
||||
background: url('/imgs/traffic/4-bg.png') no-repeat center center;
|
||||
background-size: cover;
|
||||
|
||||
&__chart {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
|
||||
.traffic-4__filter {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 30px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.chart-shell {
|
||||
position: absolute;
|
||||
left: 56px;
|
||||
right: 8px;
|
||||
top: 66px;
|
||||
bottom: 4px;
|
||||
}
|
||||
|
||||
&__chart {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,90 @@
|
|||
<template>
|
||||
<section class="traffic-7"></section>
|
||||
<section class="traffic-7">
|
||||
<StationTimeFilter
|
||||
class="traffic-7__filter"
|
||||
v-model:line="selectedLine"
|
||||
v-model:station="selectedStation"
|
||||
v-model:month="selectedMonth"
|
||||
/>
|
||||
|
||||
<div class="activity-list">
|
||||
|
||||
<article v-for="activity in activityList" :key="activity.name" class="activity-card">
|
||||
<div class="activity-status" :class="`activity-status--${activity.statusType}`">
|
||||
{{ activity.status }}
|
||||
</div>
|
||||
|
||||
<h3 class="activity-name">{{ activity.name }}</h3>
|
||||
|
||||
<div class="activity-meta">
|
||||
<span class="activity-label">时间:</span>
|
||||
<span>{{ activity.time }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="activity.venue" class="activity-meta activity-meta--venue">
|
||||
<span class="activity-label">举办场馆:</span>
|
||||
<span>{{ activity.venue }}</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import StationTimeFilter from './StationTimeFilter.vue'
|
||||
|
||||
const selectedLine = ref('7')
|
||||
const selectedStation = ref('0753')
|
||||
const selectedMonth = ref('2026-5')
|
||||
|
||||
const activityList = [
|
||||
{
|
||||
name: 'CBE中国美容博览会',
|
||||
time: '2026/05/12--2026/05/14',
|
||||
venue: '新国际博览中心',
|
||||
status: '进行中',
|
||||
statusType: 'active'
|
||||
},
|
||||
{
|
||||
name: '上海插画艺术节',
|
||||
time: '2026/05/01--2026/05/03',
|
||||
status: '已结束',
|
||||
statusType: 'ended'
|
||||
},
|
||||
{
|
||||
name: '中国国际自行车展览会/中国国际电动车及零配件展览会/中国国际摩托车及零配件展览会/上海国际户外骑行装备展览会',
|
||||
time: '2026/05/05--2026/05/08',
|
||||
status: '已结束',
|
||||
statusType: 'ended'
|
||||
},
|
||||
{
|
||||
name: 'SIAL 西雅国际食品展览会(上海)',
|
||||
time: '2026/05/18--2026/05/20',
|
||||
status: '未开始',
|
||||
statusType: 'pending'
|
||||
},
|
||||
{
|
||||
name: '亚洲国际有机产品博览会',
|
||||
time: '2026/05/18--2026/05/20',
|
||||
status: '未开始',
|
||||
statusType: 'pending'
|
||||
},
|
||||
{
|
||||
name: '上海网络安全博览会暨高峰论坛',
|
||||
time: '2026/05/26--2026/05/28',
|
||||
status: '未开始',
|
||||
statusType: 'pending'
|
||||
},
|
||||
{
|
||||
name: '中国国际厨房、卫浴设施展览会',
|
||||
time: '2026/05/26--2026/05/29',
|
||||
status: '未开始',
|
||||
statusType: 'pending'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.traffic-7 {
|
||||
position: absolute;
|
||||
|
|
@ -11,5 +94,130 @@
|
|||
height: 880px;
|
||||
background: url('/imgs/traffic/7-bg.png') no-repeat center center;
|
||||
background-size: cover;
|
||||
|
||||
.traffic-7__filter {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 30px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.activity-list {
|
||||
position: absolute;
|
||||
top: 75px;
|
||||
right: 12px;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
padding-right: 6px;
|
||||
|
||||
}
|
||||
|
||||
.activity-card {
|
||||
position: relative;
|
||||
min-height: 89px;
|
||||
box-sizing: border-box;
|
||||
padding: 12px 104px 10px 31px;
|
||||
overflow: hidden;
|
||||
border-radius: 5px;
|
||||
letter-spacing: 0.03em;
|
||||
flex-shrink: 0;
|
||||
background: rgba(44, 121, 236, 0.35);
|
||||
}
|
||||
|
||||
.activity-empty {
|
||||
height: 100%;
|
||||
|
||||
:deep(.el-empty__description p) {
|
||||
color: rgba(220, 236, 255, 0.78);
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
.activity-name {
|
||||
margin: 0;
|
||||
color: #FFFFFF;
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
line-height: 32px;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
|
||||
.activity-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// gap: 37px;
|
||||
margin-top: 7px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
|
||||
font-size: 20px;
|
||||
font-weight: 400;
|
||||
line-height: 28px;
|
||||
|
||||
white-space: nowrap;
|
||||
&--venue {
|
||||
margin-top: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
.activity-label {
|
||||
color: rgba(228, 243, 255, 0.74);
|
||||
flex-shrink: 0;
|
||||
width: 94px;
|
||||
}
|
||||
|
||||
.activity-status {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
width: 91px;
|
||||
height: 35px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.5);
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -20px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 35px solid var(--status-bg-start);
|
||||
border-left: 20px solid transparent;
|
||||
}
|
||||
|
||||
&--active {
|
||||
--status-bg-start: #078b66;
|
||||
--status-bg-end: #08b279;
|
||||
color: #02FF5F;
|
||||
background: linear-gradient(90deg, var(--status-bg-start) 0%, var(--status-bg-end) 100%);
|
||||
}
|
||||
|
||||
&--ended {
|
||||
--status-bg-start: #9b7f7f;
|
||||
--status-bg-end: #bba1a1;
|
||||
color: #cfcfcf;
|
||||
background: linear-gradient(90deg, var(--status-bg-start) 0%, var(--status-bg-end) 100%);
|
||||
}
|
||||
|
||||
&--pending {
|
||||
--status-bg-start: #546174;
|
||||
--status-bg-end: #6f7c91;
|
||||
color: #f0f0f0;
|
||||
background: linear-gradient(90deg, var(--status-bg-start) 0%, var(--status-bg-end) 100%);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||