基本配置修改 优化
This commit is contained in:
parent
82abf1cb8f
commit
62b6cf70fb
|
|
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue