Browse Source

Merge remote-tracking branch 'origin/master'

master
常熟吴彦祖 3 months ago
parent
commit
b052537c7e
  1. 4
      src/api/outsourcing/outsourcing-issue.js
  2. 2
      src/api/outsourcing/outsourcing-return.js
  3. 6
      src/views/modules/outsourcing-issue/index.vue
  4. 52
      src/views/modules/outsourcing-issue/outsourcingDirectIssue.vue
  5. 589
      src/views/modules/outsourcing-issue/outsourcingDirectIssueDetail.vue
  6. 5
      src/views/modules/outsourcing-issue/outsourcingDirectIssueList.vue
  7. 3
      src/views/modules/outsourcing-return/outsourcingReturn.vue
  8. 283
      src/views/modules/outsourcing-return/outsourcingReturnPDAIssueList.vue
  9. 2
      src/views/modules/outsourcing-return/outsourcingReturnPDAList.vue
  10. 3
      src/views/modules/production-return/productionReturnPDAIssueList.vue
  11. 7
      src/views/modules/production-return/productionReturnPickingDetail.vue

4
src/api/outsourcing/outsourcing-issue.js

@ -15,4 +15,6 @@ export const scanOutsourcingMaterialLabel = data => createAPI(`/pda/outsourcing/
export const confirmOutsourcingDirectIssue = data => createAPI(`/pda/outsourcing/issue/confirmOutsourcingDirectIssue`,'post',data)
// 验证委外订单状态
export const validateOutsourcingOrder = data => createAPI(`/pda/outsourcing/issue/validateOutsourcingOrder`,'post',data)
export const validateOutsourcingOrder = data => createAPI(`/pda/outsourcing/issue/validateOutsourcingOrder`,'post',data)
export const printLabelCommon = data => createAPI('/label/setting/printLabelCommon','post',data)

2
src/api/outsourcing/outsourcing-return.js

@ -15,3 +15,5 @@ export const scanMaterialLabelForOutsourcing = data => createAPI(`/pda/outsourci
// 确认委外退料
export const outsourcingReturnUnissueConfirm = data => createAPI(`/pda/outsourcing/return/outsourcingReturnUnissueConfirm`,'post',data)
export const printLabelCommon = data => createAPI('/label/setting/printLabelCommon','post',data)

6
src/views/modules/outsourcing-issue/index.vue

@ -43,7 +43,7 @@ export default {
label: "申请单发料",
iconClass: "picking",
to: "outsourcingPicking",
disabled: true,
disabled: false,
}, */
/* {
icon: "logistics",
@ -67,6 +67,10 @@ export default {
if (btn.disabled) {
this.$message.warning("正在开发中,敬请期待...");
} else {
//
if (btn.to === 'outsourcingDirectIssue') {
sessionStorage.setItem('outsourcingDirectIssue_clearCache', 'true')
}
this.$router.push(btn.to);
}
},

52
src/views/modules/outsourcing-issue/outsourcingDirectIssue.vue

@ -112,6 +112,14 @@ import { getOutsourcingOrderInfo } from '@/api/outsourcing/outsourcing.js'
import moment from 'moment'
export default {
name:'outsourcingDirectIssue',
beforeRouteEnter(to, from, next) {
// index
if (from.name === 'outsource' || from.path === '/outsource') {
sessionStorage.setItem('outsourcingDirectIssue_clearCache', 'true')
}
next()
},
data() {
return {
outsourcingNo: '',
@ -122,6 +130,37 @@ export default {
}
},
methods: {
//
initPage() {
// index
const clearCache = sessionStorage.getItem('outsourcingDirectIssue_clearCache')
if (clearCache === 'true') {
//
this.outsourcingNo = ''
this.orderList = []
this.selectedOrder = null
this.materialList = []
//
sessionStorage.removeItem('outsourcingDirectIssue_clearCache')
sessionStorage.removeItem('outsourcingDirectIssue_shouldRestore')
sessionStorage.removeItem('outsourcingDirectIssue_state_fromList')
//
this.$nextTick(() => {
this.$forceUpdate()
if (this.$refs.orderInput) {
this.$refs.orderInput.focus()
}
})
} else {
//
this.restorePageStateFromList()
this.$nextTick(() => {
if (this.$refs.orderInput) {
this.$refs.orderInput.focus()
}
})
}
},
goBack() {
this.$router.back()
},
@ -238,6 +277,7 @@ export default {
query: {
outsourcingNo: this.selectedOrder.orderNo,
partNo: material.partNo,
partDesc: material.description,
outsourcingInfo:{
requiredQty: material.purchaseQty || 0,
lineNo: material.lineNo,
@ -249,13 +289,11 @@ export default {
},
},
mounted() {
//
this.restorePageStateFromList()
this.$nextTick(() => {
if (this.$refs.orderInput) {
this.$refs.orderInput.focus()
}
})
this.initPage()
},
activated() {
// keepAlive
this.initPage()
},
}
</script>

589
src/views/modules/outsourcing-issue/outsourcingDirectIssueDetail.vue

@ -11,86 +11,153 @@
<!-- 扫描框 -->
<div class="search-container">
<el-input clearable class="compact-input" v-model="scanCode" placeholder="请扫描材料纸质标签" prefix-icon="el-icon-search"
@keyup.enter.native="handleScan" ref="scanInput" />
<div class="mode-switch">
<el-switch class="custom-switch" v-model="isRemoveMode" active-color="#ff4949" inactive-color="#13ce66">
</el-switch>
<span v-if="isRemoveMode" class="switch-text">{{ '移除' }}</span>
<span v-else class="switch-text2">{{ '添加' }}</span>
<div class="search-row">
<el-input clearable class="compact-input" v-model="scanCode" placeholder="请扫描材料纸质标签" prefix-icon="el-icon-search"
@keyup.enter.native="handleScan" ref="scanInput" />
<div class="mode-switch">
<el-switch class="custom-switch" v-model="isRemoveMode" active-color="#ff4949" inactive-color="#13ce66">
</el-switch>
<span v-if="isRemoveMode" class="switch-text">{{ '移除' }}</span>
<span v-else class="switch-text2">{{ '添加' }}</span>
</div>
</div>
<div class="print-checkbox">
<el-checkbox v-model="isPrint">是否打印</el-checkbox>
</div>
</div>
<!-- 订单及物料信息 -->
<div class="work-order-list" v-if="outsourcingNo && componentPartNo">
<div class="work-order-card">
<div class="card-title">
<span class="title-label">委外订单号{{ outsourcingNo }}</span>
</div>
<div class="part-desc-row">
<span class="desc-text">料号{{ componentPartNo }}</span>
</div>
<div class="part-desc-row">
<span class="desc-text">料名{{ componentPartDesc }}</span>
</div>
<!-- 可滚动区域仅保留一个滚动条 -->
<div class="scroll-area">
<!-- 订单及物料信息 -->
<div class="work-order-list" v-if="outsourcingNo && componentPartNo">
<div class="work-order-card">
<div class="card-title">
<span class="title-label">委外订单号{{ outsourcingNo }}</span>
</div>
<div class="card-details">
<div class="detail-item">
<div class="detail-label">需求数量</div>
<div class="detail-value">{{ requiredQty }}</div>
<div class="part-desc-row">
<span class="desc-text">料号{{ componentPartNo }}</span>
</div>
<div class="detail-item">
<div class="detail-label">已发数量</div>
<div class="detail-value">{{ issuedQty }}</div>
<div class="part-desc-row">
<span class="desc-text">料名{{ componentPartDesc }}</span>
</div>
<div class="detail-item">
<div class="detail-label">本次</div>
<div class="detail-value">{{ totalScannedQty }}</div>
<div class="card-details">
<div class="detail-item">
<div class="detail-label">需求数量</div>
<div class="detail-value">{{ requiredQty }}</div>
</div>
<div class="detail-item">
<div class="detail-label">已发数量</div>
<div class="detail-value">{{ issuedQty }}</div>
</div>
<div class="detail-item">
<div class="detail-label">本次</div>
<div class="detail-value">{{ totalScannedQty }}</div>
</div>
</div>
</div>
</div>
</div>
<div class="section-title">
<div class="title-left">
<i class="el-icon-circle-check"></i>
<span>发料信息确认</span>
</div>
</div>
<!-- 标签列表 -->
<div class="label-list">
<div class="list-header">
<div class="col-no">NO.</div>
<div class="col-label">标签条码</div>
<div class="col-batch">库位</div>
<div class="col-batch">批次号</div>
<div class="col-qty">数量</div>
<div class="section-title">
<div class="title-left">
<i class="el-icon-circle-check"></i>
<span>发料信息确认</span>
</div>
</div>
<div v-for="(label, index) in scannedLabels" :key="label.id" class="list-item">
<div class="col-no">{{ index+1 }}</div>
<div class="col-label">{{ label.labelCode }}</div>
<div class="col-batch">{{label.locationId}}</div>
<div class="col-batch">{{ label.batchNo || '-' }}</div>
<div class="col-qty">{{ label.quantity }}</div>
</div>
<!-- 标签列表 - 卡片形式对齐客户发料样式 -->
<div class="label-card-container">
<div v-for="(label, index) in scannedLabels" :key="label.id" class="label-card"
@click="handleLabelClick(label, index)">
<div class="card-content">
<div class="card-row">
<span class="card-label">标签号</span>
<span class="card-value">{{ label.labelCode }}</span>
<i class="el-icon-edit edit-icon"></i>
</div>
<div class="card-row">
<span class="card-label">物料号</span>
<span class="card-value">{{ label.componentPartNo || '-' }}</span>
</div>
<div class="card-row">
<span class="card-label">批次号</span>
<span class="card-value">{{ label.batchNo || '-' }}</span>
</div>
<div class="card-row">
<span class="card-label">库位</span>
<span class="card-value">{{ label.locationId || '-' }}</span>
</div>
<div class="card-row">
<span class="card-label">剩余高度</span>
<span class="card-value">{{ label.height || '-' }}</span>
</div>
<div class="card-row">
<span class="card-label">发料数量</span>
<span class="card-value highlight">{{ label.quantity }}</span>
</div>
</div>
</div>
<div v-if="scannedLabels.length === 0" class="empty-labels">
<p>暂无扫描标签</p>
<div v-if="scannedLabels.length === 0" class="empty-labels">
<p>暂无扫描标签</p>
</div>
</div>
</div>
<!-- 底部操作按钮 -->
<div class="bottom-actions">
<el-button class="action-btn secondary" :loading="loading" @click="confirmIssue" :disabled="scannedLabels.length === 0">
<el-button class="action-btn secondary" :loading="loading" @click="confirmIssue"
:disabled="scannedLabels.length === 0">
确定
</el-button>
<button class="action-btn secondary" style="margin-left: 10px;" @click="clearScannedLabels">
取消
</button>
</div>
<!-- 修改数量弹框 -->
<div v-if="quantityDialogVisible" class="edit-overlay" @click.self="quantityDialogVisible = false">
<div class="edit-modal">
<div class="modal-header">
<span class="modal-title">修改数量</span>
<i class="el-icon-close close-btn" @click="quantityDialogVisible = false"></i>
</div>
<div class="modal-body">
<div class="form-group">
<label class="form-label">标签条码</label>
<el-input v-model="currentEditLabel.labelCode" disabled class="form-input" />
</div>
<div class="form-group">
<label class="form-label">物料号</label>
<el-input v-model="currentEditLabel.componentPartNo" disabled class="form-input" />
</div>
<div class="form-group">
<label class="form-label">批次号</label>
<el-input v-model="currentEditLabel.batchNo" disabled class="form-input" />
</div>
<div class="form-group">
<label class="form-label">剩余高度(mm)</label>
<el-input-number v-model="editHeight" :min="0" :precision="3" :step="0.001" class="form-input"
style="width: 100%;" :controls="false" />
</div>
<div class="form-group">
<label class="form-label">需要发料数量<span class="required">*</span></label>
<el-input-number v-model="editQuantity" :min="0.0001" :precision="4" :step="0.0001" class="form-input"
style="width: 100%;" :controls="false" />
</div>
</div>
<div class="modal-footer">
<button class="btn-cancel" @click="quantityDialogVisible = false">取消</button>
<button class="btn-confirm" @click="confirmQuantityChange">确定</button>
</div>
</div>
</div>
</div>
</template>
@ -100,6 +167,7 @@ import moment from 'moment'
import {
scanOutsourcingMaterialLabel,
confirmOutsourcingDirectIssue,
printLabelCommon,
} from '@/api/outsourcing/outsourcing-issue'
export default {
@ -107,6 +175,7 @@ export default {
return {
scanCode: '',
isRemoveMode: false,
isPrint: true,
scannedLabels: [],
outsourcingNo: '',
componentPartNo: '',
@ -115,9 +184,15 @@ export default {
issuedQty: 0,
itemNo: '',
loading: false,
partNo:'',
releaseNo:'',
lineNo:''
partNo: '',
releaseNo: '',
lineNo: '',
batchNo: '',
quantityDialogVisible: false,
currentEditLabel: {},
currentEditIndex: -1,
editQuantity: 0,
editHeight: 0,
}
},
computed: {
@ -168,6 +243,7 @@ export default {
warehouseId: data.labelInfo.warehouseId,
locationId: data.labelInfo.locationId,
wdrNo: data.labelInfo.wdrNo,
height: data.labelInfo.height,
engChgLevel: data.labelInfo.engChgLevel || '1',
})
this.$message.success('扫描成功')
@ -180,7 +256,9 @@ export default {
})
},
removeLabelByCode(labelCode) {
const index = this.scannedLabels.findIndex((item) => item.labelCode === labelCode)
const index = this.scannedLabels.findIndex(
(item) => item.labelCode === labelCode
)
if (index !== -1) {
this.scannedLabels.splice(index, 1)
this.$message.success('移除成功')
@ -197,13 +275,19 @@ export default {
})
.then(() => {
this.scannedLabels = []
sessionStorage.setItem('outsourcingDirectIssueList_shouldRestore', 'true')
sessionStorage.setItem(
'outsourcingDirectIssueList_shouldRestore',
'true'
)
this.$router.back()
this.$message.success('已清空')
})
.catch(() => {})
} else {
sessionStorage.setItem('outsourcingDirectIssueList_shouldRestore', 'true')
sessionStorage.setItem(
'outsourcingDirectIssueList_shouldRestore',
'true'
)
this.$router.back()
}
},
@ -228,6 +312,7 @@ export default {
warehouseId: l.warehouseId,
locationId: l.locationId,
materialCode: l.componentPartNo,
height: l.height,
wdrNo: l.wdrNo,
engCngLevel: l.engChgLevel || '1',
})),
@ -236,8 +321,23 @@ export default {
confirmOutsourcingDirectIssue(params)
.then(({ data }) => {
if (data && data.code === 0) {
if (this.isPrint && data.unitIds.length > 0) {
let printLabelType
if (
this.componentPartNo &&
this.componentPartNo.startsWith('80')
) {
printLabelType = '库存成品标签'
} else {
printLabelType = 'BIL标签'
}
this.printViaServer(data.unitIds, printLabelType)
}
this.$message.success('委外发料成功')
sessionStorage.setItem('outsourcingDirectIssueList_shouldRestore', 'true')
sessionStorage.setItem(
'outsourcingDirectIssueList_shouldRestore',
'true'
)
this.$router.back()
} else {
this.$message.error(data.msg || '委外发料失败')
@ -245,33 +345,114 @@ export default {
})
.catch(() => {
this.$message.error('委外发料失败')
}).finally(()=>{
})
.finally(() => {
this.loading = false
})
},
async printViaServer(unitIds, printLabelType) {
if (!unitIds || unitIds.length === 0) {
console.warn('没有可打印的标签')
return
}
this.printLoading = true
try {
const printRequest = {
userId: localStorage.getItem('userName'),
username: localStorage.getItem('userName'),
site: localStorage.getItem('site'),
unitIds: unitIds,
labelType: printLabelType,
}
console.log('打印请求:', printRequest)
const { data } = await printLabelCommon(printRequest)
if (data.code === 200 || data.code === 0) {
this.$message.success(`打印任务已发送!`)
this.clearData()
} else {
this.$message.error(data.msg || '打印失败')
}
} catch (error) {
console.error('服务器打印失败:', error)
this.$message.error(`打印失败: ${error.message || error}`)
} finally {
this.printLoading = false
}
},
handleLabelClick(label, index) {
this.currentEditLabel = { ...label }
this.currentEditIndex = index
this.editHeight = label.height || 0
this.editQuantity = Number(label.quantity) || 0
this.quantityDialogVisible = true
},
confirmQuantityChange() {
if (this.editHeight == null ||this.editHeight === '') {
this.$message.warning('高度必填!')
return
}
if (this.editQuantity == null || this.editQuantity === '') {
this.$message.warning('数量必填!')
return
}
if (this.editHeight < 0) {
this.$message.warning('高度不能小于0')
return
}
if (this.editQuantity <= 0) {
this.$message.warning('数量必须大于0')
return
}
if (
this.currentEditIndex >= 0 &&
this.currentEditIndex < this.scannedLabels.length
) {
this.$set(
this.scannedLabels[this.currentEditIndex],
'quantity',
this.editQuantity
)
this.$set(
this.scannedLabels[this.currentEditIndex],
'height',
this.editHeight
)
this.$message.success('数量修改成功')
this.quantityDialogVisible = false
}
},
initFromRoute() {
this.outsourcingNo = this.$route.query.outsourcingNo
this.partNo = this.$route.query.partNo
//
const issueRecord = this.$route.query.issueRecord
if (issueRecord) {
this.componentPartNo = issueRecord.componentPartNo
this.componentPartDesc = issueRecord.componentPartDescription || ''
this.requiredQty = Number(issueRecord.requiredQty || this.$route.query.requiredQty || 0)
this.requiredQty = Number(
issueRecord.requiredQty || this.$route.query.requiredQty || 0
)
this.issuedQty = Number(issueRecord.issuedQty || 0)
this.releaseNo = issueRecord.releaseNo
this.lineNo = issueRecord.lineNo
this.itemNo = issueRecord.lineItemNo
this.batchNo = issueRecord.batchNo
} else {
//
this.componentPartNo = issueRecord.componentPartNo
this.componentPartDesc = this.$route.query.componentPartDescription || ''
this.componentPartDesc =
this.$route.query.componentPartDescription || ''
this.requiredQty = Number(this.$route.query.requiredQty || 0)
this.issuedQty = Number(this.$route.query.issuedQty || 0)
this.releaseNo = this.$route.query.releaseNo
this.lineNo = this.$route.query.lineNo
this.itemNo = this.$route.query.lineItemNo
this.releaseNo = this.$route.query.releaseNo
this.lineNo = this.$route.query.lineNo
this.itemNo = this.$route.query.lineItemNo
this.batchNo = this.$route.query.batchNo
}
},
},
@ -293,6 +474,7 @@ export default {
display: flex;
flex-direction: column;
background: #f5f5f5;
overflow: hidden;
}
.header-bar {
display: flex;
@ -323,6 +505,11 @@ export default {
.search-container {
padding: 12px 16px;
background: white;
display: flex;
flex-direction: column;
gap: 12px;
}
.search-row {
display: flex;
align-items: center;
gap: 12px;
@ -393,14 +580,25 @@ export default {
width: 60px;
height: 28px;
}
.work-order-list {
.print-checkbox {
display: flex;
align-items: center;
}
.print-checkbox ::v-deep .el-checkbox__label {
font-size: 14px;
color: #606266;
}
.scroll-area {
flex: 1;
overflow-y: auto;
min-height: 0;
}
.work-order-list {
padding: 12px 16px;
}
.work-order-card {
background: white;
border-radius: 8px;
margin-bottom: 12px;
padding: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
cursor: pointer;
@ -442,7 +640,7 @@ export default {
margin: 0 10px;
margin-top: 4px;
border-radius: 8px 8px 0 0;
border-bottom: 2px solid #17B3A3;
border-bottom: 2px solid #17b3a3;
}
.part-desc-row {
margin-bottom: 12px;
@ -479,51 +677,198 @@ export default {
line-height: 1.2;
margin-left: -12px;
}
.label-list {
.label-card-container {
padding: 0 8px 8px;
background: #f5f5f5;
}
.label-card {
background: white;
margin: 0 10px 12px;
border-radius: 8px;
overflow: hidden;
border-radius: 4px;
margin-bottom: 6px;
padding: 6px 8px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
border: 1px solid #e0e0e0;
cursor: pointer;
transition: all 0.2s ease;
position: relative;
}
.label-card:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12);
border-color: #17b3a3;
}
.list-header {
.label-card:active {
transform: scale(0.98);
}
.card-content {
}
.card-row {
display: flex;
background: #f8f9fa;
padding: 12px 8px;
border-bottom: 1px solid #e0e0e0;
font-size: 12px;
align-items: center;
font-size: 11px;
line-height: 1.5;
margin-bottom: 3px;
}
.card-row:last-child {
margin-bottom: 0;
}
.card-label {
color: #666;
min-width: 65px;
flex-shrink: 0;
font-size: 11px;
}
.card-value {
color: #333;
flex: 1;
word-break: break-all;
font-size: 11px;
}
.card-value.highlight {
color: #17b3a3;
font-weight: 600;
}
.edit-icon {
margin-left: 8px;
color: #17b3a3;
font-size: 14px;
cursor: pointer;
flex-shrink: 0;
}
.edit-icon:hover {
color: #13998c;
}
.edit-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.edit-modal {
background: white;
border-radius: 12px;
width: 100%;
max-width: 400px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
overflow: hidden;
display: flex;
flex-direction: column;
}
.edit-modal .modal-header {
background: #17b3a3;
color: white;
padding: 12px 16px;
display: flex;
justify-content: space-between;
align-items: center;
}
.edit-modal .modal-title {
font-size: 16px;
font-weight: 500;
margin: 0;
}
.list-item {
.edit-modal .close-btn {
font-size: 16px;
cursor: pointer;
color: white;
transition: color 0.2s ease;
padding: 4px;
display: flex;
padding: 12px 8px;
border-bottom: 1px solid #f0f0f0;
font-size: 12px;
align-items: center;
justify-content: center;
}
.edit-modal .close-btn:hover {
color: #e0e0e0;
}
.edit-modal .modal-body {
padding: 20px;
}
.edit-modal .form-group {
margin-bottom: 16px;
}
.edit-modal .form-group:last-child {
margin-bottom: 0;
}
.edit-modal .form-label {
display: block;
font-size: 14px;
color: #333;
align-items: flex-start;
min-height: 40px;
margin-bottom: 6px;
font-weight: 500;
}
.list-item:last-child {
border-bottom: none;
.edit-modal .form-input {
width: 100%;
}
.col-no {
width: 20px;
text-align: center;
.edit-modal .form-input ::v-deep .el-input__inner {
height: 40px;
border: 2px solid #dcdfe6;
border-radius: 6px;
font-size: 14px;
padding: 0 12px;
}
.col-label {
flex: 1.5;
text-align: center;
word-break: break-all;
white-space: normal;
line-height: 1.2;
.edit-modal .form-input ::v-deep .el-input__inner:focus {
border-color: #17b3a3;
outline: none;
}
.col-batch {
flex: 1;
text-align: center;
.edit-modal .form-input ::v-deep .el-input__inner:disabled {
background: #f5f7fa;
color: #c0c4cc;
border-color: #e4e7ed;
}
.col-qty {
width: 60px;
text-align: center;
.edit-modal .form-input ::v-deep .el-input-number {
width: 100%;
}
.edit-modal .form-input ::v-deep .el-input-number .el-input__inner {
height: 40px;
border: 2px solid #dcdfe6;
border-radius: 6px;
font-size: 14px;
padding: 0 12px;
}
.edit-modal .form-input ::v-deep .el-input-number .el-input__inner:focus {
border-color: #17b3a3;
outline: none;
}
.edit-modal .modal-footer {
padding: 16px 20px;
display: flex;
gap: 12px;
justify-content: flex-end;
border-top: 1px solid #f0f0f0;
}
.edit-modal .btn-cancel {
padding: 10px 20px;
border-radius: 6px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
border: 1px solid #dcdfe6;
background: white;
color: #606266;
}
.edit-modal .btn-cancel:hover {
background: #f5f7fa;
border-color: #c0c4cc;
}
.edit-modal .btn-confirm {
padding: 10px 20px;
border-radius: 6px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
border: 1px solid #17b3a3;
background: #17b3a3;
color: white;
}
.edit-modal .btn-confirm:hover {
background: #13998c;
border-color: #13998c;
}
.empty-labels {
padding: 40px 20px;
@ -537,6 +882,9 @@ export default {
background: white;
margin-top: auto;
}
.edit-modal .required {
color: #ff4949;
}
.action-btn {
flex: 1;
padding: 12px;
@ -556,13 +904,30 @@ export default {
transform: scale(0.98);
}
@media (max-width: 360px) {
.header-bar { padding: 8px 12px; }
.search-container { padding: 8px 12px; }
.work-order-list { padding: 8px 12px; }
.work-order-card { padding: 12px; }
.card-details { flex-wrap: wrap; gap: 6px; }
.detail-item { flex: 0 0 48%; margin-bottom: 6px; min-width: 50px; }
.label-list { margin: 0 12px 8px; }
.header-bar {
padding: 8px 12px;
}
.search-container {
padding: 8px 12px;
}
.work-order-list {
padding: 8px 12px;
}
.work-order-card {
padding: 12px;
}
.card-details {
flex-wrap: wrap;
gap: 6px;
}
.detail-item {
flex: 0 0 48%;
margin-bottom: 6px;
min-width: 50px;
}
.label-list {
margin: 0 12px 8px;
}
}
</style>

5
src/views/modules/outsourcing-issue/outsourcingDirectIssueList.vue

@ -4,7 +4,7 @@
<div class="header-bar">
<div class="header-left" @click="handleBack">
<i class="el-icon-arrow-left"></i>
<span>委外直接发料 - 发料记录</span>
<span>委外直接发料 - 物料</span>
</div>
<div class="header-right" @click="$router.push({ path: '/' })">首页</div>
</div>
@ -371,9 +371,6 @@ export default {
.search-container {
padding: 8px 12px;
}
.work-order-list {
padding: 8px 12px;
}
.material-card {
padding: 12px;
}

3
src/views/modules/outsourcing-return/outsourcingReturn.vue

@ -273,6 +273,7 @@ export default {
query: {
orderNo: item.orderNo,
partNo: item.componentPartNo,
partDesc: item.componentPartDescription,
unissureQty: returnableQty,
itemNo: {
lineNo: item.lineNo,
@ -532,7 +533,7 @@ export default {
}
.work-order-list {
padding: 8px 12px;
padding: 1px 1px;
}
.card-details {

283
src/views/modules/outsourcing-return/outsourcingReturnPDAIssueList.vue

@ -19,65 +19,68 @@
<span v-if="isRemoveMode" class="switch-text">{{ "移除" }}</span>
<span v-else class="switch-text2">{{ "添加" }}</span>
</div>
<el-button class="new-label-btn" @click="openNewLabelDialog">新标签</el-button>
</div>
<!-- 订单信息卡片对齐直接发料明细样式 -->
<div class="work-order-list" v-if="orderNo">
<div class="work-order-card">
<div class="card-title">
<span class="title-label">{{
orderInfo.type === "outsourcingOrder" ? "委外单号" : "退料申请单号"
}}{{ orderInfo.orderNo }}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;批次号{{ batchNo }}</span>
</div>
<!-- 关联信息单独一行 -->
<div class="part-desc-row">
<span class="desc-text">{{ orderInfo.type === "outsourcingOrder" ? "关联单号" : "关联委外订单" }}{{
orderInfo.transactionId
}}</span>
</div>
<div class="part-desc-row">
<span class="desc-text">{{ orderInfo.partNo }}</span>
</div>
<div class="part-desc-row">
<span class="desc-text">{{ orderInfo.description }}</span>
</div>
<div class="scrollable-content">
<!-- 订单信息卡片对齐直接发料明细样式 -->
<div class="work-order-list" v-if="orderNo">
<div class="work-order-card">
<div class="card-title">
<span class="title-label">{{
orderInfo.type === "outsourcingOrder" ? "委外单号" : "退料申请单号"
}}{{ orderInfo.orderNo }}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;批次号{{ batchNo }}</span>
</div>
<div class="card-details">
<div class="detail-item">
<div class="detail-label">可退数量</div>
<div class="detail-value">{{ unissureQty }}</div>
<!-- 关联信息单独一行 -->
<div class="part-desc-row">
<span class="desc-text">{{ orderInfo.type === "outsourcingOrder" ? "关联单号" : "关联委外订单" }}{{
orderInfo.transactionId
}}</span>
</div>
<div class="detail-item">
<div class="detail-label">发料数量</div>
<div class="detail-value">{{ orderInfo.quantity }}</div>
<div class="part-desc-row">
<span class="desc-text">{{ orderInfo.partNo }}</span>
</div>
<div class="detail-item">
<div class="detail-label">本次</div>
<div class="detail-value">{{ totalScannedQty }}</div>
<div class="part-desc-row">
<span class="desc-text">{{ orderInfo.description }}</span>
</div>
<div class="card-details">
<div class="detail-item">
<div class="detail-label">可退数量</div>
<div class="detail-value">{{ unissureQty }}</div>
</div>
<div class="detail-item">
<div class="detail-label">发料数量</div>
<div class="detail-value">{{ orderInfo.quantity }}</div>
</div>
<div class="detail-item">
<div class="detail-label">本次</div>
<div class="detail-value">{{ totalScannedQty }}</div>
</div>
</div>
</div>
</div>
</div>
<!-- 退料信息确认标题 -->
<div class="section-title">
<div class="title-left">
<i class="el-icon-circle-check"></i>
<span>退料信息确认</span>
<!-- 退料信息确认标题 -->
<div class="section-title">
<div class="title-left">
<i class="el-icon-circle-check"></i>
<span>退料信息确认</span>
</div>
<!-- <div class="title-right">
<span class="material-list-link" @click="showMaterialListDialog">物料清单</span>
</div> -->
</div>
<!-- <div class="title-right">
<span class="material-list-link" @click="showMaterialListDialog">物料清单</span>
</div> -->
</div>
<!-- 退料标签列表 -->
<div class="label-list">
<!-- 退料标签列表 -->
<div class="label-list">
<div class="list-header">
<div class="col-no">NO.</div>
<div class="col-label">物料标签</div>
<!-- <div class="col-batch">批次号</div> -->
<div class="col-part">库位</div>
<div class="col-qty">高度</div>
<div class="col-qty">退料数量</div>
</div>
@ -86,6 +89,7 @@
<div class="col-label">{{ label.labelCode }}</div>
<!-- <div class="col-batch">{{ label.batchNo }}</div> -->
<div class="col-part">{{ label.locationId }}</div>
<div class="col-qty">{{ label.quantity }}</div>
<div class="col-qty" @click="openEditDialog(label, index)">
<span class="quantity-display">{{ label.quantity }}</span>
<i class="el-icon-edit edit-icon"></i>
@ -97,6 +101,7 @@
<p>暂无扫描标签</p>
</div>
</div>
</div>
<!-- 底部操作按钮 -->
<div class="bottom-actions">
@ -183,7 +188,11 @@
<label class="form-label">库位 <span class="required">*</span></label>
<el-input v-model="editForm.locationId" placeholder="请输入库位" class="form-input" />
</div>
<div class="form-group">
<label class="form-label">高度(mm) <span class="required">*</span></label>
<el-input-number v-model="editForm.height" :min="0" :controls="false" placeholder="请输入高度"
class="form-input" style="width: 100%;" />
</div>
<div class="form-group">
<label class="form-label">退料数量 <span class="required">*</span></label>
<el-input v-model="editForm.quantity" type="number" :min="0" placeholder="请输入退料数量" class="form-input" />
@ -196,6 +205,46 @@
</div>
</div>
</div>
<!-- 新标签弹框 -->
<div v-if="showNewLabelDialog" class="edit-overlay">
<div class="edit-modal">
<div class="modal-header">
<span class="modal-title">新标签</span>
<i class="el-icon-close close-btn" @click="closeNewLabelDialog"></i>
</div>
<div class="modal-body">
<div class="form-group">
<label class="form-label">物料编号</label>
<el-input v-model="newLabelForm.partNo" disabled class="form-input" />
</div>
<div class="form-group">
<label class="form-label">WDR</label>
<el-input v-model="newLabelForm.wdrNo" placeholder="请输入WDR" class="form-input" disabled/>
</div>
<div class="form-group">
<label class="form-label">库位 <span class="required">*</span></label>
<el-input v-model="newLabelForm.locationId" placeholder="请输入库位" class="form-input" />
</div>
<div class="form-group">
<label class="form-label">高度(mm) <span class="required">*</span></label>
<el-input-number v-model="newLabelForm.height" :min="0" :controls="false" placeholder="请输入高度"
class="form-input" style="width: 100%;" />
</div>
<div class="form-group">
<label class="form-label">退料数量 <span class="required">*</span></label>
<el-input-number v-model="newLabelForm.quantity" :min="0" :controls="false" placeholder="请输入数量"
class="form-input" style="width: 100%;" />
</div>
</div>
<div class="modal-footer">
<button class="btn-cancel" @click="closeNewLabelDialog">取消</button>
<button class="btn-confirm" @click="confirmNewLabel">确认</button>
</div>
</div>
</div>
</div>
</template>
@ -204,6 +253,7 @@ import {
getInventoryPartForOutsourcing,
scanMaterialLabelForOutsourcing,
outsourcingReturnUnissueConfirm,
printLabelCommon
} from '@/api/outsourcing/outsourcing-return'
import moment from 'moment'
@ -238,6 +288,15 @@ export default {
unissureQty: 0, //
itemNo: {}, // ID
loading: false, //
//
showNewLabelDialog: false,
newLabelForm: {
partNo: '',
partDesc: '',
wdrNo: '',
locationId: '',
quantity: 0,
},
}
},
computed: {
@ -337,6 +396,7 @@ export default {
labelCode: label.labelCode,
batchNo: label.batchNo,
locationId: label.locationId || '',
height: label.height || 0,
quantity: label.quantity,
}
this.editIndex = index
@ -355,6 +415,59 @@ export default {
this.editIndex = -1
},
//
openNewLabelDialog() {
this.newLabelForm = {
partNo: this.partNo,
partDesc: this.orderInfo.description || '',
wdrNo: '*',
locationId: '',
quantity: 0,
}
this.showNewLabelDialog = true
},
//
closeNewLabelDialog() {
this.showNewLabelDialog = false
this.newLabelForm = {
partNo: '',
partDesc: '',
wdrNo: '',
locationId: '',
quantity: 0,
}
},
//
confirmNewLabel() {
if (!this.newLabelForm.locationId || !this.newLabelForm.locationId.trim()) {
this.$message.warning('请输入库位')
return
}
if (!this.newLabelForm.quantity || this.newLabelForm.quantity <= 0) {
this.$message.warning('请输入有效的数量')
return
}
const labelCode = `NEW-${Date.now()}`
this.labelList.push({
id: Date.now(),
labelCode,
partNo: this.newLabelForm.partNo.trim(),
quantity: Number(this.newLabelForm.quantity),
batchNo: this.batchNo || '',
locationId: this.newLabelForm.locationId || '',
warehouseId: '',
wdrNo: this.newLabelForm.wdrNo || '*',
engChgLevel: '1',
height: Number(this.newLabelForm.height) || 0,
newPrint: 'NEW',
})
this.$message.success('添加成功')
this.closeNewLabelDialog()
},
//
confirmEdit() {
//
@ -371,6 +484,7 @@ export default {
//
if (this.editIndex >= 0 && this.editIndex < this.labelList.length) {
this.labelList[this.editIndex].locationId = this.editForm.locationId
this.labelList[this.editIndex].height = Number(this.editForm.height)
this.labelList[this.editIndex].quantity = Number(this.editForm.quantity)
this.$message.success('修改成功')
}
@ -415,8 +529,9 @@ export default {
locationId: label.locationId,
warehouseId: label.warehouseId,
wdrNo: label.wdrNo || '*',
height: label.height || 0,
engCngLevel: label.engChgLevel || '1',
itemNo: index+1
newPrint: label.newPrint || ''
})),
}
@ -424,11 +539,23 @@ export default {
outsourcingReturnUnissueConfirm(returnParams)
.then(({ data }) => {
if (data.code === 0 && data) {
if ( data.unitIds && data.unitIds.length > 0) {
let printLabelType
if (
this.orderInfo.partNo &&
this.orderInfo.partNo.startsWith('80')
) {
printLabelType = '库存成品标签'
} else {
printLabelType = 'BIL标签'
}
this.printViaServer(data.unitIds, printLabelType)
}
this.$message.success('委外退料成功')
sessionStorage.setItem('outsourcingReturnPDAList_shouldRestore', 'true')
this.$router.back()
} else {
this.$message.error(data.message || '操作失败')
this.$message.error(data.msg|| '操作失败')
}
})
.catch(() => {
@ -438,6 +565,39 @@ export default {
this.loading = false
})
},
async printViaServer(unitIds, printLabelType) {
if (!unitIds || unitIds.length === 0) {
console.warn('没有可打印的标签')
return
}
this.printLoading = true
try {
const printRequest = {
userId: localStorage.getItem('userName'),
username: localStorage.getItem('userName'),
site: localStorage.getItem('site'),
unitIds: unitIds,
labelType: printLabelType,
}
console.log('打印请求:', printRequest)
const { data } = await printLabelCommon(printRequest)
if (data.code === 200 || data.code === 0) {
this.$message.success(`打印任务已发送!`)
this.clearData()
} else {
this.$message.error(data.msg || '打印失败')
}
} catch (error) {
console.error('服务器打印失败:', error)
this.$message.error(`打印失败: ${error.message || error}`)
} finally {
this.printLoading = false
}
},
// 退
cancelReturn() {
@ -632,6 +792,7 @@ export default {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.search-container .el-input {
@ -639,6 +800,26 @@ export default {
margin-right: 12px;
}
.new-label-btn {
border: 1px solid #17b3a3;
background: #17b3a3;
color: white;
border-radius: 6px;
padding: 8px 16px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s ease;
}
.new-label-btn:hover {
background: #13998c;
border-color: #13998c;
}
.new-label-btn:active {
transform: scale(0.98);
}
/* 紧凑型输入框样式 */
.compact-input ::v-deep .el-input__inner {
height: 36px;
@ -803,10 +984,16 @@ export default {
border-bottom: 2px solid #17b3a3;
}
/* 可滚动内容容器 */
.scrollable-content {
flex: 1;
overflow-y: auto;
min-height: 0;
}
/* 对齐直接领料明细的工单卡片样式 */
/* 工单列表容器背景与间距 */
.work-order-list {
overflow-y: auto;
padding: 10px 10px;
}
@ -884,8 +1071,6 @@ export default {
margin: 0 10px 12px;
border-radius: 0 0 8px 8px;
overflow: hidden;
max-height: 300px;
overflow-y: auto;
}
.list-header {

2
src/views/modules/outsourcing-return/outsourcingReturnPDAList.vue

@ -201,7 +201,7 @@ export default {
.header-left i { margin-right: 8px; font-size: 18px; }
.header-right { cursor: pointer; font-size: 16px; font-weight: 500; }
.content-area { flex: 1; overflow-y: auto; }
.work-order-list { overflow-y: auto; padding: 12px 16px; }
.work-order-list { overflow-y: auto; }
.material-card { background: white; border-radius: 8px; margin-bottom: 12px; padding: 16px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); cursor: pointer; transition: all 0.2s ease; border: 2px solid transparent; }
.material-card:hover { box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); transform: translateY(-1px); }
.material-card:active { transform: translateY(0); }

3
src/views/modules/production-return/productionReturnPDAIssueList.vue

@ -395,6 +395,7 @@ import {
scanMaterialLabel,
productionReturnUnissueConfirm,
printLabelInfo,
printLabelCommon,
getMaterialLabelByIssueDetail,
} from '@/api/production/production-return'
import moment from 'moment'
@ -663,7 +664,7 @@ export default {
return
}
if (!this.editForm.quantity || this.editForm.quantity <= 0) {
if (!this.editForm.quantity || this.editForm.quantity < 0) {
this.$message.warning('请输入有效的退料数量')
return
}

7
src/views/modules/production-return/productionReturnPickingDetail.vue

@ -592,8 +592,9 @@ export default {
this.$message.warning('请输入有效的高度')
return
}
if (!this.newLabelForm.quantity || this.newLabelForm.quantity <= 0) {
console.log(!this.newLabelForm.quantity || this.newLabelForm.quantity < 0);
if (!this.newLabelForm.quantity || this.newLabelForm.quantity < 0) {
this.$message.warning('请输入有效的数量')
return
}
@ -628,7 +629,7 @@ export default {
return
}
if (!this.editForm.quantity || this.editForm.quantity <= 0) {
if (!this.editForm.quantity || this.editForm.quantity < 0) {
this.$message.warning('请输入有效的标签数量')
return
}

Loading…
Cancel
Save