<template>
|
<div class="dashboard-container">
|
<!-- 顶部KPI卡片:显示总货位及各仓库货位 -->
|
<div class="kpi-cards">
|
<div class="kpi-card">
|
<div class="kpi-icon">🏚️</div>
|
<div class="kpi-info">
|
<div class="kpi-label">总货位</div>
|
<div class="kpi-value">{{ totalLocation }}</div>
|
</div>
|
</div>
|
<div class="kpi-card">
|
<div class="kpi-icon">🔥</div>
|
<div class="kpi-info">
|
<div class="kpi-label">化成库</div>
|
<div class="kpi-value">{{ warehouseLocations.hc }}</div>
|
</div>
|
</div>
|
<div class="kpi-card">
|
<div class="kpi-icon">🌡️</div>
|
<div class="kpi-info">
|
<div class="kpi-label">高温库</div>
|
<div class="kpi-value">{{ warehouseLocations.gw }}</div>
|
</div>
|
</div>
|
<div class="kpi-card">
|
<div class="kpi-icon">❄️</div>
|
<div class="kpi-info">
|
<div class="kpi-label">常温库</div>
|
<div class="kpi-value">{{ warehouseLocations.cw }}</div>
|
</div>
|
</div>
|
<div class="kpi-card">
|
<div class="kpi-icon">📜</div>
|
<div class="kpi-info">
|
<div class="kpi-label">极卷库</div>
|
<div class="kpi-value">{{ warehouseLocations.jj }}</div>
|
</div>
|
</div>
|
</div>
|
|
<!-- 第一行:4个每日出入库趋势图(每行2个) -->
|
<div class="chart-row daily-grid">
|
<div class="chart-card" v-for="warehouse in dailyWarehouses" :key="warehouse.code">
|
<div class="card-title">{{ warehouse.name }} - 每日趋势</div>
|
<!-- 仓库数字显示区域:显示每日总量和空托盘数量 -->
|
<div class="warehouse-numbers">
|
<!-- 极卷库显示有货托盘(电池数量)和空托盘 -->
|
<template v-if="warehouse.code === 'ROLL'">
|
<div class="number-item battery">
|
<span class="number-label">电池数量</span>
|
<span class="number-value">{{ getBatteryCount(warehouse.code) }}</span>
|
</div>
|
<div class="number-item empty-tray">
|
<span class="number-label">空托盘数量</span>
|
<span class="number-value">{{ getEmptyTrayCount(warehouse.code) }}</span>
|
</div>
|
</template>
|
<!-- 其他仓库显示电池数量和空托盘数量 -->
|
<template v-else>
|
<div class="number-item inbound">
|
<span class="number-label">电池数量</span>
|
<span class="number-value">{{ getBatteryCount(warehouse.code) }}</span>
|
</div>
|
<div class="number-item empty-tray">
|
<span class="number-label">空托盘数量</span>
|
<span class="number-value">{{ getEmptyTrayCount(warehouse.code) }}</span>
|
</div>
|
</template>
|
</div>
|
<div :id="`daily-chart-${warehouse.code}`" class="chart-content"></div>
|
</div>
|
</div>
|
|
<!-- 仓库分布(柱状图,显示各仓库已用/剩余容量) -->
|
<div class="chart-row">
|
<div class="chart-card">
|
<div class="card-title">各仓库库存分布</div>
|
<div id="chart-warehouse" class="chart-content"></div>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import * as echarts from "echarts";
|
|
export default {
|
name: "Home",
|
data() {
|
return {
|
charts: {},
|
// 四个核心仓库(合并了正负极卷库为极卷库)
|
dailyWarehouses: [
|
{ code: "HCSC1", name: "化成库", type: "hc" },
|
{ code: "GWSC1", name: "高温库", type: "gw" },
|
{ code: "CWSC1", name: "常温库", type: "cw" },
|
{ code: "ROLL", name: "极卷库", type: "jj" }
|
],
|
// 原始每日数据存储 (其中ROLL为合并后的极卷库数据)
|
dailyDataMap: {
|
GWSC1: [],
|
CWSC1: [],
|
HCSC1: [],
|
ROLL: []
|
},
|
// 存储每个仓库的电池数量
|
warehouseStocks: {
|
GWSC1: 0,
|
CWSC1: 0,
|
HCSC1: 0,
|
ROLL: 0
|
},
|
// 极卷库特殊数据
|
rollData: {
|
batteryCount: 0, // 电池数量
|
emptyTrayCount: 0 // 空托盘数量
|
},
|
// 其他仓库的空托盘数量
|
emptyTrayCounts: {
|
GWSC1: 0,
|
CWSC1: 0,
|
HCSC1: 0
|
},
|
warehouseData: [], // 仓库分布图数据
|
// 仓库货位数据(固定配置)
|
warehouseLocations: {
|
hc: 35, // 化成库
|
gw: 324, // 高温库
|
cw: 140, // 常温库
|
jj: 104 // 极卷库
|
}
|
};
|
},
|
computed: {
|
// 总货位计算
|
totalLocation() {
|
return this.warehouseLocations.hc + this.warehouseLocations.gw +
|
this.warehouseLocations.cw + this.warehouseLocations.jj;
|
}
|
},
|
mounted() {
|
this.initCharts();
|
this.loadData();
|
window.addEventListener("resize", this.handleResize);
|
},
|
beforeUnmount() {
|
window.removeEventListener("resize", this.handleResize);
|
Object.values(this.charts).forEach(chart => chart && chart.dispose());
|
},
|
methods: {
|
handleResize() {
|
Object.values(this.charts).forEach(chart => chart && chart.resize());
|
},
|
|
initCharts() {
|
// 初始化每日图表
|
this.dailyWarehouses.forEach(warehouse => {
|
const chartId = `daily-chart-${warehouse.code}`;
|
const el = document.getElementById(chartId);
|
if (el) {
|
this.charts[`daily-${warehouse.code}`] = echarts.init(el);
|
}
|
});
|
// 初始化仓库分布图表
|
this.charts.warehouse = echarts.init(document.getElementById("chart-warehouse"));
|
},
|
|
async loadData() {
|
try {
|
// 并行加载所有数据
|
await Promise.all([
|
this.loadAllDailyStats(),
|
this.loadStockAndTrayCount(),
|
this.loadStockByWarehouse()
|
]);
|
|
// 更新所有图表
|
this.updateAllDailyCharts();
|
} catch (error) {
|
console.error("加载数据失败:", error);
|
this.$message?.error("数据加载失败,请稍后重试");
|
}
|
},
|
|
async loadAllDailyStats() {
|
console.log("正在加载所有仓库的每日统计数据...");
|
const res = await this.http.get("/api/Dashboard/DailyStats?days=10");
|
if (res.status && res.data) {
|
console.log("所有仓库每日统计数据:", res.data);
|
|
const dataArray = res.data;
|
|
// 按仓库分类数据
|
dataArray.forEach(item => {
|
const roadway = item.roadway;
|
const dailyStats = item.dailyStats || [];
|
|
switch(roadway) {
|
case "GWSC1":
|
this.dailyDataMap.GWSC1 = dailyStats;
|
break;
|
case "CWSC1":
|
this.dailyDataMap.CWSC1 = dailyStats;
|
break;
|
case "HCSC1":
|
this.dailyDataMap.HCSC1 = dailyStats;
|
break;
|
case "ZJSC1":
|
case "FJSC1":
|
// 极卷库数据合并处理
|
this.mergeRollDailyStats(dailyStats);
|
break;
|
}
|
});
|
|
console.log("GWSC1数据:", this.dailyDataMap.GWSC1);
|
console.log("CWSC1数据:", this.dailyDataMap.CWSC1);
|
console.log("HCSC1数据:", this.dailyDataMap.HCSC1);
|
console.log("极卷库合并数据:", this.dailyDataMap.ROLL);
|
} else {
|
console.error("获取每日数据失败");
|
}
|
},
|
|
mergeRollDailyStats(newData) {
|
// 合并正极卷库和负极卷库的每日数据
|
if (!this.dailyDataMap.ROLL.length) {
|
this.dailyDataMap.ROLL = [...newData];
|
} else {
|
const dateMap = new Map();
|
[...this.dailyDataMap.ROLL, ...newData].forEach(item => {
|
const date = item.date;
|
if (date) {
|
if (!dateMap.has(date)) {
|
dateMap.set(date, { date, inbound: 0, outbound: 0 });
|
}
|
const existing = dateMap.get(date);
|
existing.inbound += item.inbound || 0;
|
existing.outbound += item.outbound || 0;
|
}
|
});
|
|
const sortedDates = Array.from(dateMap.keys()).sort();
|
const mergedData = sortedDates.map(date => dateMap.get(date));
|
this.dailyDataMap["ROLL"] = mergedData;
|
}
|
},
|
|
async loadStockAndTrayCount() {
|
// 加载电池数量和空托盘数量
|
console.log("正在加载电池数量和空托盘数据...");
|
const res = await this.http.get("/api/Dashboard/StockAndTrayCount");
|
|
if (res.status && res.data) {
|
console.log("电池和空托盘数据:", res.data);
|
|
// 重置数据
|
this.rollData.batteryCount = 0;
|
this.rollData.emptyTrayCount = 0;
|
|
// 根据返回的数据结构解析
|
res.data.forEach(item => {
|
const warehouseName = item.warehouseName;
|
const batteryCount = item.batteryCount || 0;
|
const emptyTrayCount = item.emptyTrayCount || 0;
|
|
// 根据仓库名称映射到对应的代码
|
if (warehouseName === "高温库") {
|
this.emptyTrayCounts.GWSC1 = emptyTrayCount;
|
this.warehouseStocks.GWSC1 = batteryCount;
|
} else if (warehouseName === "常温库") {
|
this.emptyTrayCounts.CWSC1 = emptyTrayCount;
|
this.warehouseStocks.CWSC1 = batteryCount;
|
} else if (warehouseName === "化成库") {
|
this.emptyTrayCounts.HCSC1 = emptyTrayCount;
|
this.warehouseStocks.HCSC1 = batteryCount;
|
} else if (warehouseName === "极卷库") {
|
// 极卷库需要合并两个极卷库的数据
|
this.rollData.batteryCount += batteryCount;
|
this.rollData.emptyTrayCount += emptyTrayCount;
|
}
|
});
|
|
// 设置极卷库总电池数量
|
this.warehouseStocks.ROLL = this.rollData.batteryCount;
|
|
console.log("特殊数据加载完成:", {
|
rollData: this.rollData,
|
emptyTrayCounts: this.emptyTrayCounts,
|
warehouseStocks: this.warehouseStocks
|
});
|
} else {
|
console.error("获取电池和空托盘数据失败");
|
throw new Error("获取电池和空托盘数据失败");
|
}
|
},
|
|
async loadStockByWarehouse() {
|
console.log("正在加载仓库分布数据...");
|
const res = await this.http.get("/api/Dashboard/StockByWarehouse");
|
|
if (res.status && res.data) {
|
console.log("仓库分布数据:", res.data);
|
const rawData = res.data.data || res.data;
|
|
// 处理极卷库合并
|
let rollHasStock = 0;
|
let rollNoStock = 0;
|
let rollTotal = 0;
|
const otherWarehouses = [];
|
|
rawData.forEach(item => {
|
if (item.warehouse === "极卷库" || item.warehouse.includes("极卷库")) {
|
// 合并极卷库数据
|
rollHasStock += item.hasStock || 0;
|
rollNoStock += item.noStock || 0;
|
rollTotal += item.total || 0;
|
} else {
|
otherWarehouses.push(item);
|
}
|
});
|
|
// 添加合并后的极卷库
|
if (rollTotal > 0) {
|
const hasStockPercentage = ((rollHasStock / rollTotal) * 100).toFixed(1) + "%";
|
const noStockPercentage = ((rollNoStock / rollTotal) * 100).toFixed(1) + "%";
|
|
otherWarehouses.push({
|
warehouse: "极卷库",
|
hasStock: rollHasStock,
|
noStock: rollNoStock,
|
total: rollTotal,
|
hasStockPercentage: hasStockPercentage,
|
noStockPercentage: noStockPercentage
|
});
|
}
|
|
this.warehouseData = otherWarehouses;
|
this.updateWarehouseChart();
|
} else {
|
console.error("获取仓库分布数据失败");
|
throw new Error("获取仓库分布数据失败");
|
}
|
},
|
|
getDailyTotalInbound(warehouseCode) {
|
const data = this.dailyDataMap[warehouseCode] || [];
|
return data.reduce((sum, item) => sum + (item.inbound || 0), 0);
|
},
|
|
getDailyTotalOutbound(warehouseCode) {
|
const data = this.dailyDataMap[warehouseCode] || [];
|
return data.reduce((sum, item) => sum + (item.outbound || 0), 0);
|
},
|
|
getWarehouseStock(warehouseCode) {
|
return this.warehouseStocks[warehouseCode] || 0;
|
},
|
|
getBatteryCount(warehouseCode) {
|
if (warehouseCode === 'ROLL') {
|
return this.rollData.batteryCount;
|
} else if (warehouseCode === 'GWSC1') {
|
return this.warehouseStocks.GWSC1;
|
} else if (warehouseCode === 'CWSC1') {
|
return this.warehouseStocks.CWSC1;
|
} else if (warehouseCode === 'HCSC1') {
|
return this.warehouseStocks.HCSC1;
|
}
|
return 0;
|
},
|
|
getEmptyTrayCount(warehouseCode) {
|
if (warehouseCode === 'ROLL') {
|
return this.rollData.emptyTrayCount;
|
} else if (warehouseCode === 'GWSC1') {
|
return this.emptyTrayCounts.GWSC1;
|
} else if (warehouseCode === 'CWSC1') {
|
return this.emptyTrayCounts.CWSC1;
|
} else if (warehouseCode === 'HCSC1') {
|
return this.emptyTrayCounts.HCSC1;
|
}
|
return 0;
|
},
|
|
updateAllDailyCharts() {
|
this.dailyWarehouses.forEach(warehouse => {
|
this.updateDailyChartForWarehouse(warehouse.code);
|
});
|
},
|
|
updateDailyChartForWarehouse(roadway) {
|
const chart = this.charts[`daily-${roadway}`];
|
if (!chart) return;
|
|
const data = this.dailyDataMap[roadway] || [];
|
|
// 如果没有数据,显示空图表提示
|
if (!data.length) {
|
chart.setOption({
|
title: {
|
show: true,
|
text: '暂无数据',
|
left: 'center',
|
top: 'center',
|
textStyle: { color: '#ccc', fontSize: 14 }
|
}
|
}, true);
|
return;
|
}
|
|
const dates = data.map(d => d.date);
|
const inboundData = data.map(d => d.inbound || 0);
|
const outboundData = data.map(d => d.outbound || 0);
|
|
const option = {
|
tooltip: {
|
trigger: "axis",
|
formatter: function(params) {
|
let result = params[0].axisValue + "<br/>";
|
params.forEach(p => {
|
result += `${p.marker}${p.seriesName}: ${p.value}<br/>`;
|
});
|
return result;
|
}
|
},
|
legend: {
|
data: ["入库", "出库"],
|
textStyle: { color: "#fff" },
|
top: 0,
|
right: 10,
|
itemWidth: 20,
|
itemHeight: 12
|
},
|
grid: {
|
left: "8%",
|
right: "8%",
|
top: "18%",
|
bottom: "12%",
|
containLabel: true
|
},
|
xAxis: {
|
type: "category",
|
data: dates,
|
axisLabel: {
|
color: "#ccc",
|
rotate: 45,
|
fontSize: 10,
|
interval: 0,
|
margin: 8
|
},
|
axisLine: { lineStyle: { color: "#4a5b6e" } }
|
},
|
yAxis: {
|
type: "value",
|
name: "数量",
|
nameTextStyle: { color: "#ccc", fontSize: 11 },
|
axisLabel: { color: "#ccc" },
|
splitLine: { lineStyle: { color: "#2a3a4a", type: "dashed" } }
|
},
|
series: [
|
{
|
name: "入库",
|
type: "bar",
|
data: inboundData,
|
itemStyle: {
|
color: "#5470c6",
|
borderRadius: [4, 4, 0, 0]
|
},
|
barWidth: "40%",
|
label: {
|
show: true,
|
position: "top",
|
color: "#5470c6",
|
fontSize: 10,
|
formatter: (params) => params.value
|
}
|
},
|
{
|
name: "出库",
|
type: "line",
|
data: outboundData,
|
symbol: "circle",
|
symbolSize: 6,
|
itemStyle: { color: "#91cc75" },
|
lineStyle: { width: 2, type: "solid" },
|
smooth: false,
|
label: {
|
show: true,
|
position: "top",
|
color: "#91cc75",
|
fontSize: 10,
|
formatter: (params) => params.value
|
}
|
}
|
]
|
};
|
chart.setOption(option, true);
|
},
|
|
updateWarehouseChart() {
|
if (!this.charts.warehouse) return;
|
|
if (!this.warehouseData.length) {
|
this.charts.warehouse.setOption({
|
title: {
|
show: true,
|
text: '暂无仓库数据',
|
left: 'center',
|
top: 'center',
|
textStyle: { color: '#ccc' }
|
}
|
});
|
return;
|
}
|
|
const warehouseNames = this.warehouseData.map(w => w.warehouse);
|
const hasStocks = this.warehouseData.map(w => w.hasStock);
|
const noStocks = this.warehouseData.map(w => w.noStock);
|
const hasStockPercentages = this.warehouseData.map(w => w.hasStockPercentage);
|
const noStockPercentages = this.warehouseData.map(w => w.noStockPercentage);
|
|
const option = {
|
tooltip: {
|
trigger: "axis",
|
axisPointer: { type: "shadow" },
|
formatter: (params) => {
|
let tip = params[0].name + "<br/>";
|
params.forEach(param => {
|
const dataIndex = param.dataIndex;
|
const warehouse = this.warehouseData[dataIndex];
|
if (warehouse) {
|
if (param.seriesName === "已用容量") {
|
tip += `${param.marker}${param.seriesName}: ${param.value} (${warehouse.hasStockPercentage})<br/>`;
|
tip += `有库存: ${warehouse.hasStock}<br/>`;
|
tip += `无库存: ${warehouse.noStock}<br/>`;
|
tip += `总容量: ${warehouse.total}`;
|
} else if (param.seriesName === "剩余容量") {
|
tip += `${param.marker}${param.seriesName}: ${param.value} (${warehouse.noStockPercentage})<br/>`;
|
}
|
} else {
|
tip += `${param.marker}${param.seriesName}: ${param.value}<br/>`;
|
}
|
});
|
return tip;
|
}
|
},
|
legend: {
|
data: ["已用容量", "剩余容量"],
|
textStyle: { color: "#fff" }
|
},
|
xAxis: {
|
type: "category",
|
data: warehouseNames,
|
axisLabel: { color: "#fff", rotate: 30, interval: 0 }
|
},
|
yAxis: {
|
type: "value",
|
name: "容量",
|
axisLabel: { color: "#fff" }
|
},
|
series: [
|
{
|
name: "已用容量",
|
type: "bar",
|
data: hasStocks.map((value, index) => ({
|
value: value,
|
label: {
|
show: true,
|
position: "top",
|
formatter: () => {
|
const pct = hasStockPercentages[index];
|
return `${value} (${pct})`;
|
},
|
color: "#91cc75",
|
fontSize: 11
|
}
|
})),
|
itemStyle: { color: "#91cc75" }
|
},
|
{
|
name: "剩余容量",
|
type: "bar",
|
data: noStocks.map((value, index) => ({
|
value: value,
|
label: {
|
show: true,
|
position: "top",
|
formatter: () => {
|
const pct = noStockPercentages[index];
|
return `${value} (${pct})`;
|
},
|
color: "#fac858",
|
fontSize: 11
|
}
|
})),
|
itemStyle: { color: "#fac858" }
|
}
|
]
|
};
|
|
this.charts.warehouse.setOption(option, true);
|
}
|
}
|
};
|
</script>
|
|
<style scoped>
|
.dashboard-container {
|
padding: 20px;
|
color: #e0e0e0;
|
min-height: calc(100vh - 60px);
|
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
|
background-attachment: fixed;
|
}
|
|
/* KPI 卡片样式 - 5列布局 */
|
.kpi-cards {
|
display: grid;
|
grid-template-columns: repeat(5, 1fr);
|
gap: 20px;
|
margin-bottom: 24px;
|
}
|
|
.kpi-card {
|
background: rgba(10, 16, 35, 0.7);
|
backdrop-filter: blur(10px);
|
border: 1px solid rgba(64, 224, 208, 0.3);
|
border-radius: 16px;
|
padding: 16px 20px;
|
display: flex;
|
align-items: center;
|
gap: 16px;
|
transition: all 0.3s ease;
|
box-shadow: 0 0 15px rgba(0, 255, 255, 0.1);
|
}
|
|
.kpi-card:hover {
|
transform: translateY(-3px);
|
border-color: rgba(64, 224, 208, 0.6);
|
box-shadow: 0 0 25px rgba(0, 255, 255, 0.2);
|
}
|
|
.kpi-icon {
|
font-size: 32px;
|
opacity: 0.9;
|
}
|
|
.kpi-info {
|
flex: 1;
|
}
|
|
.kpi-label {
|
font-size: 13px;
|
color: #8ba0b5;
|
margin-bottom: 6px;
|
letter-spacing: 1px;
|
}
|
|
.kpi-value {
|
font-size: 28px;
|
font-weight: 700;
|
color: #00ffff;
|
text-shadow: 0 0 10px rgba(0, 255, 255, 0.5);
|
line-height: 1.2;
|
}
|
|
/* 每日图表布局 - 每行2个 */
|
.chart-row.daily-grid {
|
display: grid;
|
grid-template-columns: repeat(2, 1fr);
|
gap: 20px;
|
margin-bottom: 20px;
|
}
|
|
.chart-card {
|
background: rgba(10, 16, 35, 0.6);
|
backdrop-filter: blur(10px);
|
border: 1px solid rgba(64, 224, 208, 0.3);
|
border-radius: 12px;
|
padding: 15px;
|
position: relative;
|
box-shadow: 0 0 15px rgba(0, 255, 255, 0.1), inset 0 0 10px rgba(64, 224, 208, 0.1);
|
transition: all 0.3s ease;
|
overflow: hidden;
|
}
|
|
.chart-card:hover {
|
transform: translateY(-5px);
|
box-shadow: 0 0 25px rgba(0, 255, 255, 0.3), inset 0 0 15px rgba(64, 224, 208, 0.2);
|
border: 1px solid rgba(64, 224, 208, 0.6);
|
}
|
|
.chart-card::before {
|
content: "";
|
position: absolute;
|
top: 0;
|
left: 0;
|
width: 10px;
|
height: 10px;
|
border-top: 2px solid #00ffff;
|
border-left: 2px solid #00ffff;
|
box-shadow: -2px -2px 10px #00ffff, 0 0 10px rgba(0, 255, 255, 0.7);
|
}
|
|
.chart-card::after {
|
content: "";
|
position: absolute;
|
top: 0;
|
right: 0;
|
width: 10px;
|
height: 10px;
|
border-top: 2px solid #00ffff;
|
border-right: 2px solid #00ffff;
|
box-shadow: 2px -2px 10px #00ffff, 0 0 10px rgba(0, 255, 255, 0.7);
|
}
|
|
.card-title {
|
color: #00ffff;
|
font-size: 15px;
|
text-align: center;
|
margin-bottom: 12px;
|
text-shadow: 0 0 10px rgba(0, 255, 255, 0.7);
|
font-weight: 500;
|
white-space: nowrap;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
}
|
|
/* 仓库数字显示区域 */
|
.warehouse-numbers {
|
display: flex;
|
justify-content: space-around;
|
margin-bottom: 12px;
|
padding: 8px 0;
|
background: rgba(0, 0, 0, 0.3);
|
border-radius: 8px;
|
flex-wrap: wrap;
|
}
|
|
.number-item {
|
text-align: center;
|
flex: 1;
|
min-width: 80px;
|
}
|
|
.number-label {
|
display: block;
|
font-size: 11px;
|
color: #8ba0b5;
|
margin-bottom: 4px;
|
}
|
|
.number-value {
|
display: block;
|
font-size: 18px;
|
font-weight: 700;
|
letter-spacing: 1px;
|
}
|
|
.number-item.inbound .number-value {
|
color: #5470c6;
|
}
|
|
.number-item.battery .number-value {
|
color: #ee6666;
|
}
|
|
.number-item.empty-tray .number-value {
|
color: #fc8452;
|
}
|
|
.chart-content {
|
height: 280px;
|
width: 100%;
|
}
|
|
@media (max-width: 768px) {
|
.kpi-cards {
|
grid-template-columns: repeat(2, 1fr);
|
}
|
.chart-row.daily-grid {
|
grid-template-columns: 1fr;
|
}
|
.chart-content {
|
height: 240px;
|
}
|
.card-title {
|
font-size: 13px;
|
white-space: normal;
|
}
|
.number-value {
|
font-size: 14px;
|
}
|
.number-item {
|
min-width: 60px;
|
}
|
}
|
|
.dashboard-container::before {
|
content: "";
|
position: fixed;
|
top: 0;
|
left: 0;
|
right: 0;
|
bottom: 0;
|
background-image: linear-gradient(rgba(64, 224, 208, 0.05) 1px, transparent 1px),
|
linear-gradient(90deg, rgba(64, 224, 208, 0.05) 1px, transparent 1px);
|
background-size: 30px 30px;
|
pointer-events: none;
|
z-index: -1;
|
}
|
</style>
|