12 changed files with 1935 additions and 988 deletions
-
22src/api/production/production-inbound.js
-
9src/api/sales-return/sales-return.js
-
3src/i18n/locales/cn.js
-
3src/i18n/locales/en.js
-
8src/router/index.js
-
305src/views/common/login.vue
-
56src/views/main.vue
-
1450src/views/modules/production-inbound/index.vue
-
394src/views/modules/production-inbound/receive.vue
-
299src/views/modules/sales-return/index.vue
-
241src/views/modules/sales-return/sales-return-inbound.vue
-
133src/views/modules/sales-return/sales-return-scrap.vue
@ -0,0 +1,22 @@ |
|||
import { createAPI } from "@/utils/httpRequest.js"; |
|||
|
|||
// 查询处理单元列表
|
|||
export const getOrderInfo = data => createAPI(`/production/inbound/getOrderInfo`,'post',data) |
|||
// 创建包装箱
|
|||
export const createPackage = data => createAPI(`/production/inbound/createPackage`,'post',data) |
|||
// 打印箱标签
|
|||
export const printPackageLabel = data => createAPI(`/production/inbound/printPackageLabel`,'post',data) |
|||
// 装托盘
|
|||
export const packToPallet = data => createAPI(`/production/inbound/packToPallet`,'post',data) |
|||
// 扫描包装箱获取信息
|
|||
export const scanPackage = data => createAPI(`/production/inbound/scanPackage`,'post',data) |
|||
// 根据包装编码获取包装信息
|
|||
export const getPackageInfo = data => createAPI(`/production/inbound/getPackageInfo`,'post',data) |
|||
// 入库登记
|
|||
export const inboundRegister = data => createAPI(`/production/inbound/inboundRegister`,'post',data) |
|||
// 查询入库记录
|
|||
export const getInboundRecords = data => createAPI(`/production/inbound/getInboundRecords`,'post',data) |
|||
// 生产订单退库
|
|||
export const returnStock = data => createAPI(`/production/inbound/returnStock`,'post',data) |
|||
// 扫描单元获取退库信息
|
|||
export const scanUnitForReturn = data => createAPI(`/production/inbound/scanUnitForReturn`,'post',data) |
|||
@ -0,0 +1,9 @@ |
|||
import { createAPI } from "@/utils/httpRequest.js"; |
|||
|
|||
|
|||
// 获取采购单信息
|
|||
export const processReturn = data => createAPI(`salesreturn/processReturn`,'post',data) |
|||
|
|||
// 接收采购单信息
|
|||
export const getRmaList = data => createAPI(`salesreturn/getRmaList`,'post',data) |
|||
|
|||
1450
src/views/modules/production-inbound/index.vue
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,394 +0,0 @@ |
|||
<template> |
|||
<div class="receive-container"> |
|||
<van-nav-bar title="生产入库" left-arrow @click-left="$router.back()" /> |
|||
|
|||
<!-- 订单信息 --> |
|||
<div class="order-info"> |
|||
<div class="info-header"> |
|||
<div class="order-no">{{ orderInfo.orderNo }}</div> |
|||
<div class="order-status">{{ getStatusText(orderInfo.status) }}</div> |
|||
</div> |
|||
<van-cell-group> |
|||
<van-cell title="产品编码" :value="orderInfo.productCode" /> |
|||
<van-cell title="产品名称" :value="orderInfo.productName" /> |
|||
<van-cell title="计划数量" :value="orderInfo.planQuantity" /> |
|||
<van-cell title="已完工" :value="orderInfo.completedQuantity" /> |
|||
<van-cell title="已入库" :value="orderInfo.inboundQuantity" /> |
|||
</van-cell-group> |
|||
</div> |
|||
|
|||
<!-- 入库明细 --> |
|||
<div class="inbound-section"> |
|||
<div class="section-title">入库明细</div> |
|||
<div class="inbound-item"> |
|||
<div class="product-info"> |
|||
<div class="product-name">{{ orderInfo.productCode }} - {{ orderInfo.productName }}</div> |
|||
<div class="product-spec">规格:{{ orderInfo.specification }}</div> |
|||
<div class="product-quantity"> |
|||
可入库:{{ orderInfo.completedQuantity - orderInfo.inboundQuantity }} |
|||
</div> |
|||
</div> |
|||
<div class="inbound-input"> |
|||
<van-stepper |
|||
v-model="inboundQuantity" |
|||
:min="0" |
|||
:max="orderInfo.completedQuantity - orderInfo.inboundQuantity" |
|||
integer |
|||
/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 质量检验 --> |
|||
<div class="quality-section"> |
|||
<div class="section-title">质量检验</div> |
|||
<van-field |
|||
v-model="qualityInfo.inspector" |
|||
label="检验员" |
|||
placeholder="请输入检验员" |
|||
/> |
|||
<van-field |
|||
v-model="qualityInfo.qualityStatus" |
|||
label="质量状态" |
|||
placeholder="请选择质量状态" |
|||
readonly |
|||
is-link |
|||
@click="showQualityPicker = true" |
|||
/> |
|||
<van-field |
|||
v-model="qualityInfo.qualityRemark" |
|||
label="检验备注" |
|||
type="textarea" |
|||
placeholder="请输入检验备注" |
|||
rows="2" |
|||
/> |
|||
</div> |
|||
|
|||
<!-- 批次信息 --> |
|||
<div class="batch-section"> |
|||
<div class="section-title">批次信息</div> |
|||
<van-field |
|||
v-model="batchInfo.batchNo" |
|||
label="批次号" |
|||
placeholder="系统自动生成" |
|||
disabled |
|||
/> |
|||
<van-field |
|||
v-model="batchInfo.productionDate" |
|||
label="生产日期" |
|||
placeholder="请选择生产日期" |
|||
readonly |
|||
is-link |
|||
@click="showDatePicker = true" |
|||
/> |
|||
<van-field |
|||
v-model="batchInfo.expiryDate" |
|||
label="有效期至" |
|||
placeholder="请选择有效期" |
|||
readonly |
|||
is-link |
|||
@click="showExpiryPicker = true" |
|||
/> |
|||
</div> |
|||
|
|||
<!-- 库位分配 --> |
|||
<div class="location-section"> |
|||
<div class="section-title">库位分配</div> |
|||
<van-field |
|||
v-model="selectedLocation" |
|||
label="入库库位" |
|||
placeholder="请选择或扫描库位" |
|||
readonly |
|||
is-link |
|||
@click="showLocationPicker = true" |
|||
> |
|||
<template #right-icon> |
|||
<van-icon name="scan" @click.stop="handleScanLocation" /> |
|||
</template> |
|||
</van-field> |
|||
</div> |
|||
|
|||
<!-- 备注 --> |
|||
<div class="remark-section"> |
|||
<van-field |
|||
v-model="remark" |
|||
label="备注" |
|||
type="textarea" |
|||
placeholder="请输入入库备注" |
|||
rows="3" |
|||
autosize |
|||
/> |
|||
</div> |
|||
|
|||
<!-- 底部按钮 --> |
|||
<div class="bottom-actions"> |
|||
<van-button |
|||
type="primary" |
|||
block |
|||
:loading="submitting" |
|||
@click="handleSubmit" |
|||
> |
|||
确认入库 |
|||
</van-button> |
|||
</div> |
|||
|
|||
<!-- 选择器 --> |
|||
<van-popup v-model="showQualityPicker" position="bottom"> |
|||
<van-picker |
|||
:columns="qualityColumns" |
|||
@confirm="onQualityConfirm" |
|||
@cancel="showQualityPicker = false" |
|||
/> |
|||
</van-popup> |
|||
|
|||
<van-popup v-model="showDatePicker" position="bottom"> |
|||
<van-datetime-picker |
|||
v-model="productionDate" |
|||
type="date" |
|||
title="选择生产日期" |
|||
@confirm="onDateConfirm" |
|||
@cancel="showDatePicker = false" |
|||
/> |
|||
</van-popup> |
|||
|
|||
<van-popup v-model="showExpiryPicker" position="bottom"> |
|||
<van-datetime-picker |
|||
v-model="expiryDate" |
|||
type="date" |
|||
title="选择有效期" |
|||
@confirm="onExpiryConfirm" |
|||
@cancel="showExpiryPicker = false" |
|||
/> |
|||
</van-popup> |
|||
|
|||
<van-popup v-model="showLocationPicker" position="bottom"> |
|||
<van-picker |
|||
:columns="locationColumns" |
|||
@confirm="onLocationConfirm" |
|||
@cancel="showLocationPicker = false" |
|||
/> |
|||
</van-popup> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'ProductionReceive', |
|||
data() { |
|||
return { |
|||
orderInfo: { |
|||
orderNo: 'MO202401001', |
|||
productCode: 'PROD001', |
|||
productName: '成品A', |
|||
specification: '标准规格', |
|||
planQuantity: 100, |
|||
completedQuantity: 80, |
|||
inboundQuantity: 0, |
|||
status: 0 |
|||
}, |
|||
inboundQuantity: 0, |
|||
qualityInfo: { |
|||
inspector: '', |
|||
qualityStatus: '', |
|||
qualityRemark: '' |
|||
}, |
|||
batchInfo: { |
|||
batchNo: 'BATCH' + Date.now(), |
|||
productionDate: '', |
|||
expiryDate: '' |
|||
}, |
|||
selectedLocation: '', |
|||
remark: '', |
|||
submitting: false, |
|||
showQualityPicker: false, |
|||
showDatePicker: false, |
|||
showExpiryPicker: false, |
|||
showLocationPicker: false, |
|||
productionDate: new Date(), |
|||
expiryDate: new Date(), |
|||
qualityColumns: [ |
|||
'合格', |
|||
'待检', |
|||
'不合格', |
|||
'返工' |
|||
], |
|||
locationColumns: [ |
|||
'FG01-01-01', |
|||
'FG01-01-02', |
|||
'FG01-02-01', |
|||
'FG01-02-02', |
|||
'FG02-01-01' |
|||
] |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.loadOrderData() |
|||
}, |
|||
methods: { |
|||
loadOrderData() { |
|||
const orderNo = this.$route.params.orderNo |
|||
console.log('加载生产订单数据:', orderNo) |
|||
}, |
|||
handleScanLocation() { |
|||
this.$toast('扫描库位功能开发中...') |
|||
}, |
|||
onQualityConfirm(value) { |
|||
this.qualityInfo.qualityStatus = value |
|||
this.showQualityPicker = false |
|||
}, |
|||
onDateConfirm(value) { |
|||
this.batchInfo.productionDate = this.formatDate(value) |
|||
this.showDatePicker = false |
|||
}, |
|||
onExpiryConfirm(value) { |
|||
this.batchInfo.expiryDate = this.formatDate(value) |
|||
this.showExpiryPicker = false |
|||
}, |
|||
onLocationConfirm(value) { |
|||
this.selectedLocation = value |
|||
this.showLocationPicker = false |
|||
}, |
|||
formatDate(date) { |
|||
const year = date.getFullYear() |
|||
const month = String(date.getMonth() + 1).padStart(2, '0') |
|||
const day = String(date.getDate()).padStart(2, '0') |
|||
return `${year}-${month}-${day}` |
|||
}, |
|||
async handleSubmit() { |
|||
// 验证入库数量 |
|||
if (this.inboundQuantity <= 0) { |
|||
this.$toast('请输入入库数量') |
|||
return |
|||
} |
|||
|
|||
// 验证质量状态 |
|||
if (!this.qualityInfo.qualityStatus) { |
|||
this.$toast('请选择质量状态') |
|||
return |
|||
} |
|||
|
|||
// 验证库位 |
|||
if (!this.selectedLocation) { |
|||
this.$toast('请选择入库库位') |
|||
return |
|||
} |
|||
|
|||
this.submitting = true |
|||
|
|||
try { |
|||
await new Promise(resolve => setTimeout(resolve, 2000)) |
|||
|
|||
this.$toast.success('入库成功') |
|||
this.$router.back() |
|||
} catch (error) { |
|||
this.$toast.fail('入库失败') |
|||
} finally { |
|||
this.submitting = false |
|||
} |
|||
}, |
|||
getStatusText(status) { |
|||
const statusMap = { |
|||
0: '待入库', |
|||
1: '部分入库', |
|||
2: '已完成' |
|||
} |
|||
return statusMap[status] || '未知' |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.receive-container { |
|||
min-height: 100vh; |
|||
background-color: #f7f8fa; |
|||
padding-bottom: 80px; |
|||
} |
|||
|
|||
.order-info { |
|||
background: white; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.info-header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 16px; |
|||
border-bottom: 1px solid #ebedf0; |
|||
} |
|||
|
|||
.order-no { |
|||
font-size: 18px; |
|||
font-weight: bold; |
|||
color: #323233; |
|||
} |
|||
|
|||
.order-status { |
|||
padding: 4px 8px; |
|||
border-radius: 4px; |
|||
font-size: 12px; |
|||
color: white; |
|||
background-color: #ff976a; |
|||
} |
|||
|
|||
.inbound-section, |
|||
.quality-section, |
|||
.batch-section, |
|||
.location-section, |
|||
.remark-section { |
|||
background: white; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.section-title { |
|||
padding: 16px; |
|||
font-size: 16px; |
|||
font-weight: bold; |
|||
color: #323233; |
|||
border-bottom: 1px solid #ebedf0; |
|||
} |
|||
|
|||
.inbound-item { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 16px; |
|||
} |
|||
|
|||
.product-info { |
|||
flex: 1; |
|||
} |
|||
|
|||
.product-name { |
|||
font-size: 16px; |
|||
font-weight: bold; |
|||
color: #323233; |
|||
margin-bottom: 4px; |
|||
} |
|||
|
|||
.product-spec { |
|||
font-size: 12px; |
|||
color: #969799; |
|||
margin-bottom: 4px; |
|||
} |
|||
|
|||
.product-quantity { |
|||
font-size: 14px; |
|||
color: #646566; |
|||
} |
|||
|
|||
.inbound-input { |
|||
margin-left: 16px; |
|||
} |
|||
|
|||
.bottom-actions { |
|||
position: fixed; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
padding: 16px; |
|||
background: white; |
|||
border-top: 1px solid #ebedf0; |
|||
} |
|||
</style> |
|||
@ -1,266 +1,119 @@ |
|||
<template> |
|||
<div class="sales-return-container"> |
|||
<van-nav-bar title="销售退货" left-arrow @click-left="$router.back()" /> |
|||
|
|||
<!-- 搜索栏 --> |
|||
<div class="search-section"> |
|||
<van-search |
|||
v-model="searchValue" |
|||
placeholder="请输入退货单号" |
|||
@search="handleSearch" |
|||
@clear="handleClear" |
|||
/> |
|||
<div class="pda-container"> |
|||
<!-- 状态栏 --> |
|||
<div class="status-bar"> |
|||
<div class="goBack" @click="$router.back()"><i class="el-icon-arrow-left"></i>上一页</div> |
|||
<div class="time">销售退货</div> |
|||
<div class="network" style="color: #fff" @click="$router.push({path: '/'})">🏠首页</div> |
|||
</div> |
|||
|
|||
<!-- 状态筛选 --> |
|||
<div class="filter-section"> |
|||
<van-tabs v-model="activeTab" @change="handleTabChange"> |
|||
<van-tab title="全部" name="all" /> |
|||
<van-tab title="待收货" name="0" /> |
|||
<van-tab title="质检中" name="1" /> |
|||
<van-tab title="已完成" name="2" /> |
|||
</van-tabs> |
|||
</div> |
|||
|
|||
<!-- 退货单列表 --> |
|||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh"> |
|||
<van-list |
|||
v-model="loading" |
|||
:finished="finished" |
|||
finished-text="没有更多了" |
|||
@load="onLoad" |
|||
<!-- 功能菜单 --> |
|||
<div class="menu-grid"> |
|||
<div |
|||
class="menu-item" |
|||
v-for="(btn, index) in buttons" |
|||
:key="index" |
|||
@click="$router.push(btn.to)" |
|||
> |
|||
<div |
|||
v-for="item in returnList" |
|||
:key="item.id" |
|||
class="return-item" |
|||
@click="handleReturnClick(item)" |
|||
> |
|||
<div class="return-header"> |
|||
<div class="return-no">{{ item.returnNo }}</div> |
|||
<div class="return-status" :class="getStatusClass(item.status)"> |
|||
{{ getStatusText(item.status) }} |
|||
</div> |
|||
</div> |
|||
<div class="return-info"> |
|||
<div class="info-row"> |
|||
<span class="label">原订单号:</span> |
|||
<span class="value">{{ item.originalOrderNo }}</span> |
|||
</div> |
|||
<div class="info-row"> |
|||
<span class="label">客户:</span> |
|||
<span class="value">{{ item.customerName }}</span> |
|||
</div> |
|||
<div class="info-row"> |
|||
<span class="label">退货原因:</span> |
|||
<span class="value">{{ item.returnReason }}</span> |
|||
</div> |
|||
<div class="info-row"> |
|||
<span class="label">退货数量:</span> |
|||
<span class="value">{{ item.returnQuantity }}</span> |
|||
</div> |
|||
<div class="info-row"> |
|||
<span class="label">退货金额:</span> |
|||
<span class="value amount">¥{{ item.returnAmount }}</span> |
|||
</div> |
|||
<div class="info-row"> |
|||
<span class="label">申请时间:</span> |
|||
<span class="value">{{ item.applyTime }}</span> |
|||
</div> |
|||
</div> |
|||
<div class="menu-icon" :class="btn.iconClass"> |
|||
<van-icon :name="btn.icon" size="24" /> |
|||
</div> |
|||
</van-list> |
|||
</van-pull-refresh> |
|||
<div class="menu-text">{{ btn.label }}</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'SalesReturn', |
|||
data() { |
|||
return { |
|||
searchValue: '', |
|||
activeTab: 'all', |
|||
refreshing: false, |
|||
loading: false, |
|||
finished: false, |
|||
returnList: [ |
|||
{ |
|||
id: 1, |
|||
returnNo: 'RT202401001', |
|||
originalOrderNo: 'SO202401001', |
|||
customerName: '客户A有限公司', |
|||
returnReason: '质量问题', |
|||
returnQuantity: 10, |
|||
returnAmount: 25000.00, |
|||
applyTime: '2024-01-15 10:30', |
|||
status: 0 |
|||
}, |
|||
{ |
|||
id: 2, |
|||
returnNo: 'RT202401002', |
|||
originalOrderNo: 'SO202401002', |
|||
customerName: '客户B有限公司', |
|||
returnReason: '规格不符', |
|||
returnQuantity: 5, |
|||
returnAmount: 12500.00, |
|||
applyTime: '2024-01-14 09:20', |
|||
status: 1 |
|||
}, |
|||
{ |
|||
id: 3, |
|||
returnNo: 'RT202401003', |
|||
originalOrderNo: 'SO202401003', |
|||
customerName: '客户C有限公司', |
|||
returnReason: '数量错误', |
|||
returnQuantity: 8, |
|||
returnAmount: 18000.00, |
|||
applyTime: '2024-01-13 14:15', |
|||
status: 2 |
|||
} |
|||
buttons: [ |
|||
{ icon: 'shopping-cart-o', label: '入库', iconClass: 'purchase', to: 'salereturn-inbound' }, |
|||
{ icon: 'orders-o', label: '报废', iconClass: 'inspection', to: 'salereturn-scrap' } |
|||
] |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.loadData() |
|||
}, |
|||
methods: { |
|||
loadData() { |
|||
this.loading = true |
|||
setTimeout(() => { |
|||
this.loading = false |
|||
this.finished = true |
|||
}, 1000) |
|||
}, |
|||
onRefresh() { |
|||
this.refreshing = true |
|||
setTimeout(() => { |
|||
this.refreshing = false |
|||
this.$toast.success('刷新成功') |
|||
}, 1000) |
|||
}, |
|||
onLoad() { |
|||
this.loadData() |
|||
}, |
|||
handleSearch() { |
|||
this.loadData() |
|||
}, |
|||
handleClear() { |
|||
this.searchValue = '' |
|||
this.loadData() |
|||
}, |
|||
handleTabChange() { |
|||
this.loadData() |
|||
}, |
|||
handleReturnClick(item) { |
|||
if (item.status === 0 || item.status === 1) { |
|||
this.$router.push(`/sales-return/receive/${item.returnNo}`) |
|||
} else { |
|||
this.$toast('该退货单已完成处理') |
|||
} |
|||
}, |
|||
getStatusText(status) { |
|||
const statusMap = { |
|||
0: '待收货', |
|||
1: '质检中', |
|||
2: '已完成' |
|||
} |
|||
return statusMap[status] || '未知' |
|||
}, |
|||
getStatusClass(status) { |
|||
const classMap = { |
|||
0: 'status-pending', |
|||
1: 'status-checking', |
|||
2: 'status-completed' |
|||
} |
|||
return classMap[status] || '' |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.sales-return-container { |
|||
min-height: 100vh; |
|||
background-color: #f7f8fa; |
|||
} |
|||
|
|||
.search-section { |
|||
padding: 10px 16px; |
|||
background: white; |
|||
} |
|||
|
|||
.filter-section { |
|||
background: white; |
|||
border-bottom: 1px solid #ebedf0; |
|||
<style> |
|||
/* filepath: D:\xjcode\wms-pda\src\views\modules\recv\po-recv.vue */ |
|||
:root { |
|||
--columns: 3; |
|||
--button-size: calc(100vw / var(--columns) - 20px); |
|||
} |
|||
|
|||
.return-item { |
|||
background: white; |
|||
margin: 10px 16px; |
|||
border-radius: 8px; |
|||
padding: 16px; |
|||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
|||
.pda-container { |
|||
width: 100vw; |
|||
height: 100vh; |
|||
display: flex; |
|||
flex-direction: column; |
|||
background: #f5f5f5; |
|||
font-family: 'Arial', sans-serif; |
|||
overflow: auto; |
|||
} |
|||
|
|||
.return-header { |
|||
.status-bar { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 12px; |
|||
} |
|||
|
|||
.return-no { |
|||
font-size: 16px; |
|||
font-weight: bold; |
|||
color: #323233; |
|||
} |
|||
|
|||
.return-status { |
|||
padding: 4px 8px; |
|||
border-radius: 4px; |
|||
font-size: 12px; |
|||
color: white; |
|||
padding: 10px 20px; |
|||
background: #17B3A3; |
|||
} |
|||
|
|||
.status-pending { |
|||
background-color: #ff976a; |
|||
.menu-grid { |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 1fr); |
|||
gap: 15px; |
|||
padding: 20px; |
|||
justify-content: center; /* 水平居中 */ |
|||
align-content: center; /* 垂直居中 */ |
|||
width: 100%; /* 确保占满容器宽度 */ |
|||
} |
|||
|
|||
.status-checking { |
|||
background-color: #1989fa; |
|||
} |
|||
|
|||
.status-completed { |
|||
background-color: #07c160; |
|||
.menu-item { |
|||
background: white; |
|||
border-radius: 12px; |
|||
padding: 20px 10px; |
|||
text-align: center; |
|||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
|||
transition: transform 0.2s; |
|||
} |
|||
|
|||
.return-info { |
|||
font-size: 14px; |
|||
.menu-item:active { |
|||
transform: scale(0.95); |
|||
} |
|||
|
|||
.info-row { |
|||
.menu-icon { |
|||
width: 50px; |
|||
height: 50px; |
|||
border-radius: 50%; |
|||
display: flex; |
|||
margin-bottom: 6px; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin: 0 auto 10px; |
|||
color: white; |
|||
} |
|||
|
|||
.info-row:last-child { |
|||
margin-bottom: 0; |
|||
.menu-icon.purchase { |
|||
background: linear-gradient(135deg, #17B3A3 0%, #1dc5ef 100%); |
|||
} |
|||
|
|||
.label { |
|||
color: #969799; |
|||
width: 80px; |
|||
flex-shrink: 0; |
|||
.menu-icon.inspection { |
|||
background: linear-gradient(135deg, #17B3A3 0%, #1dc5ef 100%); |
|||
} |
|||
|
|||
.value { |
|||
color: #323233; |
|||
flex: 1; |
|||
.menu-icon.qualified { |
|||
background: linear-gradient(135deg, #17B3A3 0%, #1dc5ef 100%); |
|||
} |
|||
|
|||
.value.amount { |
|||
color: #ee0a24; |
|||
font-weight: bold; |
|||
.menu-text { |
|||
font-size: 13px; |
|||
color: #333; |
|||
font-weight: bold; /* 加粗字体 */ |
|||
white-space: nowrap; /* 防止文字换行 */ |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
} |
|||
</style> |
|||
</style> |
|||
@ -0,0 +1,241 @@ |
|||
<template> |
|||
<div> |
|||
<div class="pda-container"> |
|||
<div class="status-bar"> |
|||
<div class="goBack" @click="handleBack"><i class="el-icon-arrow-left"></i>上一页</div> |
|||
<div class="goBack">销售退货-入库</div> |
|||
<div class="network" style="color: #fff" @click="$router.push({ path: '/' })">🏠首页</div> |
|||
</div> |
|||
<div class="main-content"> |
|||
<!-- RMA号输入/扫描 --> |
|||
<el-input v-model="scanRma" placeholder="扫描RMA条码或输入RMA号" @keyup.enter.native="searchRmaList" ref="scanRmaRef" class="rma-input" /> |
|||
<!-- RMA明细选择 --> |
|||
<div v-if="rmaList.length > 0" class="rma-list"> |
|||
<el-form> |
|||
<el-row v-for="(rmaDetail, index) in rmaList[0].detailList" :key="index" :class="index < rmaList.length - 1 ? 'bottom-line-row' : ''"> |
|||
<el-col :span="8"> |
|||
<el-form-item label="物料"><span>{{ rmaDetail.partNo }}</span></el-form-item> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<el-form-item label="批号"><span>{{ rmaDetail.batchNo }}</span></el-form-item> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<el-form-item label="数量"><span>{{ rmaDetail.processQty }}</span></el-form-item> |
|||
</el-col> |
|||
<el-col :span="24"> |
|||
<el-button type="primary" size="mini" @click="addToReturnList(rmaDetail)" :disabled="isInReturnList(rmaDetail)">添加到退货明细</el-button> |
|||
</el-col> |
|||
</el-row> |
|||
</el-form> |
|||
</div> |
|||
<!-- 退货明细列表 --> |
|||
<div v-if="returnList.length > 0"> |
|||
<div class="return-list-title">退货明细列表</div> |
|||
<div v-for="(detail, dIdx) in returnList" :key="dIdx" class="detail-block"> |
|||
<el-card shadow="hover" class="detail-card"> |
|||
<div slot="header" class="detail-header"> |
|||
<span>明细{{ dIdx + 1 }}</span> |
|||
<el-button type="danger" icon="el-icon-delete" circle size="mini" @click="removeDetail(dIdx)" v-if="returnList.length > 1" style="float:right;"></el-button> |
|||
</div> |
|||
<el-form label-position="top" class="detail-form"> |
|||
<el-row :gutter="10"> |
|||
<el-col :span="12"><el-form-item label="物料"><el-input v-model="detail.partNo" size="small" /></el-form-item></el-col> |
|||
<el-col :span="12"><el-form-item label="数量"><el-input v-model="detail.processQty" type="number" size="small" /></el-form-item></el-col> |
|||
<el-col :span="12"><el-form-item label="批号"><el-input v-model="detail.batchNo" size="small" /></el-form-item></el-col> |
|||
<el-col :span="12"><el-form-item label="库位"><el-input v-model="detail.locationNo" size="small" /></el-form-item></el-col> |
|||
<el-col :span="12"><el-form-item label="仓库"><el-input v-model="detail.warehouseId" size="small" /></el-form-item></el-col> |
|||
</el-row> |
|||
<!-- 包装单元 --> |
|||
<div class="pack-unit-area"> |
|||
<div class="pack-title">包装单元</div> |
|||
<div v-for="(pack, pIdx) in detail.packUnitList" :key="pIdx" class="pack-block"> |
|||
<el-row :gutter="10"> |
|||
<el-col :span="6"><el-input v-model="pack.code" placeholder="编码" size="small" /></el-col> |
|||
<el-col :span="6"><el-input v-model="pack.qty" placeholder="数量" type="number" size="small" /></el-col> |
|||
<el-col :span="6"><el-input v-model="pack.perQty" placeholder="单包数量" type="number" size="small" /></el-col> |
|||
<el-col :span="4"><el-input v-model="pack.packageQty" placeholder="包数" type="number" size="small" /></el-col> |
|||
<el-col :span="2"> |
|||
<el-button type="danger" icon="el-icon-delete" circle size="mini" @click="removePackUnit(detail, pIdx)"></el-button> |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
<el-button type="primary" size="mini" icon="el-icon-plus" @click="addPackUnit(detail)" class="add-pack-btn">添加包装单元</el-button> |
|||
</div> |
|||
</el-form> |
|||
</el-card> |
|||
</div> |
|||
<el-button type="success" class="submit-btn" @click="submitReturn">提交</el-button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { getRmaList, processReturn } from "@/api/sales-return/sales-return.js"; |
|||
export default { |
|||
data() { |
|||
return { |
|||
scanRma: "", |
|||
rmaList: [], |
|||
returnList: [] // 退货明细列表 |
|||
}; |
|||
}, |
|||
methods: { |
|||
handleBack() { |
|||
this.$router.back(); |
|||
}, |
|||
searchRmaList() { |
|||
if (!this.scanRma) return (this.rmaList = []); |
|||
getRmaList({ rmaNo: this.scanRma }).then(({ data }) => { |
|||
if (data.code === 0) this.rmaList = data.rows; |
|||
}); |
|||
}, |
|||
addToReturnList(rmaDetail) { |
|||
// 避免重复添加 |
|||
if (this.isInReturnList(rmaDetail)) return; |
|||
this.returnList.push({ |
|||
site: "1", |
|||
partNo: rmaDetail.partNo, |
|||
processQty: rmaDetail.processQty, |
|||
batchNo: rmaDetail.batchNo, |
|||
locationNo: "", |
|||
warehouseId: "", |
|||
packUnitList: [] |
|||
}); |
|||
}, |
|||
isInReturnList(rmaDetail) { |
|||
return this.returnList.some( |
|||
d => d.partNo === rmaDetail.partNo && d.batchNo === rmaDetail.batchNo |
|||
); |
|||
}, |
|||
removeDetail(idx) { |
|||
this.returnList.splice(idx, 1); |
|||
}, |
|||
addPackUnit(detail) { |
|||
detail.packUnitList.push({code: "", qty: '', perQty: '', packageQty: ''}); |
|||
}, |
|||
removePackUnit(detail, idx) { |
|||
detail.packUnitList.splice(idx, 1); |
|||
}, |
|||
submitReturn() { |
|||
if (!this.scanRma || this.returnList.length === 0) { |
|||
this.$message.error("请先扫描RMA号并选择退货明细"); |
|||
return; |
|||
} |
|||
processReturn({ |
|||
rmaNo: this.scanRma, |
|||
processType: "inbound", |
|||
detailList: this.returnList |
|||
}).then(({data}) => { |
|||
if (data.code === 0) { |
|||
this.$message.success("操作成功"); |
|||
this.scanRma = ""; |
|||
this.rmaList = []; |
|||
this.returnList = []; |
|||
} else { |
|||
this.$message.error(data.msg); |
|||
} |
|||
}); |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$nextTick(() => this.$refs.scanRmaRef && this.$refs.scanRmaRef.focus()); |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.pda-container { |
|||
background: #f5f5f5; |
|||
min-height: 100vh; |
|||
} |
|||
|
|||
.status-bar { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
background: #409EFF; |
|||
color: #fff; |
|||
padding: 8px 12px; |
|||
} |
|||
|
|||
.goBack { |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.main-content { |
|||
padding: 10px 6px 30px 6px; |
|||
} |
|||
|
|||
.rma-input { |
|||
margin-bottom: 12px; |
|||
} |
|||
|
|||
.rma-list { |
|||
margin-bottom: 18px; |
|||
background: #fff; |
|||
border-radius: 8px; |
|||
box-shadow: 0 2px 8px #e6e6e6; |
|||
padding: 10px; |
|||
} |
|||
|
|||
.return-list-title { |
|||
font-size: 16px; |
|||
font-weight: bold; |
|||
color: #409EFF; |
|||
margin: 12px 0 8px 0; |
|||
} |
|||
|
|||
.detail-block { |
|||
margin-bottom: 18px; |
|||
} |
|||
|
|||
.detail-card { |
|||
border-radius: 10px; |
|||
box-shadow: 0 2px 12px #e0e7ef; |
|||
} |
|||
|
|||
.detail-header { |
|||
font-weight: bold; |
|||
font-size: 15px; |
|||
color: #333; |
|||
border-left: 4px solid #409EFF; |
|||
padding-left: 8px; |
|||
} |
|||
|
|||
.detail-form { |
|||
padding: 6px 0 0 0; |
|||
} |
|||
|
|||
.pack-unit-area { |
|||
background: #f8fafd; |
|||
border-radius: 6px; |
|||
padding: 8px 6px 6px 6px; |
|||
margin-top: 8px; |
|||
} |
|||
|
|||
.pack-title { |
|||
font-weight: bold; |
|||
color: #666; |
|||
margin-bottom: 4px; |
|||
} |
|||
|
|||
.pack-block { |
|||
margin-bottom: 6px; |
|||
} |
|||
|
|||
.add-pack-btn { |
|||
margin-top: 4px; |
|||
} |
|||
|
|||
.submit-btn { |
|||
width: 100%; |
|||
font-size: 16px; |
|||
margin-top: 18px; |
|||
} |
|||
|
|||
.bottom-line-row { |
|||
border-bottom: 1px solid #eee; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,133 @@ |
|||
<template> |
|||
<div> |
|||
<div class="pda-container"> |
|||
<div class="status-bar"> |
|||
<div class="goBack" @click="handleBack"><i class="el-icon-arrow-left"></i>上一页</div> |
|||
<div class="goBack">销售退货-报废</div> |
|||
<div class="network" style="color: #fff" @click="$router.push({ path: '/' })">🏠首页</div> |
|||
</div> |
|||
<div class="main-content"> |
|||
<!-- RMA号输入/扫描 --> |
|||
<el-input v-model="scanRma" placeholder="扫描RMA条码或输入RMA号" @keyup.enter.native="searchRmaList" ref="scanRmaRef" class="rma-input" /> |
|||
<!-- RMA明细选择 --> |
|||
<div v-if="rmaList.length > 0" class="rma-list"> |
|||
<el-form> |
|||
<el-row v-for="(rmaDetail, index) in rmaList[0].detailList" :key="index" :class="index < rmaList.length - 1 ? 'bottom-line-row' : ''"> |
|||
<el-col :span="8"><el-form-item label="物料"><span>{{ rmaDetail.partNo }}</span></el-form-item></el-col> |
|||
<el-col :span="8"><el-form-item label="批号"><span>{{ rmaDetail.batchNo }}</span></el-form-item></el-col> |
|||
<el-col :span="8"><el-form-item label="数量"><span>{{ rmaDetail.processQty }}</span></el-form-item></el-col> |
|||
<el-col :span="24"><el-form-item label="描述"><span>{{ rmaDetail.desc }}</span></el-form-item></el-col> |
|||
<el-col :span="24"> |
|||
<el-button type="primary" size="mini" @click="addToReturnList(rmaDetail)" :disabled="isInReturnList(rmaDetail)">添加到退货明细</el-button> |
|||
</el-col> |
|||
</el-row> |
|||
</el-form> |
|||
</div> |
|||
<!-- 退货明细列表 --> |
|||
<div v-if="returnList.length > 0"> |
|||
<div class="return-list-title">退货明细列表</div> |
|||
<div v-for="(detail, dIdx) in returnList" :key="dIdx" class="detail-block"> |
|||
<el-card shadow="hover" class="detail-card"> |
|||
<div slot="header" class="detail-header"> |
|||
<span>明细{{ dIdx + 1 }}</span> |
|||
<el-button type="danger" icon="el-icon-delete" circle size="mini" @click="removeDetail(dIdx)" v-if="returnList.length > 1" style="float:right;"></el-button> |
|||
</div> |
|||
<el-form label-position="top" class="detail-form"> |
|||
<el-row :gutter="10"> |
|||
<el-col :span="12"><el-form-item label="物料"><el-input v-model="detail.partNo" size="small" /></el-form-item></el-col> |
|||
<el-col :span="12"><el-form-item label="数量"><el-input v-model="detail.processQty" type="number" size="small" /></el-form-item></el-col> |
|||
<el-col :span="12"><el-form-item label="批号"><el-input v-model="detail.batchNo" size="small" /></el-form-item></el-col> |
|||
<el-col :span="12"><el-form-item label="库位"><el-input v-model="detail.locationNo" size="small" /></el-form-item></el-col> |
|||
<el-col :span="12"><el-form-item label="仓库"><el-input v-model="detail.warehouseId" size="small" /></el-form-item></el-col> |
|||
</el-row> |
|||
</el-form> |
|||
</el-card> |
|||
</div> |
|||
<el-button type="success" class="submit-btn" @click="submitReturn">提交</el-button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { getRmaList, processReturn } from "@/api/sales-return/sales-return.js"; |
|||
export default { |
|||
data() { |
|||
return { |
|||
scanRma: "", |
|||
rmaList: [], |
|||
returnList: [] |
|||
}; |
|||
}, |
|||
methods: { |
|||
handleBack() { |
|||
this.$router.back(); |
|||
}, |
|||
searchRmaList() { |
|||
if (!this.scanRma) return (this.rmaList = []); |
|||
getRmaList({ rmaNo: this.scanRma }).then(({ data }) => { |
|||
if (data.code === 0) this.rmaList = data.rows; |
|||
}); |
|||
}, |
|||
addToReturnList(rmaDetail) { |
|||
if (this.isInReturnList(rmaDetail)) return; |
|||
this.returnList.push({ |
|||
site: "1", |
|||
partNo: rmaDetail.partNo, |
|||
processQty: rmaDetail.processQty, |
|||
batchNo: rmaDetail.batchNo, |
|||
locationNo: "", |
|||
warehouseId: "" |
|||
}); |
|||
}, |
|||
isInReturnList(rmaDetail) { |
|||
return this.returnList.some( |
|||
d => d.partNo === rmaDetail.partNo && d.batchNo === rmaDetail.batchNo |
|||
); |
|||
}, |
|||
removeDetail(idx) { |
|||
this.returnList.splice(idx, 1); |
|||
}, |
|||
submitReturn() { |
|||
if (!this.scanRma || this.returnList.length === 0) { |
|||
this.$message.error("请先扫描RMA号并选择退货明细"); |
|||
return; |
|||
} |
|||
processReturn({ |
|||
rmaNo: this.scanRma, |
|||
processType: "scrap", |
|||
detailList: this.returnList |
|||
}).then(({ data }) => { |
|||
if (data.code === 0) { |
|||
this.$message.success("操作成功"); |
|||
this.scanRma = ""; |
|||
this.rmaList = []; |
|||
this.returnList = []; |
|||
} else { |
|||
this.$message.error(data.msg); |
|||
} |
|||
}); |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$nextTick(() => this.$refs.scanRmaRef && this.$refs.scanRmaRef.focus()); |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.pda-container { background: #f5f5f5; min-height: 100vh; } |
|||
.status-bar { display: flex; justify-content: space-between; align-items: center; background: #409EFF; color: #fff; padding: 8px 12px; } |
|||
.goBack { cursor: pointer; } |
|||
.main-content { padding: 10px 6px 30px 6px; } |
|||
.rma-input { margin-bottom: 12px; } |
|||
.rma-list { margin-bottom: 18px; background: #fff; border-radius: 8px; box-shadow: 0 2px 8px #e6e6e6; padding: 10px; } |
|||
.return-list-title { font-size: 16px; font-weight: bold; color: #409EFF; margin: 12px 0 8px 0; } |
|||
.detail-block { margin-bottom: 18px; } |
|||
.detail-card { border-radius: 10px; box-shadow: 0 2px 12px #e0e7ef; } |
|||
.detail-header { font-weight: bold; font-size: 15px; color: #333; border-left: 4px solid #409EFF; padding-left: 8px; } |
|||
.detail-form { padding: 6px 0 0 0; } |
|||
.submit-btn { width: 100%; font-size: 16px; margin-top: 18px; } |
|||
.bottom-line-row { border-bottom: 1px solid #eee; } |
|||
</style> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue