Files
FT577-WMS/pda/pages/warehouse/outbound/exception.vue
2026-06-10 10:03:08 +08:00

412 lines
9.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="page-container">
<!-- 任务信息 -->
<view class="task-info" v-if="taskNo">
<text class="task-label">异常任务编号</text>
<text class="task-value">{{ taskNo }}</text>
</view>
<!-- 扫码区域 -->
<view class="scan-section">
<view class="scan-header">
<text class="scan-title">扫描异常物料条码</text>
<view class="scan-btn" @click="startScan">
<uni-icons type="scan" size="18" color="#f5222d"></uni-icons>
<text class="scan-btn-text red">扫码</text>
</view>
</view>
<view class="input-wrap">
<input class="scan-input" v-model="barcode" placeholder="请输入或扫描物料条码"
@confirm="handleBarcode" focus />
</view>
</view>
<!-- 异常信息填写 -->
<view class="form-section">
<text class="form-title">异常信息</text>
<view class="form-item">
<text class="form-label">异常类型</text>
<picker mode="selector" :range="exceptionTypes" range-key="label" @change="onTypeChange">
<view class="picker-value">{{ selectedType ? selectedType.label : '请选择异常类型' }}</view>
</picker>
<uni-icons type="bottom" size="16" color="#ccc"></uni-icons>
</view>
<view class="form-item">
<text class="form-label">处理方式</text>
<picker mode="selector" :range="handleMethods" range-key="label" @change="onMethodChange">
<view class="picker-value">{{ selectedMethod ? selectedMethod.label : '请选择处理方式' }}</view>
</picker>
<uni-icons type="bottom" size="16" color="#ccc"></uni-icons>
</view>
<view class="form-item">
<text class="form-label">异常描述</text>
<input class="form-input" v-model="form.description" placeholder="请描述异常情况" />
</view>
<view class="form-item column">
<text class="form-label">拍照留证</text>
<view class="photo-list">
<view class="photo-item" v-for="(photo, index) in photos" :key="index"
@click="previewPhoto(index)">
<image :src="photo" mode="aspectFill" class="photo-img"></image>
</view>
<view class="photo-add" @click="takePhoto" v-if="photos.length < 3">
<uni-icons type="plusempty" size="28" color="#ccc"></uni-icons>
</view>
</view>
</view>
</view>
<!-- 出库信息(扫码后显示) -->
<view class="form-section" v-if="outboundInfo">
<text class="form-title">出库任务信息</text>
<view class="info-row">
<text class="info-label">物料编码</text>
<text class="info-value">{{ outboundInfo.materialCode }}</text>
</view>
<view class="info-row">
<text class="info-label">物料名称</text>
<text class="info-value">{{ outboundInfo.materialName }}</text>
</view>
<view class="info-row">
<text class="info-label">出库数量</text>
<text class="info-value">{{ outboundInfo.quantity }}</text>
</view>
<view class="info-row">
<text class="info-label">出库口</text>
<text class="info-value">{{ outboundInfo.portName }}</text>
</view>
</view>
<!-- 操作按钮 -->
<view class="btn-section">
<button class="btn btn-danger" @click="submitException">提交异常确认</button>
<button class="btn btn-default" @click="resetForm">重置</button>
</view>
</view>
</template>
<script>
import { getOutboundDetail, submitOutboundException } from '@/api/warehouse/outbound'
export default {
data() {
return {
taskNo: '',
barcode: '',
outboundInfo: null,
photos: [],
exceptionTypes: [
{ value: 'damage', label: '物料损坏' },
{ value: 'missing', label: '物料缺失' },
{ value: 'wrong', label: '物料错误' },
{ value: 'qty_mismatch', label: '数量不符' },
{ value: 'other', label: '其他异常' }
],
handleMethods: [
{ value: 'return', label: '退回入库' },
{ value: 'replace', label: '更换物料' },
{ value: 'skip', label: '跳过本次' },
{ value: 'manual', label: '人工处理' }
],
selectedType: null,
selectedMethod: null,
form: {
description: ''
}
}
},
onLoad(options) {
if (options.taskNo) {
this.taskNo = options.taskNo
}
},
methods: {
startScan() {
var that = this
uni.scanCode({
onlyFromCamera: false,
scanType: ['barCode', 'qrCode'],
success: function(res) {
that.barcode = res.result
that.handleBarcode()
}
})
},
handleBarcode() {
if (!this.barcode) {
this.$modal.msg('请输入物料条码')
return
}
var that = this
var params = { taskNo: this.taskNo, barcode: this.barcode }
getOutboundDetail(params).then(function(res) {
that.outboundInfo = res.data
that.$modal.msgSuccess('出库信息获取成功')
}).catch(function() {
that.outboundInfo = null
})
},
onTypeChange(e) {
this.selectedType = this.exceptionTypes[e.detail.value]
},
onMethodChange(e) {
this.selectedMethod = this.handleMethods[e.detail.value]
},
takePhoto() {
var that = this
uni.chooseImage({
count: 1,
sourceType: ['camera', 'album'],
success: function(res) {
that.photos = that.photos.concat(res.tempFilePaths)
}
})
},
previewPhoto(index) {
uni.previewImage({
current: this.photos[index],
urls: this.photos
})
},
submitException() {
if (!this.barcode) {
this.$modal.msg('请输入物料条码')
return
}
if (!this.selectedType) {
this.$modal.msg('请选择异常类型')
return
}
if (!this.selectedMethod) {
this.$modal.msg('请选择处理方式')
return
}
var data = {
taskNo: this.taskNo,
barcode: this.barcode,
exceptionType: this.selectedType.value,
handleMethod: this.selectedMethod.value,
description: this.form.description
}
var that = this
submitOutboundException(data).then(function() {
that.$modal.msgSuccess('异常确认提交成功')
that.resetForm()
})
},
resetForm() {
this.barcode = ''
this.outboundInfo = null
this.photos = []
this.selectedType = null
this.selectedMethod = null
this.form = {
description: ''
}
}
}
}
</script>
<style lang="scss" scoped>
page {
background-color: #f5f7fa;
min-height: 100%;
}
.page-container {
padding: 24rpx;
}
.task-info {
background: #fff1f0;
border-radius: 12rpx;
padding: 20rpx 24rpx;
margin-bottom: 24rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.task-label {
font-size: 26rpx;
color: #f5222d;
}
.task-value {
font-size: 26rpx;
color: #333;
font-weight: 500;
}
.scan-section {
background: #fff;
border-radius: 16rpx;
padding: 28rpx;
margin-bottom: 24rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
}
.scan-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
}
.scan-title {
font-size: 30rpx;
font-weight: 500;
color: #333;
}
.scan-btn {
display: flex;
align-items: center;
padding: 8rpx 20rpx;
border: 1rpx solid #f5222d;
border-radius: 8rpx;
}
.scan-btn-text {
font-size: 24rpx;
margin-left: 8rpx;
}
.scan-btn-text.red {
color: #f5222d;
}
.input-wrap {
border: 1rpx solid #e8e8e8;
border-radius: 8rpx;
padding: 4rpx;
}
.scan-input {
font-size: 28rpx;
padding: 16rpx;
}
.form-section {
background: #fff;
border-radius: 16rpx;
padding: 28rpx;
margin-bottom: 24rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
}
.form-title {
font-size: 30rpx;
font-weight: 500;
color: #333;
margin-bottom: 24rpx;
padding-bottom: 16rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.form-item {
display: flex;
align-items: center;
padding: 16rpx 0;
}
.form-item.column {
flex-direction: column;
align-items: flex-start;
}
.form-label {
font-size: 28rpx;
color: #666;
width: 160rpx;
flex-shrink: 0;
}
.form-item.column .form-label {
width: auto;
margin-bottom: 16rpx;
}
.form-input {
flex: 1;
font-size: 28rpx;
border: 1rpx solid #e8e8e8;
border-radius: 8rpx;
padding: 16rpx;
}
.picker-value {
flex: 1;
font-size: 28rpx;
color: #333;
padding: 16rpx;
}
.photo-list {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
}
.photo-item {
width: 160rpx;
height: 160rpx;
border-radius: 12rpx;
overflow: hidden;
}
.photo-img {
width: 100%;
height: 100%;
}
.photo-add {
width: 160rpx;
height: 160rpx;
border-radius: 12rpx;
border: 1rpx dashed #d9d9d9;
display: flex;
align-items: center;
justify-content: center;
}
.info-row {
display: flex;
justify-content: space-between;
padding: 16rpx 0;
border-bottom: 1rpx solid #f5f5f5;
}
.info-label {
font-size: 28rpx;
color: #999;
}
.info-value {
font-size: 28rpx;
color: #333;
}
.btn-section {
padding: 24rpx 0;
}
.btn {
font-size: 30rpx;
border-radius: 12rpx;
margin-bottom: 20rpx;
}
.btn-danger {
background: #f5222d;
color: #fff;
}
.btn-default {
background: #fff;
color: #666;
border: 1rpx solid #d9d9d9;
}
</style>