feat(wms): 新增钢卷去向标签和异常信息查看功能

- 新增钢卷去向标签(WhereTag)及相关配置
- 在base.vue中添加钢卷去向选择功能
- 新增异常信息查看弹窗组件(abnormal.vue)
- 新增多个仓库视图页面(mini.vue, scrap.vue等)
- 在发货单组件中新增Excel导出功能
- 优化标签打印功能,支持多种标签类型
- 修复报表查询时间参数问题
This commit is contained in:
砂糖
2026-02-07 14:36:56 +08:00
parent 0fae7ad434
commit 8efb46289c
14 changed files with 1331 additions and 15 deletions

View File

@@ -0,0 +1,44 @@
<template>
<el-tabs class="app-container" v-model="activeTab">
<el-tab-pane label="待收卷" name="second">
<BasePage :qrcode="qrcode" :querys="querys2" :labelType="labelType" :hideWarehouseQuery="hideWarehouseQuery"
:hideType="hideType" />
</el-tab-pane>
<el-tab-pane label="已收卷" name="first">
<BasePage :qrcode="qrcode" :querys="querys" :labelType="labelType" :hideWarehouseQuery="hideWarehouseQuery"
:hideType="hideType" />
</el-tab-pane>
</el-tabs>
</template>
<script>
import BasePage from './panels/base.vue';
export default {
components: {
BasePage
},
data() {
return {
qrcode: false,
activeTab: 'second',
querys: {
dataType: 1,
status: 0,
warehouseIds: '2019583656787259393,2019583325311414274,2019583137616310273,2019583429955104769', // 技术部逻辑库
// materialType: '废品'
},
querys2: {
dataType: 1,
status: 0,
nextWarehouseIds: '2019583656787259393,2019583325311414274,2019583137616310273,2019583429955104769', // 技术部逻辑库
// materialType: '废品'
},
hideWarehouseQuery: true,
showAbnormal: true,
labelType: '2',
hideType: false,
}
}
}
</script>

View File

