<script setup lang="ts">
|
import { computed, nextTick, onMounted, ref } from 'vue';
|
import { jsonClone } from '@sa/utils';
|
import dompdf from 'dompdf.js';
|
import ExcelJS from 'exceljs';
|
import '@/assets/fonts/SourceHanSansSC-Normal-Min-normal.js';
|
import { fetchGetStoreSilkList } from '@/service/api/analy/store-silk';
|
import { useNaiveForm } from '@/hooks/common/form';
|
import { $t } from '@/locales';
|
|
defineOptions({
|
name: 'BatchProductionReport'
|
});
|
|
const { formRef, validate, restoreValidation } = useNaiveForm();
|
const zoom = ref(1);
|
const exportLoading = ref(false);
|
|
async function beginExportLoading() {
|
exportLoading.value = true;
|
await nextTick();
|
await new Promise<void>(resolve => {
|
requestAnimationFrame(() => {
|
requestAnimationFrame(() => resolve());
|
});
|
});
|
}
|
|
function formatNow() {
|
const now = new Date();
|
const y = now.getFullYear();
|
const m = String(now.getMonth() + 1).padStart(2, '0');
|
const d = String(now.getDate()).padStart(2, '0');
|
const hh = String(now.getHours()).padStart(2, '0');
|
const mm = String(now.getMinutes()).padStart(2, '0');
|
const ss = String(now.getSeconds()).padStart(2, '0');
|
return `${y}${m}${d}${hh}${mm}${ss}`;
|
}
|
|
// 搜索参数
|
const searchParams = ref<Api.Analy.StoreSilkSearchParams>({
|
pageNum: 1,
|
pageSize: 1000, // 报表通常显示较多数据
|
materialname: null,
|
batchcode: null,
|
actualstarttime: null,
|
distimebegin: null,
|
distimeend: null,
|
siloid: null,
|
params: {
|
beginTime: undefined,
|
endTime: undefined
|
}
|
});
|
|
const defaultSearchParams = jsonClone(searchParams.value);
|
|
// 日期范围 (用于搜索表单)
|
const searchDateRange = ref<[string, string] | null>(null);
|
|
function onDateRangeUpdate(value: [string, string] | null) {
|
if (!searchParams.value.params) {
|
searchParams.value.params = {};
|
}
|
if (value?.[0] && value?.[1]) {
|
searchParams.value.params.beginTime = value[0];
|
searchParams.value.params.endTime = value[1];
|
} else {
|
searchParams.value.params.beginTime = undefined;
|
searchParams.value.params.endTime = undefined;
|
}
|
}
|
|
// 柜子号选项
|
const siloOptions = Array.from({ length: 12 }, (_, i) => ({
|
label: `${i + 1}号储丝柜`,
|
value: String(i + 1)
|
}));
|
|
const selectedSilos = ref<string[]>([]);
|
|
function handleSiloChange(val: string[]) {
|
selectedSilos.value = val;
|
searchParams.value.siloid = val.join(',');
|
}
|
|
// 表格数据
|
const loading = ref(false);
|
const tableRows = ref<any[]>([]);
|
|
// 计算显示文本用的日期
|
const displayDateRange = ref<[string, string] | null>(null);
|
|
// 日期范围显示文本
|
const dateRangeText = computed(() => {
|
if (displayDateRange.value && displayDateRange.value[0] && displayDateRange.value[1]) {
|
return `日期:${displayDateRange.value[0]}—${displayDateRange.value[1]}`;
|
}
|
return '';
|
});
|
|
// 计算产量辅助函数
|
function calcRollerBox(val: unknown) {
|
if (val === null || val === undefined) return null;
|
const v = Number(val) / 50;
|
if (!Number.isFinite(v)) return null;
|
return v.toFixed(1);
|
}
|
|
function calcPackerBox(val: unknown) {
|
if (val === null || val === undefined) return null;
|
const v = Number(val) / 10 / 250;
|
if (!Number.isFinite(v)) return null;
|
return v.toFixed(1);
|
}
|
|
function setZoom(next: number) {
|
const v = Math.max(0.6, Math.min(1.2, Number(next)));
|
zoom.value = Number.isFinite(v) ? v : 1;
|
}
|
|
// 格式化柜号 (取最后一下下划线后面的数字)
|
function formatSiloId(val: string) {
|
if (!val) return '';
|
const parts = val.split('_');
|
return parts[parts.length - 1];
|
}
|
|
// 计算烟丝重量 (jobinput - weight)
|
function calculateSilkWeight(jobinput: any, weight: any) {
|
const res = Number(jobinput || 0) - Number(weight || 0);
|
return res.toFixed(2);
|
}
|
|
// 格式化生产机组 (取 rollerDetailList 里面的 equNo, 并去重)
|
function formatProductionUnits(list: any[]) {
|
if (!Array.isArray(list)) return '';
|
const equNos = list.map(item => item.equNo).filter(Boolean);
|
const unique = Array.from(new Set(equNos));
|
unique.sort((a, b) => {
|
const aStr = String(a);
|
const bStr = String(b);
|
const aNum = Number(aStr);
|
const bNum = Number(bStr);
|
const aIsNum = Number.isFinite(aNum);
|
const bIsNum = Number.isFinite(bNum);
|
if (aIsNum && bIsNum) return aNum - bNum;
|
if (aIsNum) return -1;
|
if (bIsNum) return 1;
|
return aStr.localeCompare(bStr, 'zh-CN', { numeric: true });
|
});
|
return unique.join(',');
|
}
|
|
async function handleSearch() {
|
await validate();
|
loading.value = true;
|
try {
|
const { data, error } = await fetchGetStoreSilkList(searchParams.value);
|
if (!error && data) {
|
tableRows.value = data.rows || [];
|
// 更新报表顶部的显示日期
|
if (searchParams.value.params?.beginTime && searchParams.value.params?.endTime) {
|
displayDateRange.value = [searchParams.value.params.beginTime, searchParams.value.params.endTime];
|
} else {
|
displayDateRange.value = null;
|
}
|
}
|
} finally {
|
loading.value = false;
|
}
|
}
|
|
function setDefaultDateRange() {
|
const now = new Date();
|
const daysAgo = new Date(now.getTime() - 10 * 24 * 60 * 60 * 1000);
|
const beginTime = `${daysAgo.getFullYear()}-${String(daysAgo.getMonth() + 1).padStart(2, '0')}-${String(daysAgo.getDate()).padStart(2, '0')} 00:00:00`;
|
const endTime = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} 23:59:59`;
|
|
searchDateRange.value = [beginTime, endTime];
|
onDateRangeUpdate([beginTime, endTime]);
|
}
|
|
function toNumberOrNull(val: unknown) {
|
const num = Number(val);
|
return Number.isFinite(num) ? num : null;
|
}
|
|
async function handleExport() {
|
await beginExportLoading();
|
|
const workbook = new ExcelJS.Workbook();
|
const worksheet = workbook.addWorksheet('批次产量统计报表');
|
|
worksheet.columns = [
|
{ key: 'batchcode', width: 16 },
|
{ key: 'materialname', width: 22 },
|
{ key: 'distimebegin', width: 20 },
|
{ key: 'distimeend', width: 20 },
|
{ key: 'siloid', width: 8 },
|
{ key: 'silkWeight', width: 12 },
|
{ key: 'units', width: 14 },
|
{ key: 'roller', width: 12 },
|
{ key: 'packer', width: 12 },
|
{ key: 'elevator', width: 12 }
|
];
|
|
const totalColumns = 10;
|
const titleRow = worksheet.addRow(['批次产量统计报表']);
|
worksheet.mergeCells(1, 1, 1, totalColumns);
|
titleRow.height = 26;
|
titleRow.getCell(1).font = { size: 16, bold: true, color: { argb: 'FF111827' } };
|
titleRow.getCell(1).alignment = { horizontal: 'center', vertical: 'middle' };
|
|
const dateText = dateRangeText.value || '';
|
const dateRow = worksheet.addRow([dateText]);
|
worksheet.mergeCells(2, 1, 2, totalColumns);
|
dateRow.height = 20;
|
dateRow.getCell(1).font = { size: 12, bold: true, color: { argb: 'FF0066CC' } };
|
dateRow.getCell(1).alignment = { horizontal: 'right', vertical: 'middle' };
|
|
const headerRow1 = worksheet.addRow([
|
'批次号',
|
'牌号',
|
'批次开始时间',
|
'批次结束时间',
|
'柜号',
|
'烟丝重量',
|
'生产机组',
|
'卷烟机总产',
|
'包装机总产',
|
'提升机总产'
|
]);
|
const headerRow2 = worksheet.addRow(['', '', '', '', '', '', '', '量(箱)', '量(箱)', '量(箱)']);
|
|
for (let i = 1; i <= 7; i += 1) {
|
worksheet.mergeCells(3, i, 4, i);
|
}
|
|
const headerFill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF337AB7' } } as const;
|
const headerFont = { bold: true, color: { argb: 'FFFFFFFF' }, size: 12 } as const;
|
const headerBorder = {
|
top: { style: 'thin', color: { argb: 'FF4A90D9' } },
|
left: { style: 'thin', color: { argb: 'FF4A90D9' } },
|
bottom: { style: 'thin', color: { argb: 'FF4A90D9' } },
|
right: { style: 'thin', color: { argb: 'FF4A90D9' } }
|
} as const;
|
|
[headerRow1, headerRow2].forEach(row => {
|
row.height = 22;
|
row.eachCell({ includeEmpty: true }, cell => {
|
cell.fill = headerFill;
|
cell.font = headerFont;
|
cell.border = headerBorder;
|
cell.alignment = { horizontal: 'center', vertical: 'middle', wrapText: true };
|
});
|
});
|
|
const dataBorder = {
|
top: { style: 'thin', color: { argb: 'FFCCCCCC' } },
|
left: { style: 'thin', color: { argb: 'FFCCCCCC' } },
|
bottom: { style: 'thin', color: { argb: 'FFCCCCCC' } },
|
right: { style: 'thin', color: { argb: 'FFCCCCCC' } }
|
} as const;
|
|
tableRows.value.forEach((row, index) => {
|
const dataRow = worksheet.addRow([
|
row.batchcode ?? '',
|
row.materialname ?? '',
|
row.distimebegin ?? '',
|
row.distimeend ?? '',
|
formatSiloId(row.siloid),
|
toNumberOrNull(calculateSilkWeight(row.jobinput, row.weight)),
|
formatProductionUnits(row.rollerDetailList),
|
toNumberOrNull(calcRollerBox(row.rollerOutput)),
|
toNumberOrNull(calcPackerBox(row.packerOutput)),
|
toNumberOrNull(calcPackerBox(row.packerOutput))
|
]);
|
|
dataRow.height = 20;
|
|
dataRow.eachCell({ includeEmpty: true }, (cell, colNumber) => {
|
cell.border = dataBorder;
|
cell.alignment = { horizontal: 'center', vertical: 'middle' };
|
|
if (colNumber === 2) {
|
cell.alignment = { horizontal: 'left', vertical: 'middle' };
|
}
|
|
if (colNumber === 6) {
|
cell.numFmt = '0.00';
|
}
|
|
if (colNumber >= 8 && colNumber <= 10) {
|
cell.numFmt = '0.0';
|
}
|
|
if (index % 2 === 1) {
|
cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF9F9F9' } };
|
}
|
});
|
});
|
|
worksheet.views = [{ state: 'frozen', ySplit: 4 }];
|
|
try {
|
const buffer = await workbook.xlsx.writeBuffer();
|
const blob = new Blob([buffer], {
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
});
|
const url = URL.createObjectURL(blob);
|
const link = document.createElement('a');
|
link.href = url;
|
link.download = `储丝柜出料产量报表_${formatNow()}.xlsx`;
|
link.click();
|
URL.revokeObjectURL(url);
|
} finally {
|
exportLoading.value = false;
|
}
|
}
|
|
async function handleExportCsv() {
|
await beginExportLoading();
|
|
const headers = [
|
'批次号',
|
'牌号',
|
'批次开始时间',
|
'批次结束时间',
|
'柜号',
|
'烟丝重量',
|
'生产机组',
|
'卷烟机总产量(箱)',
|
'包装机总产量(箱)',
|
'提升机总产量(箱)'
|
];
|
|
const rows = tableRows.value.map(row => [
|
row.batchcode ?? '',
|
row.materialname ?? '',
|
row.distimebegin ?? '',
|
row.distimeend ?? '',
|
formatSiloId(row.siloid),
|
calculateSilkWeight(row.jobinput, row.weight),
|
formatProductionUnits(row.rollerDetailList),
|
calcRollerBox(row.rollerOutput),
|
calcPackerBox(row.packerOutput),
|
calcPackerBox(row.packerOutput)
|
]);
|
|
const escapeCsv = (value: unknown) => {
|
const str = value === null || value === undefined ? '' : String(value);
|
if (/["\n,]/.test(str)) {
|
return `"${str.replace(/"/g, '""')}"`;
|
}
|
return str;
|
};
|
|
const csvContent = [headers, ...rows].map(row => row.map(escapeCsv).join(',')).join('\n');
|
const blob = new Blob([`\uFEFF${csvContent}`], { type: 'text/csv;charset=utf-8;' });
|
try {
|
const url = URL.createObjectURL(blob);
|
const link = document.createElement('a');
|
link.href = url;
|
link.download = `储丝柜出料产量报表_${formatNow()}.csv`;
|
link.click();
|
URL.revokeObjectURL(url);
|
} finally {
|
exportLoading.value = false;
|
}
|
}
|
|
function printReportSheet() {
|
const sheet = document.querySelector('.report-sheet') as HTMLElement | null;
|
if (!sheet) return;
|
|
const styles = Array.from(document.querySelectorAll('style, link[rel="stylesheet"]'))
|
.map(node => node.outerHTML)
|
.join('\n');
|
|
const printWindow = window.open('', '_blank');
|
if (!printWindow) return;
|
|
printWindow.document.open();
|
printWindow.document.write(`
|
<!DOCTYPE html>
|
<html>
|
<head>
|
<meta charset="utf-8" />
|
<title>批次产量统计报表</title>
|
${styles}
|
<style>
|
@page {
|
size: A4 landscape;
|
margin: 10mm;
|
}
|
body {
|
margin: 0;
|
padding: 16px;
|
background: #fff;
|
}
|
.print-container {
|
display: flex;
|
justify-content: center;
|
width: 100%;
|
}
|
.report-sheet {
|
transform: none !important;
|
box-shadow: none !important;
|
width: 100% !important;
|
margin: 0 !important;
|
padding: 0 !important;
|
}
|
.report-table-scroll {
|
overflow: visible !important;
|
}
|
.report-table {
|
width: 100% !important;
|
min-width: 0 !important;
|
table-layout: fixed;
|
}
|
</style>
|
</head>
|
<body>
|
<div class="print-container">${sheet.outerHTML}</div>
|
</body>
|
</html>
|
`);
|
printWindow.document.close();
|
printWindow.focus();
|
printWindow.addEventListener('load', () => {
|
setTimeout(() => {
|
printWindow.print();
|
}, 100);
|
});
|
printWindow.onafterprint = () => {
|
printWindow.close();
|
};
|
}
|
|
function handlePrint() {
|
printReportSheet();
|
}
|
|
async function handleExportPdf() {
|
await beginExportLoading();
|
|
setTimeout(async () => {
|
const sheet = document.querySelector('#report-capture') as HTMLElement | null;
|
if (!sheet) {
|
exportLoading.value = false;
|
return;
|
}
|
|
const sheetWidth = sheet.scrollWidth || sheet.getBoundingClientRect().width || 1200;
|
const scale = Math.min(1, 794 / sheetWidth);
|
|
const clone = sheet.cloneNode(true) as HTMLElement;
|
clone.style.transform = `scale(${scale})`;
|
clone.style.transformOrigin = 'top left';
|
clone.style.width = `${sheetWidth}px`;
|
clone.style.minWidth = '0';
|
clone.style.margin = '0';
|
clone.style.boxShadow = 'none';
|
clone.style.position = 'fixed';
|
clone.style.left = '-10000px';
|
clone.style.top = '0';
|
clone.style.background = '#ffffff';
|
clone.style.fontFamily = 'SourceHanSansSC-Normal-Min, sans-serif';
|
|
document.body.appendChild(clone);
|
|
try {
|
const blob = (await dompdf(clone, {
|
pagination: true,
|
format: 'a4',
|
useCORS: true,
|
backgroundColor: '#ffffff',
|
fontConfig: {
|
fontFamily: 'SourceHanSansSC-Normal-Min',
|
fontBase64: (window as any).fontBase64,
|
fontStyle: 'normal',
|
fontWeight: 400
|
}
|
})) as Blob;
|
|
const url = URL.createObjectURL(blob);
|
const link = document.createElement('a');
|
link.href = url;
|
link.download = `储丝柜出料产量报表_${formatNow()}.pdf`;
|
document.body.appendChild(link);
|
link.click();
|
document.body.removeChild(link);
|
URL.revokeObjectURL(url);
|
} catch (err) {
|
console.error(err);
|
} finally {
|
document.body.removeChild(clone);
|
exportLoading.value = false;
|
}
|
}, 0);
|
}
|
|
async function handleReset() {
|
await restoreValidation();
|
searchParams.value = jsonClone(defaultSearchParams);
|
selectedSilos.value = [];
|
setDefaultDateRange();
|
handleSearch();
|
}
|
|
onMounted(() => {
|
setDefaultDateRange();
|
handleSearch();
|
});
|
</script>
|
|
<template>
|
<div class="h-full min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
<!-- 搜索区域 -->
|
<NCard :bordered="false" size="small" class="card-wrapper">
|
<NCollapse :default-expanded-names="['report-search']">
|
<NCollapseItem :title="$t('common.search')" name="report-search">
|
<NForm ref="formRef" :model="searchParams" label-placement="left" :label-width="80">
|
<NGrid responsive="screen" item-responsive>
|
<NFormItemGi span="24 s:12 m:8" label="牌号" label-width="auto" path="materialname" class="pr-24px">
|
<NInput v-model:value="searchParams.materialname" clearable placeholder="请输入牌号" />
|
</NFormItemGi>
|
<NFormItemGi span="24 s:12 m:8" label="批次号" label-width="auto" path="batchcode" class="pr-24px">
|
<NInput v-model:value="searchParams.batchcode" clearable placeholder="请输入批次号" />
|
</NFormItemGi>
|
<NFormItemGi
|
span="24 s:12 m:8"
|
label="投料日期"
|
label-width="auto"
|
path="actualstarttime"
|
class="pr-24px"
|
>
|
<NDatePicker
|
v-model:formatted-value="searchParams.actualstarttime"
|
type="date"
|
value-format="yyyy-MM-dd"
|
clearable
|
class="w-full"
|
/>
|
</NFormItemGi>
|
<NFormItemGi
|
span="24 s:12 m:8"
|
label="出料时间"
|
label-width="auto"
|
path="params.beginTime"
|
class="pr-24px"
|
>
|
<NDatePicker
|
v-model:formatted-value="searchDateRange"
|
type="datetimerange"
|
value-format="yyyy-MM-dd HH:mm:ss"
|
clearable
|
:default-time="['00:00:00', '23:59:59']"
|
class="w-full"
|
@update:formatted-value="onDateRangeUpdate"
|
/>
|
</NFormItemGi>
|
<NFormItemGi span="24 s:12 m:8" label="柜子号" label-width="auto" path="siloid" class="pr-24px">
|
<NSelect
|
v-model:value="selectedSilos"
|
multiple
|
clearable
|
:options="siloOptions"
|
placeholder="请选择柜子号"
|
@update:value="handleSiloChange"
|
/>
|
</NFormItemGi>
|
<NFormItemGi span="24 s:12 m:8">
|
<NSpace>
|
<NButton type="primary" :loading="loading" @click="handleSearch">
|
<template #icon>
|
<icon-ic-round-search class="text-icon" />
|
</template>
|
查询
|
</NButton>
|
<NButton @click="handleReset">
|
<template #icon>
|
<icon-ic-round-refresh class="text-icon" />
|
</template>
|
重置
|
</NButton>
|
</NSpace>
|
</NFormItemGi>
|
</NGrid>
|
</NForm>
|
</NCollapseItem>
|
</NCollapse>
|
</NCard>
|
|
<!-- 报表显示区域 -->
|
<NCard
|
:bordered="false"
|
size="small"
|
class="flex flex-col card-wrapper sm:flex-1-hidden"
|
content-style="padding: 0; flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden;"
|
>
|
<div class="report-root">
|
<div class="report-toolbar">
|
<div class="flex-y-center gap-8px">
|
<NButton size="small" type="warning" ghost @click="handleExport">
|
<template #icon>
|
<icon-mdi-export class="text-icon" />
|
</template>
|
导出 Excel
|
</NButton>
|
<NButton size="small" secondary @click="handleExportPdf">
|
<template #icon>
|
<icon-mdi-file-pdf-box class="text-icon" />
|
</template>
|
导出 PDF
|
</NButton>
|
<NButton size="small" secondary @click="handleExportCsv">
|
<template #icon>
|
<icon-mdi-file-delimited class="text-icon" />
|
</template>
|
导出 CSV
|
</NButton>
|
<NButton size="small" type="primary" @click="handlePrint">
|
<template #icon>
|
<icon-mdi-printer class="text-icon" />
|
</template>
|
打印
|
</NButton>
|
</div>
|
<div class="flex-y-center gap-8px">
|
<span class="report-toolbar__label">缩放</span>
|
<NButton size="small" @click="setZoom(zoom - 0.1)">-</NButton>
|
<NInputNumber v-model:value="zoom" size="small" :min="0.6" :max="1.2" :step="0.1" class="w-90px" />
|
<NButton size="small" @click="setZoom(zoom + 0.1)">+</NButton>
|
</div>
|
</div>
|
|
<div class="report-stage">
|
<NSpin :show="exportLoading" size="large" description="导出中..." :delay="0">
|
<div id="report-capture" class="report-sheet" :style="{ transform: `scale(${zoom})` }">
|
<!-- 报表标题 -->
|
<div class="report-title">批次产量统计报表</div>
|
|
<!-- 日期范围显示 -->
|
<div class="report-date-range">
|
<span class="report-date-range__text">{{ dateRangeText }}</span>
|
</div>
|
|
<!-- 数据表格 -->
|
<div class="report-table-scroll">
|
<table id="report-table" class="report-table">
|
<thead>
|
<tr>
|
<th rowspan="2" class="col-batch-no">批次号</th>
|
<th rowspan="2" class="col-brand">牌号</th>
|
<th rowspan="2" class="col-time">批次开始时间</th>
|
<th rowspan="2" class="col-time">批次结束时间</th>
|
<th rowspan="2" class="col-cabinet">柜号</th>
|
<th rowspan="2" class="col-weight">烟丝重量</th>
|
<th rowspan="2" class="col-unit">生产机组</th>
|
<th class="col-output">卷烟机总产</th>
|
<th class="col-output">包装机总产</th>
|
<th class="col-output">提升机总产</th>
|
</tr>
|
<tr>
|
<th class="col-output">量(箱)</th>
|
<th class="col-output">量(箱)</th>
|
<th class="col-output">量(箱)</th>
|
</tr>
|
</thead>
|
<tbody>
|
<tr v-for="row in tableRows" :key="row.id">
|
<td>{{ row.batchcode }}</td>
|
<td class="report-left">{{ row.materialname }}</td>
|
<td>{{ row.distimebegin }}</td>
|
<td>{{ row.distimeend }}</td>
|
<td>{{ formatSiloId(row.siloid) }}</td>
|
<td>{{ row.weight }}</td>
|
<td>{{ formatProductionUnits(row.rollerDetailList) }}</td>
|
<td>{{ calcRollerBox(row.rollerOutput) }}</td>
|
<td>{{ calcPackerBox(row.packerOutput) }}</td>
|
<td> - </td>
|
</tr>
|
</tbody>
|
</table>
|
</div>
|
</div>
|
</NSpin>
|
</div>
|
</div>
|
</NCard>
|
</div>
|
</template>
|
|
<style scoped>
|
/* ==================== 报表容器 ==================== */
|
.report-root {
|
background: #f3f4f6;
|
padding: 12px;
|
display: flex;
|
flex-direction: column;
|
flex: 1;
|
min-height: 0;
|
}
|
|
.report-toolbar {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 8px 12px;
|
background: #fff;
|
border-bottom: 1px solid #e5e7eb;
|
flex: none;
|
}
|
|
.report-toolbar__label {
|
font-size: 12px;
|
color: #6b7280;
|
}
|
|
.report-stage {
|
padding: 12px;
|
overflow: auto;
|
flex: 1;
|
min-height: 0;
|
}
|
|
.report-sheet {
|
transform-origin: top center;
|
background: #fff;
|
width: 1200px;
|
margin: 0 auto;
|
padding: 18px 18px 16px;
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
|
}
|
|
/* ==================== 报表标题 ==================== */
|
.report-title {
|
text-align: center;
|
font-size: 18px;
|
font-weight: 600;
|
padding: 10px 0 4px;
|
color: #111827;
|
}
|
|
/* ==================== 日期范围 ==================== */
|
.report-date-range {
|
display: flex;
|
justify-content: flex-end;
|
padding: 4px 0 8px;
|
}
|
|
.report-date-range__text {
|
font-size: 13px;
|
font-weight: 600;
|
color: #0066cc;
|
}
|
|
/* ==================== 表格 ==================== */
|
.report-table-scroll {
|
width: 100%;
|
overflow-x: auto;
|
overflow-y: hidden;
|
}
|
|
.report-table {
|
width: 100%;
|
min-width: 1100px;
|
border-collapse: collapse;
|
table-layout: fixed;
|
font-size: 12px;
|
color: #111827;
|
}
|
|
/* 列宽定义 */
|
.col-batch-no {
|
width: 120px;
|
}
|
|
.col-brand {
|
width: 170px;
|
}
|
|
.col-time {
|
width: 150px;
|
}
|
|
.col-cabinet {
|
width: 50px;
|
}
|
|
.col-weight {
|
width: 80px;
|
}
|
|
.col-unit {
|
width: 95px;
|
}
|
|
.col-output {
|
width: 90px;
|
}
|
|
/* 表头样式 - 蓝色背景白色文字 */
|
.report-table th {
|
border: 1px solid #4a90d9;
|
padding: 6px 6px;
|
text-align: center;
|
vertical-align: middle;
|
line-height: 1.3;
|
background: #337ab7;
|
color: #fff;
|
font-weight: 600;
|
font-size: 12px;
|
}
|
|
/* 数据单元格 */
|
.report-table td {
|
border: 1px solid #ccc;
|
padding: 6px 6px;
|
text-align: center;
|
vertical-align: middle;
|
line-height: 1.3;
|
}
|
|
/* 隔行变色 */
|
.report-table tbody tr:nth-child(even) {
|
background: #f9f9f9;
|
}
|
|
.report-table tbody tr:hover {
|
background: #e8f0fe;
|
}
|
|
/* 左对齐 */
|
.report-left {
|
text-align: left;
|
}
|
|
/* ==================== 打印样式 ==================== */
|
@media print {
|
@page {
|
size: A4 landscape;
|
margin: 10mm;
|
}
|
|
.report-root {
|
background: #fff;
|
padding: 0;
|
}
|
|
.report-toolbar {
|
display: none;
|
}
|
|
.report-stage {
|
padding: 0;
|
overflow: visible;
|
}
|
|
.report-sheet {
|
width: 100%;
|
margin: 0;
|
padding: 0;
|
box-shadow: none;
|
transform: none !important;
|
}
|
|
.report-table-scroll {
|
overflow: visible;
|
}
|
|
.report-table {
|
width: 100%;
|
min-width: 0;
|
table-layout: fixed;
|
}
|
}
|
</style>
|