整合前端

This commit is contained in:
砂糖
2026-04-13 17:04:38 +08:00
parent 69609a2cb1
commit 5d4794c9bd
915 changed files with 144259 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
<template>
<div>
<!-- <el-button type="primary" size="mini" style="margin-bottom: 10px" :disabled="selected.length === 0"
@click="handleExport">导出选中</el-button> -->
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" width="60" prop="sequence" />
<el-table-column label="工序名称" prop="processName" />
<el-table-column label="工序详情" prop="processDetail" show-overflow-tooltip />
<el-table-column label="作业责任人" prop="workResponsiblePerson" />
<el-table-column label="工序开始时间" prop="processStartTime" />
<el-table-column label="工序结束时间" prop="processEndTime" />
<el-table-column label="质检员" prop="inspector" />
<el-table-column label="不合格内容" prop="unqualifiedContent" />
<el-table-column label="备注" prop="remark" />
</el-table>
</div>
</template>
<script>
export default {
name: 'DetailTable',
props: {
list: {
type: Array,
default: () => []
},
loading: {
type: Boolean,
default: false
},
total: {
type: Number,
default: 0
}
},
data () {
return {
queryParams: {
pageNum: 1,
pageSize: 999
},
selected: []
}
},
methods: {
handleSelectionChange (val) {
this.selected = val;
},
handleExport () {
this.$emit('export-detail', this.selected);
},
handlePagination (val) {
this.$emit('pagination', val);
}
}
}
</script>

View File

@@ -0,0 +1,304 @@
<template>
<div>
<el-table v-loading="loading" :data="list">
<el-table-column label="设备名称" align="center" prop="equipmentName" />
<el-table-column label="设备数量" align="center" prop="equipmentQuantity" />
<el-table-column label="制造负责人" align="center" prop="manufacturingLeader" />
<el-table-column label="作业负责人" align="center" prop="operationLeader" />
<el-table-column label="计划交货日期" align="center" prop="plannedDeliveryDate" />
<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">
<el-button v-loading="buttonLoading" size="mini" type="text" icon="el-icon-search"
@click="handleShowDetail(scope.row)">查看详情</el-button>
<el-button v-loading="buttonLoading" size="mini" type="text" icon="el-icon-printer"
@click="handlePrint(scope.row)">打印</el-button>
<el-button v-loading="buttonLoading" size="mini" type="text" icon="el-icon-delete"
@click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 详情弹窗 -->
<el-dialog title="工艺卡详情" :visible.sync="detail" width="95%" append-to-body v-loading="formLoading">
<!-- 主表详情 -->
<el-form ref="detailForm" :model="detailData" label-width="100px" style="margin-bottom: 20px;">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item prop="equipmentName" label="设备名称">
<el-input v-model="detailData.equipmentName" placeholder="请输入设备名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="equipmentQuantity" label="设备数量">
<el-input v-model="detailData.equipmentQuantity" placeholder="请输入设备数量" type="number" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item prop="manufacturingLeader" label="制造负责人">
<el-select filterable allow-create v-model="detailData.manufacturingLeader">
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.nickName">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="operationLeader" label="作业负责人">
<el-select filterable allow-create v-model="detailData.operationLeader">
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.nickName">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item prop="plannedDeliveryDate" label="计划交货日期">
<el-date-picker v-model="detailData.plannedDeliveryDate" type="date" placeholder="请选择计划交货日期"
style="width: 100%;" value-format="yyyy-MM-DD HH:mm:ss" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item prop="remark" label="备注">
<el-input v-model="detailData.remark" placeholder="请输入备注" type="textarea" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 明细列表 -->
<el-divider>工艺卡明细</el-divider>
<div style="margin-bottom: 10px; display: flex; align-items: center;">
<el-button v-loading="buttonLoading" @click="addDetailRow" type="primary" size="mini">添加明细</el-button>
<el-alert title="工艺卡明细的变更会立刻生效,无需手动保存"></el-alert>
</div>
<el-table v-loading="loading" :data="detailData.oaProcessCardDetailList" border>
<el-table-column label="序号" width="80" prop="sequence" />
<el-table-column label="工序名称">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.processName" placeholder="请输入工序名称"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="工序详情">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.processDetail" placeholder="请输入工序详情"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="作业责任人">
<template slot-scope="scope">
<el-select filterable allow-create v-model="scope.row.workResponsiblePerson"
@change="handleDetailChange(scope.row)" placeholder="请选择或输入作业责任人">
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.nickName">
</el-option>
</el-select>
</template>
</el-table-column>
<el-table-column label="工序开始时间">
<template slot-scope="scope">
<el-date-picker v-model="scope.row.processStartTime" type="datetime" placeholder="请选择开始时间"
style="width: 100%;" @change="handleDetailChange(scope.row)" value-format="yyyy-MM-dd HH:mm:ss" />
</template>
</el-table-column>
<el-table-column label="工序结束时间">
<template slot-scope="scope">
<el-date-picker v-model="scope.row.processEndTime" type="datetime" placeholder="请选择结束时间"
style="width: 100%;" @change="handleDetailChange(scope.row)" value-format="yyyy-MM-dd HH:mm:ss" />
</template>
</el-table-column>
<el-table-column label="质检员">
<template slot-scope="scope">
<el-select filterable allow-create placeholder="请选择或输入质检员" v-model="scope.row.inspector"
@change="handleDetailChange(scope.row)">
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.nickName">
</el-option>
</el-select>
</template>
</el-table-column>
<el-table-column label="不合格内容">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.unqualifiedContent" placeholder="请输入不合格内容"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="备注">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.remark" placeholder="请输入备注"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template slot-scope="scope">
<el-button v-loading="buttonLoading" type="danger" size="mini"
@click="removeDetailRow(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div slot="footer" class="dialog-footer">
<el-button @click="detail = false">取消</el-button>
<el-button type="primary" @click="handleSave" v-loading="buttonLoading">保存修改</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { delProcessCard, updateProcessCard } from "@/api/oa/workshop/processCard";
import { addProcessCardDetail, delProcessCardDetail, listProcessCardDetail, updateProcessCardDetail } from "@/api/oa/workshop/processCardDetail";
import { listUser } from "@/api/system/user";
export default {
name: 'MasterTable',
props: {
list: {
type: Array,
default: () => []
},
loading: {
type: Boolean,
default: false
},
total: {
type: Number,
default: 0
}
},
data () {
return {
showSearch: true,
detail: false,
detailData: {
oaProcessCardDetailList: []
},
userList: [],
queryParams: {
pageNum: 1,
pageSize: 999,
signTime: undefined
},
// 表单验证规则
rules: {
equipmentName: [{ required: true, message: '请输入设备名称', trigger: 'blur' }],
equipmentQuantity: [{ required: true, message: '请输入设备数量', trigger: 'blur' }]
},
buttonLoading: false,
formLoading: false
}
},
mounted () {
this.getAllUser()
},
methods: {
getAllUser () {
listUser({ pageNum: 1, pageSize: 999 }).then(res => {
this.userList = res.rows
})
},
handleShowDetail (row) {
// 调用list接口查询详情
this.formLoading = true;
this.detail = true;
listProcessCardDetail({ cardId: row.cardId, pageSize: 999 }).then(response => {
this.detailData = { ...row, oaProcessCardDetailList: response.rows || [] };
}).finally(() => {
this.formLoading = false;
});
},
// 添加明细行
addDetailRow () {
this.buttonLoading = true;
addProcessCardDetail({
sequence: this.detailData.oaProcessCardDetailList.length + 1,
orderId: this.detailData.orderId,
processName: '',
processDetail: '',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
}).then(response => {
listProcessCardDetail({ orderId: this.detailData.orderId, pageSize: 999 }).then(response => {
this.detailData.oaProcessCardDetailList = response.rows || [];
this.$message.success("添加成功");
});
}).finally(() => {
this.buttonLoading = false;
});
},
// 删除明细行
removeDetailRow (row) {
this.buttonLoading = true;
delProcessCardDetail(row.detailId).then(response => {
listProcessCardDetail({ orderId: this.detailData.orderId, pageSize: 999 }).then(response => {
this.detailData.oaProcessCardDetailList = response.rows || [];
this.$message.success("删除成功");
});
}).finally(() => {
this.buttonLoading = false;
});
},
// 明细行数据改变时触发
handleDetailChange (row) {
updateProcessCardDetail(row)
},
// 保存修改
handleSave () {
this.$refs.detailForm.validate(valid => {
if (valid) {
this.loading = true;
updateProcessCard(this.detailData).then(response => {
this.$message.success("更新成功");
this.detail = false;
// 刷新父组件数据
this.$emit('refresh-data');
}).finally(() => {
this.loading = false;
});
}
});
},
handleDelete (row) {
// 删除添加二次确认
this.$modal.confirm('确认删除该工艺卡吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.buttonLoading = true;
delProcessCard(row.cardId).then(response => {
this.$message.success("删除成功");
this.detail = false;
// 刷新父组件数据
this.$emit('refresh-data');
}).finally(() => {
this.buttonLoading = false;
});
});
},
// 打印工艺卡
handlePrint (row) {
this.buttonLoading = true;
// 获取工艺卡明细
listProcessCardDetail({ cardId: row.cardId, pageSize: 999 }).then(response => {
// 通过事件将数据传递给父组件
this.$emit('print', {
waybill: row,
waybillDetails: response.rows || []
});
}).finally(() => {
this.buttonLoading = false;
});
}
}
}
</script>

View File

