| | |
| | | cancelProductIssue, |
| | | createProductIssue, |
| | | deleteProductIssue, |
| | | getProductIssue, |
| | | getProductIssuePage, |
| | | submitProductIssue, |
| | | updateProductIssue, |
| | | } from '#/api/mes/wm/productissue'; |
| | | import { getProductIssueLinesByIssue } from '#/api/mes/wm/productissue/line'; |
| | | import dayjs from 'dayjs'; |
| | | import { MdWorkstationSelect } from '#/views/mes/md/workstation/components'; |
| | | import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components'; |
| | | |
| | |
| | | props: { type: DICT_TYPE.MES_WM_PRODUCT_ISSUE_STATUS }, |
| | | }, |
| | | }, |
| | | { title: '操作', width: 260, fixed: 'right', slots: { default: 'actions' } }, |
| | | { title: '操作', width: 360, fixed: 'right', slots: { default: 'actions' } }, |
| | | ]; |
| | | |
| | | const gridHeight = ref(300); |
| | |
| | | /** 是否已选中工作站和任务,未选中时不展示表格 */ |
| | | const isReady = computed(() => !!props.taskId && !!props.workstationId); |
| | | |
| | | /** 单据内容全部按文本转义,避免物料名称或备注影响打印页面结构。 */ |
| | | function escapePrintText(value: unknown) { |
| | | return String(value ?? '').replace(/[&<>"']/g, (char) => ({ |
| | | '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', |
| | | })[char] || char); |
| | | } |
| | | |
| | | async function handlePrintIssue(row: MesWmProductIssueApi.ProductIssue) { |
| | | if (!row.id) return; |
| | | // 先打开窗口,避免异步请求结束后被浏览器作为弹窗拦截。 |
| | | const popup = window.open('', '_blank'); |
| | | if (!popup) { message.warning('浏览器拦截了打印窗口,请允许弹窗后重试'); return; } |
| | | popup.document.title = '正在准备领料单'; |
| | | popup.document.body.textContent = '正在准备领料单…'; |
| | | try { |
| | | const [issue, lines] = await Promise.all([getProductIssue(row.id), getProductIssueLinesByIssue(row.id)]); |
| | | if (!issue) throw new Error('领料单不存在'); |
| | | const safe = escapePrintText; |
| | | const date = (value: unknown) => value && dayjs(value as string | number | Date).isValid() |
| | | ? dayjs(value as string | number | Date).format('YYYY-MM-DD HH:mm') : ''; |
| | | const statusNames: Record<number, string> = { |
| | | [MesWmProductIssueStatusEnum.PREPARE]: '草稿', |
| | | [MesWmProductIssueStatusEnum.APPROVING]: '待拣货', |
| | | [MesWmProductIssueStatusEnum.APPROVED]: '待领出', |
| | | [MesWmProductIssueStatusEnum.FINISHED]: '已完成', |
| | | [MesWmProductIssueStatusEnum.CANCELED]: '已取消', |
| | | }; |
| | | const rows = lines.map((item, index) => `<tr><td>${index + 1}</td><td>${safe(item.itemCode)}</td><td>${safe(item.itemName)}</td><td>${safe(item.specification)}</td><td>${safe(item.unitMeasureName)}</td><td>${safe(item.quantity)}</td><td>${safe(item.remark)}</td></tr>`).join(''); |
| | | popup.document.open(); |
| | | popup.document.write(`<!doctype html><html lang="zh-CN"><head><meta charset="UTF-8"><title>领料单 ${safe(issue.code)}</title><style> |
| | | @page { size: A4; margin: 15mm; } body { color: #111; font: 13px 'Microsoft YaHei', sans-serif; margin: 0 auto; max-width: 180mm; } |
| | | h1 { text-align: center; font-size: 22px; margin: 12px 0 20px; } .meta { display: grid; grid-template-columns: 1fr 1fr; gap: 9px 16px; margin-bottom: 16px; overflow-wrap: anywhere; } |
| | | table { border-collapse: collapse; width: 100%; table-layout: fixed; } th,td { border: 1px solid #555; padding: 7px 4px; word-break: break-word; text-align: left; } th:first-child,td:first-child { width: 32px; text-align: center; } th:nth-child(5),td:nth-child(5) { width: 42px; } th:nth-child(6),td:nth-child(6) { width: 56px; } thead { display: table-header-group; } tr { break-inside: avoid; } |
| | | .sign { display: flex; justify-content: space-between; gap: 18px; margin-top: 32px; } .toolbar { text-align: right; padding: 12px 0; } button { padding: 7px 14px; cursor: pointer; } @media print { .toolbar { display: none; } } |
| | | </style></head><body><div class="toolbar"><button onclick="window.print()">打印 / 保存为 PDF</button></div><h1>领料单</h1> |
| | | <div class="meta"><div>领料单号:${safe(issue.code)}</div><div>领料单名称:${safe(issue.name)}</div><div>生产任务:${safe(issue.taskCode)}</div><div>生产订单:${safe(issue.workOrderCode)}</div><div>工作站:${safe(issue.workstationName || issue.workstationCode)}</div><div>需求时间:${safe(date(issue.requiredTime))}</div><div>状态:${safe(statusNames[issue.status ?? -1] ?? '未知')}</div><div>备注:${safe(issue.remark)}</div></div> |
| | | <table><thead><tr><th>序号</th><th>物料编码</th><th>物料名称</th><th>规格型号</th><th>单位</th><th>申请数量</th><th>备注</th></tr></thead><tbody>${rows || '<tr><td colspan="7">暂无领料明细</td></tr>'}</tbody></table> |
| | | <div class="sign"><span>申请人:____________</span><span>发料人:____________</span><span>领料人:____________</span><span>日期:____________</span></div></body></html>`); |
| | | popup.document.close(); |
| | | } catch (error) { |
| | | popup.close(); |
| | | message.error('无法生成领料单,请稍后重试'); |
| | | console.error(error); |
| | | } |
| | | } |
| | | |
| | | /** 编辑弹窗 */ |
| | | const [EditFormModal, editFormModalApi] = useVbenModal({ |
| | | connectedComponent: ProductIssueFormModal, |
| | |
| | | <div ref="listRef" class="issue-tab__list"> |
| | | <Grid table-title="领料记录"> |
| | | <template #actions="{ row }"> |
| | | <Button type="link" size="small" @click="handlePrintIssue(row)">打印 / 导出 PDF</Button> |
| | | <Button |
| | | v-if="row.status === MesWmProductIssueStatusEnum.PREPARE" |
| | | type="link" |