基本配置修改 优化

This commit is contained in:
lizhenhua 2025-11-10 11:36:26 +08:00
parent 82abf1cb8f
commit 62b6cf70fb
1 changed files with 495 additions and 0 deletions

View File

@ -0,0 +1,495 @@
<template>
<div style="padding: 10px; background: #E5EBF6; min-height: 830px;">
<!-- 基本信息卡片 -->
<div style="background: #FFF; padding: 10px; border-radius: 10px; margin-bottom: 20px;">
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px;">
<div style="display: flex; align-items: center;">
<el-button
type="primary"
icon="el-icon-arrow-left"
circle
size="mini"
@click="jumpList"
style="margin-right: 10px;"
></el-button>
<span style="font-weight: bold;">基本信息</span>
</div>
<div style="display: flex; gap: 10px;">
<el-button
type="success"
icon="el-icon-printer"
size="mini"
@click="handlePrint"
>打印</el-button>
<el-button
type="warning"
icon="el-icon-download"
size="mini"
@click="handleExport"
:loading="exportLoading"
>导出</el-button>
</div>
</div>
<el-descriptions :column="4" size="medium" border>
<el-descriptions-item label="盘点单号">{{ baseInfo.checkId }}</el-descriptions-item>
<el-descriptions-item label="盘点状态">{{ getStatusText(baseInfo.status) }}</el-descriptions-item>
<el-descriptions-item label="所属区域">{{ baseInfo.areaName }}</el-descriptions-item>
<el-descriptions-item label="货品仓库">{{ baseInfo.warehouseName }}</el-descriptions-item>
<el-descriptions-item label="盘点方式">仓库盘点</el-descriptions-item>
<el-descriptions-item label="初盘人">{{ baseInfo.firstCheckUserName }}</el-descriptions-item>
<el-descriptions-item label="初盘日期">{{ baseInfo.firstCheckDate }}</el-descriptions-item>
<el-descriptions-item label="复盘人">{{ baseInfo.secondCheckUserName }}</el-descriptions-item>
<el-descriptions-item label="复盘日期">{{ baseInfo.secondCheckDate }}</el-descriptions-item>
<el-descriptions-item label="监盘人">{{ baseInfo.inspectUserName }}</el-descriptions-item>
<el-descriptions-item label="总盈亏(元)">{{ (baseInfo.totalProfitLoss/100).toFixed(2) }}</el-descriptions-item>
<el-descriptions-item label="备注说明">{{ baseInfo.remark }}</el-descriptions-item>
<el-descriptions-item label="盘点签名" :span="4">{{ baseInfo.checkSignature }}</el-descriptions-item>
</el-descriptions>
</div>
<!-- 货品明细表格 -->
<div style="background: #FFF; padding: 10px; border-radius: 10px;">
<el-table
v-loading="loading"
:data="materialList"
border
style="width: 100%"
height="600"
>
<el-table-column type="index" label="序号" width="60"></el-table-column>
<el-table-column label="货品编码" prop="materialCode"></el-table-column>
<el-table-column label="货品名称" prop="materialName"></el-table-column>
<el-table-column label="货品类别" prop="categoryName"></el-table-column>
<el-table-column label="计量单位" prop="unitName"></el-table-column>
<el-table-column label="货品规格" prop="size"></el-table-column>
<el-table-column label="单价(元)" prop="price">
<template #default="scope">
{{ (scope.row.price/100).toFixed(2) }}
</template>
</el-table-column>
<el-table-column label="账面数" prop="bookNum"></el-table-column>
<el-table-column label="账面总额(元)">
<template #default="scope">
{{ (scope.row.bookNum * (scope.row.price / 100)).toFixed(2) }}
</template>
</el-table-column>
<el-table-column label="实盘总额(元)">
<template #default="scope">
{{ (scope.row.actualNum * (scope.row.price / 100)).toFixed(2) }}
</template>
</el-table-column>
<el-table-column label="差异数">
<template #default="scope">
{{ scope.row.actualNum - scope.row.bookNum }}
</template>
</el-table-column>
<el-table-column label="差异总额(元)">
<template #default="scope">
{{ ((scope.row.actualNum - scope.row.bookNum) * scope.row.price / 100).toFixed(2) }}
</template>
</el-table-column>
<el-table-column label="实盘数量" prop="actualNum"></el-table-column>
<el-table-column label="差异原因" prop="differReason"></el-table-column>
</el-table>
</div>
<!-- 打印列选择对话框 -->
<el-dialog
title="选择打印列"
:visible.sync="printColumnDialogVisible"
width="600px"
:before-close="handlePrintColumnClose"
>
<div>
<el-checkbox-group v-model="tempSelectedPrintColumns">
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;">
<el-checkbox
v-for="column in printColumnOptions"
:key="column.key"
:label="column.key"
:disabled="column.required"
>
{{ column.label }}
</el-checkbox>
</div>
</el-checkbox-group>
<div style="margin-top: 20px; color: #666; font-size: 12px;">
<p>提示</p>
<p>1. 序号列为必选列无法取消</p>
<p>2. 请至少选择一列进行打印</p>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="handlePrintColumnClose">取消</el-button>
<el-button type="primary" @click="confirmAndPrint">确认</el-button>
</span>
</el-dialog>
<!-- 清零确认对话框 -->
<el-dialog
title="打印设置"
:visible.sync="clearZeroDialogVisible"
width="400px"
:close-on-click-modal="false"
>
<div>是否清除账面数为0的货品</div>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClearZeroCancel"></el-button>
<el-button type="primary" @click="handleClearZeroConfirm"></el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { getCheckInventoryInfoApi } from "@/api/inventoryCount/index";
import ExcelJS from 'exceljs';
export default {
name: "InventoryCountDetail",
data() {
return {
countRowData: {},
loading: false,
exportLoading: false,
baseInfo: {},
materialList: [],
printColumnDialogVisible: false,
tempSelectedPrintColumns: [],
selectedPrintColumns: [],
printColumnOptions: [
{ key: 'index', label: '序号', required: true },
{ key: 'materialCode', label: '货品编码' },
{ key: 'materialName', label: '货品名称' },
{ key: 'categoryName', label: '货品类别' },
{ key: 'unitName', label: '计量单位' },
{ key: 'size', label: '货品规格' },
{ key: 'price', label: '单价(元)' },
{ key: 'bookNum', label: '账面数' },
{ key: 'bookTotal', label: '账面总额(元)' },
{ key: 'actualTotal', label: '实盘总额(元)' },
{ key: 'differNum', label: '差异数' },
{ key: 'differTotal', label: '差异总额(元)' },
{ key: 'actualNum', label: '实盘数量' },
{ key: 'differReason', label: '差异原因' }
],
clearZeroDialogVisible: false,
clearZeroFlag: false
};
},
created() {
if (this.$route.query.countRowData) {
this.countRowData = JSON.parse(this.$route.query.countRowData);
this.getContractInfo();
}
this.selectedPrintColumns = this.printColumnOptions.map(c => c.key);
this.tempSelectedPrintColumns = [...this.selectedPrintColumns];
},
methods: {
jumpList() {
const obj = { path: "/inventoryCount/inventoryCountDetail" };
this.$tab.closeOpenPage(obj);
this.$router.replace({ path: "/inventoryCount/inventoryCount" });
},
getContractInfo() {
this.baseInfo = this.countRowData;
let param = {
checkId: this.countRowData.checkId,
secondCheckDate: this.countRowData.secondCheckDate,
warehouseId: this.countRowData.warehouseId
};
getCheckInventoryInfoApi(param).then((res) => {
let list = res.rows || [];
const grouped = {};
list.forEach(item => {
if (!grouped[item.materialName]) grouped[item.materialName] = [];
grouped[item.materialName].push(item);
});
Object.values(grouped).forEach(group => {
if (group.length > 1) {
const bookNums = group.map(i => i.bookNum);
const hasDiff = new Set(bookNums).size > 1;
if (hasDiff) group.forEach(item => item.actualNum = item.bookNum);
}
});
this.materialList = list;
});
},
getStatusText(status) {
if (status == 2) return '已盘点';
if (status == 1) return '待盘点';
return '未知状态';
},
//
handlePrint() {
this.tempSelectedPrintColumns = [...this.selectedPrintColumns];
this.printColumnDialogVisible = true;
},
handlePrintColumnClose() { this.printColumnDialogVisible = false; },
confirmAndPrint() {
if (this.tempSelectedPrintColumns.length === 0) {
this.$message.warning('请至少选择一列进行打印');
return;
}
this.selectedPrintColumns = [...this.tempSelectedPrintColumns];
this.printColumnDialogVisible = false;
this.clearZeroDialogVisible = true;
},
handleClearZeroConfirm() { this.clearZeroFlag = true; this.clearZeroDialogVisible = false; this.doPrint(); },
handleClearZeroCancel() { this.clearZeroFlag = false; this.clearZeroDialogVisible = false; this.doPrint(); },
async handleExport() {
this.exportLoading = true;
try {
const workbook = new ExcelJS.Workbook();
const sheet = workbook.addWorksheet('货品明细');
//
const columns = [];
this.printColumnOptions.forEach(col => {
if (this.selectedPrintColumns.includes(col.key)) {
columns.push({
header: col.label,
key: col.key,
width: col.key === 'index' ? 8 :
col.key === 'materialCode' ? 15 :
col.key === 'materialName' ? 20 :
col.key === 'categoryName' ? 15 :
col.key === 'unitName' ? 12 :
col.key === 'size' ? 15 :
col.key.includes('price') || col.key.includes('Total') ? 15 : 12
});
}
});
sheet.columns = columns;
//
sheet.getRow(1).eachCell((cell) => {
cell.font = { bold: true, color: { argb: 'FF000000' } };
cell.alignment = { vertical: 'middle', horizontal: 'center' };
cell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFD9D9D9' },
};
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' },
};
});
//
this.materialList.forEach((item, index) => {
const price = Number((item.price / 100).toFixed(2));
const bookTotal = Number((item.bookNum * price).toFixed(2));
const actualTotal = Number((item.actualNum * price).toFixed(2));
const differNum = item.actualNum - item.bookNum;
const differTotal = Number((differNum * price).toFixed(2));
const rowData = {};
this.printColumnOptions.forEach(col => {
if (this.selectedPrintColumns.includes(col.key)) {
switch(col.key) {
case 'index':
rowData[col.key] = index + 1;
break;
case 'materialCode':
rowData[col.key] = item.materialCode || '';
break;
case 'materialName':
rowData[col.key] = item.materialName || '';
break;
case 'categoryName':
rowData[col.key] = item.categoryName || '';
break;
case 'unitName':
rowData[col.key] = item.unitName || '';
break;
case 'size':
rowData[col.key] = item.size || '';
break;
case 'price':
rowData[col.key] = price;
break;
case 'bookNum':
rowData[col.key] = item.bookNum || 0;
break;
case 'bookTotal':
rowData[col.key] = bookTotal;
break;
case 'actualTotal':
rowData[col.key] = actualTotal;
break;
case 'differNum':
rowData[col.key] = differNum;
break;
case 'differTotal':
rowData[col.key] = differTotal;
break;
case 'actualNum':
rowData[col.key] = item.actualNum || 0;
break;
case 'differReason':
rowData[col.key] = item.differReason || '';
break;
}
}
});
const row = sheet.addRow(rowData);
//
row.eachCell((cell, colNumber) => {
cell.alignment = { vertical: 'middle', horizontal: 'center' };
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' },
};
//
const colKey = columns[colNumber - 1]?.key;
if (colKey && (colKey.includes('price') || colKey.includes('Total'))) {
cell.numFmt = '0.00';
}
});
});
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `盘点明细_${this.baseInfo.checkId || ''}.xlsx`;
a.click();
URL.revokeObjectURL(url);
this.$message.success('导出成功');
} catch (err) {
console.error(err);
this.$message.error('导出失败');
} finally {
this.exportLoading = false;
}
},
doPrint() {
const printWindow = window.open('', '_blank');
//
const printList = this.clearZeroFlag
? this.materialList.filter(item => item.bookNum !== 0)
: this.materialList;
// === ===
const totalBookNum = printList.reduce((sum, i) => sum + (i.bookNum || 0), 0);
const totalBookAmount = printList.reduce((sum, i) => sum + (i.bookNum * i.price / 100), 0);
const totalActualAmount = printList.reduce((sum, i) => sum + (i.actualNum * i.price / 100), 0);
const totalActualNum = printList.reduce((sum, i) => sum + (i.actualNum || 0), 0);
// === ===
let materialHeaderHtml = '<thead><tr>';
this.printColumnOptions.forEach(col => {
if (this.selectedPrintColumns.includes(col.key))
materialHeaderHtml += `<th>${col.label}</th>`;
});
materialHeaderHtml += '</tr></thead>';
// === ===
let materialBodyHtml = '<tbody>';
printList.forEach((item, index) => {
const price = (item.price / 100).toFixed(2);
const bookTotal = (item.bookNum * (item.price / 100)).toFixed(2);
const actualTotal = (item.actualNum * (item.price / 100)).toFixed(2);
const differNum = item.actualNum - item.bookNum;
const differTotal = ((differNum * item.price) / 100).toFixed(2);
materialBodyHtml += '<tr>';
this.printColumnOptions.forEach(col => {
if (this.selectedPrintColumns.includes(col.key)) {
let val = '';
switch (col.key) {
case 'index': val = index + 1; break;
case 'price': val = price; break;
case 'bookTotal': val = bookTotal; break;
case 'actualTotal': val = actualTotal; break;
case 'differNum': val = differNum; break;
case 'differTotal': val = differTotal; break;
default: val = item[col.key] || ''; break;
}
materialBodyHtml += `<td>${val}</td>`;
}
});
materialBodyHtml += '</tr>';
});
materialBodyHtml += '</tbody>';
// === HTML ===
const baseInfoHtml = `
<table border="1" cellspacing="0" cellpadding="5" style="width:100%;border-collapse:collapse;margin-bottom:20px;">
<tr><th>盘点单号</th><td>${this.baseInfo.checkId || ''}</td><th>盘点状态</th><td>${this.getStatusText(this.baseInfo.status)}</td></tr>
<tr><th>所属区域</th><td>${this.baseInfo.areaName || ''}</td><th>货品仓库</th><td>${this.baseInfo.warehouseName || ''}</td></tr>
<tr><th>盘点方式</th><td>仓库盘点</td><th>初盘人</th><td>${this.baseInfo.firstCheckUserName || ''}</td></tr>
<tr><th>初盘日期</th><td>${this.baseInfo.firstCheckDate || ''}</td><th>复盘人</th><td>${this.baseInfo.secondCheckUserName || ''}</td></tr>
<tr><th>复盘日期</th><td>${this.baseInfo.secondCheckDate || ''}</td><th>监盘人</th><td>${this.baseInfo.inspectUserName || ''}</td></tr>
<tr><th>总盈亏()</th><td>${(this.baseInfo.totalProfitLoss / 100).toFixed(2)}</td><th>备注说明</th><td>${this.baseInfo.remark || ''}</td></tr>
<tr><th>盘点签名</th><td colspan="3">${this.baseInfo.checkSignature || ''}</td></tr>
</table>`;
const summaryHtml = `
<div style="margin-top:20px;text-align:right;font-size:14px;font-weight:bold;">
账面数合计${totalBookNum.toFixed(2)} 
账面总额合计()${totalBookAmount.toFixed(2)} 
实盘总额合计()${totalActualAmount.toFixed(2)} 
实盘数量合计${totalActualNum.toFixed(2)}
</div>`;
const materialHtml = `
<table border="1" cellspacing="0" cellpadding="5"
style="width:100%;border-collapse:collapse;text-align:center;">
${materialHeaderHtml}${materialBodyHtml}
</table>`;
// === ===
printWindow.document.write(`
<html>
<head>
<title>盘点单详情 - ${this.baseInfo.checkId || ''}</title>
<style>
body{font-family:"Microsoft YaHei",Arial;margin:20px;}
h2,h3{text-align:center;}
table{border-collapse:collapse;width:100%;}
th,td{border:1px solid #333;padding:6px;text-align:center;vertical-align:middle;}
th{background:#f5f5f5;font-weight:bold;}
@media print {
body { margin: 0; }
table { page-break-inside:auto; }
tr { page-break-inside:avoid; page-break-after:auto; }
}
</style>
</head>
<body>
<h2>盘点单详情</h2>
${baseInfoHtml}
<h3>货品明细</h3>
${materialHtml}
${summaryHtml}
<div style="margin-top:20px;text-align:right;font-size:12px;color:#666;">
打印时间: ${new Date().toLocaleString()}
</div>
</body>
</html>
`);
printWindow.document.close();
printWindow.focus();
printWindow.print();
}
}
};
</script>