@@ -0,0 +1,297 @@
<template>
<div class="label-container" :style="{ '--print-scale': printScale }">
<table class="material-label-table">
<tr>
<td class="label-cell" style="width: 16.67%; padding: 4px;">卷号</td>
<td class="value-cell" colspan="2" style="width: 33.33%; padding: 4px;">
<div class="nob" contenteditable>{{ content.currentCoilNo || '' }}</div>
</td>
<td class="label-cell" style="width: 16.67%; padding: 4px;">来源</td>
<td class="value-cell" colspan="2" style="width: 33.33%; padding: 4px;">
<div class="nob" contenteditable>{{ content.warehouseName || '' }}</div>
</td>
</tr>
<tr>
<td class="label-cell" style="width: 16.67%; padding: 4px;">班组</td>
<td class="value-cell" colspan="2" style="width: 33.33%; padding: 4px;">
<div class="nob" contenteditable>{{ content.team || '' }}</div>
</td>
<td class="label-cell" style="width: 16.67%; padding: 4px;">净重</td>
<td class="value-cell" colspan="2" style="width: 33.33%; padding: 4px;">
<div class="nob" contenteditable>{{ content.netWeight || '' }}</div>
</td>
</tr>
<tr>
<td class="label-cell" style="width: 16.67%; padding: 4px;">规格</td>
<td class="value-cell" colspan="2" style="width: 33.33%; padding: 4px;">
<div class="nob" contenteditable>{{ content.specification || '' }}</div>
</td>
<td class="label-cell" style="width: 16.67%; padding: 4px;">材质</td>
<td class="value-cell" colspan="2" style="width: 33.33%; padding: 4px;">
<div class="nob" contenteditable>{{ content.material || '' }}</div>
</td>
</tr>
<tr>
<td class="label-cell" style="width: 16.67%; padding: 4px;">卷名</td>
<td class="value-cell" colspan="2" style="width: 33.33%; padding: 4px;">
<div class="nob" contenteditable>{{ content.itemName || '' }}</div>
</td>
<td class="label-cell" style="width: 16.67%; padding: 4px;">厂家</td>
<td class="value-cell" colspan="2" style="width: 33.33%; padding: 4px;">
<div class="nob" contenteditable>{{ content.manufacturer || '' }}</div>
</td>
</tr>
<tr>
<td class="label-cell" style="width: 16.67%; padding: 4px;">时间</td>
<td class="value-cell" colspan="2" style="width: 33.33%; padding: 4px;">
<div class="nob" contenteditable>{{ content.updateTime || '' }}</div>
</td>
<td class="label-cell" style="width: 16.67%; padding: 4px;">去向</td>
<td class="value-cell" colspan="2" style="width: 33.33%; padding: 4px;">
<div class="nob" contenteditable>{{ content.nextWarehouseName || '' }}</div>
</td>
</tr>
</table>
</div>
</template>
<script>
export default {
name: 'WhereTag',
props: {
content: {
type: Object,
default: () => ({
coilNumber: '',
specification: '',
netWeight: '',
material: '',
nextProcess: '',
productionTeam: '',
productionDate: '',
qrcodeRecordId: '',
})
},
paperWidthMm: {
type: Number,
default: 100 // 原料码100mm x 80mm宽100高80
},
paperHeightMm: {
type: Number,
default: 80
}
},
data() {
return {
printScale: 1,
}
},
mounted() {
// 使用 matchMedia 监听打印状态(更可靠)
this.printMediaQuery = window.matchMedia('print');
this.printMediaQuery.addListener(this.handlePrintMediaChange);
// 监听打印事件作为备用
window.addEventListener('beforeprint', this.handleBeforePrint);
window.addEventListener('afterprint', this.handleAfterPrint);
// 计算初始缩放比例
this.$nextTick(() => {
this.calculatePrintScale();
});
},
beforeDestroy() {
if (this.printMediaQuery) {
this.printMediaQuery.removeListener(this.handlePrintMediaChange);
}
window.removeEventListener('beforeprint', this.handleBeforePrint);
window.removeEventListener('afterprint', this.handleAfterPrint);
},
methods: {
handlePrintMediaChange(mq) {
if (mq.matches) {
// 进入打印模式
this.calculatePrintScale();
} else {
// 退出打印模式
this.resetPrintScale();
}
},
handleBeforePrint() {
// 延迟计算确保DOM已更新
setTimeout(() => {
this.calculatePrintScale();
}, 100);
},
handleAfterPrint() {
this.resetPrintScale();
},
calculatePrintScale() {
this.$nextTick(() => {
const container = this.$el;
if (!container) return;
// 纸张尺寸180mm x 100mm
const dpi = 96; // 标准 DPI
const mmToPx = dpi / 25.4; // 1mm = 3.779527559px
const paperWidthMm = this.paperWidthMm || 100;
const paperHeightMm = this.paperHeightMm || 80;
const marginMm = 2;
const paperWidthPx = paperWidthMm * mmToPx;
const paperHeightPx = paperHeightMm * mmToPx;
const marginPx = marginMm * mmToPx;
// 获取内容实际尺寸
const rect = container.getBoundingClientRect();
let contentWidth = rect.width;
let contentHeight = rect.height;
// 如果尺寸为0或无效尝试使用 scrollWidth/scrollHeight
if (contentWidth === 0 || contentHeight === 0) {
contentWidth = container.scrollWidth || contentWidth;
contentHeight = container.scrollHeight || contentHeight;
}
// 计算可用空间(减去边距)
const availableWidth = paperWidthPx - marginPx * 2;
const availableHeight = paperHeightPx - marginPx * 2;
// 计算缩放比例
const scaleX = contentWidth > 0 ? availableWidth / contentWidth : 1;
const scaleY = contentHeight > 0 ? availableHeight / contentHeight : 1;
// 取较小的缩放比例确保内容完全适配不超过1不放大
this.printScale = Math.min(scaleX, scaleY, 1);
// 设置CSS变量和内联样式
container.style.setProperty('--print-scale', this.printScale);
container.style.setProperty('--paper-width', `${paperWidthMm}mm`);
container.style.setProperty('--paper-height', `${paperHeightMm}mm`);
});
},
resetPrintScale() {
this.printScale = 1;
if (this.$el) {
this.$el.style.setProperty('--print-scale', 1);
this.$el.style.removeProperty('--paper-width');
this.$el.style.removeProperty('--paper-height');
}
}
}
}
</script>
<style scoped>
.label-container {
width: 25em;
height: 20em;
padding: 0px;
display: flex;
/* 启用Flex布局 */
flex-direction: column;
/* 子元素垂直排列 */
font-family: "SimSun", serif;
box-sizing: border-box;
/* 确保内边距/边框不影响总尺寸 */
}
.material-label-table {
border-collapse: collapse;
width: 100%;
table-layout: fixed;
flex-grow: 1;
/* 让表格拉伸,占满剩余垂直空间 */
height: 0;
/* 配合flex-grow自动计算高度 */
border: 1px solid #333;
/* 确保表格有最外层边框 */
}
/* 四列均分宽度每列占25% */
.material-label-table td {
border: 1px solid #333;
padding: 0;
font-size: 14px;
/* width: 25%; */
box-sizing: border-box;
text-align: center;
word-break: break-all;
overflow-wrap: break-word;
white-space: normal;
overflow: hidden;
}
.label-cell {
background-color: #f5f5f5;
font-weight: bold;
}
.value-cell {
text-align: center;
}
.nob {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
border: none;
outline: none;
background: transparent;
text-align: center;
font-size: inherit;
word-break: break-all;
overflow-wrap: break-word;
white-space: normal;
}
/* 打印样式 - 强制单页适配100mm x 80mm纸张保持原有样式不变 */
@media print {
@page {
size: 100mm 80mm;
margin: 0 !important;
padding: 0 !important;
}
* {
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
}
html,
body {
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
}
/* 隐藏所有其他内容,只显示标签容器 */
body>*:not(.material-label-container) {
display: none !important;
}
.material-label-container {
/* 防止分页 - 多重保护 */
page-break-inside: avoid !important;
break-inside: avoid !important;
page-break-after: avoid !important;
break-after: avoid !important;
page-break-before: avoid !important;
break-before: avoid !important;
orphans: 999 !important;
widows: 999 !important;
/* 应用动态缩放,保持原有样式 */
transform: scale(var(--print-scale, 1)) !important;
transform-origin: top left !important;
/* 确保缩放后不超出纸张 */
max-width: var(--paper-width, 100mm) !important;
max-height: var(--paper-height, 80mm) !important;
overflow: hidden !important;
}
}
</style>

View File