@@ -0,0 +1,620 @@
<!-- 收货单组件 -->
<template>
<div>
<div class="waybill-container" ref="waybillRef">
<!-- 头部信息 -->
<div class="waybill-header">
<div class="header-left" style="width: 33%">
<span class="label">设备名称</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.equipmentName" />
</div>
<div class="header-center" style="width: 33%">
<span class="label">设备数量</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.equipmentQuantity" />
</div>
<div class="header-right" style="width: 33%">
<span class="label">交货日期</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.plannedDeliveryDate" />
</div>
</div>
<div class="waybill-header">
<div class="header-left" style="width: 33%">
<span class="label">制造负责人</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.manufacturingLeader" />
</div>
<div class="header-center" style="width: 33%">
<span class="label">作业负责人</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.operationLeader" />
</div>
<div class="header-right" style="width: 33%">
<span class="label">创建人</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.createBy" />
</div>
</div>
<div class="waybill-header">
<div class="header-left" style="width: 100%">
<span class="label">备注</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.remark"
style="width: calc(100% - 80px)" />
</div>
</div>
<!-- 表格 -->
<table class="waybill-table" v-loading="loading" loading-text="加载中...">
<thead>
<tr>
<th>序号</th>
<th>工序名称</th>
<th>工序详情</th>
<th>作业责任人</th>
<th>工序开始时间</th>
<th>工序结束时间</th>
<th>质检员</th>
<th>不合格内容</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<!-- 无明细提示 -->
<tr v-if="localWaybillDetails.length === 0">
<td colspan="9" class="no-data">
<div class="no-data-content">
<el-empty description="暂无工艺卡明细" />
</div>
</td>
</tr>
<!-- 明细数据 -->
<tr v-for="(item, index) in localWaybillDetails" :key="index">
<td><input type="text" class="table-input transparent-input" v-model="item.sequence" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.processName" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.processDetail" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.workResponsiblePerson" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.processStartTime" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.processEndTime" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.inspector" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.unqualifiedContent" />
</td>
<td>
<div class="table-cell-with-action">
<input type="text" class="table-input transparent-input" v-model="item.remark" />
</div>
</td>
</tr>
</tbody>
</table>
<!-- 签名栏 -->
<div class="waybill-footer">
<div class="footer-item inline">
<span class="label">制单</span>
<input type="text" class="editable-input signature-input transparent-input" v-model="localWaybill.createBy" />
</div>
<div class="footer-item inline">
<span class="label">审核</span>
<input type="text" class="editable-input signature-input transparent-input" />
</div>
<div class="footer-item inline">
<span class="label">确认</span>
<input type="text" class="editable-input signature-input transparent-input" />
</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="waybill-actions">
<el-button type="primary" @click="saveAsImage">保存为图片</el-button>
<el-button type="success" @click="printWaybill">打印</el-button>
</div>
</div>
</template>
<script>
import domtoimage from 'dom-to-image';
import printJS from 'print-js';
export default {
props: {
// 组件接收完整的工艺卡内容, 渲染工艺卡,这个面板内包括一个保存为图片和一个打印按钮
waybill: {
type: Object,
default: () => { }
},
waybillDetails: {
type: Array,
default: () => []
}
},
data () {
return {
// 本地可编辑的工艺卡数据
localWaybill: {
equipmentName: '',
equipmentQuantity: '',
manufacturingLeader: '',
operationLeader: '',
plannedDeliveryDate: '',
remark: '',
createTime: '',
createBy: ''
},
// 本地可编辑的工艺卡明细
localWaybillDetails: [],
loading: false
};
},
watch: {
// 监听props变化更新本地数据
waybill: {
handler (newVal) {
if (newVal) {
this.localWaybill = {
equipmentName: newVal.equipmentName || '',
equipmentQuantity: newVal.equipmentQuantity || '',
manufacturingLeader: newVal.manufacturingLeader || '',
operationLeader: newVal.operationLeader || '',
plannedDeliveryDate: newVal.plannedDeliveryDate ? this.formatDate(newVal.plannedDeliveryDate) : '',
remark: newVal.remark || '',
createTime: newVal.createTime ? this.formatDate(newVal.createTime) : '',
createBy: newVal.createBy || ''
};
}
},
immediate: true,
deep: true
},
waybillDetails: {
handler (newVal) {
if (newVal && Array.isArray(newVal)) {
this.localWaybillDetails = newVal.map(item => ({
...item,
// 格式化日期字段
processStartTime: item.processStartTime ? this.formatDate(item.processStartTime) : '',
processEndTime: item.processEndTime ? this.formatDate(item.processEndTime) : ''
}));
} else {
this.localWaybillDetails = [];
}
},
immediate: true,
deep: true
}
},
methods: {
// 格式化日期
formatDate (dateStr) {
if (dateStr) {
const date = new Date(dateStr);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}`;
}
return '';
},
// 保存为图片
saveAsImage () {
const node = this.$refs.waybillRef;
// 确保容器在保存图片时能完整显示所有内容
const originalWidth = node.style.width;
const originalOverflow = node.style.overflow;
// 临时调整容器样式,确保所有内容可见
node.style.width = 'auto';
node.style.overflow = 'visible';
// 获取实际内容宽度
const contentWidth = node.scrollWidth;
const contentHeight = node.scrollHeight;
domtoimage.toPng(node, {
width: contentWidth,
height: contentHeight,
style: {
width: `${contentWidth}px`,
height: `${contentHeight}px`,
overflow: 'visible'
}
})
.then(dataUrl => {
const link = document.createElement('a');
link.download = `工艺卡_${this.waybill.equipmentName || this.waybill.cardId || Date.now()}.png`;
link.href = dataUrl;
link.click();
})
.catch(error => {
console.error('保存图片失败:', error);
this.$message.error('保存图片失败');
})
.finally(() => {
// 恢复原始样式
node.style.width = originalWidth;
node.style.overflow = originalOverflow;
});
},
// 打印工艺卡
printWaybill () {
const node = this.$refs.waybillRef;
// 确保容器在打印时能完整显示所有内容
const originalWidth = node.style.width;
const originalOverflow = node.style.overflow;
// 临时调整容器样式,确保所有内容可见
node.style.width = 'auto';
node.style.overflow = 'visible';
// 获取实际内容宽度
const contentWidth = node.scrollWidth;
printJS({
printable: node,
maxWidth: contentWidth,
type: 'html',
scanStyles: true,
style: `
@page { size: A4 landscape; margin: 1cm; }
.waybill-container { width: 100%; max-width: none; overflow: visible; }
.waybill-table { width: 100%; table-layout: auto; }
`,
targetStyles: ['*']
});
// 恢复原始样式
setTimeout(() => {
node.style.width = originalWidth;
node.style.overflow = originalOverflow;
}, 100);
}
}
}
</script>
<style scoped>
.waybill-container {
width: 870px;
max-width: none;
min-width: 870px;
margin: 0 auto;
padding: 20px;
background: white;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
font-family: SimSun, serif;
overflow-x: auto;
overflow-y: visible;
}
/* 头部样式 */
.waybill-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
font-size: 16px;
}
.header-left,
.header-right {
display: flex;
align-items: center;
}
.header-center {
display: flex;
align-items: center;
gap: 5px;
}
.label {
font-weight: bold;
display: inline-block;
width: 80px;
text-align: right;
white-space: nowrap;
}
.date-label {
width: 1em;
}
/* 可编辑输入框样式 */
.editable-input {
padding: 4px 8px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 14px;
font-family: SimSun, serif;
outline: none;
transition: all 0.2s;
border-bottom: 1px dashed #dcdfe6;
}
.editable-input:focus {
border-color: #409eff;
}
.date-input {
width: 30px;
text-align: center;
margin-right: 5px;
}
/* 透明输入框样式 */
.transparent-input {
border: none;
border-radius: 0;
background-color: transparent;
}
.transparent-input:focus {
border-bottom-color: #409eff;
background-color: rgba(64, 158, 255, 0.05);
}
/* 表格样式 */
.waybill-table {
width: 100%;
max-width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
font-size: 12px;
table-layout: fixed;
}
.waybill-table th,
.waybill-table td {
border: 1px solid #000;
box-sizing: border-box;
line-height: 24px;
text-align: center;
vertical-align: middle;
word-wrap: break-word;
word-break: break-all;
}
/* 表格列宽设置 */
.waybill-table th:nth-child(1),
.waybill-table td:nth-child(1) {
width: 40px;
/* 卷ID */
}
.waybill-table th:nth-child(2),
.waybill-table td:nth-child(2) {
width: 80px;
/* 卷号 */
}
.waybill-table th:nth-child(3),
.waybill-table td:nth-child(3) {
width: 200px;
/* 动作状态 */
}
.waybill-table th:nth-child(4),
.waybill-table td:nth-child(4) {
width: 80px;
/* 项目类型 */
}
.waybill-table th:nth-child(5),
.waybill-table td:nth-child(5) {
width: 80px;
/* 项目ID */
}
.waybill-table th:nth-child(6),
.waybill-table td:nth-child(6) {
width: 80px;
/* 动作类型 */
}
.waybill-table th:nth-child(7),
.waybill-table td:nth-child(7) {
width: 80px;
/* 操作类型 */
}
.waybill-table th:nth-child(8),
.waybill-table td:nth-child(8) {
width: 80px;
/* 仓库ID */
}
.waybill-table th:nth-child(9),
.waybill-table td:nth-child(9) {
width: 120px;
}
.waybill-table th {
background-color: #f5f7fa;
font-weight: bold;
}
.waybill-table tr:nth-child(even) {
background-color: #fafafa;
}
/* 表格输入框样式 */
.table-input {
box-sizing: border-box;
width: 100%;
height: 100%;
padding: 4px;
}
.table-input:focus {
border-color: #409eff;
}
/* 无数据样式 */
.no-data {
height: 200px;
vertical-align: middle;
}
.no-data-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
/* 表格单元格操作区 */
.table-cell-with-action {
display: flex;
align-items: center;
gap: 5px;
}
/* 备注样式 */
.waybill-remarks {
margin-bottom: 30px;
font-size: 14px;
line-height: 1.5;
text-align: justify;
}
.waybill-remarks p {
margin: 5px 0;
}
/* 底部签名样式 */
.waybill-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
font-size: 16px;
}
.waybill-pickup-location {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
font-size: 16px;
}
.waybill-pickup-location label {
font-size: 14px;
margin-right: 10px;
width: 40px;
}
.footer-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
width: 200px;
}
.footer-item.inline {
flex-direction: row;
align-items: center;
width: auto;
}
.footer-item .label {
font-size: 14px;
margin-right: 10px;
width: 40px;
}
.signature-input {
min-width: 150px;
}
.full-input {
/* 占满本行的剩余空间父容器不是flex */
flex: 1;
}
/* 操作按钮样式 */
.waybill-actions {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 30px;
}
/* 添加明细按钮 */
.add-detail-btn {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
/* 打印样式 */
@media print {
.waybill-container {
width: 100%;
max-width: none;
box-shadow: none;
padding: 0;
}
.waybill-header {
flex-wrap: nowrap;
justify-content: space-between;
}
.waybill-footer {
flex-wrap: nowrap;
justify-content: space-between;
}
.label {
width: 80px;
text-align: right;
white-space: nowrap;
}
.waybill-actions {
display: none;
}
}
/* 响应式设计 */
@media (max-width: 768px) {
.waybill-header {
flex-direction: column;
gap: 15px;
align-items: flex-start;
}
.waybill-table {
font-size: 12px;
}
.waybill-table th,
.waybill-table td {
padding: 2px;
}
.waybill-footer {
flex-direction: column;
align-items: flex-start;
gap: 15px;
}
.footer-item.inline {
width: 100%;
}
.label {
width: auto;
text-align: left;
}
}
</style>

View File

@@ -0,0 +1,608 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<!-- 左侧项目列表 -->
<el-col :span="6">
<ProjectTree v-model="currentProject" @select="handleProjectSelect" :list="projectList">
<template slot-scope="scope">
<!-- 如果scope.data.processCardCount > 0改为蓝色文本#2bf -->
<span
:style="{ 'color': scope.data.processCardCount > 0 ? '#2bf' : '', display: 'flex', alignItems: 'center' }">
<span style="margin-right: 1px;">[{{ scope.data.processCardCount || 0
}}]</span>
<span
style="text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: inline-block; width: calc(100% - 20px);">{{
scope.data.projectName }}</span>
</span>
</template>
</ProjectTree>
</el-col>
<!-- 右侧发货明细 -->
<el-col :span="18">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>{{ currentProject.projectName || '请选择项目' }}</span>
<span v-if="currentProject.projectCode" style="margin-left: 5px; color: #2bf">[{{ currentProject.projectCode
}}]</span>
<span v-if="currentProject.projectNum" style="margin-left: 5px;">({{ currentProject.projectNum
}})</span>
<div style="float: right;">
<el-button v-if="currentProject.projectId" type="text" @click="getList">刷新</el-button>
<el-button v-if="currentProject.projectId" type="text" @click="handleAdd">新增单据</el-button>
</div>
</div>
<el-empty v-if="!currentProject.projectId" description="请从左侧选择项目" :image-size="200">
<el-button type="primary" @click="handleSelectFirstProject" v-if="projectList.length > 0">
选择第一个项目
</el-button>
</el-empty>
<el-tabs v-else v-model="activeTab" @tab-click="getList">
<el-tab-pane label="单据维度" name="master">
<MasterTable :list="masterList" :loading="loading" @refresh-data="getList" @print="handlePrint" />
</el-tab-pane>
<el-tab-pane label="明细维度" name="detail">
<DetailTable :list="detailList" :loading="loading" :total="total" />
</el-tab-pane>
</el-tabs>
</el-card>
</el-col>
</el-row>
<!-- 新增工艺卡弹窗 -->
<el-drawer :title="title" :visible.sync="open" append-to-body direction="btt" size="90%">
<el-form ref="form" :model="form" label-width="100px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item prop="equipmentName" label="设备名称">
<el-input placeholder="请输入设备名称" v-model="form.equipmentName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="equipmentQuantity" label="设备数量">
<el-input placeholder="请输入设备数量" v-model="form.equipmentQuantity" type="number" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item prop="manufacturingLeader" label="制造负责人">
<el-select filterable allow-create placeholder="请选择或输入制造负责人" v-model="form.manufacturingLeader">
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.nickName">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="operationLeader" label="作业负责人">
<el-select filterable allow-create placeholder="请选择或输入作业负责人" v-model="form.operationLeader">
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.nickName">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item prop="plannedDeliveryDate" label="计划交货日期">
<el-date-picker v-model="form.plannedDeliveryDate" type="date" placeholder="请选择计划交货日期"
style="width: 100%;" value-format="yyyy-MM-DD HH:mm:ss" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item prop="remark" label="备注">
<el-input type="textarea" placeholder="请输入备注" v-model="form.remark" />
</el-form-item>
</el-col>
</el-row>
<el-divider>工艺卡明细</el-divider>
<div>
<div style="margin-bottom: 10px">
<el-button @click="addRow" type="primary">添加明细</el-button>
</div>
<el-table :data="form.oaProcessCardDetailList" style="width: 100%" border stripe v-loading="loading">
<el-table-column label="序号" width="80">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.sequence" placeholder="请输入序号"></input>
</template>
</el-table-column>
<el-table-column label="工序名称">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.processName" placeholder="请输入工序名称"></input>
</template>
</el-table-column>
<el-table-column label="工序详情">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.processDetail" placeholder="请输入工序详情"></input>
</template>
</el-table-column>
<el-table-column label="作业责任人">
<template slot-scope="scope">
<el-select filterable allow-create placeholder="请选择或输入作业责任人" v-model="scope.row.workResponsiblePerson">
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.nickName">
</el-option>
</el-select>
</template>
</el-table-column>
<el-table-column label="工序开始时间">
<template slot-scope="scope">
<el-date-picker v-model="scope.row.processStartTime" type="datetime" placeholder="请选择开始时间"
style="width: 100%;" value-format="yyyy-MM-dd HH:mm:ss" />
</template>
</el-table-column>
<el-table-column label="工序结束时间">
<template slot-scope="scope">
<el-date-picker v-model="scope.row.processEndTime" type="datetime" placeholder="请选择结束时间"
style="width: 100%;" value-format="yyyy-MM-dd HH:mm:ss" />
</template>
</el-table-column>
<el-table-column label="质检员">
<template slot-scope="scope">
<el-select filterable allow-create placeholder="请选择或输入质检员" v-model="scope.row.inspector">
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.nickName">
</el-option>
</el-select>
</template>
</el-table-column>
<el-table-column label="不合格内容">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.unqualifiedContent" placeholder="请输入不合格内容"></input>
</template>
</el-table-column>
<el-table-column label="备注">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.remark" placeholder="请输入备注"></input>
</template>
</el-table-column>
<el-table-column label="操作" width="60">
<template slot-scope="scope">
<el-button type="danger" size="mini" @click="removeRow(scope.$index)">-</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-form>
<div style="display: flex; justify-content: flex-end;">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-drawer>
<!-- 打印组件 -->
<el-dialog title="打印工艺卡" :visible.sync="printVisible" width="95%" append-to-body>
<Printer :waybill="printData" :waybillDetails="printDetails" />
</el-dialog>
</div>
</template>
<script>
import { listUser } from "@/api/system/user";
import ProjectTree from '@/components/fad-service/ProjectList';
import DetailTable from './components/DetailTable';
import MasterTable from './components/MasterTable';
import Printer from './components/Printer';
import { insertProcessCard, listProcessCard, listProjectWithCount } from "@/api/oa/workshop/processCard";
import { listProcessCardDetailByProjectId } from "@/api/oa/workshop/processCardDetail";
export default {
name: "ProjectOutWarehouse",
components: {
ProjectTree,
MasterTable,
DetailTable,
Printer
},
mounted () {
this.getAllUser()
this.getProjectList()
},
data () {
return {
// 用户列表
userList: [],
// 当前选中的项目
currentProject: {},
// 项目列表
projectList: [],
// 发货列表
outWareHouseList: [],
// 新增弹窗
open: false,
// 打印弹窗
printVisible: false,
// 打印数据
printData: {},
// 打印明细
printDetails: [],
// 标题
title: "",
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 总条数
total: 0,
// 库存数据
oaWarehouseList: [],
// 选中的行
selectedRows: [],
// 当前激活的tab
activeTab: 'master',
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 9999,
projectId: undefined,
type: 0
},
// 表单参数
form: {
projectId: '',
oaProcessCardDetailList: []
},
detailList: [],
masterList: [],
};
},
methods: {
getAllUser () {
listUser({ pageNum: 1, pageSize: 999 }).then(res => {
this.userList = res.rows
})
},
// 获取项目列表(带工艺卡和发货单据数量)
getProjectList () {
listProjectWithCount({ pageNum: 1, pageSize: 999 }).then(res => {
this.projectList = res.data;
})
},
// 项目选择
handleProjectSelect (data) {
this.currentProject = data;
this.queryParams.projectId = data.projectId;
this.getList();
},
// 获取发货列表
getList () {
if (!this.currentProject.projectId) return;
this.loading = true;
if (this.activeTab === 'master') {
listProcessCard(this.queryParams).then(res => {
this.masterList = res.rows;
this.total = res.total;
this.loading = false;
});
} else {
listProcessCardDetailByProjectId(this.queryParams.projectId).then(res => {
this.detailList = res.data;
this.total = res.total;
this.loading = false;
});
}
},
// 添加新行
addRow () {
this.form.oaProcessCardDetailList.push({
sequence: this.form.oaProcessCardDetailList.length + 1,
processName: '',
processDetail: '',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
processStartTime: undefined,
processEndTime: undefined,
remark: ''
});
},
// 删除选中行
removeRow (index) {
this.form.oaProcessCardDetailList.splice(index, 1);
// 更新序号
this.form.oaProcessCardDetailList.forEach((item, idx) => {
item.sequence = idx + 1;
});
},
// 新增
handleAdd () {
this.reset();
this.open = true;
this.title = "添加工艺卡";
this.form.projectId = this.currentProject.projectId;
},
// 取消
cancel () {
this.open = false;
this.reset();
},
// 重置表单
reset () {
this.form = {
projectId: this.currentProject.projectId,
oaProcessCardDetailList: [
{
sequence: 1,
processName: '图纸设计',
processDetail: '图纸资料是否齐全',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 2,
processName: '钣金安装',
processDetail: '框架的开孔/尺寸是否正确',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 3,
processName: '钣金安装',
processDetail: '安装板尺寸/数量是否正确',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 4,
processName: '钣金安装',
processDetail: '组装配件是否齐全',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 5,
processName: '钣金安装',
processDetail: '涂装是否正确无损伤',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 6,
processName: '钣金安装',
processDetail: '钣金安装是否可靠美观',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 7,
processName: '元件安装',
processDetail: '元件数量/型号安装是否正确',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 8,
processName: '元件安装',
processDetail: '元件外观是否完好',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 9,
processName: '元件安装',
processDetail: '元件固定是否可靠',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 10,
processName: '元件安装',
processDetail: '元件说明书是否齐全',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 11,
processName: '元件安装',
processDetail: '元件标记是否齐全',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 12,
processName: '母排制作',
processDetail: '母排型号规格是否正确',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 13,
processName: '母排制作',
processDetail: '母排支架是否结实可靠',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 14,
processName: '母排制作',
processDetail: '母排制作安装是否符合标准',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 15,
processName: '母排制作',
processDetail: '母排连接是否结实',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 16,
processName: '配线电缆',
processDetail: '线/电缆型号是否正确',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 17,
processName: '配线电缆',
processDetail: '配线是否符合标准,互相不干扰',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 18,
processName: '配线电缆',
processDetail: '线/缆是否固定可靠',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 19,
processName: '配线电缆',
processDetail: '末端处理是否良好',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
},
{
sequence: 20,
processName: '配线电缆',
processDetail: '终端连接是否紧固',
workResponsiblePerson: '',
inspector: '',
unqualifiedContent: '',
remark: ''
}
]
};
this.resetForm("form");
},
// 提交表单
submitForm () {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
this.form.oaProcessCardDetailList.forEach((item, index) => {
item.sequence = index + 1;
});
insertProcessCard(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
});
},
// 选择第一个项目
handleSelectFirstProject () {
if (this.projectList.length > 0) {
console.log(this.projectList[0], '选择第一个项目');
this.handleProjectSelect(this.projectList[0]);
}
},
// 处理打印
handlePrint (data) {
this.printData = data.waybill;
this.printDetails = data.waybillDetails;
this.printVisible = true;
},
}
};
</script>
<style scoped>
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
.project-info {
margin-left: 10px;
}
/* 修改滚动条样式 */
:deep(.el-card__body) {
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* IE and Edge */
}
:deep(.el-card__body::-webkit-scrollbar) {
display: none;
/* Chrome, Safari, Opera */
}
/* 修改表格滚动条样式 */
:deep(.el-table__body-wrapper) {
scrollbar-width: none;
-ms-overflow-style: none;
}
:deep(.el-table__body-wrapper::-webkit-scrollbar) {
display: none;
}
/* 添加box-card滚动条样式 */
.box-card {
height: calc(100vh - 120px);
overflow-y: auto;
}
.table-input {
width: 100%;
border: none;
outline: none;
background-color: transparent;
color: #000;
}
</style>

View File

@@ -0,0 +1,445 @@
<template>
<div class="workshop-report-container">
<!-- 筛选区域 -->
<div class="filter-bar">
<el-form :inline="true" :model="queryParams" class="demo-form-inline">
<el-form-item label="时间范围:">
<el-date-picker v-model="dateRange" type="daterange" range-separator="至" start-placeholder="开始日期"
end-placeholder="结束日期" format="yyyy-MM-dd" value-format="yyyy-MM-dd"
@change="handleDateChange"></el-date-picker>
</el-form-item>
</el-form>
</div>
<!-- 数据概览卡片 -->
<el-row :gutter="20" class="summary-card-row">
<el-col :span="4">
<el-card class="summary-card">
<div class="card-title">涉及项目数</div>
<div class="card-value">{{ summary.involvedProjectCount || 0 }}</div>
</el-card>
</el-col>
<el-col :span="4">
<el-card class="summary-card">
<div class="card-title">工艺卡总数</div>
<div class="card-value">{{ summary.processCardCount || 0 }}</div>
</el-card>
</el-col>
<el-col :span="4">
<el-card class="summary-card">
<div class="card-title">工艺步骤总数</div>
<div class="card-value">{{ summary.processCardDetailCount || 0 }}</div>
</el-card>
</el-col>
<el-col :span="4">
<el-card class="summary-card">
<div class="card-title">总工时</div>
<div class="card-value">{{ summary.totalWorkHours || 0 }}h</div>
</el-card>
</el-col>
<el-col :span="4">
<el-card class="summary-card">
<div class="card-title">平均工时</div>
<div class="card-value">{{ summary.avgWorkHours || 0 }}h</div>
</el-card>
</el-col>
<el-col :span="4">
<el-card class="summary-card">
<div class="card-title">设备种类数</div>
<div class="card-value">{{ summary.equipmentKinds || 0 }}</div>
</el-card>
</el-col>
</el-row>
<!-- 图表统计区域 -->
<el-row :gutter="20" class="chart-row">
<!-- 按项目统计工艺卡数量 -->
<el-col :span="8">
<el-card class="chart-card">
<div slot="header" class="clearfix">
<span>按项目统计工艺卡数量</span>
</div>
<div id="projectProcessCardChart" class="chart-container"></div>
</el-card>
</el-col>
<!-- 按作业责任人统计工艺步骤数量 -->
<el-col :span="8">
<el-card class="chart-card">
<div slot="header" class="clearfix">
<span>按作业责任人统计工艺步骤数量</span>
</div>
<div id="responsPersonStepChart" class="chart-container"></div>
</el-card>
</el-col>
<!-- 按作业负责人统计工艺卡数量 -->
<el-col :span="8">
<el-card class="chart-card">
<div slot="header" class="clearfix">
<span>按作业负责人统计工艺卡数量</span>
</div>
<div id="responsPersonCardChart" class="chart-container"></div>
</el-card>
</el-col>
</el-row>
<!-- 工艺卡列表 -->
<el-card class="table-card" style="margin-top: 20px;">
<div slot="header" class="clearfix">
<span>工艺卡列表</span>
</div>
<el-table :data="processCardList" border stripe style="width: 100%;" v-loading="loading">
<el-table-column prop="projectName" label="项目名称" min-width="200"></el-table-column>
<el-table-column prop="projectNum" label="项目编号"></el-table-column>
<el-table-column prop="equipmentName" label="设备名称"></el-table-column>
<el-table-column prop="equipmentQuantity" label="设备数量"></el-table-column>
<el-table-column prop="manufacturingLeader" label="生产负责人"></el-table-column>
<el-table-column prop="operationLeader" label="作业负责人"></el-table-column>
<el-table-column prop="plannedDeliveryDate" label="计划交付日期">
<template slot-scope="scope">
{{ scope.row.plannedDeliveryDate ? scope.row.plannedDeliveryDate.split(' ')[0] : '-' }}
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 工艺卡详情列表 -->
<el-card class="table-card" style="margin-top: 20px;">
<div slot="header" class="clearfix">
<span>工艺卡详情列表</span>
</div>
<el-table :data="processCardDetailList" border stripe style="width: 100%;" v-loading="loading">
<el-table-column prop="processName" label="工序名称"></el-table-column>
<el-table-column prop="processDetail" label="工序详情" min-width="200"></el-table-column>
<el-table-column prop="workResponsiblePerson" label="作业责任人">
<template slot-scope="scope">
{{ scope.row.workResponsiblePerson || '未指定' }}
</template>
</el-table-column>
<el-table-column prop="sequence" label="工序序号"></el-table-column>
<el-table-column prop="processStartTime" label="工序开始时间">
<template slot-scope="scope">
{{ scope.row.processStartTime ? scope.row.processStartTime.split(' ')[0] : '-' }}
</template>
</el-table-column>
<el-table-column prop="processEndTime" label="工序结束时间">
<template slot-scope="scope">
{{ scope.row.processEndTime ? scope.row.processEndTime.split(' ')[0] : '-' }}
</template>
</el-table-column>
<el-table-column prop="inspector" label="检验员">
<template slot-scope="scope">
{{ scope.row.inspector || '-' }}
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
import { listProcessCard } from "@/api/oa/workshop/processCard";
import { listProcessCardDetail } from "@/api/oa/workshop/processCardDetail";
import { getSummary } from "@/api/oa/workshop/workshopReport";
import * as echarts from 'echarts';
export default {
name: "WorkshopReport",
data () {
return {
// 查询参数
queryParams: {
startTime: "",
endTime: ""
},
// 时间范围选择器绑定值
dateRange: [],
// 加载状态
loading: false,
// 汇总数据
summary: {},
// 工艺卡列表
processCardList: [],
// 工艺卡详情列表
processCardDetailList: [],
// echarts实例
projectChart: null,
personStepChart: null,
personCardChart: null
};
},
watch: {
queryParams: {
handler (newVal, oldVal) {
if (newVal.startTime && newVal.endTime) {
this.fetchAllData();
}
},
deep: true,
immediate: true
}
},
mounted () {
// 初始化当月时间范围
this.initDate();
// 初始化图表
this.initCharts();
},
beforeDestroy () {
// 销毁echarts实例
if (this.projectChart) this.projectChart.dispose();
if (this.personStepChart) this.personStepChart.dispose();
if (this.personCardChart) this.personCardChart.dispose();
},
methods: {
// 初始化当月时间范围
initDate () {
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth();
// 当月第一天
const firstDay = new Date(year, month, 1);
// 当月最后一天
const lastDay = new Date(year, month + 1, 0);
// 格式化日期为YYYY-MM-DD
const formatDate = (date) => {
return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
};
const start = formatDate(firstDay);
const end = formatDate(lastDay);
this.dateRange = [start, end];
this.queryParams.startTime = start;
this.queryParams.endTime = end;
},
// 时间范围改变处理
handleDateChange (val) {
if (val && val.length === 2) {
this.queryParams.startTime = val[0];
this.queryParams.endTime = val[1];
}
},
// 获取所有数据
fetchAllData () {
this.loading = true;
// 并发请求所有接口
Promise.all([
this.getSummary(),
this.getProcessCard(),
this.getProcessCardDetail()
]).then(() => {
// 更新图表数据
this.updateCharts();
this.loading = false;
}).catch(() => {
this.loading = false;
this.$message.error('数据加载失败');
});
},
// 获取汇总数据
getSummary () {
return new Promise((resolve, reject) => {
getSummary(this.queryParams)
.then((res) => {
if (res.code === 200 && res.data) {
this.summary = res.data;
}
resolve();
})
.catch((err) => {
reject(err);
});
});
},
// 获取工艺卡列表
getProcessCard () {
return new Promise((resolve, reject) => {
listProcessCard(this.queryParams)
.then((res) => {
if (res.code === 200 && res.rows) {
this.processCardList = res.rows;
}
resolve();
})
.catch((err) => {
reject(err);
});
});
},
// 获取工艺卡详情列表
getProcessCardDetail () {
return new Promise((resolve, reject) => {
listProcessCardDetail(this.queryParams)
.then((res) => {
if (res.code === 200 && res.rows) {
this.processCardDetailList = res.rows;
}
resolve();
})
.catch((err) => {
reject(err);
});
});
},
// 初始化图表
initCharts () {
// 按项目统计工艺卡图表
this.projectChart = echarts.init(document.getElementById('projectProcessCardChart'));
// 按作业责任人统计工艺步骤图表
this.personStepChart = echarts.init(document.getElementById('responsPersonStepChart'));
// 按作业负责人统计工艺卡图表
this.personCardChart = echarts.init(document.getElementById('responsPersonCardChart'));
// 初始化默认配置
this.projectChart.setOption({
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: [], axisLabel: { rotate: 30 } },
yAxis: { type: 'value', name: '工艺卡数量' },
series: [{ type: 'bar', data: [], name: '工艺卡数' }]
});
this.personStepChart.setOption({
tooltip: { trigger: 'item' },
series: [{ type: 'pie', radius: ['40%', '70%'], data: [] }]
});
this.personCardChart.setOption({
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: [], axisLabel: { rotate: 30 } },
yAxis: { type: 'value', name: '工艺卡数量' },
series: [{ type: 'bar', data: [], name: '工艺卡数' }]
});
// 监听窗口大小变化,自适应图表
window.addEventListener('resize', () => {
this.projectChart.resize();
this.personStepChart.resize();
this.personCardChart.resize();
});
},
// 更新图表数据
updateCharts () {
// 1. 按项目统计工艺卡数量
const projectCardData = this.statProjectCard();
this.projectChart.setOption({
xAxis: { data: projectCardData.labels },
series: [{ data: projectCardData.values }]
});
// 2. 按作业责任人统计工艺步骤数量
const personStepData = this.statPersonStep();
this.personStepChart.setOption({
series: [{ data: personStepData }]
});
// 3. 按作业负责人统计工艺卡数量
const personCardData = this.statPersonCard();
this.personCardChart.setOption({
xAxis: { data: personCardData.labels },
series: [{ data: personCardData.values }]
});
},
// 统计:按项目统计工艺卡数量
statProjectCard () {
const result = {};
this.processCardList.forEach(item => {
const projectName = item.projectName || '未知项目';
result[projectName] = (result[projectName] || 0) + 1;
});
return {
labels: Object.keys(result),
values: Object.values(result)
};
},
// 统计:按作业责任人统计工艺步骤数量
statPersonStep () {
const result = {};
this.processCardDetailList.forEach(item => {
const person = item.workResponsiblePerson || '未指定责任人';
result[person] = (result[person] || 0) + 1;
});
return Object.entries(result).map(([name, value]) => ({
name,
value
}));
},
// 统计:按作业负责人统计工艺卡数量
statPersonCard () {
const result = {};
this.processCardList.forEach(item => {
const person = item.operationLeader || '未指定负责人';
result[person] = (result[person] || 0) + 1;
});
return {
labels: Object.keys(result),
values: Object.values(result)
};
}
}
};
</script>
<style scoped>
.workshop-report-container {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
.filter-bar {
margin-bottom: 20px;
padding: 10px;
background: #fff;
border-radius: 4px;
}
.summary-card-row {
margin-bottom: 20px;
}
.summary-card {
text-align: center;
height: 120px;
display: flex;
flex-direction: column;
justify-content: center;
}
.summary-card .card-title {
font-size: 14px;
color: #666;
margin-bottom: 10px;
}
.summary-card .card-value {
font-size: 24px;
font-weight: bold;
color: #1989fa;
}
.chart-row {
margin-bottom: 20px;
}
.chart-card {
height: 350px;
}
.chart-container {
width: 100%;
height: 300px;
}
.table-card {
background: #fff;
}
/* 适配小屏幕 */
@media (max-width: 1200px) {
.el-col-8 {
width: 100%;
margin-bottom: 20px;
}
}
</style>

View File

@@ -0,0 +1,59 @@
<template>
<div>
<!-- <el-button type="primary" size="mini" style="margin-bottom: 10px" :disabled="selected.length === 0"
@click="handleExport">导出选中</el-button> -->
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="设备名称" prop="equipmentName" />
<el-table-column label="型号规格" prop="modelSpec" />
<el-table-column label="数量" width="60" prop="quantity" />
<el-table-column label="单位" width="60" prop="unit" />
<el-table-column label="包装类型" width="100" prop="packagingType" />
<el-table-column label="净重(kg)" width="80" prop="netWeight" />
<el-table-column label="毛重(kg)" width="80" prop="grossWeight" />
<el-table-column label="体积(m³)" width="80" prop="volume" />
<el-table-column label="箱尺寸(mm,长*宽*高)" width="150" prop="boxSize" />
<el-table-column label="备注" prop="detailRemark" />
</el-table>
</div>
</template>
<script>
export default {
name: 'DetailTable',
props: {
list: {
type: Array,
default: () => []
},
loading: {
type: Boolean,
default: false
},
total: {
type: Number,
default: 0
}
},
data () {
return {
queryParams: {
pageNum: 1,
pageSize: 999
},
selected: []
}
},
methods: {
handleSelectionChange (val) {
this.selected = val;
},
handleExport () {
this.$emit('export-detail', this.selected);
},
handlePagination (val) {
this.$emit('pagination', val);
}
}
}
</script>

View File

@@ -0,0 +1,410 @@
<template>
<div>
<el-table v-loading="loading" :data="list">
<el-table-column label="项目" align="center" prop="projectName" show-overflow-tooltip />
<el-table-column label="供应商" align="center" prop="supplierFullname" show-overflow-tooltip />
<el-table-column label="送货单号" align="center" prop="deliveryOrderNo" />
<el-table-column label="送货地址" align="center" prop="deliveryAddress" />
<el-table-column label="送达目的地" align="center" prop="deliveryDestination" />
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<el-select v-model="scope.row.status" placeholder="请选择状态" @change="handleStatusChange(scope.row)">
<el-option label="已完成" :value="0" />
<el-option label="未完成" :value="1" />
</el-select>
</template>
</el-table-column>
<el-table-column label="附件">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-upload" @click="handleUpload(scope.row)">上传({{
scope.row.accessory ? scope.row.accessory.split(',').length : 0 }})</el-button>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button v-loading="buttonLoading" size="mini" type="text" icon="el-icon-search"
@click="handleShowDetail(scope.row)">查看详情</el-button>
<el-button v-loading="buttonLoading" size="mini" type="text" icon="el-icon-printer"
@click="handlePrint(scope.row)">打印</el-button>
<el-button v-loading="buttonLoading" size="mini" type="text" icon="el-icon-delete"
@click="handleDelete(scope.row)">删除</el-button>
<!-- <el-button size="mini" type="text" icon="el-icon-download"
@click="$emit('export-detail', scope.row)">导出</el-button> -->
</template>
</el-table-column>
</el-table>
<!-- 详情弹窗 -->
<el-dialog title="出库物料详情" :visible.sync="detail" width="95%" append-to-body v-loading="formLoading">
<!-- 主表详情 -->
<el-form ref="detailForm" :model="detailData" label-width="100px" style="margin-bottom: 20px;">
<el-form-item prop="deliveryOrderNo" label="编号">
<el-input v-model="detailData.deliveryOrderNo" placeholder="请输入送货单号" />
</el-form-item>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item prop="contractNo" label="合同号">
<el-input v-model="detailData.contractNo" placeholder="请输入合同号" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="userContractNo" label="用户合同号">
<el-input v-model="detailData.userContractNo" placeholder="请输入用户合同号" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="procurementNo" label="采购订单号">
<el-input v-model="detailData.procurementNo" placeholder="请输入采购订单号" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item prop="deliveryDestination" label="送货目的地">
<el-input v-model="detailData.deliveryDestination" placeholder="请输入送货目的地" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="deliveryAddress" label="送货地址">
<el-input v-model="detailData.deliveryAddress" placeholder="请输入送货地址" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item prop="receiver" label="接收人">
<el-input v-model="detailData.receiver" placeholder="请输入接收人" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="receiverPhone" label="接收人手机号">
<el-input v-model="detailData.receiverPhone" placeholder="请输入接收人手机号" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="supplierFullname" label="供应商名称">
<el-input v-model="detailData.supplierFullname" placeholder="请输入供应商名称" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item prop="supplierContact" label="供应商联系人">
<el-input v-model="detailData.supplierContact" placeholder="请输入供应商联系人" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="supplierPhone" label="供应商手机号">
<el-input v-model="detailData.supplierPhone" placeholder="请输入供应商手机号" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="receivingCompany" label="收货单位">
<el-input v-model="detailData.receivingCompany" placeholder="请输入收货单位" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item prop="actualReceiver" label="实际接收人">
<el-input v-model="detailData.actualReceiver" placeholder="请输入实际接收人" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="constructionCompany" label="施工单位">
<el-input v-model="detailData.constructionCompany" placeholder="请输入施工单位" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="deliveryRemark" label="送货备注">
<el-input v-model="detailData.deliveryRemark" placeholder="请输入送货备注" type="textarea" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 明细列表 -->
<el-divider>物料明细</el-divider>
<div style="margin-bottom: 10px; display: flex; align-items: center;">
<el-button v-loading="buttonLoading" @click="addDetailRow" type="primary" size="mini">添加明细</el-button>
<el-alert title="物料明细的变更会立刻生效,无需手动保存"></el-alert>
</div>
<el-table v-loading="loading" :data="detailData.detailList" border>
<el-table-column label="序号" width="50" type="index" />
<el-table-column label="分箱编号/总箱件数">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.boxNoTotal" placeholder="请输入分箱编号/总箱件数"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="设备工位号">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.equipmentStationNo" placeholder="请输入设备工位号"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="设备名称">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.equipmentName" placeholder="请输入设备名称"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="型号规格">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.modelSpec" placeholder="请输入设备规格"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="数量" width="80">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.quantity" placeholder="请输入数量"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="单位" width="80">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.unit" placeholder="请输入单位"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="包装类型" width="100">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.packagingType" placeholder="请输入包装类型"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="净重(kg)" width="100">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.netWeight" placeholder="请输入净重"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="毛重(kg)" width="100">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.grossWeight" placeholder="请输入毛重"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="体积(m³)" width="100">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.volume" placeholder="请输入体积"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="箱尺寸(mm)" width="150">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.boxSize" placeholder="请输入箱尺寸"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="备注">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.detailRemark" placeholder="请输入备注"
@change="handleDetailChange(scope.row)" size="small" />
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template slot-scope="scope">
<el-button v-loading="buttonLoading" type="danger" size="mini"
@click="removeDetailRow(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div slot="footer" class="dialog-footer">
<el-button @click="detail = false">取消</el-button>
<el-button type="primary" @click="handleSave" v-loading="buttonLoading">保存修改</el-button>
</div>
</el-dialog>
<el-dialog title="附件上传" :visible.sync="fileOpen">
<file-upload v-model="detailData.accessory"></file-upload>
<div slot="footer" class="dialog-footer">
<el-button @click="fileOpen = false">取消</el-button>
<el-button type="primary" @click="handleFileSave" v-loading="buttonLoading">确认</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { delDeliveryOrder, updateDeliveryOrder } from "@/api/oa/workshop/deliveryOrder";
import { addDeliveryOrderDetail, delDeliveryOrderDetail, listDeliveryOrderDetail, updateDeliveryOrderDetail } from "@/api/oa/workshop/deliveryOrderDetail";
export default {
name: 'MasterTable',
props: {
list: {
type: Array,
default: () => []
},
loading: {
type: Boolean,
default: false
},
total: {
type: Number,
default: 0
}
},
data () {
return {
showSearch: true,
detail: false,
detailData: {
detailList: []
},
queryParams: {
pageNum: 1,
pageSize: 999,
signTime: undefined
},
// 表单验证规则
rules: {
deliveryOrderNo: [{ required: true, message: '请输入送货单号', trigger: 'blur' }],
deliveryDestination: [{ required: true, message: '请输入送货目的地', trigger: 'blur' }],
deliveryAddress: [{ required: true, message: '请输入送货地址', trigger: 'blur' }],
supplierFullname: [{ required: true, message: '请输入供应商名称', trigger: 'blur' }]
},
buttonLoading: false,
formLoading: false,
fileOpen: false,
}
},
methods: {
handleShowDetail (row) {
// 调用list接口查询详情
this.formLoading = true;
this.detail = true;
listDeliveryOrderDetail({ orderId: row.orderId, pageSize: 999 }).then(response => {
this.detailData = { ...row, detailList: response.rows || [] };
}).finally(() => {
this.formLoading = false;
});
},
// 添加明细行
addDetailRow () {
this.buttonLoading = true;
addDeliveryOrderDetail({
sequence: this.detailData.detailList.length + 1,
orderId: this.detailData.orderId,
boxNoTotal: '',
equipmentStationNo: '',
equipmentName: '',
modelSpec: '',
quantity: 1,
unit: '',
packagingType: '',
netWeight: 0,
grossWeight: 0,
volume: 0,
boxSize: '',
detailRemark: ''
}).then(response => {
listDeliveryOrderDetail({ orderId: this.detailData.orderId, pageSize: 999 }).then(response => {
this.detailData.detailList = response.rows || [];
this.$message.success("添加成功");
});
}).finally(() => {
this.buttonLoading = false;
});
},
// 删除明细行
removeDetailRow (row) {
this.buttonLoading = true;
delDeliveryOrderDetail(row.detailId).then(response => {
listDeliveryOrderDetail({ orderId: this.detailData.orderId, pageSize: 999 }).then(response => {
this.detailData.detailList = response.rows || [];
this.$message.success("删除成功");
});
}).finally(() => {
this.buttonLoading = false;
});
},
// 明细行数据改变时触发
handleDetailChange (row) {
updateDeliveryOrderDetail(row)
},
// 保存修改
handleSave () {
this.$refs.detailForm.validate(valid => {
if (valid) {
this.loading = true;
updateDeliveryOrder(this.detailData).then(response => {
this.$message.success("更新成功");
this.detail = false;
this.fileOpen = false;
// 刷新父组件数据
this.$emit('refresh-data');
}).finally(() => {
this.loading = false;
});
}
});
},
handleStatusChange (row) {
this.buttonLoading = true;
updateDeliveryOrder(row).then(response => {
this.$message.success("更新成功");
// 刷新父组件数据
// this.$emit('refresh-data');
}).finally(() => {
this.buttonLoading = false;
});
},
handleUpload (row) {
this.detailData = row;
this.fileOpen = true;
},
handleFileSave () {
updateDeliveryOrder(this.detailData).then(response => {
this.$message.success("更新成功");
this.detail = false;
this.fileOpen = false;
// 刷新父组件数据
this.$emit('refresh-data');
}).finally(() => {
this.buttonLoading = false;
});
},
handleDelete (row) {
this.$modal.confirm('确认删除该送货单吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.buttonLoading = true;
delDeliveryOrder(row.orderId).then(response => {
this.$message.success("删除成功");
this.detail = false;
// 刷新父组件数据
this.$emit('refresh-data');
}).finally(() => {
this.buttonLoading = false;
});
});
},
// 处理打印
handlePrint (row) {
this.buttonLoading = true;
// 获取发货单据明细
listDeliveryOrderDetail({ orderId: row.orderId, pageSize: 999 }).then(response => {
// 通过事件将数据传递给父组件
this.$emit('print', {
waybill: row,
waybillDetails: response.rows || []
});
}).finally(() => {
this.buttonLoading = false;
});
}
}
}
</script>

View File

@@ -0,0 +1,731 @@
<!-- 收货单组件 -->
<template>
<div>
<div class="waybill-container" ref="waybillRef">
<!-- 头部信息 -->
<div class="waybill-title">
<h2>发货单据</h2>
</div>
<div class="waybill-header">
<div class="header-left" style="width: 33%">
<span class="label">编号</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.deliveryOrderNo" />
</div>
<div class="header-center" style="width: 33%">
<span class="label">合同号</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.contractNo" />
</div>
<div class="header-right" style="width: 33%">
<span class="label">用户合同号</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.userContractNo" />
</div>
</div>
<div class="waybill-header">
<div class="header-left" style="width: 33%">
<span class="label">采购订单号</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.procurementNo" />
</div>
<div class="header-center" style="width: 33%">
<span class="label">送货目的地</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.deliveryDestination" />
</div>
<div class="header-right" style="width: 33%">
<span class="label">送货地址</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.deliveryAddress" />
</div>
</div>
<div class="waybill-header">
<div class="header-left" style="width: 33%">
<span class="label">接收人</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.receiver" />
</div>
<div class="header-center" style="width: 33%">
<span class="label">接收人手机号</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.receiverPhone" />
</div>
<div class="header-right" style="width: 33%">
<span class="label">供应商名称</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.supplierFullname" />
</div>
</div>
<div class="waybill-header">
<div class="header-left" style="width: 33%">
<span class="label">供应商联系人</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.supplierContact" />
</div>
<div class="header-center" style="width: 33%">
<span class="label">供应商手机号</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.supplierPhone" />
</div>
<div class="header-right" style="width: 33%">
<span class="label">收货单位</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.receivingCompany" />
</div>
</div>
<div class="waybill-header">
<div class="header-left" style="width: 33%">
<span class="label">实际接收人</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.actualReceiver" />
</div>
<div class="header-center" style="width: 33%">
<span class="label">施工单位</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.constructionCompany" />
</div>
<div class="header-right" style="width: 33%">
<span class="label">创建人</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.createBy" />
</div>
</div>
<div class="waybill-header">
<div class="header-left" style="width: 100%">
<span class="label">送货备注</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.deliveryRemark"
style="width: calc(100% - 80px)" />
</div>
</div>
<!-- 表格 -->
<table class="waybill-table" v-loading="loading" loading-text="加载中...">
<thead>
<tr>
<th>序号</th>
<th>分箱编号</th>
<th>工位号</th>
<th>设备名称</th>
<th>型号规格</th>
<th>数量</th>
<th>单位</th>
<th>包装类型</th>
<th>净重(kg)</th>
<th>毛重(kg)</th>
<th>体积()</th>
<th>箱尺寸(mm,**)</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<!-- 无明细提示 -->
<tr v-if="localWaybillDetails.length === 0">
<td colspan="13" class="no-data">
<div class="no-data-content">
<el-empty description="暂无发货单据明细" />
</div>
</td>
</tr>
<!-- 明细数据 -->
<tr v-for="(item, index) in localWaybillDetails" :key="index">
<td>{{ index + 1 }}</td>
<td><input type="text" class="table-input transparent-input" v-model="item.boxNoTotal" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.equipmentStationNo" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.equipmentName" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.modelSpec" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.quantity" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.unit" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.packagingType" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.netWeight" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.grossWeight" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.volume" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.boxSize" />
</td>
<td>
<div class="table-cell-with-action">
<input type="text" class="table-input transparent-input" v-model="item.detailRemark" />
</div>
</td>
</tr>
</tbody>
</table>
<!-- 签名栏 -->
<div class="waybill-footer">
<div class="footer-item inline">
<span class="label">制单</span>
<input type="text" class="editable-input signature-input transparent-input" v-model="localWaybill.createBy" />
</div>
<div class="footer-item inline">
<span class="label">审核</span>
<input type="text" class="editable-input signature-input transparent-input" />
</div>
<div class="footer-item inline">
<span class="label">确认</span>
<input type="text" class="editable-input signature-input transparent-input" />
</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="waybill-actions">
<el-button type="primary" @click="saveAsImage">保存为图片</el-button>
<el-button type="success" @click="printWaybill">打印</el-button>
</div>
</div>
</template>
<script>
import domtoimage from 'dom-to-image';
import printJS from 'print-js';
export default {
props: {
// 组件接收完整的发货单据内容, 渲染发货单据,这个面板内包括一个保存为图片和一个打印按钮
waybill: {
type: Object,
default: () => { }
},
waybillDetails: {
type: Array,
default: () => []
}
},
data () {
return {
// 本地可编辑的发货单据数据
localWaybill: {
deliveryOrderNo: '',
contractNo: '',
userContractNo: '',
procurementNo: '',
deliveryDestination: '',
deliveryAddress: '',
receiver: '',
receiverPhone: '',
supplierFullname: '',
supplierContact: '',
supplierPhone: '',
receivingCompany: '',
actualReceiver: '',
constructionCompany: '',
deliveryRemark: '',
createTime: '',
createBy: ''
},
// 本地可编辑的发货单据明细
localWaybillDetails: [],
loading: false
};
},
watch: {
// 监听props变化更新本地数据
waybill: {
handler (newVal) {
if (newVal) {
this.localWaybill = {
deliveryOrderNo: newVal.deliveryOrderNo || '',
contractNo: newVal.contractNo || '',
userContractNo: newVal.userContractNo || '',
procurementNo: newVal.procurementNo || '',
deliveryDestination: newVal.deliveryDestination || '',
deliveryAddress: newVal.deliveryAddress || '',
receiver: newVal.receiver || '',
receiverPhone: newVal.receiverPhone || '',
supplierFullname: newVal.supplierFullname || '',
supplierContact: newVal.supplierContact || '',
supplierPhone: newVal.supplierPhone || '',
receivingCompany: newVal.receivingCompany || '',
actualReceiver: newVal.actualReceiver || '',
constructionCompany: newVal.constructionCompany || '',
deliveryRemark: newVal.deliveryRemark || '',
createTime: newVal.createTime ? this.formatDate(newVal.createTime) : '',
createBy: newVal.createBy || ''
};
}
},
immediate: true,
deep: true
},
waybillDetails: {
handler (newVal) {
if (newVal && Array.isArray(newVal)) {
this.localWaybillDetails = newVal;
} else {
this.localWaybillDetails = [];
}
},
immediate: true,
deep: true
}
},
methods: {
// 格式化日期
formatDate (dateStr) {
if (dateStr) {
const date = new Date(dateStr);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}`;
}
return '';
},
// 保存为图片
saveAsImage () {
const node = this.$refs.waybillRef;
// 确保容器在保存图片时能完整显示所有内容
const originalWidth = node.style.width;
const originalOverflow = node.style.overflow;
// 临时调整容器样式,确保所有内容可见
node.style.width = 'auto';
node.style.overflow = 'visible';
// 获取实际内容宽度
const contentWidth = node.scrollWidth;
const contentHeight = node.scrollHeight;
domtoimage.toPng(node, {
width: contentWidth,
height: contentHeight,
style: {
width: `${contentWidth}px`,
height: `${contentHeight}px`,
overflow: 'visible'
}
})
.then(dataUrl => {
const link = document.createElement('a');
link.download = `发货单据_${this.waybill.deliveryOrderNo || this.waybill.orderId || Date.now()}.png`;
link.href = dataUrl;
link.click();
})
.catch(error => {
console.error('保存图片失败:', error);
this.$message.error('保存图片失败');
})
.finally(() => {
// 恢复原始样式
node.style.width = originalWidth;
node.style.overflow = originalOverflow;
});
},
// 打印发货单据
printWaybill () {
const node = this.$refs.waybillRef;
// 确保容器在打印时能完整显示所有内容
const originalWidth = node.style.width;
const originalOverflow = node.style.overflow;
// 临时调整容器样式,确保所有内容可见
node.style.width = 'auto';
node.style.overflow = 'visible';
// 获取实际内容宽度
const contentWidth = node.scrollWidth;
printJS({
printable: node,
maxWidth: contentWidth,
type: 'html',
scanStyles: true,
style: `
@page { size: A4 landscape; margin: 1cm; }
.waybill-container { width: 100%; max-width: none; overflow: visible; }
.waybill-table { width: 100%; table-layout: auto; }
`,
targetStyles: ['*']
});
// 恢复原始样式
setTimeout(() => {
node.style.width = originalWidth;
node.style.overflow = originalOverflow;
}, 100);
}
}
}
</script>
<style scoped>
.waybill-container {
width: 1000px;
max-width: none;
min-width: 1000px;
margin: 0 auto;
padding: 20px;
background: white;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
font-family: SimSun, serif;
overflow-x: auto;
overflow-y: visible;
}
/* 标题样式 */
.waybill-title {
text-align: center;
margin-bottom: 20px;
}
.waybill-title h2 {
margin: 0;
font-size: 24px;
font-weight: bold;
color: #333;
}
/* 头部样式 */
.waybill-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
font-size: 16px;
}
.header-left,
.header-right {
display: flex;
align-items: center;
}
.header-center {
display: flex;
align-items: center;
gap: 5px;
}
.label {
font-weight: bold;
display: inline-block;
width: 80px;
text-align: right;
white-space: nowrap;
}
.date-label {
width: 1em;
}
/* 可编辑输入框样式 */
.editable-input {
padding: 4px 8px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 14px;
font-family: SimSun, serif;
outline: none;
transition: all 0.2s;
border-bottom: 1px dashed #dcdfe6;
}
.editable-input:focus {
border-color: #409eff;
}
.date-input {
width: 30px;
text-align: center;
margin-right: 5px;
}
/* 透明输入框样式 */
.transparent-input {
border: none;
border-radius: 0;
background-color: transparent;
}
.transparent-input:focus {
border-bottom-color: #409eff;
background-color: rgba(64, 158, 255, 0.05);
}
/* 表格样式 */
.waybill-table {
width: 100%;
max-width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
font-size: 12px;
table-layout: fixed;
}
.waybill-table th,
.waybill-table td {
border: 1px solid #000;
box-sizing: border-box;
line-height: 24px;
text-align: center;
vertical-align: middle;
word-wrap: break-word;
word-break: break-all;
}
/* 表格列宽设置 */
.waybill-table th:nth-child(1),
.waybill-table td:nth-child(1) {
width: 40px;
/* 序号 */
}
.waybill-table th:nth-child(2),
.waybill-table td:nth-child(2) {
width: 80px;
/* 分箱编号/总箱件数 */
}
.waybill-table th:nth-child(3),
.waybill-table td:nth-child(3) {
width: 40px;
/* 设备工位号 */
}
.waybill-table th:nth-child(4),
.waybill-table td:nth-child(4) {
width: 100px;
/* 设备名称 */
}
.waybill-table th:nth-child(5),
.waybill-table td:nth-child(5) {
width: 100px;
/* 型号规格 */
}
.waybill-table th:nth-child(6),
.waybill-table td:nth-child(6) {
width: 40px;
/* 数量 */
}
.waybill-table th:nth-child(7),
.waybill-table td:nth-child(7) {
width: 40px;
/* 单位 */
}
.waybill-table th:nth-child(8),
.waybill-table td:nth-child(8) {
width: 80px;
/* 包装类型 */
}
.waybill-table th:nth-child(9),
.waybill-table td:nth-child(9) {
width: 60px;
/* 净重(kg) */
}
.waybill-table th:nth-child(10),
.waybill-table td:nth-child(10) {
width: 60px;
/* 毛重(kg) */
}
.waybill-table th:nth-child(11),
.waybill-table td:nth-child(11) {
width: 60px;
/* 体积(m³) */
}
.waybill-table th:nth-child(12),
.waybill-table td:nth-child(12) {
width: 120px;
/* 箱尺寸(mm,长*宽*高) */
}
.waybill-table th:nth-child(13),
.waybill-table td:nth-child(13) {
width: 100px;
/* 备注 */
}
.waybill-table th {
background-color: #f5f7fa;
font-weight: bold;
}
.waybill-table tr:nth-child(even) {
background-color: #fafafa;
}
/* 表格输入框样式 */
.table-input {
box-sizing: border-box;
width: 100%;
height: 100%;
padding: 4px;
}
.table-input:focus {
border-color: #409eff;
}
/* 无数据样式 */
.no-data {
height: 200px;
vertical-align: middle;
}
.no-data-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
/* 表格单元格操作区 */
.table-cell-with-action {
display: flex;
align-items: center;
gap: 5px;
}
/* 备注样式 */
.waybill-remarks {
margin-bottom: 30px;
font-size: 14px;
line-height: 1.5;
text-align: justify;
}
.waybill-remarks p {
margin: 5px 0;
}
/* 底部签名样式 */
.waybill-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
font-size: 16px;
}
.waybill-pickup-location {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
font-size: 16px;
}
.waybill-pickup-location label {
font-size: 14px;
margin-right: 10px;
width: 40px;
}
.footer-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
width: 200px;
}
.footer-item.inline {
flex-direction: row;
align-items: center;
width: auto;
}
.footer-item .label {
font-size: 14px;
margin-right: 10px;
width: 40px;
}
.signature-input {
min-width: 150px;
}
.full-input {
/* 占满本行的剩余空间父容器不是flex */
flex: 1;
}
/* 操作按钮样式 */
.waybill-actions {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 30px;
}
/* 添加明细按钮 */
.add-detail-btn {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
/* 打印样式 */
@media print {
.waybill-container {
width: 100%;
max-width: none;
box-shadow: none;
padding: 0;
}
.waybill-header {
flex-wrap: nowrap;
justify-content: space-between;
}
.waybill-footer {
flex-wrap: nowrap;
justify-content: space-between;
}
.label {
width: 80px;
text-align: right;
white-space: nowrap;
}
.waybill-actions {
display: none;
}
}
/* 响应式设计 */
@media (max-width: 768px) {
.waybill-header {
flex-direction: column;
gap: 15px;
align-items: flex-start;
}
.waybill-table {
font-size: 12px;
}
.waybill-table th,
.waybill-table td {
padding: 2px;
}
.waybill-footer {
flex-direction: column;
align-items: flex-start;
gap: 15px;
}
.footer-item.inline {
width: 100%;
}
.label {
width: auto;
text-align: left;
}
}
</style>

View File

@@ -0,0 +1,483 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<!-- 左侧项目列表 -->
<el-col :span="6">
<ProjectTree v-model="currentProject" @select="handleProjectSelect" :list="projectList">
<template slot-scope="scope">
<!-- 如果scope.data.processCardCount > 0改为蓝色文本#2bf -->
<span
:style="{ 'color': scope.data.processCardCount > 0 ? '#2bf' : '', display: 'flex', alignItems: 'center' }">
<span style="margin-right: 1px;">[{{ scope.data.processCardCount || 0
}}]</span>
<span
style="text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: inline-block; width: calc(100% - 20px);">{{
scope.data.projectName }}</span>
</span>
</template>
</ProjectTree>
</el-col>
<!-- 右侧发货明细 -->
<el-col :span="18">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>{{ currentProject.projectName || '请选择项目' }}</span>
<span v-if="currentProject.projectCode" style="margin-left: 5px; color: #2bf">[{{ currentProject.projectCode
}}]</span>
<span v-if="currentProject.projectNum" style="margin-left: 5px;">({{ currentProject.projectNum
}})</span>
<div style="float: right;">
<el-button v-if="currentProject.projectId" type="text" @click="getList">刷新</el-button>
<el-button v-if="currentProject.projectId" type="text" @click="handleAdd">新增单据</el-button>
</div>
</div>
<el-empty v-if="!currentProject.projectId" description="请从左侧选择项目" :image-size="200">
<el-button type="primary" @click="handleSelectFirstProject" v-if="projectList.length > 0">
选择第一个项目
</el-button>
</el-empty>
<el-tabs v-else v-model="activeTab" @tab-click="getList">
<el-tab-pane label="单据维度" name="master">
<MasterTable :list="masterList" :loading="loading" @refresh-data="getList" @print="handlePrint" />
</el-tab-pane>
<el-tab-pane label="明细维度" name="detail">
<DetailTable :list="detailList" :loading="loading" :total="total" />
</el-tab-pane>
</el-tabs>
</el-card>
</el-col>
</el-row>
<!-- 新增发货弹窗 -->
<el-drawer :title="title" :visible.sync="open" append-to-body direction="btt" size="90%">
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item prop="deliveryOrderNo" label="编号">
<el-input placeholder="请输入送货单号" v-model="form.deliveryOrderNo" />
</el-form-item>
<el-row>
<el-col :span="8">
<el-form-item prop="contractNo" label="合同号">
<el-input placeholder="请输入合同号" v-model="form.contractNo" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="userContractNo" label="用户合同号">
<el-input placeholder="请输入用户合同号" v-model="form.userContractNo" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="procurementNo" label="采购订单号">
<el-input placeholder="请输入采购订单号" v-model="form.procurementNo" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item prop="deliveryDestination" label="送货目的地">
<el-input placeholder="请输入送货目的地" v-model="form.deliveryDestination" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="deliveryAddress" label="送货地址">
<el-input placeholder="请输入送货地址" v-model="form.deliveryAddress" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item prop="receiver" label="接收人">
<el-input placeholder="请输入接收人" v-model="form.receiver" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="receiverPhone" label="接收人手机号">
<el-input placeholder="请输入接收人手机号" v-model="form.receiverPhone" />
</el-form-item>
</el-col>
</el-row>
<el-divider>明细</el-divider>
<div>
<div style="margin-bottom: 10px">
<el-button @click="addRow" type="primary">添加</el-button>
</div>
<el-table :data="form.detailList" style="width: 100%" border stripe v-loading="loading">
<el-table-column label="序号" width="50" type="index" />
<el-table-column label="分箱编号/总箱件数">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.boxNoTotal" placeholder="请输入分箱编号/总箱件数"></input>
</template>
</el-table-column>
<el-table-column label="设备工位号">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.equipmentStationNo" placeholder="请输入设备工位号"></input>
</template>
</el-table-column>
<el-table-column label="设备名称">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.equipmentName" placeholder="请输入设备名称"></input>
</template>
</el-table-column>
<el-table-column label="型号规格">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.modelSpec" placeholder="请输入设备规格"></input>
</template>
</el-table-column>
<el-table-column label="数量" width="60">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.quantity" placeholder="请输入数量"></input>
</template>
</el-table-column>
<el-table-column label="单位" width="60">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.unit" placeholder="请输入单位"></input>
</template>
</el-table-column>
<el-table-column label="包装类型" width="100">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.packagingType" placeholder="请输入包装类型"></input>
</template>
</el-table-column>
<el-table-column label="净重(kg)" width="80">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.netWeight" placeholder="请输入净重"></input>
</template>
</el-table-column>
<el-table-column label="毛重(kg)" width="80">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.grossWeight" placeholder="请输入毛重"></input>
</template>
</el-table-column>
<el-table-column label="体积(m³)" width="80">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.volume" placeholder="请输入体积"></input>
</template>
</el-table-column>
<el-table-column label="箱尺寸(mm,长*宽*高)" width="150">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.boxSize" placeholder="请输入箱尺寸"></input>
</template>
</el-table-column>
<el-table-column label="备注">
<template slot-scope="scope">
<input class="table-input" v-model="scope.row.detailRemark" placeholder="请输入备注"></input>
</template>
</el-table-column>
<el-table-column label="操作" width="60">
<template slot-scope="scope">
<el-button type="danger" size="mini" @click="removeRow(scope.$index)">-</el-button>
</template>
</el-table-column>
</el-table>
</div>
<el-row style="margin-top: 10px;">
<el-col :span="8">
<el-form-item prop="supplierFullname" label="供应商名称">
<el-input placeholder="请输入供应商名称" v-model="form.supplierFullname" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="supplierContact" label="供应商联系人">
<el-input placeholder="请输入供应商联系人" v-model="form.supplierContact" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="supplierPhone" label="供应商手机号">
<el-input placeholder="请输入供应商手机号" v-model="form.supplierPhone" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item prop="receivingCompany" label="收货单位">
<el-input placeholder="请输入收货单位" v-model="form.receivingCompany" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="actualReceiver" label="实际接收人">
<el-input placeholder="请输入实际接收人" v-model="form.actualReceiver" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item prop="constructionCompany" label="施工单位">
<el-input placeholder="请输入施工单位" v-model="form.constructionCompany" />
</el-form-item>
</el-col>
</el-row>
<el-form-item prop="deliveryRemark" label="送货备注">
<el-input type="textarea" placeholder="请输入送货备注" v-model="form.deliveryRemark" />
</el-form-item>
</el-form>
<div style="display: flex; justify-content: flex-end;">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-drawer>
<!-- 打印组件 -->
<el-dialog title="打印发货单据" :visible.sync="printVisible" width="95%" append-to-body>
<Printer :waybill="printData" :waybillDetails="printDetails" />
</el-dialog>
</div>
</template>
<script>
import ProjectTree from '@/components/fad-service/ProjectList';
import DetailTable from './components/DetailTable';
import MasterTable from './components/MasterTable';
import Printer from './components/Printer.vue';
import { insertDeliveryOrder, listDeliveryOrder } from "@/api/oa/workshop/deliveryOrder";
import { listDeliveryOrderDetailByProjectId } from "@/api/oa/workshop/deliveryOrderDetail";
import { listProjectWithCount } from "@/api/oa/workshop/processCard";
export default {
name: "ProjectOutWarehouse",
components: {
ProjectTree,
MasterTable,
DetailTable,
Printer
},
data () {
return {
// 当前选中的项目
currentProject: {},
// 项目列表
projectList: [],
// 发货列表
outWareHouseList: [],
// 新增弹窗
open: false,
// 标题
title: "",
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 总条数
total: 0,
// 库存数据
oaWarehouseList: [],
// 选中的行
selectedRows: [],
// 当前激活的tab
activeTab: 'master',
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 9999,
projectId: undefined,
type: 0
},
// 表单参数
form: {
projectId: '',
warehouseList: []
},
detailList: [],
masterList: [],
// 打印相关
printVisible: false,
printData: {},
printDetails: [],
rules: {
deliveryOrderNo: [
{ required: true, message: '请输入送货单号', trigger: 'blur' }
],
}
};
},
methods: {
// 项目选择
handleProjectSelect (data) {
this.currentProject = data;
this.queryParams.projectId = data.projectId;
this.getList();
},
// 获取项目列表
getProjectList () {
listProjectWithCount().then(res => {
this.projectList = res.data;
this.loading = false;
});
},
// 生成编号
// 年-月-日-时-分-秒-毫秒
generateDeliveryOrderNo () {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hour = String(now.getHours()).padStart(2, '0');
const minute = String(now.getMinutes()).padStart(2, '0');
const second = String(now.getSeconds()).padStart(2, '0');
const millisecond = String(now.getMilliseconds()).padStart(3, '0');
return `${year}-${month}-${day}-${hour}-${minute}-${second}-${millisecond}`;
},
// 获取发货列表
getList () {
if (!this.currentProject.projectId) return;
this.loading = true;
if (this.activeTab === 'master') {
listDeliveryOrder(this.queryParams).then(res => {
this.masterList = res.rows;
this.total = res.total;
this.loading = false;
});
} else {
listDeliveryOrderDetailByProjectId(this.queryParams.projectId).then(res => {
this.detailList = res.data;
this.total = res.total;
this.loading = false;
});
}
},
// 添加新行
addRow () {
this.form.detailList.push({
boxNoTotal: '',
equipmentName: '',
equipmentStationNo: '',
modelSpec: '',
quantity: 0,
unit: '',
packagingType: '',
netWeight: 0,
grossWeight: 0,
volume: 0,
boxSize: '',
detailRemark: '',
});
},
// 删除选中行
removeRow (index) {
this.form.detailList.splice(index, 1);
},
// 新增
handleAdd () {
this.reset();
this.open = true;
this.title = "添加发货单据";
this.form.projectId = this.currentProject.projectId;
this.form.deliveryOrderNo = this.generateDeliveryOrderNo();
},
// 取消
cancel () {
this.open = false;
this.reset();
},
// 重置表单
reset () {
this.form = {
projectId: undefined,
deliveryOrderNo: '',
detailList: []
};
this.resetForm("form");
},
// 提交表单
submitForm () {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
this.form.detailList.forEach((item, index) => {
item.sequence = index + 1;
});
insertDeliveryOrder(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
});
},
// 选择第一个项目
handleSelectFirstProject () {
if (this.projectList.length > 0) {
console.log(this.projectList[0], '选择第一个项目');
this.handleProjectSelect(this.projectList[0]);
}
},
// 处理打印
handlePrint (data) {
this.printData = data.waybill;
this.printDetails = data.waybillDetails;
this.printVisible = true;
},
}
};
</script>
<style scoped>
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
.project-info {
margin-left: 10px;
}
/* 修改滚动条样式 */
:deep(.el-card__body) {
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* IE and Edge */
}
:deep(.el-card__body::-webkit-scrollbar) {
display: none;
/* Chrome, Safari, Opera */
}
/* 修改表格滚动条样式 */
:deep(.el-table__body-wrapper) {
scrollbar-width: none;
-ms-overflow-style: none;
}
:deep(.el-table__body-wrapper::-webkit-scrollbar) {
display: none;
}
/* 添加box-card滚动条样式 */
.box-card {
height: calc(100vh - 120px);
overflow-y: auto;
}
.table-input {
width: 100%;
border: none;
outline: none;
background-color: transparent;
color: #000;
}
</style>