365 lines
9.5 KiB
Vue
365 lines
9.5 KiB
Vue
<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>
|