|
|
@ -0,0 +1,3 @@
|
|||
# 开发环境配置
|
||||
# 使用相对路径,通过 vite proxy 代理到目标服务器
|
||||
VITE_API_BASE_URL=
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# 生产环境配置
|
||||
VITE_API_BASE_URL=http://10.104.10.151:8888
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
# 云智控大屏系统
|
||||
|
||||
基于 Vue3 + Element Plus 的数据可视化大屏系统,支持 4800x1600 大屏自适应缩放。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- **Vue3 Composition API** - 使用最新的 Vue3 语法
|
||||
- **Element Plus** - 企业级 UI 组件库
|
||||
- **模块化路由** - 清晰的路由结构,支持路由守卫
|
||||
- **Axios 封装** - 统一的请求拦截、错误处理
|
||||
- **SM4 加解密** - 国密算法支持(需要后端配合)
|
||||
- **自适应缩放** - 根据浏览器窗口自动缩放到指定尺寸
|
||||
- **大屏样式** - 深色主题,科技感设计
|
||||
|
||||
## 页面结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── views/
|
||||
│ ├── login/ # 登录页
|
||||
│ ├── layout/ # 布局组件
|
||||
│ ├── home/ # 首页
|
||||
│ ├── dashboard/ # 数据大屏
|
||||
│ └── error/ # 错误页面(404/500)
|
||||
├── utils/
|
||||
│ ├── request.js # Axios 请求封装
|
||||
│ ├── sm4.js # SM4 加解密
|
||||
│ ├── scale.js # 大屏缩放工具
|
||||
│ └── format.js # 格式化工具
|
||||
├── router/
|
||||
│ └── index.js # 路由配置
|
||||
└── styles/
|
||||
└── global.scss # 全局样式
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 安装依赖
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### 启动开发服务器
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 构建生产版本
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
## 默认登录账号
|
||||
|
||||
- 用户名:admin
|
||||
- 密码:admin123
|
||||
|
||||
## 大屏配置
|
||||
|
||||
页面默认尺寸为 **4800 x 1600**,系统会自动根据浏览器窗口缩放。
|
||||
|
||||
如需修改尺寸,修改以下文件:
|
||||
|
||||
- `src/utils/scale.js` - 修改 `baseWidth` 和 `baseHeight`
|
||||
|
||||
## 接口配置
|
||||
|
||||
修改 `src/utils/request.js` 中的 `baseURL`,或创建 `.env` 文件:
|
||||
|
||||
```env
|
||||
VITE_API_BASE_URL=http://your-api-server.com/api
|
||||
```
|
||||
|
||||
## SM4 加密
|
||||
|
||||
系统默认使用 SM4 加密传输数据。如需调整:
|
||||
|
||||
1. 修改 `src/utils/sm4.js` 中的 `defaultKey`
|
||||
2. 确保后端使用相同的密钥
|
||||
|
||||
如不需要加密,可以修改 `request.js` 中的请求拦截器。
|
||||
|
||||
## 路由说明
|
||||
|
||||
| 路径 | 页面 | 需要认证 |
|
||||
|------|------|----------|
|
||||
| /login | 登录页 | 否 |
|
||||
| /home | 首页 | 是 |
|
||||
| /dashboard | 数据大屏 | 是 |
|
||||
| /404 | 404错误页 | 否 |
|
||||
| /500 | 500错误页 | 否 |
|
||||
|
||||
## 静态资源使用
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
public/ # 不经过构建处理的静态资源
|
||||
├── imgs/ # 全局图片(logo、背景图等)
|
||||
├── js/ # 第三方JS库
|
||||
├── fonts/ # 字体文件
|
||||
└── data/ # 静态JSON数据
|
||||
|
||||
src/assets/ # 需要构建处理的资源
|
||||
├── imgs/ # 组件级图片
|
||||
├── icons/ # SVG图标
|
||||
└── styles/ # SCSS样式文件
|
||||
```
|
||||
|
||||
### 使用示例
|
||||
|
||||
**public 目录资源(直接通过根路径访问):**
|
||||
```vue
|
||||
<template>
|
||||
<img src="/imgs/logo.png" alt="logo">
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getPublicImageUrl } from '@/utils/assets'
|
||||
const logoUrl = getPublicImageUrl('imgs/logo.png')
|
||||
</script>
|
||||
```
|
||||
|
||||
**assets 目录资源(通过别名访问):**
|
||||
```vue
|
||||
<template>
|
||||
<img src="@/assets/imgs/avatar.png" alt="avatar">
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAssetImageUrl } from '@/utils/assets'
|
||||
const avatarUrl = getAssetImageUrl('imgs/avatar.png')
|
||||
</script>
|
||||
```
|
||||
|
||||
**加载静态JSON数据:**
|
||||
```javascript
|
||||
import { loadJsonData } from '@/utils/assets'
|
||||
const config = await loadJsonData('config.json')
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
yun3v2/
|
||||
├── index.html
|
||||
├── package.json
|
||||
├── vite.config.js
|
||||
├── src/
|
||||
│ ├── main.js
|
||||
│ ├── App.vue
|
||||
│ ├── views/
|
||||
│ ├── utils/
|
||||
│ ├── router/
|
||||
│ └── styles/
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 技术栈
|
||||
|
||||
- Vue 3.4
|
||||
- Vue Router 4.3
|
||||
- Pinia 2.1
|
||||
- Element Plus 2.6
|
||||
- Axios 1.6
|
||||
- Vite 5.1
|
||||
- SCSS
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
# Tomcat 部署配置说明
|
||||
|
||||
## 问题原因
|
||||
Vue Router 使用 history 模式,刷新页面时 Tomcat 会尝试查找对应的物理路径,导致 404 错误。
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 方案一:配置 Tomcat rewrite 规则(推荐)
|
||||
|
||||
1. **下载 rewrite.jar**
|
||||
- 下载 Tomcat rewrite 模块:https://tomcat.apache.org/download-90.cgi
|
||||
- 将 `rewrite.jar` 放到 `$CATALINA_HOME/lib` 目录
|
||||
|
||||
2. **创建 WEB-INF/rewrite.config**
|
||||
在 `wdk/WEB-INF/` 目录下创建 `rewrite.config` 文件,内容如下:
|
||||
```
|
||||
# 所有非文件请求都转发到 index.html
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^.*$ /wdk/index.html [L]
|
||||
```
|
||||
|
||||
3. **修改 WEB-INF/web.xml**
|
||||
在 `wdk/WEB-INF/web.xml` 中添加 rewrite 过滤器:
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
|
||||
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
|
||||
version="4.0">
|
||||
|
||||
<display-name>Yun3v2 Application</display-name>
|
||||
|
||||
<!-- Rewrite Filter -->
|
||||
<filter>
|
||||
<filter-name>rewriteFilter</filter-name>
|
||||
<filter-class>org.apache.rewrite.RewriteFilter</filter-class>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>rewriteFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<!-- Welcome File -->
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.html</welcome-file>
|
||||
</welcome-file-list>
|
||||
</web-app>
|
||||
```
|
||||
|
||||
### 方案二:使用 hash 模式(简单但 URL 不美观)
|
||||
|
||||
修改 `src/router/index.js`:
|
||||
```javascript
|
||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(), // 使用 hash 模式
|
||||
routes
|
||||
})
|
||||
```
|
||||
|
||||
这样 URL 会变成:`http://localhost:8080/wdk/#/home`
|
||||
|
||||
### 方案三:配置 Tomcat 全局 error-page
|
||||
|
||||
在 `wdk/WEB-INF/web.xml` 中添加:
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
|
||||
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
|
||||
version="4.0">
|
||||
|
||||
<display-name>Yun3v2 Application</display-name>
|
||||
|
||||
<!-- 404 错误页面重定向到 index.html -->
|
||||
<error-page>
|
||||
<error-code>404</error-code>
|
||||
<location>/index.html</location>
|
||||
</error-page>
|
||||
|
||||
<!-- Welcome File -->
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.html</welcome-file>
|
||||
</welcome-file-list>
|
||||
</web-app>
|
||||
```
|
||||
|
||||
## 部署步骤
|
||||
|
||||
1. **重新构建项目**
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
2. **复制文件到 Tomcat**
|
||||
```
|
||||
dist/ → tomcat/webapps/wdk/
|
||||
```
|
||||
|
||||
3. **创建 WEB-INF 目录和配置文件**
|
||||
```
|
||||
tomcat/webapps/wdk/WEB-INF/
|
||||
├── web.xml
|
||||
└── rewrite.config (如果使用方案一)
|
||||
```
|
||||
|
||||
4. **重启 Tomcat**
|
||||
|
||||
## 推荐方案
|
||||
- **生产环境**:使用方案一(rewrite 规则)
|
||||
- **快速测试**:使用方案三(error-page)
|
||||
- **内网简单部署**:使用方案二(hash 模式)
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>上海地铁运三运营有限公司数字监管平台</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; }
|
||||
html, body, #app { width: 100%; height: 100%; overflow: auto; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 403 B |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
|
@ -0,0 +1,21 @@
|
|||
<template>
|
||||
<section class="traffic-1">1</section>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.traffic-1 {
|
||||
position: absolute;
|
||||
left: 21.33px;
|
||||
top: 128px;
|
||||
width: 861.53px;
|
||||
height: 894px;
|
||||
opacity: 1;
|
||||
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: url('/imgs/traffic/1-bg.png') no-repeat center center;
|
||||
background-size: cover;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
<template>
|
||||
<div class="traffic-2">
|
||||
<!-- <div class="module-title">模块四</div> -->
|
||||
<div class="module-body">
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import server from '@/utils/service'
|
||||
|
||||
const stationData = ref([])
|
||||
|
||||
const fetchStationMaxList = async () => {
|
||||
try {
|
||||
const response = await server.getStationMaxList()
|
||||
if (response.data.success) {
|
||||
// console.log('原始最大客流列表:', response.data.data)
|
||||
const maxTotal = Math.max(...response.data.data.map(item => parseFloat(item.total)))
|
||||
stationData.value = response.data.data.map((item, index) => ({
|
||||
id: item.stationId,
|
||||
rank: index + 1,
|
||||
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>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.traffic-2 {
|
||||
position: absolute;
|
||||
left: 892.45px;
|
||||
top: 128px;
|
||||
width: 787.46px;
|
||||
height: 894px;
|
||||
opacity: 1;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: url('/imgs/traffic/2-bg.png') no-repeat center center;
|
||||
background-size: cover;
|
||||
backdrop-filter: blur(10px);
|
||||
|
||||
.module-title {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
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 {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
overflow: hidden;
|
||||
|
||||
.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>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<template>
|
||||
<section class="traffic-3">3</section>
|
||||
</template>
|
||||
|
||||
<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;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
<template>
|
||||
<section class="traffic-4">
|
||||
<div class="chart-shell">
|
||||
<v-chart class="traffic-4__chart" :option="chartOption" autoresize />
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import VChart from 'vue-echarts'
|
||||
import * as echarts from 'echarts'
|
||||
|
||||
const hours = ['5', '7', '9', '11', '13', '15', '17', '19', '21', '23']
|
||||
|
||||
const topActual = [800, 900, 2100, 4050, 1500, 1450, 1200, 2300, 900, 900]
|
||||
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 chartOption = computed(() => ({
|
||||
backgroundColor: 'transparent',
|
||||
animationDuration: 900,
|
||||
animationDurationUpdate: 700,
|
||||
animationEasing: 'cubicOut',
|
||||
|
||||
grid: [
|
||||
{
|
||||
left: 0,
|
||||
right: 16,
|
||||
top: 15,
|
||||
height: 225,
|
||||
containLabel: true
|
||||
},
|
||||
{
|
||||
left: 0,
|
||||
right: 16,
|
||||
bottom: 20,
|
||||
height: 225,
|
||||
containLabel: true
|
||||
}
|
||||
],
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: hours,
|
||||
gridIndex: 0,
|
||||
axisLine: {
|
||||
show: true
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: 'rgba(226, 239, 255, 0.95)',
|
||||
fontSize: 13,
|
||||
fontWeight: 600,
|
||||
margin: 12
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: hours,
|
||||
gridIndex: 1,
|
||||
position: 'top',
|
||||
axisLine: {
|
||||
show: true
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
gridIndex: 0,
|
||||
interval: 1000,
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: 'rgba(222, 236, 255, 0.9)',
|
||||
fontSize: 12,
|
||||
margin: 10
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(225, 238, 255, 0.48)',
|
||||
type: 'dashed',
|
||||
width: 1.5,
|
||||
dashOffset: 10
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
gridIndex: 1,
|
||||
interval: 1000,
|
||||
inverse: true,
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: 'rgba(222, 236, 255, 0.9)',
|
||||
fontSize: 12,
|
||||
margin: 10
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(225, 238, 255, 0.48)',
|
||||
type: 'dashed',
|
||||
width: 1.5,
|
||||
dashOffset: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '进出站',
|
||||
type: 'line',
|
||||
xAxisIndex: 0,
|
||||
yAxisIndex: 0,
|
||||
data: topActual,
|
||||
smooth: false,
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
z: 5,
|
||||
lineStyle: {
|
||||
color: '#44d9ff',
|
||||
width: 4,
|
||||
cap: 'round',
|
||||
join: 'round',
|
||||
shadowBlur: 6,
|
||||
shadowColor: 'rgba(68, 217, 255, 0.25)'
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#ffffff',
|
||||
borderColor: 'rgba(167, 244, 255, 0.55)',
|
||||
borderWidth: 1,
|
||||
shadowBlur: 10,
|
||||
shadowColor: 'rgba(90, 224, 255, 0.48)'
|
||||
},
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(42, 200, 255, 0.9)' },
|
||||
{ offset: 0.55, color: 'rgba(28, 132, 222, 0.5)' },
|
||||
{ offset: 1, color: 'rgba(20, 88, 188, 0.2)' }
|
||||
])
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '进出站对比',
|
||||
type: 'line',
|
||||
xAxisIndex: 0,
|
||||
yAxisIndex: 0,
|
||||
data: topCompare,
|
||||
smooth: false,
|
||||
symbol: 'none',
|
||||
z: 4,
|
||||
lineStyle: {
|
||||
color: '#F5C10B',
|
||||
width: 3,
|
||||
cap: 'round',
|
||||
join: 'round'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '换乘站',
|
||||
type: 'line',
|
||||
xAxisIndex: 1,
|
||||
yAxisIndex: 1,
|
||||
data: bottomActual,
|
||||
smooth: false,
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
z: 5,
|
||||
lineStyle: {
|
||||
color: '#29ffd0',
|
||||
width: 4,
|
||||
cap: 'round',
|
||||
join: 'round',
|
||||
shadowBlur: 6,
|
||||
shadowColor: 'rgba(41, 255, 208, 0.22)'
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#ffffff',
|
||||
borderColor: 'rgba(180, 255, 238, 0.55)',
|
||||
borderWidth: 1.5,
|
||||
shadowBlur: 10,
|
||||
shadowColor: 'rgba(93, 255, 220, 0.42)'
|
||||
},
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(16, 172, 138, 0.2)' },
|
||||
{ offset: 0.42, color: 'rgba(22, 202, 168, 0.5)' },
|
||||
{ offset: 1, color: 'rgba(22, 224, 174, 0.9)' }
|
||||
])
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '换乘站对比',
|
||||
type: 'line',
|
||||
xAxisIndex: 1,
|
||||
yAxisIndex: 1,
|
||||
data: bottomCompare,
|
||||
smooth: false,
|
||||
symbol: 'none',
|
||||
z: 4,
|
||||
lineStyle: {
|
||||
color: '#F5C10B',
|
||||
width: 3,
|
||||
cap: 'round',
|
||||
join: 'round'
|
||||
}
|
||||
}
|
||||
],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 12
|
||||
},
|
||||
formatter: params => {
|
||||
const { name, seriesName, value } = params[0]
|
||||
return `${name}时<br>${seriesName}: ${value}`
|
||||
}
|
||||
}
|
||||
}))
|
||||
</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 {
|
||||
position: absolute;
|
||||
left: 56px;
|
||||
right: 8px;
|
||||
top: 66px;
|
||||
bottom: 4px;
|
||||
background: #041a4b;
|
||||
}
|
||||
|
||||
&__chart {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
<template>
|
||||
<section class="traffic-5">
|
||||
<div class="panel-body">
|
||||
<div class="rank-column">
|
||||
<div v-for="item in leftList" :key="item.rank" class="rank-card">
|
||||
<div class="rank-card__top">
|
||||
<div class="rank-info">
|
||||
<span class="rank-no" :class="`rank-no--${item.rank}`">NO.{{ item.rank }}</span>
|
||||
<span class="rank-name">{{ item.name }}</span>
|
||||
</div>
|
||||
<div class="rank-value">
|
||||
<span class="rank-value__num">{{ item.value }}</span>
|
||||
<img src="/imgs/traffic/5-item1.png" alt="" class="rank-value__icon">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rank-bar">
|
||||
<div class="rank-bar__fill" :style="{ width: `${item.percent}%` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="summary-column">
|
||||
<div v-for="item in rightTopList" :key="item.rank" class="rank-card rank-card--compact">
|
||||
<div class="rank-card__top">
|
||||
<div class="rank-info">
|
||||
<span class="rank-no" :class="`rank-no--${item.rank}`">NO.{{ item.rank }}</span>
|
||||
<span class="rank-name">{{ item.name }}</span>
|
||||
</div>
|
||||
<div class="rank-value">
|
||||
<span class="rank-value__num">{{ item.value }}</span>
|
||||
<img src="/imgs/traffic/5-item1.png" alt="" class="rank-value__icon">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rank-bar">
|
||||
<div class="rank-bar__fill" :style="{ width: `${item.percent}%` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-for="card in summaryCards" :key="card.label" class="summary-card">
|
||||
<div class="summary-card__icon">
|
||||
<img src="/imgs/traffic/5-item.png" :alt="card.label" class="summary-card__icon-img">
|
||||
</div>
|
||||
|
||||
<div class="summary-card__content">
|
||||
<div class="summary-label">{{ card.label }}</div>
|
||||
<div class="summary-value">
|
||||
<span class="summary-value__num">{{ card.value }}</span>
|
||||
<span class="summary-value__unit">个</span>
|
||||
<img src="/imgs/traffic/5-item1.png" alt="" class="rank-value__icon">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
const rankList = ref([
|
||||
{ rank: 1, name: '安检方式及设备', value: 57, percent: 100 },
|
||||
{ rank: 2, name: '求助', value: 52, percent: 71 },
|
||||
{ rank: 3, name: '车站管理', value: 50, percent: 66 },
|
||||
{ rank: 4, name: '安检方式及设备', value: 26, percent: 58 },
|
||||
{ rank: 5, name: '寻物', value: 16, percent: 33 },
|
||||
{ rank: 6, name: '客运组织', value: 10, percent: 36 },
|
||||
{ rank: 7, name: '运营计划', value: 8, percent: 28 }
|
||||
])
|
||||
|
||||
setTimeout(() => {
|
||||
rankList.value[0].value = 82
|
||||
rankList.value[0].percent = 50
|
||||
}, 2000)
|
||||
|
||||
const leftList = computed(() => rankList.value.slice(0, 5))
|
||||
const rightTopList = computed(() => rankList.value.slice(5, 7))
|
||||
|
||||
const summaryCards = ref([
|
||||
{ label: '年度客诉总数', value: 282 },
|
||||
{ label: '投诉(A类)', value: 282 }
|
||||
])
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$card-bg: #0d2e71;
|
||||
$text-main: #ffffff;
|
||||
$text-soft: #f4fbff;
|
||||
$text-muted: rgba(255, 255, 255, 0.7);
|
||||
$rank-colors: (
|
||||
1: #ff342d,
|
||||
2: #ffca17,
|
||||
3: #32dfff,
|
||||
4: #32dfff,
|
||||
5: #32dfff,
|
||||
6: #32dfff,
|
||||
7: #32dfff
|
||||
);
|
||||
|
||||
@mixin card-shell($padding: null, $background: $card-bg) {
|
||||
position: relative;
|
||||
background: $background;
|
||||
|
||||
@if $padding !=null {
|
||||
padding: $padding;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
.traffic-5 {
|
||||
position: absolute;
|
||||
left: 3850px;
|
||||
top: 128px;
|
||||
width: 930px;
|
||||
height: 564.59px;
|
||||
padding: 22px 18px 16px;
|
||||
box-sizing: border-box;
|
||||
background: url('/imgs/traffic/5-bg.png') no-repeat center center;
|
||||
background-size: cover;
|
||||
|
||||
.panel-body {
|
||||
position: absolute;
|
||||
top: 70px;
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.rank-column,
|
||||
.summary-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.rank-card {
|
||||
@include card-shell(18px 18px 14px);
|
||||
|
||||
height: 84px;
|
||||
box-shadow: none;
|
||||
|
||||
&--compact {
|
||||
height: 84px;
|
||||
}
|
||||
|
||||
&__top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.rank-info {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.rank-no {
|
||||
min-width: 74px;
|
||||
font-size: 26px;
|
||||
font-style: italic;
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
letter-spacing: 1px;
|
||||
text-transform: uppercase;
|
||||
text-shadow: 0 0 12px rgba(0, 210, 255, 0.15);
|
||||
|
||||
@each $rank, $color in $rank-colors {
|
||||
&--#{$rank} {
|
||||
color: $color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rank-name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 1px;
|
||||
color: $text-soft;
|
||||
}
|
||||
|
||||
.rank-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding-left: 12px;
|
||||
flex-shrink: 0;
|
||||
|
||||
&__num {
|
||||
font-size: 34px;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
color: $text-main;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
display: block;
|
||||
width: 18px;
|
||||
height: 22px;
|
||||
flex-shrink: 0;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.rank-bar {
|
||||
margin-top: 8px;
|
||||
margin-left: 2px;
|
||||
height: 6px;
|
||||
overflow: visible;
|
||||
border-radius: 999px;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
|
||||
&__fill {
|
||||
height: 100%;
|
||||
border-radius: 999px;
|
||||
background: #18FEFE;
|
||||
box-shadow: 0px 0px 4px 0px rgba(24, 254, 254, 0.6);
|
||||
transition: width 0.8s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.summary-card {
|
||||
@include card-shell(16px 20px, $card-bg);
|
||||
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 150px 1fr;
|
||||
align-items: center;
|
||||
box-shadow: none;
|
||||
|
||||
&__icon {
|
||||
width: 124px;
|
||||
height: 104px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
&__icon-img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.summary-label {
|
||||
font-size: 24px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 1px;
|
||||
color: #f6fbff;
|
||||
}
|
||||
|
||||
.summary-value {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 10px;
|
||||
|
||||
&__num {
|
||||
font-size: 38px;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
color: $text-main;
|
||||
}
|
||||
|
||||
&__unit {
|
||||
font-size: 16px;
|
||||
color: $text-muted;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<section class="traffic-6">6</section>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.traffic-6 {
|
||||
position: absolute;
|
||||
left: 16px;
|
||||
top: 1052px;
|
||||
width: 2923px;
|
||||
height: 535px;
|
||||
opacity: 1;
|
||||
background: url('/imgs/traffic/6-bg.png') no-repeat center center;
|
||||
background-size: cover;
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<template>
|
||||
<section class="traffic-7"></section>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.traffic-7 {
|
||||
position: absolute;
|
||||
left: 2948px;
|
||||
top: 707px;
|
||||
width: 892px;
|
||||
height: 880px;
|
||||
background: url('/imgs/traffic/7-bg.png') no-repeat center center;
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<section class="traffic-8"></section>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.traffic-8 {
|
||||
position: absolute;
|
||||
left: 3853.1px;
|
||||
top: 707px;
|
||||
width: 934px;
|
||||
height: 884.69px;
|
||||
opacity: 1;
|
||||
|
||||
background: url('/imgs/traffic/8-bg.png') no-repeat center center;
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,123 +1,34 @@
|
|||
<template>
|
||||
<div class="traffic-container">
|
||||
<section class="traffic-panel panel-rank-left"></section>
|
||||
<section class="traffic-panel panel-rank-middle"></section>
|
||||
<section class="traffic-panel panel-trend"></section>
|
||||
<section class="traffic-panel panel-flow"></section>
|
||||
<section class="traffic-panel panel-resource"></section>
|
||||
<section class="traffic-panel panel-video"></section>
|
||||
<section class="traffic-panel panel-list"></section>
|
||||
<section class="traffic-panel panel-top"></section>
|
||||
<section class="traffic-panel panel-events"></section>
|
||||
<Traffic1 />
|
||||
<Traffic2 />
|
||||
<Traffic3 />
|
||||
<Traffic4 />
|
||||
<Traffic5 />
|
||||
<Traffic6 />
|
||||
<Traffic7 />
|
||||
<Traffic8 />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Traffic1 from './components/Traffic1.vue'
|
||||
import Traffic2 from './components/Traffic2.vue'
|
||||
import Traffic3 from './components/Traffic3.vue'
|
||||
import Traffic4 from './components/Traffic4.vue'
|
||||
import Traffic5 from './components/Traffic5.vue'
|
||||
import Traffic6 from './components/Traffic6.vue'
|
||||
import Traffic7 from './components/Traffic7.vue'
|
||||
import Traffic8 from './components/Traffic8.vue'
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.traffic-container {
|
||||
width: 4800px;
|
||||
height: 1514px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.traffic-panel {
|
||||
height: 1620px;
|
||||
position: absolute;
|
||||
border: 2px solid rgba(0, 186, 255, 0.72);
|
||||
background:
|
||||
linear-gradient(135deg, rgba(0, 90, 180, 0.18), rgba(0, 14, 56, 0.48)),
|
||||
rgba(2, 22, 70, 0.42);
|
||||
box-shadow:
|
||||
inset 0 0 28px rgba(0, 188, 255, 0.16),
|
||||
0 0 18px rgba(0, 150, 255, 0.2);
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&::before {
|
||||
left: -2px;
|
||||
top: -2px;
|
||||
border-left: 5px solid #00e5ff;
|
||||
border-top: 5px solid #00e5ff;
|
||||
}
|
||||
|
||||
&::after {
|
||||
right: -2px;
|
||||
bottom: -2px;
|
||||
border-right: 5px solid #00e5ff;
|
||||
border-bottom: 5px solid #00e5ff;
|
||||
}
|
||||
}
|
||||
|
||||
.panel-rank-left {
|
||||
left: 16px;
|
||||
top: 28px;
|
||||
width: 880px;
|
||||
height: 820px;
|
||||
}
|
||||
|
||||
.panel-rank-middle {
|
||||
left: 916px;
|
||||
top: 28px;
|
||||
width: 780px;
|
||||
height: 820px;
|
||||
}
|
||||
|
||||
.panel-trend {
|
||||
left: 1716px;
|
||||
top: 28px;
|
||||
width: 1260px;
|
||||
height: 820px;
|
||||
}
|
||||
|
||||
.panel-flow {
|
||||
left: 2996px;
|
||||
top: 28px;
|
||||
width: 886px;
|
||||
height: 820px;
|
||||
}
|
||||
|
||||
.panel-resource {
|
||||
left: 3902px;
|
||||
top: 28px;
|
||||
width: 882px;
|
||||
height: 820px;
|
||||
}
|
||||
|
||||
.panel-video {
|
||||
left: 16px;
|
||||
top: 878px;
|
||||
width: 2948px;
|
||||
height: 608px;
|
||||
}
|
||||
|
||||
.panel-list {
|
||||
left: 2984px;
|
||||
top: 878px;
|
||||
width: 888px;
|
||||
height: 608px;
|
||||
}
|
||||
|
||||
.panel-top {
|
||||
left: 3892px;
|
||||
top: 878px;
|
||||
width: 436px;
|
||||
height: 608px;
|
||||
}
|
||||
|
||||
.panel-events {
|
||||
left: 4348px;
|
||||
top: 878px;
|
||||
width: 436px;
|
||||
height: 608px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||