<template>
|
<div class="std-cost-page">
|
<el-card class="filter-card" shadow="never">
|
<template #header>
|
<div class="card-head">
|
<div class="card-head-left">
|
<el-icon class="card-icon ui-icon"><DataLine /></el-icon>
|
<span class="card-title">标准/实际成本对比分析</span>
|
<span class="subtle">差异 = 实际成本 - 标准成本</span>
|
</div>
|
</div>
|
</template>
|
|
<div class="filter-layout">
|
<el-form :model="searchForm" :inline="true" class="filter-form">
|
<el-form-item label="月份范围">
|
<el-date-picker
|
v-model="searchForm.monthRange"
|
type="monthrange"
|
range-separator="至"
|
start-placeholder="开始月份"
|
end-placeholder="结束月份"
|
value-format="YYYY-MM"
|
class="w-260"
|
@change="handleQuery"
|
/>
|
</el-form-item>
|
<el-form-item label="产品类别">
|
<el-select
|
v-model="searchForm.category"
|
clearable
|
filterable
|
placeholder="全部类别"
|
class="w-180"
|
@change="handleQuery"
|
>
|
<el-option
|
v-for="item in categoryOptions"
|
:key="item"
|
:label="item"
|
:value="item"
|
/>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="成本类型">
|
<el-select
|
v-model="searchForm.costType"
|
clearable
|
placeholder="全部类型"
|
class="w-180"
|
@change="handleQuery"
|
>
|
<el-option label="能耗成本" value="能耗成本" />
|
<el-option label="生产成本" value="生产成本" />
|
</el-select>
|
</el-form-item>
|
</el-form>
|
|
<div class="filter-actions">
|
<div class="action-group">
|
<el-button class="lux-btn" type="primary" @click="handleQuery">刷新</el-button>
|
<el-button class="lux-btn" @click="handleReset">重置</el-button>
|
</div>
|
<div class="action-group">
|
<el-dropdown trigger="click" @command="handleImportCommand">
|
<el-button class="lux-btn" type="success" plain>
|
标准成本导入
|
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
</el-button>
|
<template #dropdown>
|
<el-dropdown-menu>
|
<el-dropdown-item command="template">下载导入模板</el-dropdown-item>
|
<el-dropdown-item command="upload">Excel 导入</el-dropdown-item>
|
</el-dropdown-menu>
|
</template>
|
</el-dropdown>
|
<el-upload
|
ref="uploadRef"
|
class="hidden-upload"
|
:auto-upload="false"
|
:show-file-list="false"
|
accept=".xlsx,.xls"
|
:on-change="handleFileChange"
|
/>
|
</div>
|
</div>
|
</div>
|
</el-card>
|
|
<el-card class="panel-card" shadow="never">
|
<div class="kpi-strip">
|
<div class="kpi-item kpi-std">
|
<div class="kpi-label">标准成本合计</div>
|
<div class="kpi-value">¥{{ formatMoney(overview.standardCost) }}</div>
|
</div>
|
<div class="kpi-item kpi-act">
|
<div class="kpi-label">实际成本合计</div>
|
<div class="kpi-value">¥{{ formatMoney(overview.actualCost) }}</div>
|
</div>
|
<div class="kpi-item kpi-diff">
|
<div class="kpi-label">差异合计</div>
|
<div class="kpi-value" :class="overview.diff >= 0 ? 'cost-value' : 'ok-value'">
|
¥{{ formatMoney(overview.diff) }}
|
</div>
|
</div>
|
<div class="kpi-item kpi-rate">
|
<div class="kpi-label">差异率</div>
|
<div class="kpi-value">{{ formatPercent(overview.diffRate) }}</div>
|
</div>
|
</div>
|
</el-card>
|
|
<el-card class="table-card" shadow="never">
|
<template #header>
|
<div class="panel-head">
|
<span class="card-title">标准/实际成本可视化(柱状 + 折线)</span>
|
<span class="subtle">支持按月份、产品类别、成本类型筛选</span>
|
</div>
|
</template>
|
<div class="chart-wrap">
|
<div ref="chartRef" class="chart-content"></div>
|
</div>
|
</el-card>
|
|
<el-card class="table-card" shadow="never">
|
<template #header>
|
<div class="panel-head">
|
<span class="card-title">对比明细</span>
|
<span class="subtle">共 {{ tableData.length }} 条</span>
|
</div>
|
</template>
|
<el-table :data="pagedTableData" stripe class="lux-table">
|
<el-table-column prop="month" label="月份" width="110" />
|
<el-table-column prop="category" label="产品类别" min-width="140" />
|
<el-table-column prop="costType" label="成本类型" min-width="120" />
|
<el-table-column prop="standardCost" label="标准成本(元)" align="right">
|
<template #default="scope">¥{{ formatMoney(scope.row.standardCost) }}</template>
|
</el-table-column>
|
<el-table-column prop="actualCost" label="实际成本(元)" align="right">
|
<template #default="scope">¥{{ formatMoney(scope.row.actualCost) }}</template>
|
</el-table-column>
|
<el-table-column prop="diff" label="差异(元)" align="right">
|
<template #default="scope">
|
<span :class="scope.row.diff >= 0 ? 'cost-value' : 'ok-value'">
|
{{ formatSignedMoney(scope.row.diff) }}
|
</span>
|
</template>
|
</el-table-column>
|
<el-table-column prop="diffRate" label="差异率" align="right">
|
<template #default="scope">
|
<span :class="scope.row.diffRate >= 0 ? 'cost-value' : 'ok-value'">
|
{{ formatPercent(scope.row.diffRate) }}
|
</span>
|
</template>
|
</el-table-column>
|
</el-table>
|
<div class="pagination-container">
|
<el-pagination
|
v-model:current-page="page.current"
|
v-model:page-size="page.size"
|
:page-sizes="[10, 20, 50, 100]"
|
:total="tableData.length"
|
layout="total, sizes, prev, pager, next, jumper"
|
@size-change="handleSizeChange"
|
@current-change="handleCurrentChange"
|
/>
|
</div>
|
</el-card>
|
</div>
|
</template>
|
|
<script setup>
|
import { computed, nextTick, onMounted, onUnmounted, reactive, ref, watch } from "vue";
|
import { ArrowDown, DataLine } from "@element-plus/icons-vue";
|
import { ElMessage } from "element-plus";
|
import * as echarts from "echarts";
|
import * as XLSX from "xlsx";
|
|
const getDefaultMonthRange = () => {
|
const end = new Date();
|
const start = new Date();
|
start.setMonth(start.getMonth() - 2);
|
return [start.toISOString().slice(0, 7), end.toISOString().slice(0, 7)];
|
};
|
|
const searchForm = reactive({
|
monthRange: getDefaultMonthRange(),
|
category: "",
|
costType: "",
|
});
|
|
const uploadRef = ref();
|
const chartRef = ref(null);
|
let chartInstance = null;
|
|
const actualCostSource = ref([
|
{ month: "2026-01", category: "瓷砖", costType: "能耗成本", actualCost: 182000 },
|
{ month: "2026-01", category: "瓷砖", costType: "生产成本", actualCost: 465000 },
|
{ month: "2026-01", category: "水泥", costType: "能耗成本", actualCost: 138500 },
|
{ month: "2026-01", category: "水泥", costType: "生产成本", actualCost: 398000 },
|
{ month: "2026-02", category: "瓷砖", costType: "能耗成本", actualCost: 191500 },
|
{ month: "2026-02", category: "瓷砖", costType: "生产成本", actualCost: 472500 },
|
{ month: "2026-02", category: "水泥", costType: "能耗成本", actualCost: 142300 },
|
{ month: "2026-02", category: "水泥", costType: "生产成本", actualCost: 407000 },
|
{ month: "2026-03", category: "砂浆", costType: "能耗成本", actualCost: 95800 },
|
{ month: "2026-03", category: "砂浆", costType: "生产成本", actualCost: 265400 },
|
{ month: "2026-03", category: "瓷砖", costType: "能耗成本", actualCost: 189800 },
|
{ month: "2026-03", category: "瓷砖", costType: "生产成本", actualCost: 469900 },
|
]);
|
|
const standardCostSource = ref([
|
{ month: "2026-01", category: "瓷砖", costType: "能耗成本", standardCost: 176000 },
|
{ month: "2026-01", category: "瓷砖", costType: "生产成本", standardCost: 452000 },
|
{ month: "2026-01", category: "水泥", costType: "能耗成本", standardCost: 136000 },
|
{ month: "2026-01", category: "水泥", costType: "生产成本", standardCost: 392000 },
|
{ month: "2026-02", category: "瓷砖", costType: "能耗成本", standardCost: 186000 },
|
{ month: "2026-02", category: "瓷砖", costType: "生产成本", standardCost: 458000 },
|
{ month: "2026-02", category: "水泥", costType: "能耗成本", standardCost: 139000 },
|
{ month: "2026-02", category: "水泥", costType: "生产成本", standardCost: 401000 },
|
{ month: "2026-03", category: "砂浆", costType: "能耗成本", standardCost: 93000 },
|
{ month: "2026-03", category: "砂浆", costType: "生产成本", standardCost: 259000 },
|
{ month: "2026-03", category: "瓷砖", costType: "能耗成本", standardCost: 185000 },
|
{ month: "2026-03", category: "瓷砖", costType: "生产成本", standardCost: 461000 },
|
]);
|
|
const categoryOptions = computed(() => {
|
const all = [...actualCostSource.value, ...standardCostSource.value];
|
return Array.from(new Set(all.map((item) => item.category)));
|
});
|
|
const inRange = (value, range) => {
|
if (!Array.isArray(range) || range.length !== 2 || !range[0] || !range[1]) return true;
|
return value >= range[0] && value <= range[1];
|
};
|
|
const mergedRows = computed(() => {
|
const key = (item) => `${item.month}__${item.category}__${item.costType}`;
|
const stdMap = new Map(standardCostSource.value.map((item) => [key(item), item]));
|
const actMap = new Map(actualCostSource.value.map((item) => [key(item), item]));
|
const keySet = new Set([...stdMap.keys(), ...actMap.keys()]);
|
const rows = [];
|
|
for (const k of keySet) {
|
const std = stdMap.get(k);
|
const act = actMap.get(k);
|
const month = std?.month || act?.month || "";
|
const category = std?.category || act?.category || "";
|
const costType = std?.costType || act?.costType || "";
|
const standardCost = Number(std?.standardCost || 0);
|
const actualCost = Number(act?.actualCost || 0);
|
const diff = actualCost - standardCost;
|
const diffRate = standardCost === 0 ? 0 : (diff / standardCost) * 100;
|
|
rows.push({ month, category, costType, standardCost, actualCost, diff, diffRate });
|
}
|
|
return rows.sort((a, b) => {
|
if (a.month !== b.month) return a.month > b.month ? 1 : -1;
|
if (a.category !== b.category) return a.category.localeCompare(b.category, "zh-Hans-CN");
|
return a.costType.localeCompare(b.costType, "zh-Hans-CN");
|
});
|
});
|
|
const tableData = computed(() =>
|
mergedRows.value.filter((item) => {
|
const hitMonth = inRange(item.month, searchForm.monthRange);
|
const hitCategory = !searchForm.category || item.category === searchForm.category;
|
const hitCostType = !searchForm.costType || item.costType === searchForm.costType;
|
return hitMonth && hitCategory && hitCostType;
|
})
|
);
|
|
const page = reactive({
|
current: 1,
|
size: 10,
|
});
|
|
const pagedTableData = computed(() => {
|
const start = (page.current - 1) * page.size;
|
return tableData.value.slice(start, start + page.size);
|
});
|
|
const overview = computed(() => {
|
const standardCost = tableData.value.reduce((sum, item) => sum + item.standardCost, 0);
|
const actualCost = tableData.value.reduce((sum, item) => sum + item.actualCost, 0);
|
const diff = actualCost - standardCost;
|
const diffRate = standardCost === 0 ? 0 : (diff / standardCost) * 100;
|
return { standardCost, actualCost, diff, diffRate };
|
});
|
|
const getChartData = () => {
|
const xAxis = tableData.value.map(
|
(item) => `${item.month}\n${item.category}-${item.costType.replace("成本", "")}`
|
);
|
const standard = tableData.value.map((item) => item.standardCost);
|
const actual = tableData.value.map((item) => item.actualCost);
|
const diffRate = tableData.value.map((item) => Number(item.diffRate.toFixed(2)));
|
return { xAxis, standard, actual, diffRate };
|
};
|
|
const updateChart = () => {
|
if (!chartInstance) return;
|
const { xAxis, standard, actual, diffRate } = getChartData();
|
chartInstance.setOption({
|
tooltip: {
|
trigger: "axis",
|
axisPointer: { type: "shadow" },
|
formatter: (params) => {
|
const row = tableData.value[params[0]?.dataIndex] || {};
|
return [
|
`${row.month || ""} ${row.category || ""} ${row.costType || ""}`,
|
`标准成本:¥${formatMoney(row.standardCost || 0)}`,
|
`实际成本:¥${formatMoney(row.actualCost || 0)}`,
|
`差异:${formatSignedMoney(row.diff || 0)}`,
|
`差异率:${formatPercent(row.diffRate || 0)}`,
|
].join("<br/>");
|
},
|
},
|
legend: { data: ["标准成本", "实际成本", "差异率"] },
|
grid: { left: "4%", right: "4%", top: "16%", bottom: "16%", containLabel: true },
|
xAxis: {
|
type: "category",
|
data: xAxis,
|
axisLabel: { color: "rgba(15, 23, 42, 0.62)" },
|
axisLine: { lineStyle: { color: "rgba(15, 23, 42, 0.08)" } },
|
},
|
yAxis: [
|
{
|
type: "value",
|
name: "成本(元)",
|
axisLabel: { color: "rgba(15, 23, 42, 0.58)" },
|
splitLine: { lineStyle: { color: "rgba(15, 23, 42, 0.06)" } },
|
},
|
{
|
type: "value",
|
name: "差异率(%)",
|
axisLabel: { color: "rgba(15, 23, 42, 0.58)" },
|
splitLine: { show: false },
|
},
|
],
|
series: [
|
{
|
name: "标准成本",
|
type: "bar",
|
barMaxWidth: 24,
|
data: standard,
|
itemStyle: { color: "#5b8cff", borderRadius: [4, 4, 0, 0] },
|
},
|
{
|
name: "实际成本",
|
type: "bar",
|
barMaxWidth: 24,
|
data: actual,
|
itemStyle: { color: "#f59e0b", borderRadius: [4, 4, 0, 0] },
|
},
|
{
|
name: "差异率",
|
type: "line",
|
yAxisIndex: 1,
|
smooth: true,
|
data: diffRate,
|
itemStyle: { color: "#ef4444" },
|
lineStyle: { width: 2 },
|
},
|
],
|
});
|
};
|
|
const normalizeCostType = (value) => {
|
const text = String(value || "").trim();
|
if (!text) return "";
|
if (text.includes("能耗")) return "能耗成本";
|
if (text.includes("生产")) return "生产成本";
|
return text;
|
};
|
|
const parseImportedRows = (rows) => {
|
const normalized = rows
|
.map((item) => {
|
const month = String(item["月份"] || item.month || "").slice(0, 7);
|
const category = String(item["产品类别"] || item.category || "").trim();
|
const costType = normalizeCostType(item["成本类型"] || item.costType);
|
const standardCost = Number(item["标准成本"] ?? item.standardCost ?? 0);
|
return { month, category, costType, standardCost };
|
})
|
.filter((item) => item.month && item.category && item.costType && Number.isFinite(item.standardCost));
|
|
return normalized;
|
};
|
|
const replaceStandardSourceByImport = (importRows) => {
|
const map = new Map();
|
for (const item of importRows) {
|
const k = `${item.month}__${item.category}__${item.costType}`;
|
map.set(k, item);
|
}
|
standardCostSource.value = Array.from(map.values());
|
};
|
|
const handleFileChange = async (uploadFile) => {
|
try {
|
const file = uploadFile.raw;
|
if (!file) return;
|
const data = await file.arrayBuffer();
|
const workbook = XLSX.read(data, { type: "array" });
|
const sheetName = workbook.SheetNames[0];
|
const sheet = workbook.Sheets[sheetName];
|
const rows = XLSX.utils.sheet_to_json(sheet, { defval: "" });
|
const parsed = parseImportedRows(rows);
|
if (!parsed.length) {
|
ElMessage.warning("导入失败:模板内容为空或字段不匹配");
|
return;
|
}
|
replaceStandardSourceByImport(parsed);
|
ElMessage.success(`导入成功:${parsed.length} 条标准成本记录`);
|
handleQuery();
|
} catch (error) {
|
console.error(error);
|
ElMessage.error("导入失败,请检查 Excel 格式");
|
} finally {
|
uploadRef.value?.clearFiles?.();
|
}
|
};
|
|
const openUploadSelector = () => {
|
const input = uploadRef.value?.$el?.querySelector?.("input[type='file']");
|
if (!input) {
|
ElMessage.warning("上传组件尚未就绪,请稍后重试");
|
return;
|
}
|
input.click();
|
};
|
|
const handleImportCommand = (command) => {
|
if (command === "template") {
|
downloadTemplate();
|
return;
|
}
|
if (command === "upload") {
|
openUploadSelector();
|
}
|
};
|
|
const downloadTemplate = () => {
|
const sample = [
|
{ 月份: "2026-03", 产品类别: "瓷砖", 成本类型: "标准能耗成本", 标准成本: 185000 },
|
{ 月份: "2026-03", 产品类别: "瓷砖", 成本类型: "标准生产成本", 标准成本: 461000 },
|
{ 月份: "2026-03", 产品类别: "水泥", 成本类型: "标准能耗成本", 标准成本: 140000 },
|
{ 月份: "2026-03", 产品类别: "水泥", 成本类型: "标准生产成本", 标准成本: 405000 },
|
];
|
const ws = XLSX.utils.json_to_sheet(sample);
|
const wb = XLSX.utils.book_new();
|
XLSX.utils.book_append_sheet(wb, ws, "标准成本模板");
|
XLSX.writeFile(wb, "标准成本按月导入模板.xlsx");
|
ElMessage.success("模板已下载");
|
};
|
|
const handleQuery = () => {
|
updateChart();
|
};
|
|
const handleReset = () => {
|
searchForm.monthRange = getDefaultMonthRange();
|
searchForm.category = "";
|
searchForm.costType = "";
|
page.current = 1;
|
handleQuery();
|
};
|
|
const handleSizeChange = (val) => {
|
page.size = val;
|
page.current = 1;
|
};
|
|
const handleCurrentChange = (val) => {
|
page.current = val;
|
};
|
|
const formatMoney = (v) => {
|
const n = Number.parseFloat(v);
|
const value = Number.isFinite(n) ? n : 0;
|
return value.toLocaleString("zh-CN", {
|
minimumFractionDigits: 2,
|
maximumFractionDigits: 2,
|
});
|
};
|
|
const formatSignedMoney = (v) => {
|
const n = Number.parseFloat(v);
|
const value = Number.isFinite(n) ? n : 0;
|
const sign = value >= 0 ? "+" : "";
|
return `${sign}¥${formatMoney(value)}`;
|
};
|
|
const formatPercent = (v) => {
|
const n = Number.parseFloat(v);
|
const value = Number.isFinite(n) ? n : 0;
|
const sign = value >= 0 ? "+" : "";
|
return `${sign}${value.toFixed(2)}%`;
|
};
|
|
const handleResize = () => {
|
chartInstance?.resize?.();
|
};
|
|
onMounted(() => {
|
nextTick(() => {
|
if (chartRef.value && !chartInstance) {
|
chartInstance = echarts.init(chartRef.value);
|
}
|
updateChart();
|
});
|
window.addEventListener("resize", handleResize);
|
});
|
|
onUnmounted(() => {
|
window.removeEventListener("resize", handleResize);
|
chartInstance?.dispose?.();
|
chartInstance = null;
|
});
|
|
watch(tableData, () => {
|
const maxPage = Math.max(1, Math.ceil(tableData.value.length / page.size));
|
if (page.current > maxPage) page.current = maxPage;
|
nextTick(updateChart);
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.std-cost-page {
|
--lux-bg: #f6f7fb;
|
--lux-card: rgba(255, 255, 255, 0.86);
|
--lux-border: rgba(15, 23, 42, 0.08);
|
--lux-text: rgba(15, 23, 42, 0.92);
|
--lux-subtle: rgba(15, 23, 42, 0.58);
|
--lux-primary: #2f6fed;
|
--lux-success: #16a34a;
|
--lux-warning: #f59e0b;
|
--lux-danger: #ef4444;
|
--lux-shadow-soft: 0 10px 28px rgba(15, 23, 42, 0.06);
|
--lux-radius: 14px;
|
|
padding: 18px 22px 24px;
|
background: radial-gradient(
|
1200px 420px at 20% 0%,
|
rgba(47, 111, 237, 0.1),
|
transparent 55%
|
),
|
linear-gradient(180deg, var(--lux-bg) 0%, #ffffff 58%);
|
}
|
|
.filter-card,
|
.panel-card,
|
.table-card {
|
border-radius: var(--lux-radius);
|
border-color: var(--lux-border);
|
background: var(--lux-card);
|
box-shadow: var(--lux-shadow-soft);
|
}
|
|
.filter-card,
|
.panel-card,
|
.table-card {
|
margin-bottom: 14px;
|
}
|
|
.filter-layout {
|
display: flex;
|
flex-direction: column;
|
gap: 10px;
|
}
|
|
.filter-form {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 10px 14px;
|
align-items: center;
|
}
|
|
.filter-form :deep(.el-form-item) {
|
margin: 0;
|
}
|
|
.filter-actions {
|
display: flex;
|
justify-content: flex-end;
|
align-items: center;
|
flex-wrap: wrap;
|
gap: 10px 14px;
|
padding-top: 10px;
|
border-top: 1px dashed rgba(15, 23, 42, 0.1);
|
}
|
|
.action-group {
|
display: flex;
|
align-items: center;
|
gap: 10px;
|
flex-wrap: wrap;
|
}
|
|
.filter-actions :deep(.el-upload) {
|
display: inline-flex;
|
}
|
|
.hidden-upload {
|
width: 0;
|
height: 0;
|
overflow: hidden;
|
}
|
|
.card-head,
|
.panel-head {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
gap: 10px;
|
}
|
|
.card-head-left {
|
display: flex;
|
align-items: center;
|
gap: 8px;
|
}
|
|
.card-icon {
|
color: var(--lux-primary);
|
}
|
|
.card-title {
|
font-weight: 760;
|
color: var(--lux-text);
|
}
|
|
.subtle {
|
color: var(--lux-subtle);
|
font-size: 12px;
|
}
|
|
.kpi-strip {
|
display: grid;
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
gap: 12px;
|
}
|
|
.kpi-item {
|
padding: 12px 14px;
|
border-radius: 12px;
|
border: 1px solid rgba(15, 23, 42, 0.08);
|
}
|
|
.kpi-std {
|
background: linear-gradient(135deg, rgba(47, 111, 237, 0.1), rgba(255, 255, 255, 0.86));
|
}
|
|
.kpi-act {
|
background: linear-gradient(135deg, rgba(245, 158, 11, 0.1), rgba(255, 255, 255, 0.86));
|
}
|
|
.kpi-diff {
|
background: linear-gradient(135deg, rgba(239, 68, 68, 0.08), rgba(255, 255, 255, 0.86));
|
}
|
|
.kpi-rate {
|
background: linear-gradient(135deg, rgba(22, 163, 74, 0.1), rgba(255, 255, 255, 0.86));
|
}
|
|
.kpi-label {
|
font-size: 12px;
|
color: var(--lux-subtle);
|
}
|
|
.kpi-value {
|
margin-top: 6px;
|
font-size: 22px;
|
font-weight: 780;
|
color: var(--lux-text);
|
}
|
|
.cost-value {
|
color: var(--lux-danger);
|
font-weight: 700;
|
}
|
|
.ok-value {
|
color: var(--lux-success);
|
font-weight: 700;
|
}
|
|
.chart-wrap {
|
border-radius: 12px;
|
overflow: hidden;
|
}
|
|
.chart-content {
|
height: 360px;
|
}
|
|
.pagination-container {
|
display: flex;
|
justify-content: flex-end;
|
padding-top: 12px;
|
}
|
|
.w-260 {
|
width: 260px;
|
}
|
|
.w-180 {
|
width: 180px;
|
}
|
|
::deep(.lux-table) {
|
border-radius: 12px;
|
overflow: hidden;
|
}
|
|
::deep(.lux-table th.el-table__cell) {
|
background: rgba(15, 23, 42, 0.03);
|
}
|
|
::deep(.lux-table .el-table__row:hover > td.el-table__cell) {
|
background-color: rgba(47, 111, 237, 0.06) !important;
|
}
|
|
@media (max-width: 1100px) {
|
.kpi-strip {
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
}
|
|
.filter-actions {
|
justify-content: flex-start;
|
padding-top: 8px;
|
}
|
}
|
</style>
|