@@ -3,23 +3,29 @@
<!-- 标签预览容器 -->
<div class="preview-container" :id="hideActions ? undefined : 'label-preview-container'" ref="labelRef">
<MaterialTag
v-if="labelType === '2'"
v-if="tagType === '2'"
:content="content"
:paperWidthMm="100"
:paperHeightMm="80"
/>
<OuterTagPreview
v-if="labelType === '3'"
v-if="tagType === '3'"
:content="content"
:paperWidthMm="180"
:paperHeightMm="100"
/>
<GalvanizedTag
v-if="labelType === '4'"
v-if="tagType === '4'"
:content="content"
:paperWidthMm="180"
:paperHeightMm="100"
/>
<WhereTag
v-if="tagType === 'where'"
:content="content"
:paperWidthMm="100"
:paperHeightMm="80"
/>
<!-- <SampleTagPreview v-if="labelType === '4'" :content="content" />
<ForgeTagPreview v-if="labelType === '5'" :content="content" />
<SaltSprayTagPreview v-if="labelType === '6'" :content="content" /> -->
@@ -40,6 +46,7 @@ import { PDFDocument } from 'pdf-lib';
import MaterialTag from './MaterialTag.vue';
import OuterTagPreview from './OuterTagPreview.vue';
import GalvanizedTag from './GalvanizedTag.vue';
import WhereTag from './WhereTag.vue';
// import SampleTagPreview from './SampleTagPreview.vue';
// import ForgeTagPreview from './ForgeTagPreview.vue';
// import SaltSprayTagPreview from './SaltSprayTagPreview.vue';
@@ -50,6 +57,7 @@ export default {
MaterialTag,
OuterTagPreview,
GalvanizedTag,
WhereTag,
// SampleTagPreview,
// ForgeTagPreview,
// SaltSprayTagPreview,
@@ -57,6 +65,32 @@ export default {
data() {
return {
labelType: '2',
tagSizeMap: {
'2': {
width: 100,
height: 80,
},
'3': {
width: 180,
height: 100,
},
'4': {
width: 180,
height: 100,
},
'where': {
width: 100,
height: 80,
},
}
}
},
computed: {
tagType() {
if (this.forceSpecialTag) {
return this.forceSpecialTag;
}
return this.labelType;
}
},
props: {
@@ -64,6 +98,10 @@ export default {
// type: String,
// required: true,
// },
forceSpecialTag: {
type: String,
required: false,
},
content: {
type: Object,
required: true,
@@ -139,8 +177,8 @@ export default {
// 2. 计算纸张尺寸(与批量导出保持一致)
// 根据 labelType 判断:'2' 是材料标签100x80宽100高80'3' 是外标180x100
const isMaterial = this.labelType === '2';
const paperWidthMm = isMaterial ? 100 : 180;
const paperHeightMm = isMaterial ? 80 : 100;
const paperWidthMm = this.tagSizeMap[this.tagType].width || 100;
const paperHeightMm = this.tagSizeMap[this.tagType].height || 80;
// 使用合适的scale值生成高清Canvas但不超过纸张尺寸
const canvasScale = 3; // 提高清晰度(单张打印)

View File

@@ -0,0 +1,267 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="位置" prop="position">
<el-select v-model="queryParams.position" placeholder="请选择位置" clearable>
<el-option v-for="dict in dict.type.coil_abnormal_position" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="缺陷代码" prop="defectCode">
<el-select v-model="queryParams.defectCode" placeholder="请选择缺陷代码" clearable>
<el-option v-for="dict in dict.type.coil_abnormal_code" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="程度" prop="degree">
<el-select v-model="queryParams.degree" placeholder="请选择程度" clearable>
<el-option v-for="dict in dict.type.coil_abnormal_degree" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="coilAbnormalList">
<el-table-column label="位置" align="center" prop="position">
<template slot-scope="scope">
<dict-tag :options="dict.type.coil_abnormal_position" :value="scope.row.position" />
</template>
</el-table-column>
<el-table-column label="长度坐标" align="center" prop="lengthCoord" />
<el-table-column label="缺陷代码" align="center" prop="defectCode">
<template slot-scope="scope">
<dict-tag :options="dict.type.coil_abnormal_code" :value="scope.row.defectCode" />
</template>
</el-table-column>
<el-table-column label="程度" align="center" prop="degree">
<template slot-scope="scope">
<dict-tag :options="dict.type.coil_abnormal_degree" :value="scope.row.degree" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
<!-- 添加或修改钢卷异常信息对话框 -->
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="位置" prop="position">
<el-radio-group v-model="form.position">
<el-radio-button v-for="dict in dict.type.coil_abnormal_position" :key="dict.value" :label="dict.value">{{
dict.label }}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="长度坐标" prop="lengthCoord">
<el-input v-model="form.lengthCoord" placeholder="请输入长度坐标" />
</el-form-item>
<el-form-item label="缺陷代码" prop="defectCode">
<el-radio-group v-model="form.defectCode">
<el-radio-button v-for="dict in dict.type.coil_abnormal_code" :key="dict.value" :label="dict.value">{{
dict.label }}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="程度" prop="degree">
<el-radio-group v-model="form.degree">
<el-radio-button v-for="dict in dict.type.coil_abnormal_degree" :key="dict.value" :label="dict.value">{{
dict.label }}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listCoilAbnormal, getCoilAbnormal, delCoilAbnormal, addCoilAbnormal, updateCoilAbnormal } from "@/api/wms/coilAbnormal";
export default {
name: "CoilAbnormal",
dicts: ['coil_abnormal_code', 'coil_abnormal_position', 'coil_abnormal_degree'],
data() {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 钢卷异常信息表格数据
coilAbnormalList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
coilId: undefined,
position: undefined,
lengthCoord: undefined,
defectCode: undefined,
degree: undefined,
judgeLevel: undefined,
judgeBy: undefined,
},
// 表单参数
form: {},
// 表单校验
rules: {
},
judgeOpen: false,
};
},
props: {
coilId: {
type: String,
required: true
}
},
watch: {
coilId: {
handler(newVal, oldVal) {
if (!newVal) {
this.coilAbnormalList = [];
this.total = 0;
return;
}
this.queryParams.coilId = newVal
this.handleQuery()
},
immediate: true
}
},
methods: {
/** 查询钢卷异常信息列表 */
getList() {
this.loading = true;
listCoilAbnormal(this.queryParams).then(response => {
this.coilAbnormalList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
abnormalId: undefined,
coilId: this.coilId,
position: undefined,
lengthCoord: undefined,
defectCode: undefined,
degree: undefined,
judgeLevel: undefined,
judgeBy: undefined,
judgeTime: undefined,
remark: undefined,
delFlag: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加钢卷异常信息";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;
this.reset();
const abnormalId = row.abnormalId || this.ids
getCoilAbnormal(abnormalId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改钢卷异常信息";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.abnormalId != null) {
updateCoilAbnormal(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addCoilAbnormal(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const abnormalIds = row.abnormalId || this.ids;
this.$modal.confirm('是否确认删除钢卷异常信息编号为"' + abnormalIds + '"的数据项?').then(() => {
this.loading = true;
return delCoilAbnormal(abnormalIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
}
};
</script>

View File

@@ -146,7 +146,17 @@
</el-select>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
<el-table-column label="钢卷去向" align="center" prop="nextWarehouseId" v-if="editNext" width="150">
<template slot-scope="scope">
<el-select v-model="scope.row.nextWarehouseId" placeholder="钢卷去向" filterable
@change="handleNextWarehouseChange(scope.row)">
<el-option v-for="item in dict.type.warehouse_sync" :key="item.value" :value="item.value"
:label="item.label" />
</el-select>
</template>
</el-table-column>
<!-- <el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip/> -->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
@@ -274,10 +284,10 @@
<!-- 标签预览弹窗 -->
<el-dialog title="标签预览" :visible.sync="labelRender.visible" append-to-body>
<label-render :content="labelRender.data" :labelType="labelRender.type" />
<label-render :forceSpecialTag="forceSpecialTag" :content="labelRender.data" :labelType="labelRender.type" />
</el-dialog>
<label-render ref="labelRender" v-show="false" :content="labelRender.data" :labelType="labelRender.type" />
<label-render :forceSpecialTag="forceSpecialTag" ref="labelRender" v-show="false" :content="labelRender.data" :labelType="labelRender.type" />
<!-- 批量导出标签PDF弹窗 -->
<el-dialog title="批量导出标签PDF" :visible.sync="batchPrint.visible" width="520px" append-to-body>
@@ -293,10 +303,14 @@
<!-- 渲染容器屏幕隐藏仅用于截图生成PDF -->
<div ref="batchPdfContainer" class="batch-pdf-root" aria-hidden="true">
<div v-for="(item, idx) in batchPrint.list" :key="item.coilId || idx" class="batch-pdf-page">
<label-render :content="item" :hideActions="true" />
<label-render :content="item" :hideActions="true" :forceSpecialTag="forceSpecialTag" />
</div>
</div>
</el-dialog>
<el-dialog title="异常信息" :visible.sync="abnormalOpen" width="90%" append-to-body>
<abnormal-list :coil-id="currentCoilId"></abnormal-list>
</el-dialog>
</div>
</template>
@@ -335,6 +349,7 @@ import MutiSelect from "@/components/MutiSelect";
import html2canvas from 'html2canvas';
import { PDFDocument } from 'pdf-lib';
import { listUser } from "@/api/system/user";
import AbnormalList from "./abnormal.vue";
export default {
name: "MaterialCoil",
@@ -354,8 +369,9 @@ export default {
MemoInput,
MutiSelect,
OuterTagPreview,
AbnormalList,
},
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status'],
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status', 'warehouse_sync'],
props: {
qrcode: {
type: Boolean,
@@ -405,6 +421,14 @@ export default {
type: Boolean,
default: false,
},
editNext: {
type: Boolean,
default: false,
},
forceSpecialTag: {
type: String,
required: false,
},
},
data() {
return {
@@ -568,6 +592,8 @@ export default {
],
title: '详细信息'
},
abnormalOpen: false,
currentCoilId: '',
userList: [],
};
},
@@ -598,6 +624,24 @@ export default {
this.userList = res.rows || [];
});
},
handleNextWarehouseChange(row) {
if (!this.editNext) {
return;
}
updateMaterialCoilSimple(row).then(res => {
if (res.code === 200) {
this.$message({
message: '更新成功',
type: 'success',
});
} else {
this.$message({
message: res.msg || '更新失败',
type: 'error',
});
}
})
},
// 打印标签
handlePrintLabel(row) {
const item = row.itemType === 'product' ? row.product : row.rawMaterial;
@@ -701,12 +745,14 @@ export default {
}
},
handleAbnormal(row) {
this.$router.push({
path: '/quality/detail',
query: {
coilId: row.coilId,
}
})
// this.$router.push({
// path: '/quality/detail',
// query: {
// coilId: row.coilId,
// }
// })
this.currentCoilId = row.coilId;
this.abnormalOpen = true;
},
// 取消按钮
cancel() {

View File

@@ -0,0 +1,28 @@
<template>
<BasePage :qrcode="qrcode" :querys="querys" :labelType="labelType" :hideWarehouseQuery="hideWarehouseQuery" :hideType="hideType" />
</template>
<script>
import BasePage from '../panels/base.vue';
export default {
components: {
BasePage
},
data() {
return {
qrcode: false,
querys: {
dataType: 1,
status: 0,
warehouseId: '2019583656787259393', // 技术部逻辑库
// materialType: '废品'
},
hideWarehouseQuery: true,
showAbnormal: true,
labelType: '2',
hideType: false,
}
}
}
</script>

View File

@@ -0,0 +1,28 @@
<template>
<BasePage :qrcode="qrcode" :querys="querys" :labelType="labelType" :hideWarehouseQuery="hideWarehouseQuery" :hideType="hideType" />
</template>
<script>
import BasePage from '../panels/base.vue';
export default {
components: {
BasePage
},
data() {
return {
qrcode: false,
querys: {
dataType: 1,
status: 0,
warehouseId: '2019583325311414274', // 小钢卷仓
// materialType: '废品'
},
hideWarehouseQuery: true,
showAbnormal: true,
labelType: '2',
hideType: false,
}
}
}
</script>

View File

@@ -0,0 +1,28 @@
<template>
<BasePage :qrcode="qrcode" :querys="querys" :labelType="labelType" :hideWarehouseQuery="hideWarehouseQuery" :hideType="hideType" />
</template>
<script>
import BasePage from '../panels/base.vue';
export default {
components: {
BasePage
},
data() {
return {
qrcode: false,
querys: {
dataType: 1,
status: 0,
warehouseId: '2019583137616310273', // 退货仓
// materialType: '废品'
},
hideWarehouseQuery: true,
showAbnormal: true,
labelType: '2',
hideType: false,
}
}
}
</script>

View File

@@ -0,0 +1,28 @@
<template>
<BasePage :qrcode="qrcode" :querys="querys" :labelType="labelType" :hideWarehouseQuery="hideWarehouseQuery" :hideType="hideType" />
</template>
<script>
import BasePage from '../panels/base.vue';
export default {
components: {
BasePage
},
data() {
return {
qrcode: false,
querys: {
dataType: 1,
status: 0,
warehouseId: '2019583429955104769', // 废品仓
// materialType: '废品'
},
hideWarehouseQuery: true,
showAbnormal: true,
labelType: '2',
hideType: false,
}
}
}
</script>

View File

@@ -0,0 +1,41 @@
<template>
<BasePage
:editNext="editNext"
:qrcode="qrcode"
:querys="querys"
:labelType="labelType"
:hideWarehouseQuery="hideWarehouseQuery"
:forceSpecialTag="forceSpecialTag"
:showControl="showControl"
:showAbnormal="showAbnormal"
:hideType="hideType"></BasePage>
</template>
<script>
import BasePage from './panels/base.vue';
export default {
components: {
BasePage
},
data() {
return {
qrcode: false,
querys: {
dataType: 1,
status: 0,
// OnlyScrap: true,
// materialType: '废品'
},
// 强制使用特殊标签
forceSpecialTag: 'where',
editNext: true,
hideWarehouseQuery: true,
labelType: '2',
hideType: false,
showControl: false,
showAbnormal: true,
}
}
}
</script>

View File

@@ -186,6 +186,7 @@
</div>
<el-button type="primary" @click="saveAsImage">保存为图片</el-button>
<el-button type="success" @click="printWaybill">打印</el-button>
<el-button type="warning" @click="exportExcel">导出Excel</el-button>
</div>
</div>
</template>
@@ -194,6 +195,8 @@
import domtoimage from 'dom-to-image';
import { PDFDocument } from 'pdf-lib';
import html2canvas from 'html2canvas';
import * as XLSX from 'xlsx';
import ExcelJS from 'exceljs';
export default {
props: {
@@ -289,6 +292,26 @@ export default {
}
return pageRows;
},
readWaybill() {
const file = this.$refs.file.files[0];
if (!file) {
return;
}
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = (e) => {
const data = e.target.result;
const wb = XLSX.read(data, { type: 'array' });
const ws = wb.Sheets[wb.SheetNames[0]];
const json = XLSX.utils.sheet_to_eth(ws);
console.log(json);
// this.localWaybillDetails = json;
// this.refreshPagination();
};
reader.onerror = (e) => {
console.error('读取文件失败:', e);
};
},
refreshPagination() {
const src = Array.isArray(this.localWaybillDetails) ? this.localWaybillDetails : [];
this.totalPages = Math.max(1, Math.ceil(src.length / this.perPage));
@@ -460,6 +483,449 @@ export default {
a.click();
document.body.removeChild(a);
}
},
async exportExcelByXLSX() {
try {
// ===== 1. 构建真实数据(替换占位符,使用实际明细)=====
const headerData = [
['科伦普发货单'], // 标题行r=0
[
`收货单位:${this.localWaybill.consigneeUnit || ''}`,
undefined, undefined, undefined,
`${this.localWaybill.deliveryYear || ''}${this.localWaybill.deliveryMonth || ''}${this.localWaybill.deliveryDay || ''}`,
undefined, undefined, undefined,
`发货单位:${this.localWaybill.senderUnit || ''}`
], // 收货/日期/发货单位行r=1
[
`负责人:${this.localWaybill.principal || ''}`,
undefined, undefined,
`电话:${this.localWaybill.principalPhone || ''}`,
undefined, undefined,
`合同号:${this.localWaybill.contractCode || ''}`,
undefined, undefined,
`车牌:${this.localWaybill.licensePlate || ''}`
], // 负责人/电话/合同号/车牌行r=2
["品名", '切边', '包装', '仓库位置', '结算', '原料厂家', '卷号', '规格', '材质', '重量(t)', '单价', '备注'], // 表格表头r=3
];
// 表格明细行替换原有E1/F1等占位符使用真实明细
const detailRows = this.displayWaybillDetails.map(item => [
item.productName || '',
item.edgeType || '',
item.packageType || '',
item.actualWarehouseName || '',
item.settlementType || '',
item.rawMaterialFactory || '',
item.coilNumber || '',
item.specification || '',
item.material || '',
item.weight || '',
item.unitPrice || '',
item.remark || ''
]);
// 底部备注/取货地点/签名栏
const footerData = [
[
'1、品名冷硬钢卷酸连轧、冷轧钢卷脱脂退火火拉矫、镀锌卷板镀锌管料镀锌分剪料2、切边净边/毛边3、包装裸包周三径四简包1周三径四内外护角简包2周三径四+防锈纸;普包:周三径四+内外护角+防锈纸+端护板精包1周三径四+内外护角+防锈纸+薄膜+端护板+内外护板精包2周三径四+内外护角+防锈纸+薄膜+端护板+内外护板+木托。'
], // 备注行r=3+明细行数)
[`取货地点:${this.localWaybill.pickupLocation || ''}`], // 取货地点行
[
`发货:${this.localWaybill.deliveryman || ''}`,
undefined, undefined, undefined,
`司机:${this.localWaybill.driver || ''}`,
undefined, undefined, undefined,
`磅房:${this.localWaybill.weightRoom || ''}`
] // 签名栏行
];
// 合并所有数据行
const data = [...headerData, ...detailRows, ...footerData];
const titleRowIdx = 0; // 标题行索引
const headerRow1Idx = 1; // 收货单位行索引
const headerRow2Idx = 2; // 负责人行索引
const tableHeaderIdx = 3; // 表格表头行索引
const remarkRowIdx = 3 + detailRows.length; // 备注行索引
const pickupRowIdx = remarkRowIdx + 1; // 取货地点行索引
const footerRowIdx = pickupRowIdx + 1; // 签名栏行索引
// ===== 2. 创建工作表并配置基础合并 =====
const ws = XLSX.utils.aoa_to_sheet(data);
ws["!cellStyles"] = true; // 必须开启才能设置单元格样式
ws["!merges"] = [
{ s: { c: 0, r: titleRowIdx }, e: { c: 11, r: titleRowIdx } }, // 标题跨列合并A1-L1
{ s: { c: 0, r: headerRow1Idx }, e: { c: 3, r: headerRow1Idx } }, // 收货单位A2-D2
{ s: { c: 4, r: headerRow1Idx }, e: { c: 7, r: headerRow1Idx } }, // 日期E2-H2
{ s: { c: 8, r: headerRow1Idx }, e: { c: 11, r: headerRow1Idx } }, // 发货单位I2-L2
{ s: { c: 0, r: headerRow2Idx }, e: { c: 2, r: headerRow2Idx } }, // 负责人A3-C3
{ s: { c: 3, r: headerRow2Idx }, e: { c: 5, r: headerRow2Idx } }, // 电话D3-F3
{ s: { c: 6, r: headerRow2Idx }, e: { c: 8, r: headerRow2Idx } }, // 合同号G3-I3
{ s: { c: 9, r: headerRow2Idx }, e: { c: 11, r: headerRow2Idx } }, // 车牌J3-L3
{ s: { c: 0, r: remarkRowIdx }, e: { c: 11, r: remarkRowIdx } }, // 备注跨列合并A*_L*
{ s: { c: 0, r: pickupRowIdx }, e: { c: 11, r: pickupRowIdx } }, // 取货地点跨列合并
{ s: { c: 0, r: footerRowIdx }, e: { c: 3, r: footerRowIdx } }, // 发货A*_D*
{ s: { c: 4, r: footerRowIdx }, e: { c: 7, r: footerRowIdx } }, // 司机E*_H*
{ s: { c: 8, r: footerRowIdx }, e: { c: 11, r: footerRowIdx } }, // 磅房I*_L*
];
// ===== 3. 配置列宽完全匹配Web端表格列宽=====
ws['!cols'] = [
{ wpx: 70 }, // 品名
{ wpx: 40 }, // 切边
{ wpx: 50 }, // 包装
{ wpx: 90 }, // 仓库位置
{ wpx: 60 }, // 结算
{ wpx: 70 }, // 原料厂家
{ wpx: 110 }, // 卷号
{ wpx: 90 }, // 规格
{ wpx: 80 }, // 材质
{ wpx: 70 }, // 重量(t)
{ wpx: 50 }, // 单价
{ wpx: 130 }, // 备注
];
// ===== 4. 逐个配置单元格样式核心匹配Web端=====
// 工具函数:生成单元格样式
const createCellStyle = (options = {}) => {
const defaultStyle = {
font: {
name: "SimSun", // 宋体匹配Web端SimSun
sz: options.sz || 16, // 默认字号16px表格单元格
bold: options.bold ?? true, // 默认加粗匹配Web端font-weight:900
},
alignment: {
horizontal: options.horizontal || "center", // 默认水平居中
vertical: options.vertical || "center", // 默认垂直居中
wrapText: options.wrapText || false, // 默认不换行
},
border: options.border || {
top: { style: "thin", color: { rgb: "000000" } },
bottom: { style: "thin", color: { rgb: "000000" } },
left: { style: "thin", color: { rgb: "000000" } },
right: { style: "thin", color: { rgb: "000000" } },
},
};
return defaultStyle;
};
// 4.1 标题单元格A124px、宋体、加粗、居中、无边框
const titleCell = XLSX.utils.encode_cell({ r: titleRowIdx, c: 0 });
ws[titleCell].s = {
...createCellStyle({
sz: 24, // Web端title的24px
border: null, // 标题无边框
}),
};
// 4.2 头部信息行(收货单位/负责人行18px、宋体、加粗、居中、无边框
const headerCells = [
// 收货单位行A2/E2/I2
XLSX.utils.encode_cell({ r: headerRow1Idx, c: 0 }),
XLSX.utils.encode_cell({ r: headerRow1Idx, c: 4 }),
XLSX.utils.encode_cell({ r: headerRow1Idx, c: 8 }),
// 负责人行A3/D3/G3/J3
XLSX.utils.encode_cell({ r: headerRow2Idx, c: 0 }),
XLSX.utils.encode_cell({ r: headerRow2Idx, c: 3 }),
XLSX.utils.encode_cell({ r: headerRow2Idx, c: 6 }),
XLSX.utils.encode_cell({ r: headerRow2Idx, c: 9 }),
];
headerCells.forEach(cellAddr => {
if (ws[cellAddr]) {
ws[cellAddr].s = {
...createCellStyle({
sz: 18, // Web端label的18px
border: null, // 头部信息无边框
}),
};
}
});
// 4.3 表格表头A4-L416px、宋体、加粗、居中、带边框
for (let c = 0; c < 12; c++) {
const cellAddr = XLSX.utils.encode_cell({ r: tableHeaderIdx, c });
if (ws[cellAddr]) {
ws[cellAddr].s = createCellStyle({ sz: 16 }); // 匹配Web表格16px
}
}
// 4.4 表格明细行16px、宋体、加粗、居中、带边框
for (let r = tableHeaderIdx + 1; r < remarkRowIdx; r++) {
for (let c = 0; c < 12; c++) {
const cellAddr = XLSX.utils.encode_cell({ r, c });
if (ws[cellAddr]) {
ws[cellAddr].s = createCellStyle({ sz: 16 });
}
}
}
// 4.5 备注行18px、宋体、加粗、居中、自动换行、无边框
const remarkCell = XLSX.utils.encode_cell({ r: remarkRowIdx, c: 0 });
if (ws[remarkCell]) {
ws[remarkCell].s = {
...createCellStyle({
sz: 18, // Web端备注18px
wrapText: true, // 自动换行匹配Web端text-align: justify
border: null, // 备注无边框
}),
};
}
// 4.6 取货地点行18px、宋体、加粗、居中、无边框
const pickupCell = XLSX.utils.encode_cell({ r: pickupRowIdx, c: 0 });
if (ws[pickupCell]) {
ws[pickupCell].s = {
...createCellStyle({
sz: 18, // Web端取货地点18px
border: null, // 无边框
}),
};
}
// 4.7 签名栏行18px、宋体、加粗、居中、无边框
const footerCells = [
XLSX.utils.encode_cell({ r: footerRowIdx, c: 0 }), // 发货
XLSX.utils.encode_cell({ r: footerRowIdx, c: 4 }), // 司机
XLSX.utils.encode_cell({ r: footerRowIdx, c: 8 }), // 磅房
];
footerCells.forEach(cellAddr => {
if (ws[cellAddr]) {
ws[cellAddr].s = {
...createCellStyle({
sz: 18, // Web端签名栏18px
border: null, // 无边框
}),
};
}
});
console.log(ws);
// ===== 5. 生成Excel并下载 =====
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "科伦普发货单"); // 工作表名称更贴合业务
// 生成Excel文件启用样式配置
const excelBuffer = XLSX.write(wb, {
bookType: "xlsx",
type: "array",
cellStyles: true, // 必须开启才能导出样式
sheetStubs: true
});
const blob = new Blob([excelBuffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8",
});
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = `科伦普发货单_${this.waybill.waybillNo || Date.now()}.xlsx`; // 文件名更规范
document.body.appendChild(link);
link.click();
// 清理资源
setTimeout(() => {
document.body.removeChild(link);
URL.revokeObjectURL(url);
}, 100);
} catch (error) {
console.error("Excel导出失败", error);
this.$message.error("导出失败,请重试"); // 替换为Vue的message提示
}
},
async exportExcel() {
try {
// 1. 创建工作簿和工作表
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('科伦普发货单');
worksheet.properties.defaultRowHeight = 25; // 设置默认行高匹配Web端行高
// 2. 构建数据(复用原有业务数据)
const title = `科伦普发货单`; // 标题
const header1 = { // 收货单位+日期+发货单位
consignee: `收货单位:${this.localWaybill.consigneeUnit || ''}`,
date: `${this.localWaybill.deliveryYear || ''}${this.localWaybill.deliveryMonth || ''}${this.localWaybill.deliveryDay || ''}`,
sender: `发货单位:${this.localWaybill.senderUnit || ''}`
};
const header2 = { // 负责人+电话+合同号+车牌
principal: `负责人:${this.localWaybill.principal || ''}`,
phone: `电话:${this.localWaybill.principalPhone || ''}`,
contract: `合同号:${this.localWaybill.contractCode || ''}`,
license: `车牌:${this.localWaybill.licensePlate || ''}`
};
const tableHeader = ["品名", '切边', '包装', '仓库位置', '结算', '原料厂家', '卷号', '规格', '材质', '重量(t)', '单价', '备注']; // 表格表头
const tableData = this.displayWaybillDetails.map(item => [ // 表格明细
item.productName || '',
item.edgeType || '',
item.packageType || '',
item.actualWarehouseName || '',
item.settlementType || '',
item.rawMaterialFactory || '',
item.coilNumber || '',
item.specification || '',
item.material || '',
item.weight || '',
item.unitPrice || '',
item.remark || ''
]);
const remark = '1、品名冷硬钢卷酸连轧、冷轧钢卷脱脂退火火拉矫、镀锌卷板镀锌管料镀锌分剪料2、切边净边/毛边3、包装裸包周三径四简包1周三径四内外护角简包2周三径四+防锈纸;普包:周三径四+内外护角+防锈纸+端护板精包1周三径四+内外护角+防锈纸+薄膜+端护板+内外护板精包2周三径四+内外护角+防锈纸+薄膜+端护板+内外护板+木托。';
const pickupLocation = `取货地点:${this.localWaybill.pickupLocation || ''}`;
const footer = { // 签名栏
deliveryman: `发货:${this.localWaybill.deliveryman || ''}`,
driver: `司机:${this.localWaybill.driver || ''}`,
weightRoom: `磅房:${this.localWaybill.weightRoom || ''}`
};
// 3. 写入数据到工作表(按行写入)
let rowIdx = 1; // exceljs行号从1开始
// 3.1 标题行第1行
const titleCell = worksheet.getCell(`A${rowIdx}`);
titleCell.value = title;
worksheet.mergeCells(`A${rowIdx}:L${rowIdx}`); // 合并A1-L1
// 3.2 收货单位行第2行
rowIdx++;
worksheet.getCell(`A${rowIdx}`).value = header1.consignee;
worksheet.getCell(`E${rowIdx}`).value = header1.date;
worksheet.getCell(`I${rowIdx}`).value = header1.sender;
worksheet.mergeCells(`A${rowIdx}:D${rowIdx}`); // 收货单位A2-D2
worksheet.mergeCells(`E${rowIdx}:H${rowIdx}`); // 日期E2-H2
worksheet.mergeCells(`I${rowIdx}:L${rowIdx}`); // 发货单位I2-L2
// 3.3 负责人行第3行
rowIdx++;
worksheet.getCell(`A${rowIdx}`).value = header2.principal;
worksheet.getCell(`D${rowIdx}`).value = header2.phone;
worksheet.getCell(`G${rowIdx}`).value = header2.contract;
worksheet.getCell(`J${rowIdx}`).value = header2.license;
worksheet.mergeCells(`A${rowIdx}:C${rowIdx}`); // 负责人A3-C3
worksheet.mergeCells(`D${rowIdx}:F${rowIdx}`); // 电话D3-F3
worksheet.mergeCells(`G${rowIdx}:I${rowIdx}`); // 合同号G3-I3
worksheet.mergeCells(`J${rowIdx}:L${rowIdx}`); // 车牌J3-L3
// 3.4 表格表头第4行
rowIdx++;
tableHeader.forEach((text, colIdx) => {
const colLetter = String.fromCharCode(65 + colIdx); // A=65, B=66...
worksheet.getCell(`${colLetter}${rowIdx}`).value = text;
});
// 3.5 表格明细行
tableData.forEach(item => {
rowIdx++;
item.forEach((text, colIdx) => {
const colLetter = String.fromCharCode(65 + colIdx);
worksheet.getCell(`${colLetter}${rowIdx}`).value = text;
});
});
// 3.6 备注行
rowIdx++;
const remarkCell = worksheet.getCell(`A${rowIdx}`);
remarkCell.value = remark;
worksheet.mergeCells(`A${rowIdx}:L${rowIdx}`); // 合并A*_L*
// 3.7 取货地点行
rowIdx++;
const pickupCell = worksheet.getCell(`A${rowIdx}`);
pickupCell.value = pickupLocation;
worksheet.mergeCells(`A${rowIdx}:L${rowIdx}`); // 合并A*_L*
// 3.8 签名栏行
rowIdx++;
worksheet.getCell(`A${rowIdx}`).value = footer.deliveryman;
worksheet.getCell(`E${rowIdx}`).value = footer.driver;
worksheet.getCell(`I${rowIdx}`).value = footer.weightRoom;
worksheet.mergeCells(`A${rowIdx}:D${rowIdx}`); // 发货A*_D*
worksheet.mergeCells(`E${rowIdx}:H${rowIdx}`); // 司机E*_H*
worksheet.mergeCells(`I${rowIdx}:L${rowIdx}`); // 磅房I*_L*
// 4. 配置列宽完全匹配Web端
const columnWidths = [70, 40, 50, 90, 60, 70, 110, 90, 80, 70, 50, 130];
worksheet.columns = columnWidths.map((width, idx) => ({
key: `col${idx + 1}`,
width: width / 5 // exceljs的width单位是字符宽度转换为px约1px=0.072字符)
}));
// 5. 配置样式核心匹配Web端
// 工具函数:设置单元格样式
const setCellStyle = (cell, options = {}) => {
// 默认样式:宋体、加粗、居中
cell.font = {
name: 'SimSun', // 宋体匹配Web端
size: options.size || 16, // 默认16px表格单元格
bold: options.bold ?? true // 默认加粗
};
cell.alignment = {
horizontal: options.horizontal || 'left', // 水平居中
vertical: options.vertical || 'middle', // 垂直居中
wrapText: options.wrapText || false // 自动换行
};
// 边框:表格单元格带边框,其他区域无边框
if (options.border) {
cell.border = {
top: { style: 'thin', color: { argb: 'FF000000' } },
bottom: { style: 'thin', color: { argb: 'FF000000' } },
left: { style: 'thin', color: { argb: 'FF000000' } },
right: { style: 'thin', color: { argb: 'FF000000' } }
};
} else {
cell.border = null; // 无边框
}
};
// 5.1 标题样式24px、宋体、加粗、居中、无边框
setCellStyle(worksheet.getCell('A1'), { size: 24, border: false, horizontal: 'center' });
// 5.2 头部信息样式18px、宋体、加粗、居中、无边框
setCellStyle(worksheet.getCell(`A2`), { size: 18, border: false });
setCellStyle(worksheet.getCell(`E2`), { size: 18, border: false });
setCellStyle(worksheet.getCell(`I2`), { size: 18, border: false });
setCellStyle(worksheet.getCell(`A3`), { size: 18, border: false });
setCellStyle(worksheet.getCell(`D3`), { size: 18, border: false });
setCellStyle(worksheet.getCell(`G3`), { size: 18, border: false });
setCellStyle(worksheet.getCell(`J3`), { size: 18, border: false });
// 5.3 表格表头样式16px、宋体、加粗、居中、带边框
for (let col = 0; col < 12; col++) {
const colLetter = String.fromCharCode(65 + col);
setCellStyle(worksheet.getCell(`${colLetter}4`), { size: 16, border: true, horizontal: 'center' });
}
// 5.4 表格明细样式16px、宋体、加粗、居中、带边框
for (let r = 5; r < rowIdx - 2; r++) { // 明细行范围第5行到备注行前一行
for (let col = 0; col < 12; col++) {
const colLetter = String.fromCharCode(65 + col);
setCellStyle(worksheet.getCell(`${colLetter}${r}`), { size: 16, border: true, horizontal: 'center' });
}
}
// 5.5 备注样式18px、宋体、加粗、居中、自动换行、无边框
setCellStyle(remarkCell, { size: 18, border: false, wrapText: true });
// 5.6 取货地点样式18px、宋体、加粗、居中、无边框
setCellStyle(pickupCell, { size: 18, border: false });
// 5.7 签名栏样式18px、宋体、加粗、居中、无边框
setCellStyle(worksheet.getCell(`A${rowIdx}`), { size: 18, border: false });
setCellStyle(worksheet.getCell(`E${rowIdx}`), { size: 18, border: false });
setCellStyle(worksheet.getCell(`I${rowIdx}`), { size: 18, border: false });
// 第一行的行高
const row1 = worksheet.getRow(1);
row1.height = 30;
// 备注行的行高
const remarkRow = worksheet.getRow(12);
remarkRow.height = 100;
// 6. 生成Excel文件并下载
const buffer = await workbook.xlsx.writeBuffer(); // 生成二进制buffer
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `科伦普发货单_${this.waybill.waybillNo || Date.now()}.xlsx`;
document.body.appendChild(link);
link.click();
// 清理资源
setTimeout(() => {
document.body.removeChild(link);
URL.revokeObjectURL(url);
}, 100);
} catch (error) {
console.error('Excel导出失败', error);
this.$message.error('导出失败,请重试');
}
}
}
}

View File

@@ -205,6 +205,8 @@ export default {
}
listCoilWithIds({
...this.queryParams,
byCreateTimeStart: undefined,
byCreateTimeEnd: undefined,
coilIds: coilIds,
}).then(res => {
this.list = res.rows

View File

@@ -205,6 +205,8 @@ export default {
}
listCoilWithIds({
...this.queryParams,
byCreateTimeStart: undefined,
byCreateTimeEnd: undefined,
coilIds: coilIds,
}).then(res => {
this.list = res.rows