<template>
|
<div class="data-dashboard">
|
<!-- 全屏按钮 - 移动到左上角 -->
|
<button class="fullscreen-btn" @click="toggleFullscreen" :title="isFullscreen ? '退出全屏' : '全屏显示'">
|
<svg v-if="!isFullscreen" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<path d="M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3"/>
|
</svg>
|
<svg v-else width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/>
|
</svg>
|
</button>
|
|
<!-- 顶部标题栏 -->
|
<div class="dashboard-header">
|
</div>
|
|
<!-- 主要内容区域 -->
|
<div class="dashboard-content">
|
<!-- 左侧区域 -->
|
<div class="left-panel">
|
<!-- 客户信息统计分析 -->
|
<div class="panel-header">
|
<span class="panel-title">客户信息统计分析</span>
|
</div>
|
<div class="panel-item-customers">
|
<div class="panel-title-second">
|
<div class="panel-title-icon"></div>
|
<div class="total-customers">
|
<span class="label">总合同金额(元)</span>
|
<span class="value">{{sum}}</span>
|
</div>
|
<!-- <div class="jiantou"></div>-->
|
</div>
|
<!-- 饼图区域 -->
|
<div style="display: flex;align-items: center;gap: 20px;justify-content: space-evenly;height: 82%;margin-top: 20px">
|
<div style="width: 240px; height: 240px; background-image: url('/src/assets/BI/zonghetongbingtubiankuang@2x.png'); background-size: contain; background-position: center; background-repeat: no-repeat; display: flex; align-items: center; justify-content: center;">
|
<Echarts ref="chart" :legend="pieLegend" :chartStyle="chartStylePie"
|
:series="materialPieSeries"
|
:tooltip="pieTooltip"
|
:options="{backgroundColor: 'transparent'}"
|
style="margin-left: 5px;"></Echarts>
|
</div>
|
<ul class="contract-list" style="margin: 0; padding: 0; display: flex; flex-direction: column;justify-content: space-around; height: 100%; overflow-y: auto; scroll-behavior: smooth;" ref="refContractList">
|
<li v-for="item in materialPieSeries[0].data" :key="item.name" style="list-style: none; margin-bottom: 12px;">
|
<div style="display: flex;align-items: center;justify-content: space-between;width: 100%">
|
<div class="line" :style="{color: item.itemStyle.color}">■ {{item.name}}</div>
|
<div style="font-weight: 700;font-size: 16px;color: #85B1E4;">¥{{item.value}}</div>
|
</div>
|
</li>
|
</ul>
|
</div>
|
</div>
|
|
<!-- 质量统计 -->
|
<div class="panel-header">
|
<span class="panel-title">质量统计</span>
|
</div>
|
<div class="main-panel">
|
<div class="panel-item-customers">
|
<div class="quality-cards">
|
<div class="quality-cardSec">
|
<div class="quality-card one"></div>
|
<div class="quality-cardTitle">
|
<div>原材料已检测数</div>
|
<div>{{qualityStatisticsObject.supplierNum}}件</div>
|
</div>
|
</div>
|
<div class="quality-cardSec">
|
<div class="quality-card two"></div>
|
<div class="quality-cardTitle">
|
<div>过程检验数量</div>
|
<div>{{qualityStatisticsObject.processNum}}件</div>
|
</div>
|
</div>
|
<div class="quality-cardSec">
|
<div class="quality-card three"></div>
|
<div class="quality-cardTitle">
|
<div>出厂已检数量</div>
|
<div>{{qualityStatisticsObject.factoryNum}}件</div>
|
</div>
|
</div>
|
</div>
|
<Echarts ref="chart"
|
:chartStyle="chartStyle"
|
:grid="grid"
|
:legend="barLegend"
|
:series="barSeries1"
|
:tooltip="tooltip"
|
:xAxis="xAxis1"
|
:yAxis="yAxis1"
|
:options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"
|
style="height: 260px"></Echarts>
|
</div>
|
</div>
|
</div>
|
|
<!-- 中间区域 -->
|
<div class="center-panel">
|
<!-- 顶部统计卡片 -->
|
<div class="stats-cards">
|
<div class="stat-card">
|
<img src="@/assets/BI/icon@2x.png" alt="图标" class="card-icon" />
|
<div class="card-content">
|
<span class="card-label">员工总数</span>
|
<span class="card-value">{{totalStaff}}</span>
|
</div>
|
</div>
|
<div class="stat-card">
|
<img src="@/assets/BI/icon@2x.png" alt="图标" class="card-icon" />
|
<div class="card-content">
|
<span class="card-label">客户总数</span>
|
<span class="card-value">{{totalCustomers}}</span>
|
</div>
|
</div>
|
<div class="stat-card">
|
<img src="@/assets/BI/icon@2x.png" alt="图标" class="card-icon" />
|
<div class="card-content">
|
<span class="card-label">供应商总数</span>
|
<span class="card-value">{{totalSuppliers}}</span>
|
</div>
|
</div>
|
</div>
|
|
<!-- 设备统计 -->
|
<div class="equipment-stats">
|
<div class="equipment-header">
|
<img src="@/assets/BI/shujutongjiicon@2x.png" alt="图标" class="equipment-icon" />
|
<span class="equipment-title">设备统计</span>
|
</div>
|
<div class="equipment-items">
|
<div class="equipment-item">
|
<span class="equipment-value">{{equipmentNum}}</span>
|
<span class="equipment-label">设备总数</span>
|
</div>
|
<div class="equipment-item">
|
<span class="equipment-value">{{equipmentRepair}}</span>
|
<span class="equipment-label">待维修设备</span>
|
</div>
|
<div class="equipment-item">
|
<span class="equipment-value">{{equipmentMaintain}}</span>
|
<span class="equipment-label">待保养设备</span>
|
</div>
|
<div class="equipment-item">
|
<span class="equipment-value">{{totalMeasuring}}</span>
|
<span class="equipment-label">计量器具总数</span>
|
</div>
|
</div>
|
</div>
|
|
<!-- 事件名称 -->
|
<div class="event-info">
|
<div class="event-header">
|
<img src="@/assets/BI/shijianmingxiicon@2x.png" alt="图标" class="event-icon" />
|
<span class="event-title">事件名称</span>
|
</div>
|
<div class="event-content">
|
<ul class="todo-list" v-if="todoList.length > 0" ref="refTodoList">
|
<li v-for="item in todoList" :key="item.id">
|
<div style="display: flex;flex-direction: column;justify-content: space-between;width: 100%;gap: 20px">
|
<div style="display: flex;justify-content: space-between;align-items: center;">
|
<div class="todo-title">待办编号:{{item.approveId}}</div>
|
<div class="todo-division">部门:{{item.approveDeptName}}</div>
|
<div class="todo-time">{{item.approveTime}}</div>
|
</div>
|
<div class="todo-division">待办事由:{{item.approveReason}}</div>
|
</div>
|
</li>
|
</ul>
|
<div v-else style="text-align: center">
|
暂无数据
|
</div>
|
</div>
|
</div>
|
|
<div class="financial-header">
|
<span class="financial-title">财务分析</span>
|
</div>
|
<div class="main-panel">
|
<div class="panel-item-customers">
|
<div class="event-header">
|
<img src="@/assets/BI/shijianmingxiicon@2x.png" alt="图标" class="event-icon" />
|
<span class="event-title">经营成果分析</span>
|
</div>
|
<Echarts ref="chart"
|
:chartStyle="chartStyle"
|
:grid="grid"
|
:legend="barLegend1"
|
:series="barSeries11"
|
:tooltip="tooltip"
|
:xAxis="xAxis3"
|
:yAxis="yAxis3"
|
:options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"
|
style="height: 300px"></Echarts>
|
</div>
|
</div>
|
</div>
|
|
<!-- 右侧区域 -->
|
<div class="right-panel">
|
<!-- 应收应付统计 -->
|
<div class="panel-header">
|
<span class="panel-title">应收应付统计</span>
|
</div>
|
<div class="panel-item-customers">
|
<div style="display: flex;justify-content: space-between;margin-bottom: 20px;">
|
<div class="section-title">应收应付统计</div>
|
<el-radio-group v-model="radio1" size="large" @change="statisticsReceivable" class="custom-radio-group">
|
<el-radio-button label="按周" :value="1" />
|
<el-radio-button label="按月" :value="2" />
|
<el-radio-button label="按季度" :value="3" />
|
</el-radio-group>
|
</div>
|
<Echarts ref="chart"
|
:color="barColors2"
|
:chartStyle="chartStyle"
|
:grid="grid"
|
:legend="barLegend2"
|
:series="barSeries"
|
:tooltip="tooltip"
|
:xAxis="xAxis"
|
:yAxis="yAxis"
|
:options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"
|
style="height: 260px"></Echarts>
|
</div>
|
|
<!-- 回款与开票分析 -->
|
<div class="panel-header">
|
<span class="panel-title">回款与开票分析</span>
|
</div>
|
<div class="panel-item-customers" style="padding-top: 60px;">
|
<Echarts ref="chart" :chartStyle="chartStyle" :grid="grid" :legend="lineLegend" :series="lineSeries"
|
:tooltip="tooltipLine" :xAxis="xAxis2" :yAxis="yAxis2" :options="{backgroundColor: 'transparent', textStyle: {color: '#FFFFFF'}}" style="height: 270px;"></Echarts>
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import * as echarts from 'echarts'
|
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
|
import autofit from 'autofit.js'
|
import Echarts from "@/components/Echarts/echarts.vue";
|
import {
|
analysisCustomerContractAmounts, getAmountHalfYear,
|
homeTodos,
|
qualityStatistics,
|
statisticsReceivablePayable
|
} from "@/api/viewIndex.js";
|
import {staffOnJobListPage} from "@/api/personnelManagement/employeeRecord.js";
|
import {listCustomer} from "@/api/basicData/customerFile.js";
|
import {listSupplier} from "@/api/basicData/supplierManageFile.js";
|
import {getLedgerPage} from "@/api/equipmentManagement/ledger.js";
|
import {getRepairPage} from "@/api/equipmentManagement/repair.js";
|
import {getUpkeepPage} from "@/api/equipmentManagement/upkeep.js";
|
import {measuringInstrumentListPage} from "@/api/equipmentManagement/measurementEquipment.js";
|
import {listPageAnalysis} from "@/api/financialManagement/expenseManagement.js";
|
|
// 全屏相关状态
|
const isFullscreen = ref(false);
|
|
// 响应式数据
|
const currentTime = ref('')
|
const currentDate = ref('')
|
const timer = ref(null)
|
const charts = ref([])
|
|
// 图表引用
|
const customerPieChartRef = ref(null)
|
const salesBarChartRef = ref(null)
|
const dataBarChartRef = ref(null)
|
const financialAreaChartRef = ref(null)
|
const realtimeLineChartRef = ref(null)
|
const refContractList = ref(null)
|
const refTodoList = ref(null)
|
const timerScroll = ref(null)
|
|
const chartStylePie = {
|
width: '140%',
|
height: '140%' // 设置图表容器的高度
|
}
|
const materialPieSeries = ref([
|
{
|
type: 'pie',
|
radius: ['0%', '90%'],
|
avoidLabelOverlap: false,
|
itemStyle: {
|
borderColor: '#fff',
|
borderWidth: 0
|
},
|
label: {
|
show: false
|
},
|
data: []
|
}
|
])
|
const pieLegend = reactive({
|
show: false,
|
})
|
const sum = ref(0)
|
const totalStaff = ref(0)
|
const totalCustomers = ref(0)
|
const totalSuppliers = ref(0)
|
const yny = ref(0)
|
const chain = ref(0)
|
const equipmentNum = ref(0)
|
const equipmentRepair = ref(0)
|
const equipmentMaintain = ref(0)
|
const totalMeasuring = ref(0)
|
const pieTooltip = reactive({
|
trigger: 'item',
|
formatter: function (params) {
|
// 动态生成提示信息,基于数据项的 name 属性
|
const description = params.name === '本月回款金额' ? '本月回款金额' : '应收款金额';
|
return `<div style="color: #B8C8E0">${description} ${params.value}元 ${params.percent}%</div>`;
|
},
|
position: 'right'
|
})
|
|
const qualityStatisticsObject = ref({
|
supplierNum: 0,
|
processNum: 0,
|
factoryNum: 0,
|
})
|
const chartStyle = {
|
width: '100%',
|
height: '150%' // 设置图表容器的高度
|
}
|
const barSeries = ref([
|
{
|
name: '应付金额',
|
type: 'bar',
|
data: [],
|
label: {
|
show: true,
|
},
|
itemStyle: {
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
{ offset: 0, color: '#00A4ED' },
|
{ offset: 1, color: '#4EE4FF' }
|
])
|
}
|
},
|
{
|
name: '应收金额',
|
type: 'bar',
|
data: [],
|
label: {
|
show: true,
|
},
|
itemStyle: {
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
{ offset: 0, color: '#537EF5' },
|
{ offset: 1, color: '#9061F8' }
|
])
|
}
|
}
|
])
|
const radio1 = ref(1)
|
const barColors2 = ['#5181DB', '#D369E0', '#F2CA6D', '#60CCA8']
|
const grid = {
|
left: '3%',
|
right: '4%',
|
bottom: '3%',
|
containLabel: true
|
}
|
const lineLegend = {
|
show: true,
|
textStyle: { color: '#B8C8E0' },
|
data: ['开票', '回款']
|
}
|
const lineSeries = ref([
|
{
|
type: 'line',
|
data: [],
|
label: {
|
show: true
|
},
|
showSymbol: true, // 显示圆点
|
},
|
])
|
const tooltipLine = {
|
trigger: 'axis',
|
}
|
const yAxis2 = ref([
|
{
|
type: 'value',
|
}
|
])
|
const xAxis2 = ref([
|
{
|
type: 'category',
|
data: [],
|
axisLabel: {
|
interval: 0,
|
formatter: function(value) {
|
return value.replace(/~/g, '\n');
|
},
|
}
|
}
|
])
|
const barLegend2 = {
|
show: true,
|
textStyle: { color: '#B8C8E0' },
|
data: ['应付金额', '应收金额']
|
}
|
const barLegend = {
|
show: true,
|
textStyle: { color: '#B8C8E0' },
|
data: ['原材料不合格数', '过程不合格数', '出厂不合格数']
|
}
|
const barLegend1 = {
|
show: true,
|
textStyle: { color: '#B8C8E0' },
|
data: ['总收入', '总支出', '净收入']
|
}
|
const barSeries11 = ref([
|
{
|
name: '总收入',
|
type: 'bar',
|
barGap: 0,
|
emphasis: {
|
focus: 'series'
|
},
|
itemStyle: {
|
color: {
|
type: 'linear',
|
x: 0,
|
y: 0,
|
x2: 0,
|
y2: 1,
|
colorStops: [
|
{ offset: 1, color: '#00A4ED' },
|
{ offset: 0, color: '#4EE4FF' }
|
]
|
}
|
},
|
data: []
|
},
|
{
|
name: '总支出',
|
type: 'bar',
|
emphasis: {
|
focus: 'series'
|
},
|
itemStyle: {
|
color: {
|
type: 'linear',
|
x: 0,
|
y: 0,
|
x2: 0,
|
y2: 1,
|
colorStops: [
|
{ offset: 1, color: '#3378FF' },
|
{ offset: 0, color: '#4E8AFF' }
|
]
|
}
|
},
|
data: []
|
},
|
{
|
name: '净收入',
|
type: 'bar',
|
emphasis: {
|
focus: 'series'
|
},
|
itemStyle: {
|
color: {
|
type: 'linear',
|
x: 0,
|
y: 0,
|
x2: 0,
|
y2: 1,
|
colorStops: [
|
{ offset: 1, color: '#537EF5' },
|
{ offset: 0, color: '#9061F8' }
|
]
|
}
|
},
|
data: []
|
},
|
])
|
const barSeries1 = ref([
|
{
|
name: '原材料不合格数',
|
type: 'bar',
|
barGap: 0,
|
emphasis: {
|
focus: 'series'
|
},
|
itemStyle: {
|
color: {
|
type: 'linear',
|
x: 0,
|
y: 0,
|
x2: 0,
|
y2: 1,
|
colorStops: [
|
{ offset: 1, color: '#00A4ED' },
|
{ offset: 0, color: '#4EE4FF' }
|
]
|
}
|
},
|
data: []
|
},
|
{
|
name: '过程不合格数',
|
type: 'bar',
|
emphasis: {
|
focus: 'series'
|
},
|
itemStyle: {
|
color: {
|
type: 'linear',
|
x: 0,
|
y: 0,
|
x2: 0,
|
y2: 1,
|
colorStops: [
|
{ offset: 1, color: '#3378FF' },
|
{ offset: 0, color: '#4E8AFF' }
|
]
|
}
|
},
|
data: []
|
},
|
{
|
name: '出厂不合格数',
|
type: 'bar',
|
emphasis: {
|
focus: 'series'
|
},
|
itemStyle: {
|
color: {
|
type: 'linear',
|
x: 0,
|
y: 0,
|
x2: 0,
|
y2: 1,
|
colorStops: [
|
{ offset: 1, color: '#537EF5' },
|
{ offset: 0, color: '#9061F8' }
|
]
|
}
|
},
|
data: []
|
},
|
])
|
const tooltip = {
|
trigger: 'axis',
|
axisPointer: {
|
type: 'shadow'
|
},
|
formatter: function (params) {
|
let result = params[0].axisValueLabel + '<br/>';
|
params.forEach(item => {
|
result += `<div style="color: #B8C8E0">${item.marker} ${item.seriesName}: ${item.value}</div>`;
|
});
|
return result;
|
}
|
}
|
const xAxis = [{
|
type: 'value',
|
}]
|
const yAxis = [{
|
type: 'category',
|
data: ['应收应付统计']
|
}]
|
const xAxis1 = ref([{
|
type: 'category',
|
axisTick: { show: false },
|
axisLabel: { color: '#B8C8E0' },
|
data: []
|
}])
|
const yAxis1 = [{
|
type: 'value',
|
axisLabel: { color: '#B8C8E0' }
|
}]
|
const xAxis3 = ref([{
|
type: 'category',
|
axisTick: { show: false },
|
axisLabel: { color: '#B8C8E0' },
|
data: []
|
}])
|
const yAxis3 = [{
|
type: 'value',
|
axisLabel: { color: '#B8C8E0' }
|
}]
|
|
// 待办事项
|
const todoList = ref([])
|
|
// 窗口大小变化处理
|
const handleResize = () => {
|
charts.value.forEach(chart => {
|
if (chart && chart.resize) {
|
chart.resize()
|
}
|
})
|
}
|
|
// 销毁图表实例
|
const disposeCharts = () => {
|
charts.value.forEach(chart => {
|
if (chart && chart.dispose) {
|
chart.dispose()
|
}
|
})
|
charts.value = []
|
}
|
// 合同金额
|
const analysisCustomer = () => {
|
analysisCustomerContractAmounts().then((res) => {
|
sum.value = res.data.sum
|
yny.value = res.data.yny
|
chain.value = res.data.chain
|
// 为每个数据项分配随机颜色
|
materialPieSeries.value[0].data = res.data.item.map(item => ({
|
...item,
|
itemStyle: { color: getRandomColor() }
|
}))
|
})
|
}
|
// 质检统计
|
const qualityStatisticsInfo = () => {
|
qualityStatistics().then((res) => {
|
res.data.item.forEach(item => {
|
xAxis1.value[0].data.push(item.date)
|
barSeries1.value[0].data.push(item.supplierNum)
|
barSeries1.value[1].data.push(item.processNum)
|
barSeries1.value[2].data.push(item.factoryNum)
|
})
|
qualityStatisticsObject.value.supplierNum = res.data.supplierNum
|
qualityStatisticsObject.value.processNum = res.data.processNum
|
qualityStatisticsObject.value.factoryNum = res.data.factoryNum
|
})
|
}
|
// 财务统计
|
const accountStatisticsInfo = () => {
|
listPageAnalysis().then((res) => {
|
xAxis3.value[0].data = res.data.days
|
barSeries11.value[0].data = res.data.totalIncome
|
barSeries11.value[1].data = res.data.totalExpense
|
barSeries11.value[2].data = res.data.netIncome
|
})
|
}
|
const getNum = () => {
|
const params = {
|
pageNum: -1,
|
pageSize: -1,
|
}
|
staffOnJobListPage({...params, staffState: 1}).then(res => {
|
totalStaff.value = res.data.total
|
})
|
listCustomer(params).then((res) => {
|
totalCustomers.value = res.total;
|
});
|
listSupplier(params).then((res) => {
|
totalSuppliers.value = res.data.total
|
});
|
}
|
const getLedgerNum = () => {
|
const params = {
|
pageNum: -1,
|
pageSize: -1,
|
}
|
getLedgerPage(params).then((res) => {
|
equipmentNum.value = res.data.total
|
});
|
getRepairPage(params).then((res) => {
|
equipmentRepair.value = res.data.total
|
});
|
getUpkeepPage(params).then((res) => {
|
equipmentMaintain.value = res.data.total
|
});
|
measuringInstrumentListPage(params).then((res) => {
|
totalMeasuring.value = res.data.total
|
});
|
}
|
// 待办事项
|
const todoInfoS = () => {
|
homeTodos().then((res) => {
|
todoList.value = res.data
|
// 在获取到待办事项数据后,初始化滚动功能
|
nextTick(() => {
|
initTodoListScroll()
|
})
|
})
|
}
|
// 应付应收统计
|
const statisticsReceivable = (type) => {
|
statisticsReceivablePayable({type: radio1.value}).then((res) => {
|
// 设置应付金额数据
|
barSeries.value[0].data = [
|
{ value: res.data.payableMoney }
|
]
|
// 设置应收金额数据
|
barSeries.value[1].data = [
|
{ value: res.data.receivableMoney }
|
]
|
})
|
}
|
const getAmountHalfYearNum = async () => {
|
const res = await getAmountHalfYear()
|
console.log(res)
|
const monthName = []
|
const receiptAmount = []
|
const invoiceAmount = []
|
res.data.forEach(item => {
|
monthName.push(item.month)
|
receiptAmount.push(item.receiptAmount)
|
invoiceAmount.push(item.invoiceAmount)
|
})
|
// 正确响应式赋值:创建新的 xAxis 和 series 对象
|
xAxis2.value[0].data = monthName
|
xAxis2.value[0].data = monthName.map(item => item.replace(/~/g, '\n~'));
|
lineSeries.value = [
|
{
|
name: '开票',
|
type: 'line',
|
data: receiptAmount,
|
stack: 'Total',
|
areaStyle: {
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
{
|
offset: 0,
|
color: 'rgba(131, 207, 255, 1)'
|
},
|
{
|
offset: 1,
|
color: 'rgba(186, 228, 255, 1)'
|
}
|
])
|
},
|
itemStyle: {
|
color: '#2D99FF',
|
borderColor: '#2D99FF'
|
},
|
emphasis: {
|
focus: 'series'
|
},
|
lineStyle: {
|
width: 0
|
},
|
showSymbol: true,
|
},
|
{
|
name: '回款',
|
type: 'line',
|
data: invoiceAmount,
|
stack: 'Total',
|
lineStyle: {
|
width: 0
|
},
|
itemStyle: {
|
color: '#83CFFF',
|
borderColor: '#83CFFF'
|
},
|
showSymbol: true,
|
areaStyle: {
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
{
|
offset: 0,
|
color: 'rgba(54, 153, 255, 1)'
|
},
|
{
|
offset: 1,
|
color: 'rgba(89, 169, 254, 1)'
|
}
|
])
|
},
|
emphasis: {
|
focus: 'series'
|
},
|
}
|
]
|
}
|
|
// 自动轮换周、月、季度的定时器
|
const autoSwitchTimer = ref(null)
|
// 初始化待办事项列表滚动功能
|
const initTodoListScroll = () => {
|
const todoList = refTodoList.value
|
// 强制启用滚动,不检查任何条件
|
if (todoList) {
|
// 创建一个克隆项,用于实现无缝滚动
|
const scrollItems = Array.from(todoList.querySelectorAll('li'))
|
if (scrollItems.length > 0) {
|
// 确保有足够的项目用于滚动
|
// 如果项目太少,多复制几次以确保滚动效果
|
if (scrollItems.length < 4) {
|
const originalItems = [...scrollItems]
|
for (let i = 0; i < 4; i++) {
|
originalItems.forEach(item => {
|
const clone = item.cloneNode(true)
|
todoList.appendChild(clone)
|
})
|
}
|
// 重新获取所有项目
|
scrollItems.push(...Array.from(todoList.querySelectorAll('li')).slice(scrollItems.length));
|
}
|
const itemHeight = scrollItems[0]?.offsetHeight || 0
|
const containerHeight = todoList.clientHeight
|
const cloneCount = Math.ceil(containerHeight / itemHeight) + 2
|
|
// 克隆前几个项目并添加到列表末尾,实现无缝滚动
|
for (let i = 0; i < cloneCount; i++) {
|
const clone = scrollItems[i % scrollItems.length].cloneNode(true)
|
todoList.appendChild(clone)
|
}
|
|
let scrollPosition = 0
|
const scrollSpeed = 1.5 // 增加滚动速度,使滚动更加明显
|
const pauseTime = 3000 // 滚动暂停时间
|
let isPaused = false
|
let lastTimestamp = 0
|
|
// 连续滚动动画函数
|
function scrollAnimation(timestamp) {
|
if (!lastTimestamp) lastTimestamp = timestamp
|
const deltaTime = timestamp - lastTimestamp
|
lastTimestamp = timestamp
|
|
if (!isPaused) {
|
scrollPosition += scrollSpeed * (deltaTime / 16) // 标准化为60fps的速度
|
|
// 当滚动超过原始内容长度时,重置位置实现无缝滚动
|
const maxScroll = Math.max(todoList.scrollHeight - containerHeight - cloneCount * itemHeight, itemHeight * scrollItems.length)
|
if (scrollPosition >= maxScroll) {
|
scrollPosition = 0
|
todoList.scrollTop = 0
|
} else {
|
todoList.scrollTop = scrollPosition
|
}
|
}
|
|
todoList._animationFrame = requestAnimationFrame(scrollAnimation)
|
}
|
|
// 启动滚动动画
|
todoList._animationFrame = requestAnimationFrame(scrollAnimation)
|
|
// 设置滚动-暂停-滚动的循环效果
|
const pauseTimer = setInterval(() => {
|
isPaused = !isPaused
|
}, pauseTime)
|
|
// 清理定时器
|
todoList._pauseTimer = pauseTimer
|
}
|
}
|
}
|
const getRandomColor = () => {
|
// 生成浅色:R、G、B 分量都在 150-255 之间
|
const r = Math.floor(Math.random() * 106) + 150; // 150-255
|
const g = Math.floor(Math.random() * 106) + 150; // 150-255
|
const b = Math.floor(Math.random() * 106) + 150; // 150-255
|
// 将 RGB 转换为十六进制颜色
|
return '#' + r.toString(16).padStart(2, '0') + g.toString(16).padStart(2, '0') + b.toString(16).padStart(2, '0');
|
}
|
|
// 更新时间
|
const updateTime = () => {
|
const now = new Date()
|
currentTime.value = now.toLocaleTimeString('zh-CN', { hour12: false })
|
currentDate.value = now.toLocaleDateString('zh-CN', {
|
year: 'numeric',
|
month: '2-digit',
|
day: '2-digit',
|
weekday: 'long'
|
})
|
}
|
|
// 初始化时间
|
const initTime = () => {
|
updateTime()
|
timer.value = setInterval(updateTime, 1000)
|
}
|
|
// 客户饼图
|
const initCustomerPieChart = () => {
|
if (!customerPieChartRef.value) return
|
const chart = echarts.init(customerPieChartRef.value)
|
const option = {
|
tooltip: {
|
trigger: 'item',
|
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
},
|
series: [{
|
name: '客户分布',
|
type: 'pie',
|
radius: ['40%', '70%'],
|
center: ['50%', '50%'],
|
data: [
|
{ value: 25, name: '潜在客户', itemStyle: { color: '#00d4ff' } },
|
{ value: 25, name: '意向客户', itemStyle: { color: '#0099ff' } },
|
{ value: 25, name: '签约客户', itemStyle: { color: '#6666ff' } },
|
{ value: 25, name: '流失客户', itemStyle: { color: '#ffcc00' } }
|
],
|
label: {
|
show: false
|
}
|
}]
|
}
|
chart.setOption(option)
|
charts.value.push(chart)
|
}
|
|
// 销售柱状图
|
const initSalesBarChart = () => {
|
if (!salesBarChartRef.value) return
|
const chart = echarts.init(salesBarChartRef.value)
|
const option = {
|
tooltip: {
|
trigger: 'axis'
|
},
|
xAxis: {
|
type: 'category',
|
data: ['6/9', '6/10', '6/11', '6/12', '6/13'],
|
axisLine: { lineStyle: { color: '#333' } },
|
axisLabel: { color: '#B8C8E0' },
|
},
|
yAxis: {
|
type: 'value',
|
axisLine: { show: false },
|
axisTick: { show: false },
|
axisLabel: { color: '#B8C8E0' },
|
splitLine: { lineStyle: { color: '#333' } }
|
},
|
series: [{
|
data: [150, 200, 180, 220, 190],
|
type: 'bar',
|
itemStyle: {
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
{ offset: 0, color: 'rgba(0,164,237,0)' },
|
{ offset: 1, color: '#4EE4FF' }
|
])
|
}
|
}]
|
}
|
chart.setOption(option)
|
charts.value.push(chart)
|
}
|
|
// 数据统计横向柱状图
|
const initDataBarChart = () => {
|
if (!dataBarChartRef.value) return
|
const chart = echarts.init(dataBarChartRef.value)
|
const option = {
|
tooltip: {
|
trigger: 'axis'
|
},
|
grid: {
|
left: '10%',
|
right: '10%',
|
top: '10%',
|
bottom: '10%'
|
},
|
xAxis: {
|
type: 'value',
|
axisLine: { show: false },
|
axisTick: { show: false },
|
axisLabel: { color: '#B8C8E0' },
|
splitLine: { lineStyle: { color: '#333' } }
|
},
|
yAxis: {
|
type: 'category',
|
data: ['设计数据', '财务数据', '生产数据', '合同数据'],
|
axisLine: { lineStyle: { color: '#333' } },
|
axisLabel: { color: '#B8C8E0' }
|
},
|
series: [{
|
data: [80, 100, 120, 90],
|
type: 'bar',
|
itemStyle: {
|
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
{ offset: 0, color: 'rgba(0,164,237,0)' },
|
{ offset: 1, color: '#4EE4FF' }
|
])
|
}
|
}]
|
}
|
chart.setOption(option)
|
charts.value.push(chart)
|
}
|
|
// 财务分析面积图
|
const initFinancialAreaChart = () => {
|
if (!financialAreaChartRef.value) return
|
const chart = echarts.init(financialAreaChartRef.value)
|
const option = {
|
tooltip: {
|
trigger: 'axis'
|
},
|
grid: {
|
left: '10%',
|
right: '10%',
|
top: '10%',
|
bottom: '20%'
|
},
|
xAxis: {
|
type: 'category',
|
data: ['6/9', '6/10', '6/11', '6/12', '6/13'],
|
axisLine: { lineStyle: { color: '#333' } },
|
axisLabel: { color: '#B8C8E0' }
|
},
|
yAxis: {
|
type: 'value',
|
axisLine: { show: false },
|
axisTick: { show: false },
|
axisLabel: { color: '#B8C8E0' },
|
splitLine: { lineStyle: { color: '#333' } }
|
},
|
series: [{
|
data: [150, 180, 200, 170, 190],
|
type: 'line',
|
areaStyle: {
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
{ offset: 0, color: 'rgba(0, 212, 255, 0.3)' },
|
{ offset: 1, color: 'rgba(0, 212, 255, 0.1)' }
|
])
|
},
|
lineStyle: { color: '#00d4ff' },
|
itemStyle: { color: '#00d4ff' }
|
}]
|
}
|
chart.setOption(option)
|
charts.value.push(chart)
|
}
|
|
// 实时数据折线图
|
const initRealtimeLineChart = () => {
|
if (!realtimeLineChartRef.value) return
|
const chart = echarts.init(realtimeLineChartRef.value)
|
const option = {
|
tooltip: {
|
trigger: 'axis'
|
},
|
grid: {
|
left: '10%',
|
right: '10%',
|
top: '10%',
|
bottom: '20%'
|
},
|
xAxis: {
|
type: 'category',
|
data: ['6/9', '6/10', '6/11', '6/12', '6/13'],
|
axisLine: { lineStyle: { color: '#333' } },
|
axisLabel: { color: '#B8C8E0' }
|
},
|
yAxis: {
|
type: 'value',
|
axisLine: { show: false },
|
axisTick: { show: false },
|
axisLabel: { color: '#B8C8E0' },
|
splitLine: { lineStyle: { color: '#333' } }
|
},
|
series: [
|
{
|
name: '数据1',
|
data: [120, 140, 160, 130, 150],
|
type: 'line',
|
lineStyle: { color: '#00d4ff' },
|
itemStyle: { color: '#00d4ff' }
|
},
|
{
|
name: '数据2',
|
data: [100, 120, 140, 110, 130],
|
type: 'line',
|
lineStyle: { color: '#0099ff' },
|
itemStyle: { color: '#0099ff' }
|
}
|
]
|
}
|
chart.setOption(option)
|
charts.value.push(chart)
|
}
|
|
// 全屏功能实现 - 针对data-dashboard元素
|
const toggleFullscreen = () => {
|
const element = document.querySelector('.data-dashboard')
|
|
if (!element) return
|
|
if (!isFullscreen.value) {
|
if (element.requestFullscreen) {
|
element.requestFullscreen()
|
} else if (element.webkitRequestFullscreen) {
|
element.webkitRequestFullscreen()
|
} else if (element.msRequestFullscreen) {
|
element.msRequestFullscreen()
|
}
|
} else {
|
if (document.exitFullscreen) {
|
document.exitFullscreen()
|
} else if (document.webkitExitFullscreen) {
|
document.webkitExitFullscreen()
|
} else if (document.msExitFullscreen) {
|
document.msExitFullscreen()
|
}
|
}
|
}
|
|
// 监听全屏变化事件
|
const handleFullscreenChange = () => {
|
const fullscreenElement = document.fullscreenElement ||
|
document.webkitFullscreenElement ||
|
document.msFullscreenElement
|
isFullscreen.value = fullscreenElement && fullscreenElement.classList.contains('data-dashboard')
|
}
|
|
// 生命周期钩子
|
onMounted(() => {
|
initTime()
|
// 使用nextTick确保DOM完全渲染后再初始化图表
|
nextTick(() => {
|
// 初始化autofit自适应
|
autofit.init({ dh: 1440, dw: 2560, el: '.data-dashboard', resize: true }, false)
|
|
// 添加自动滚动动画效果 - 客户信息列表
|
const contractList = refContractList.value
|
if (contractList && contractList.scrollHeight > contractList.clientHeight) {
|
// 创建一个克隆项,用于实现无缝滚动
|
const scrollItems = Array.from(contractList.querySelectorAll('li'))
|
const itemHeight = scrollItems[0]?.offsetHeight || 0
|
const containerHeight = contractList.clientHeight
|
const cloneCount = Math.ceil(containerHeight / itemHeight) + 2
|
|
// 克隆前几个项目并添加到列表末尾,实现无缝滚动
|
for (let i = 0; i < cloneCount; i++) {
|
const clone = scrollItems[i % scrollItems.length].cloneNode(true)
|
contractList.appendChild(clone)
|
}
|
|
let scrollPosition = 0
|
const scrollSpeed = 1.5 // 增加滚动速度,使滚动更加明显
|
const pauseTime = 3000 // 滚动暂停时间
|
let isPaused = false
|
let lastTimestamp = 0
|
|
// 连续滚动动画函数
|
function scrollAnimation(timestamp) {
|
if (!lastTimestamp) lastTimestamp = timestamp
|
const deltaTime = timestamp - lastTimestamp
|
lastTimestamp = timestamp
|
|
if (!isPaused) {
|
scrollPosition += scrollSpeed * (deltaTime / 16) // 标准化为60fps的速度
|
|
// 当滚动超过原始内容长度时,重置位置实现无缝滚动
|
if (scrollPosition >= contractList.scrollHeight - containerHeight - cloneCount * itemHeight) {
|
scrollPosition = 0
|
contractList.scrollTop = 0
|
} else {
|
contractList.scrollTop = scrollPosition
|
}
|
}
|
|
timerScroll.value = requestAnimationFrame(scrollAnimation)
|
}
|
|
// 启动滚动动画
|
timerScroll.value = requestAnimationFrame(scrollAnimation)
|
|
// 设置滚动-暂停-滚动的循环效果
|
const pauseTimer = setInterval(() => {
|
isPaused = !isPaused
|
}, pauseTime)
|
|
// 清理定时器
|
contractList._pauseTimer = pauseTimer
|
}
|
|
// 待办事项列表滚动功能已移至todoInfoS函数中,在获取数据后初始化
|
})
|
|
window.addEventListener('resize', handleResize)
|
analysisCustomer()
|
qualityStatisticsInfo()
|
accountStatisticsInfo()
|
getNum()
|
getLedgerNum()
|
todoInfoS()
|
statisticsReceivable()
|
getAmountHalfYearNum()
|
|
// 设置自动轮换周、月、季度的定时器,每10秒切换一次
|
autoSwitchTimer.value = setInterval(() => {
|
// 循环切换:1(周) -> 2(月) -> 3(季度) -> 1(周)
|
radio1.value = radio1.value === 3 ? 1 : radio1.value + 1
|
statisticsReceivable()
|
}, 10000) // 10秒切换一次
|
})
|
|
onBeforeUnmount(() => {
|
if (timer.value) {
|
clearInterval(timer.value)
|
}
|
if (timerScroll.value) {
|
cancelAnimationFrame(timerScroll.value)
|
}
|
// 清理滚动列表的暂停定时器
|
const contractList = refContractList.value
|
if (contractList && contractList._pauseTimer) {
|
clearInterval(contractList._pauseTimer)
|
}
|
|
// 清理待办事项列表的动画和定时器
|
const todoList = refTodoList.value
|
if (todoList) {
|
if (todoList._animationFrame) {
|
cancelAnimationFrame(todoList._animationFrame)
|
todoList._animationFrame = null
|
}
|
if (todoList._pauseTimer) {
|
clearInterval(todoList._pauseTimer)
|
todoList._pauseTimer = null
|
}
|
}
|
|
// 清理自动轮换周、月、季度的定时器
|
if (autoSwitchTimer.value) {
|
clearInterval(autoSwitchTimer.value)
|
autoSwitchTimer.value = null
|
}
|
|
window.removeEventListener('resize', handleResize)
|
window.removeEventListener('fullscreenchange', handleFullscreenChange)
|
window.removeEventListener('webkitfullscreenchange', handleFullscreenChange)
|
window.removeEventListener('MSFullscreenChange', handleFullscreenChange)
|
// 移除我们添加的autofit动态调整监听器
|
if (window._autofitUpdateHandler) {
|
window.removeEventListener('resize', window._autofitUpdateHandler)
|
delete window._autofitUpdateHandler
|
}
|
disposeCharts()
|
// 关闭autofit
|
autofit.off()
|
})
|
</script>
|
|
<style scoped>
|
.data-dashboard {
|
position: relative;
|
width: 100vw;
|
overflow: hidden;
|
background-image: url("@/assets/BI/backImage@2x.png");
|
background-size: cover;
|
background-position: center;
|
background-repeat: no-repeat;
|
}
|
|
/* 全屏状态的样式 */
|
.data-dashboard:fullscreen {
|
width: 100%;
|
height: 100%;
|
margin: 0;
|
padding: 0;
|
background-color: inherit;
|
z-index: 9999;
|
}
|
|
/* Webkit浏览器前缀 */
|
.data-dashboard:-webkit-full-screen {
|
width: 100%;
|
height: 100%;
|
margin: 0;
|
padding: 0;
|
background-color: inherit;
|
z-index: 9999;
|
}
|
|
/* MS浏览器前缀 */
|
.data-dashboard:-ms-fullscreen {
|
width: 100%;
|
height: 100%;
|
margin: 0;
|
padding: 0;
|
background-color: inherit;
|
z-index: 9999;
|
}
|
|
/* 全屏状态下的内容区域适配 */
|
.data-dashboard:fullscreen .dashboard-content {
|
height: calc(100vh - 120px);
|
}
|
|
.data-dashboard:-webkit-full-screen .dashboard-content {
|
height: calc(100vh - 120px);
|
}
|
|
.data-dashboard:-ms-fullscreen .dashboard-content {
|
height: calc(100vh - 120px);
|
}
|
|
.dashboard-header {
|
position: relative;
|
z-index: 1;
|
height: 170px;
|
background-image: url("@/assets/BI/biaoti.png");
|
background-size: cover;
|
background-position: center;
|
background-repeat: no-repeat;
|
}
|
|
.fullscreen-btn {
|
position: absolute;
|
top: 10px;
|
left: 20px;
|
width: 40px;
|
height: 40px;
|
background: rgba(0, 20, 60, 0.8);
|
border: 1px solid rgba(0, 212, 255, 0.3);
|
border-radius: 6px;
|
color: #00d4ff;
|
cursor: pointer;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
transition: all 0.3s;
|
z-index: 10000;
|
}
|
|
.fullscreen-btn:hover {
|
background: rgba(0, 30, 90, 0.9);
|
border-color: rgba(0, 212, 255, 0.5);
|
}
|
|
.dashboard-content {
|
position: relative;
|
z-index: 1;
|
display: flex;
|
gap: 30px;
|
padding: 0 30px;
|
height: calc(100vh - 120px);
|
overflow: hidden;
|
}
|
|
/* 确保各面板能够正确显示 */
|
.left-panel, .center-panel, .right-panel {
|
overflow: hidden;
|
}
|
|
.left-panel,
|
.right-panel {
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
gap: 24px;
|
width: 520px;
|
}
|
|
.center-panel {
|
flex: 1.5;
|
display: flex;
|
flex-direction: column;
|
gap: 20px;
|
}
|
.panel-item-customers {
|
border: 1px solid #1A58B0;
|
padding: 18px;
|
width: 100%;
|
height: 540px;
|
}
|
.panel-title-second {
|
height: 60px;
|
display: flex;
|
gap: 12px;
|
margin-bottom: 20px;
|
align-items: center;
|
}
|
.quality-cards {
|
display: flex;
|
gap: 12px;
|
width: 100%;
|
height: 94px;
|
justify-content: space-between;
|
align-items: center;
|
}
|
.quality-cardSec {
|
display: flex;
|
}
|
.quality-cardTitle {
|
font-weight: 400;
|
font-size: 14px;
|
color: #FFFFFF;
|
display: flex;
|
align-items: flex-start;
|
flex-direction: column;
|
}
|
.quality-card {
|
width: 80px;
|
height: 60px;
|
background-size: cover;
|
background-position: center;
|
background-repeat: no-repeat;
|
}
|
.quality-card.one {
|
background-image: url("@/assets/BI/yuancailiaoyijianicon@2x.png");
|
}
|
.quality-card.two {
|
background-image: url("@/assets/BI/guochengyijianicon@2x.png");
|
}
|
.quality-card.three {
|
background-image: url("@/assets/BI/chuchangyijianicon@2x.png");
|
|
}
|
.panel-title-icon {
|
width: 60px;
|
height: 60px;
|
background-image: url("@/assets/BI/hetongicon.png");
|
background-size: cover;
|
background-position: center;
|
background-repeat: no-repeat;
|
}
|
.panel-item {
|
background: rgba(0, 20, 60, 0.8);
|
border: 1px solid rgba(0, 212, 255, 0.3);
|
border-radius: 12px;
|
padding: 30px;
|
backdrop-filter: blur(10px);
|
min-height: 200px;
|
}
|
|
.panel-header {
|
background-image: url("@/assets/BI/kehuhetongback@2x.png");
|
background-size: 100% 100%;
|
background-position: center;
|
background-repeat: no-repeat;
|
height: 36px;
|
}
|
|
.panel-title {
|
width: 100%;
|
font-weight: 500;
|
font-size: 16px;
|
color: #D9ECFF;
|
padding-left: 46px;
|
line-height: 36px;
|
}
|
.total-customers {
|
background-image: url("@/assets/BI/hetongjineback@2x.png");
|
background-size: cover;
|
background-position: center;
|
background-repeat: no-repeat;
|
width: 90%;
|
height: 60px;
|
display: flex;
|
align-items: center;
|
padding: 0 20px;
|
gap: 20px;
|
}
|
|
.total-customers .label {
|
font-weight: 500;
|
font-size: 16px;
|
color: #FFFFFF;
|
}
|
|
.total-customers .value {
|
font-weight: 500;
|
font-size: 40px;
|
background: linear-gradient(360deg, #008BFD 0%, #FFFFFF 100%);
|
-webkit-background-clip: text;
|
-webkit-text-fill-color: transparent;
|
background-clip: text;
|
}
|
|
.contract-list {
|
margin-top: 16px;
|
font-size: 14px;
|
color: #666;
|
list-style: none;
|
padding: 0;
|
height: 82%;
|
overflow-y: auto;
|
width: 460px;
|
/* 隐藏滚动条但保留滚动功能 */
|
scrollbar-width: none; /* Firefox */
|
-ms-overflow-style: none; /* IE和Edge */
|
}
|
|
/* Chrome、Safari和Opera */
|
.contract-list::-webkit-scrollbar {
|
display: none;
|
}
|
.line {
|
position: relative;
|
width: 230px;
|
}
|
.line::after {
|
content: '';
|
position: absolute;
|
right: 2px;
|
top: 0;
|
bottom: 0;
|
width: 1px;
|
background-color: #C9C5C5;
|
border-radius: 2px;
|
}
|
.contract-list li {
|
margin-top: 10px;
|
}
|
.stats-cards {
|
display: flex;
|
gap: 30px;
|
}
|
|
.stat-card {
|
flex: 1;
|
display: flex;
|
align-items: center;
|
background-image: url("@/assets/BI/border@2x.png");
|
background-size: 100% 100%;
|
background-position: center;
|
background-repeat: no-repeat;
|
height: 142px;
|
}
|
|
.card-icon {
|
width: 100px;
|
height: 100px;
|
margin: 20px 20px 0 10px;
|
}
|
|
.card-content {
|
display: flex;
|
flex-direction: column;
|
gap: 10px;
|
}
|
|
.card-value {
|
font-weight: 500;
|
font-size: 40px;
|
background: linear-gradient(360deg, #008BFD 0%, #FFFFFF 100%);
|
-webkit-background-clip: text;
|
-webkit-text-fill-color: transparent;
|
background-clip: text;
|
}
|
|
.card-label {
|
font-weight: 400;
|
font-size: 19px;
|
color: rgba(208,231,255,0.7);
|
}
|
|
.equipment-stats {
|
border: 1px solid #1A58B0;
|
padding: 18px;
|
height: 240px;
|
}
|
.equipment-header {
|
font-weight: 500;
|
font-size: 21px;
|
display: flex;
|
border-bottom: 1px solid;
|
border-image: linear-gradient( 270deg, rgba(0,126,255,0) 0%, rgba(0,126,255,0.4549) 35%, #007EFF 78%, #007EFF 100%) 1;
|
padding-bottom: 2px;
|
}
|
.equipment-title {
|
font-weight: 500;
|
font-size: 21px;
|
background: linear-gradient(360deg, #056DFF 0%, #43E8FC 100%);
|
-webkit-background-clip: text;
|
-webkit-text-fill-color: transparent;
|
background-clip: text;
|
line-height: 50px;
|
}
|
.equipment-icon {
|
width: 50px;
|
height: 50px;
|
}
|
.equipment-items {
|
display: flex;
|
justify-content: space-around;
|
gap: 30px;
|
}
|
|
.equipment-item {
|
text-align: center;
|
}
|
|
.equipment-value {
|
display: block;
|
font-weight: 500;
|
font-size: 40px;
|
color: #FFFFFF;
|
width: 120px;
|
height: 110px;
|
line-height: 110px;
|
background-image: url("@/assets/BI/shujutongji@2x.png");
|
background-size: 100% 100%;
|
background-position: center;
|
background-repeat: no-repeat;
|
margin-bottom: 8px;
|
}
|
|
.equipment-label {
|
font-weight: 500;
|
font-size: 21px;
|
color: #FFFFFE;
|
}
|
|
.event-info {
|
background-image: url("@/assets/BI/shijianmingchengbeijing@2x.png");
|
background-size: 100% 100%;
|
background-position: center;
|
background-repeat: no-repeat;
|
padding: 20px;
|
height: 186px;
|
}
|
.event-header {
|
display: flex;
|
align-items: center;
|
}
|
.event-icon {
|
width: 40px;
|
height: 40px;
|
}
|
.event-title {
|
font-weight: 500;
|
font-size: 24px;
|
color: #FFFFFE;
|
line-height: 30px;
|
}
|
.todo-list {
|
list-style: none;
|
padding: 0;
|
margin: 0;
|
height: 120px; /* 按用户要求调整高度 */
|
overflow: hidden;
|
font-size: 15px;
|
}
|
.todo-list li {
|
border-radius: 8px;
|
margin-bottom: 12px;
|
padding: 12px 40px;
|
height: 74px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
}
|
.todo-title {
|
font-weight: 400;
|
font-size: 20px;
|
color: #FFFFFE;
|
position: relative;
|
}
|
.todo-title::before {
|
content: ''; /* 必需,表示这里有一个内容 */
|
position: absolute;
|
left: -10px; /* 定位到左侧 */
|
top: 50%; /* 垂直居中 */
|
transform: translateY(-50%); /* 微调垂直居中 */
|
width: 6px; /* 圆的直径 */
|
height: 6px; /* 圆的直径 */
|
background: #498CEB;
|
border-radius: 50%; /* 让其变成圆形 */
|
}
|
.todo-division {
|
font-weight: 400;
|
font-size: 20px;
|
color: #FFFFFE;
|
}
|
.todo-time {
|
font-weight: 400;
|
font-size: 20px;
|
color: #FFFFFE;
|
}
|
.data-statistics {
|
flex: 1;
|
}
|
.financial-header {
|
background-image: url("@/assets/BI/caiwufenxiback@2x.png");
|
background-size: 100% 100%;
|
background-position: center;
|
background-repeat: no-repeat;
|
}
|
.financial-title {
|
width: 100%;
|
font-weight: 500;
|
font-size: 16px;
|
color: #D9ECFF;
|
padding-left: 46px;
|
line-height: 36px;
|
}
|
.data-legend {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 20px;
|
margin-bottom: 20px;
|
}
|
|
.legend-item {
|
display: flex;
|
align-items: center;
|
gap: 12px;
|
}
|
|
.legend-color {
|
width: 12px;
|
height: 12px;
|
border-radius: 4px;
|
}
|
|
.legend-text {
|
font-size: 12px;
|
color: #999;
|
}
|
|
.horizontal-bar-chart {
|
height: 150px;
|
}
|
|
.financial-analysis,
|
.realtime-analysis {
|
flex: 1;
|
}
|
|
.financial-tabs,
|
.realtime-tabs {
|
display: flex;
|
gap: 16px;
|
margin-bottom: 20px;
|
}
|
|
.tab {
|
padding: 12px 24px;
|
background: rgba(0, 0, 0, 0.3);
|
border: 1px solid rgba(0, 212, 255, 0.3);
|
border-radius: 6px;
|
color: #999;
|
cursor: pointer;
|
transition: all 0.3s;
|
}
|
|
.tab.active {
|
background: rgba(0, 212, 255, 0.2);
|
color: #00d4ff;
|
border-color: #00d4ff;
|
}
|
|
.area-chart,
|
.line-chart {
|
height: 150px;
|
}
|
|
/* 自定义单选按钮组样式 */
|
.custom-radio-group :deep(.el-radio-button__inner) {
|
background-color: transparent;
|
color: white;
|
border-color: rgba(255, 255, 255, 0.3);
|
}
|
|
.custom-radio-group :deep(.el-radio-button__original-radio:checked + .el-radio-button__inner) {
|
background-color: rgba(255, 255, 255, 0.2);
|
color: white;
|
border-color: rgba(255, 255, 255, 0.5);
|
box-shadow: -1px 0 0 0 rgba(255, 255, 255, 0.5);
|
}
|
</style>
|