零件采购订单管理详情打印界面调整

零件采购收货预估总价 输入选中 回车总价下一行
This commit is contained in:
郑庆 2025-11-13 07:30:27 +08:00
parent 8dab672f74
commit 18782d730d
3 changed files with 451 additions and 11 deletions

View File

@ -208,6 +208,7 @@
<el-button type="primary" @click="doPrint">打印</el-button>
</template>
</el-dialog>
<Print ref="printRef"/>
</template>
<script setup lang="ts">
import { DICT_TYPE } from '@/utils/dict'
@ -227,7 +228,7 @@ import * as PurchaseOrderNoApi from '@/api/heli/purchaseorderno'
import * as PurchaseOrderNoDetailApi from '@/api/heli/purchaseordernodetail'
import {ref} from "vue";
import {update} from "lodash-es";
import Print from './print.vue'
const dialogVisible = ref(false) //
const formLoading = ref(false) // 12
const formData = ref({
@ -303,13 +304,31 @@ const isPrint = async () => {
printLoading.value = true
try {
var newVar = await PurchaseOrderNoApi.isPrint(query.id);
console.log(newVar)
openPrintDialog(newVar)
//
//createTime brief projectSubCode blueprintNo boomName compositionName matSpec purchaseAmount unitPrice estimatedPrice requireTime
const data = newVar.purchaseOrderNoDetailList?.map((item,idx) => ({
编号:idx + 1,
日期: formatDate(item.createTime),
客户名: item.brief,
模具名: item.projectSubCode,
件号: item.blueprintNo,
零件名称: item.boomName,
材料: item.compositionName,
规格: item.matSpec,
数量: item.purchaseAmount,
单价: item.unitPrice,
总价格: item.estimatedPrice,
要求日期: formatDate(item.requireTime),
})) || [];
console.log(data)
// openPrintDialog(newVar)
printRef.value?.open(data,newVar.purchaseNo)
} finally {
printLoading.value = false
}
}
const printRef = ref<InstanceType<typeof Print>>();
const updateFrom = async (row) => {
console.log(row)

View File

@ -92,7 +92,7 @@ v-model="queryParams.supplierName" placeholder="供应商" clearable @keyup.ente
<el-card class="hl-incard">
<el-form ref="subFormRef" :model="list" v-loading="formLoading" label-width="0" >
<el-table
v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" class="hl-table" ref="multipleTable" @selection-change="handleSelectionChange">
v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" class="hl-table" ref="multipleTableRef" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column label="收货状态" align="center" prop="receivingStatus" min-width="120">
<template #default="scope">
@ -119,7 +119,12 @@ v-model="queryParams.supplierName" placeholder="供应商" clearable @keyup.ente
<template #header><span class="hl-table_header">*</span>预估总价()</template>
<template #default="scope">
<el-form-item :prop="`${scope.$index}.estimatedPrice`" class="mb-0px!">
<el-input-number style="width: 100%" v-model="scope.row.estimatedPrice" placeholder="预估总价" :min="0" :precision="2" />
<el-input-number
style="width: 100%" v-model="scope.row.estimatedPrice" placeholder="预估总价" :min="0" :precision="2"
@input="(val)=>handleInput(val,scope.row)"
@keyup.enter="(e)=>handleEnter(e,scope.row)"
:id="'estimatedPrice'+scope.row.id"
/>
</el-form-item>
</template>
</el-table-column>
@ -159,7 +164,7 @@ import { ElTable } from 'element-plus'
import {useUserStore} from "@/store/modules/user";
import {dateFormatter1} from "@/utils/formatTime";
import * as PurchaseOrderNoDetailApi from "@/api/heli/purchaseordernodetail";
defineOptions({ name: 'purchaseordernopartReceived' })
defineOptions({ name: 'PurchaseordernopartReceived' })
const userStore = useUserStore()
const username = userStore.getUser.nickname
const message = useMessage() //
@ -205,7 +210,36 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const handleInput = (val: number, row: PurchaseOrderNoDetailApi.PurchaseOrderNoDetailVO) => {
console.log(val, 'val');
//
if (multipleSelection.value.indexOf(row) == -1) {
multipleSelection.value.push(row);
multipleTableRef.value.toggleRowSelection(row)
};
}
const handleEnter = (e: KeyboardEvent, row: PurchaseOrderNoDetailApi.PurchaseOrderNoDetailVO) => {
// 0.00=null
console.log(e, 'e');
//
if (list.value.indexOf(row) == list.value.length - 1) {
return
}
const index = list.value.findIndex((item) => item.id == row.id)
//
const input = document.getElementById("estimatedPrice" + list.value[index + 1].id);
if (input) {
input.focus();
if (list.value[index + 1].estimatedPrice == 0.00) {
list.value[index + 1].estimatedPrice = ''
}
}
console.log(input, 'input');
}
/** 查询列表 */
const getList = async () => {
loading.value = true
@ -241,16 +275,17 @@ const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
const multipleTable: any = ref<InstanceType<typeof ElTable>>()
const multipleTableRef: any = ref<InstanceType<typeof ElTable>>()
const multipleSelection: any = ref([])
const handleSelectionChange = (val: PurchaseOrderApi.PurchaseOrderVO[]) => {
multipleTable.value = val
multipleSelection.value = val
}
const receiveGood = async (row) => {
multipleTable.value=[]
multipleTable.value.push(row)
multipleTableRef.value.clearSelection()
multipleTableRef.value.toggleRowSelection(row)
multipleSelection.value.indexOf(row) == -1 && multipleSelection.value.push(row) ;
receiveGoods();
}
@ -258,7 +293,7 @@ const receiveGood = async (row) => {
const receiveGoods = async () => {
try {
const list = multipleTable.value|| []; //
const list = multipleSelection.value|| []; //
// 1.
if (!list || list.length==null||list.length==0) {
message.error("采购单信息未选择,请确认");

View File

@ -0,0 +1,386 @@
<template>
<el-dialog v-model="dialogVisible" title="" width="80%" 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 class="cell order-no"> 订单编号<span class="sign-space">{{ purchaseNo }}</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'
import { useUserStore } from '@/store/modules/user'
const userStore = useUserStore();
const userName = userStore.getUser.nickname//nickname
console.log(userStore,`userStore`);
//
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(() => userName)
//
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 purchaseNo = ref('')
const { query } = useRoute()
import * as PurchaseOrderNoApi from '@/api/heli/purchaseorderno'
/**
*
* @param data 打印数据
* @param str 采购订单号=订单编号
*/
const open = (data: Record<string, any>[],str: string) => {
rows.value = Array.isArray(data) ? data : []
dialogVisible.value = true;
purchaseNo.value = str;
console.log(query.id);
}
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: 5mm; }
body {
font-family: Arial, "Microsoft YaHei", sans-serif;
color:#000;
margin: 5px;
font-size: 12px;
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,
.header.header-grid .order-no{
font-size: 12px;
text-align: right;
display: flex;
align-items: center;
justify-content: flex-end;
}
.order-no{
margin-left: 12px;
}
/* 合计行样式 */
.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)
PurchaseOrderNoApi.updateIsPrint(query.id);
}
</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
.header.header-grid .order-no{
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>