heli-mes/mes-ui/mes-ui-admin-vue3/src/views/heli/partpurchasecheck/print.vue
2025-10-28 21:26:20 +08:00

365 lines
9.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-dialog v-model="dialogVisible" title="" width="1200px" append-to-body>
<div class="print-wrap">
<div class="header header-grid">
<div class="cell company-title">
<span class="company">杭州合立模具有限公司</span>
<span class="title">委外工单及送货单</span>
</div>
<div class="cell audit"> 审核:<span class="sign-space"></span> </div>
<div class="cell handler"> 委外加工经手人:<span class="sign-space"></span> </div>
<div class="cell receiver"> 收货人:<span class="sign-space"></span> </div>
</div>
<table class="sheet" border="1" cellspacing="0" cellpadding="0">
<!-- 固定列宽,总计 100% -->
<colgroup>
<col style="width: 4%" />
<col style="width: 9%" />
<col style="width: 7.5%" />
<col style="width: 19%" />
<col style="width: 5.5%" />
<col style="width: 12%" />
<col style="width: 6%" />
<col style="width: 12.5%" />
<col style="width: 5%" />
<col style="width: 5%" />
<col style="width: 6%" />
<col style="width: 8.5%" />
</colgroup>
<thead>
<tr>
<th>编号</th>
<th>日期</th>
<th>客户名</th>
<th>模具名</th>
<th>件号</th>
<th>零件名称</th>
<th>材料</th>
<th>规格</th>
<th>数量</th>
<th>单价</th>
<th>总价格</th>
<th>要求日期</th>
</tr>
</thead>
<tbody>
<tr v-for="row in rows" :key="row['编号']">
<td>{{ row['编号'] }}</td>
<td>{{ fmtDate(row['日期']) }}</td>
<td class="text-left">{{ row['客户名'] }}</td>
<td class="text-left">{{ row['模具名'] }}</td>
<td class="text-left">{{ row['件号'] }}</td>
<td class="text-left">{{ row['零件名称'] }}</td>
<td>{{ row['材料'] }}</td>
<td class="spec text-left">{{ row['规格'] }}</td>
<td class="num">{{ row['数量'] }}</td>
<td class="num">{{ row['单价'] }}</td>
<td class="num">{{ row['总价格'] }}</td>
<td>{{ fmtDate(row['要求日期']) }}</td>
</tr>
<tr class="sum-row">
<td colspan="8" class="sum-label">合计</td>
<td class="num sum-value">{{ sumQuantity }}</td>
<td></td>
<td class="num sum-value">{{ sumTotal }}</td>
<td></td>
</tr>
</tbody>
</table>
<div class="footer-sign sign-row">
<div class="sign-item">
<span class="label">合立经手人:</span>
<span class="name">{{ duEmpName }}</span>
</div>
<div class="sign-item"> 审核人:<span class="sign-space"></span> </div>
<div class="sign-item"> 委外加工经手人:<span class="sign-space"></span> </div>
</div>
</div>
<template #footer>
<el-button @click="dialogVisible = false">关闭</el-button>
<el-button type="primary" @click="onPrint">打印</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import dayjs from 'dayjs'
// 精确浮点数加法函数
const floatAdd = (a, b) => {
var c, d, e;
if (undefined === a || null === a || "" === a || isNaN(a)) { a = 0; }
if (undefined === b || null === b || "" === b || isNaN(b)) { b = 0; }
try {
c = a.toString().split(".")[1].length;
} catch (f) {
c = 0;
}
try {
d = b.toString().split(".")[1].length;
} catch (f) {
d = 0;
}
e = Math.pow(10, Math.max(c, d));
return (floatMul(a, e) + floatMul(b, e)) / e;
};
// 精确浮点数乘法函数
const floatMul = (a, b) => {
var c = 0,
d = a.toString(),
e = b.toString();
try {
c += d.split(".")[1].length;
} catch (f) {}
try {
c += e.split(".")[1].length;
} catch (f) {}
return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
}
const dialogVisible = ref(false)
const rows = ref<Record<string, any>[]>([])
const nowDate = dayjs().format('YYYY-MM-DD')
const duEmpName = computed(() => (rows.value[0] ? rows.value[0]['合立经手人'] ?? '' : ''))
// 计算总数量
const sumQuantity = computed(() => {
return rows.value.reduce((acc, cur) => {
return floatAdd(acc, Number(cur['数量']) || 0)
}, 0)
})
// 计算总价格
const sumTotal = computed(() => {
return rows.value.reduce((acc, cur) => {
return floatAdd(acc, Number(cur['总价格']) || 0)
}, 0)
})
const fmtDate = (v: any) => (v ? dayjs(v).format('YYYY-MM-DD') : '')
const open = (data: Record<string, any>[]) => {
rows.value = Array.isArray(data) ? data : []
dialogVisible.value = true
}
defineExpose({ open })
// onPrint()
const onPrint = () => {
const printNode = document.querySelector('.print-wrap') as HTMLElement
if (!printNode) return
const iframe = document.createElement('iframe')
iframe.setAttribute('style', 'width:0;height:0;position:absolute;left:-9999px;top:-9999px;')
document.body.appendChild(iframe)
const doc = iframe.contentWindow!.document
doc.open()
doc.title = ''
doc.write(`
<style>
/* 针式打印纸规格241mm×140mm撕边后222mm */
@page { size: 241mm 140mm; margin: 0; }
body {
font-family: Arial, "Microsoft YaHei", sans-serif;
color:#000;
margin: 0;
box-sizing: border-box;
}
/* 打印区域适配撕边后的有效宽度 */
.print-wrap {
width: 100%;
height: 118mm; /* 130mm - 12mm上下边距 */
}
.header.header-grid {
display: flex;
justify-content: flex-start;
align-items: center;
column-gap: 12px;
margin-bottom: 8px;
}
.header.header-grid .company-title {
font-size: 12px;
text-align: left;
display: flex;
align-items: center;
gap: 8px;
}
.header.header-grid .audit,
.header.header-grid .handler,
.header.header-grid .receiver {
font-size: 12px;
text-align: right;
display: flex;
align-items: center;
justify-content: flex-end;
}
/* 合计行样式 */
.sum-row {
border-top: 2px solid #000;
font-weight: bold;
}
.sum-label {
text-align: right;
font-weight: bold;
}
.sum-value {
font-weight: bold;
}
/* 合计行样式 */
.sum-row {
border-top: 2px solid #000;
font-weight: bold;
}
.sum-label {
text-align: right;
font-weight: bold;
}
.sum-value {
font-weight: bold;
}
.sign-space {
display: inline-block;
width: 50px;
height: 18px;
margin-left: 4px;
}
.sheet { width:100%; border-collapse:collapse; font-size:12px; table-layout: fixed; }
.sheet th, .sheet td { border:1px solid #333; padding:4px 0px; text-align:center; line-height:1; vertical-align: middle; }
.sheet thead th { background:#f5f7fa; font-weight:600; }
.sheet .text-left { text-align:left; padding-left:6px; }
.sheet .spec { word-break: break-word; white-space: normal; }
.sheet .num { text-align:right; padding-right:6px; }
.sheet tfoot .sum-label, .sheet tfoot .sum-value { font-weight:700; }
.sheet tfoot .sum-row td { border-top: 2px solid #000; }
.sign-row { display:flex; justify-content:flex-start; margin-top:12px; font-size:12px;gap:30px }
.sign-item { display: flex; align-items: center; }
.sign-item .label { margin-right: 4px; }
</style>
`)
doc.write(printNode.outerHTML)
doc.close()
iframe.contentWindow!.focus()
iframe.contentWindow!.print()
setTimeout(() => document.body.removeChild(iframe), 500)
}
</script>
<style scoped lang="less">
.print-wrap {
/* 预览时也按目标纸张尺寸展示便于校对 */
width: 100%;
min-height: 140mm;
background: #fff;
}
.header.header-grid {
display: flex;
justify-content: flex-start;
align-items: center;
column-gap: 12px;
}
.header.header-grid .company-title {
display: flex;
align-items: center;
gap: 8px;
}
.header.header-grid .company {
font-weight: bold;
}
.header.header-grid .title {
font-weight: bold;
}
.header.header-grid .audit,
.header.header-grid .handler,
.header.header-grid .receiver {
display: flex;
align-items: center;
justify-content: flex-end;
}
/* 签字空间样式 */
.sign-space {
display: inline-block;
width: 70px;
height: 18px;
margin-left: 4px;
}
.sheet {
margin-top: 8px;
table-layout: fixed;
border-collapse: collapse;
font-size: 12px;
width: 100%;
th,
td {
padding: 6px 4px;
text-align: center;
line-height: 1.3;
vertical-align: middle;
}
thead th {
background: #f5f7fa;
font-weight: 600;
}
.text-left {
text-align: left;
padding-left: 6px;
}
.spec {
word-break: break-word;
white-space: normal;
}
.num {
text-align: right;
padding-right: 6px;
}
tfoot .sum-row td {
border-top: 2px solid #000;
}
}
.footer-sign.sign-row {
display: flex;
justify-content: flex-start;
margin-top: 12px;
gap: 30px;
}
.sign-item {
display: flex;
align-items: center;
}
.sign-item .label {
margin-right: 4px;
}
.sign-item .name {
// font-weight: bold;
}
</style>