han\hanst 4 months ago
parent
commit
5b5374ceb9
  1. 7
      src/api/other-transaction/scrap.js
  2. 10
      src/api/other-transaction/transit.js
  3. 2
      src/router/index.js
  4. 389
      src/views/modules/other-transaction/execute.vue
  5. 394
      src/views/modules/other-transaction/index.vue
  6. 651
      src/views/modules/other-transaction/receiveFromTransit.vue
  7. 539
      src/views/modules/other-transaction/scrap.vue
  8. 597
      src/views/modules/sales-return/sales-return-inbound.vue
  9. 545
      src/views/modules/sales-return/sales-return-scrap.vue

7
src/api/other-transaction/scrap.js

@ -0,0 +1,7 @@
import { createAPI } from "@/utils/httpRequest.js";
// 扫描报废标签
export const scanScrapLabel = data => createAPI(`scrap/scanScrapLabel`,'POST',data)
// 确认报废
export const confirmScrap = data => createAPI(`scrap/confirmScrap`,'POST',data)

10
src/api/other-transaction/transit.js

@ -0,0 +1,10 @@
import { createAPI } from "@/utils/httpRequest.js";
// 获取移库记录
export const getTransitRecord = data => createAPI(`transit/getTransitRecord`,'POST',data)
// 扫描移库标签
export const scanTransitLabel = data => createAPI(`transit/scanTransitLabel`,'POST',data)
// 确认移库接收
export const confirmTransitReceive = data => createAPI(`transit/confirmTransitReceive`,'POST',data)

2
src/router/index.js

@ -70,6 +70,8 @@ const globalRoutes = [
// 其他出入库
{path: "/otherinout",name: "otherinout", component: resolve => require(["@/views/modules/other-transaction/index.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/receiveFromTransit",name: "receiveFromTransit", component: resolve => require(["@/views/modules/other-transaction/receiveFromTransit.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{path: "/scrap",name: "scrap", component: resolve => require(["@/views/modules/other-transaction/scrap.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
// Material Requisition
{path: "/mrissue",name: "mrissue", component: resolve => require(["@/views/modules/mr-issue/index.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},

389
src/views/modules/other-transaction/execute.vue

@ -1,389 +0,0 @@
<template>
<div class="execute-container">
<van-nav-bar title="执行出入库" left-arrow @click-left="$router.back()" />
<!-- 单据信息 -->
<div class="transaction-info">
<div class="info-header">
<div class="transaction-no">{{ transactionInfo.transactionNo }}</div>
<div class="transaction-type" :class="getTypeClass(transactionInfo.type)">
{{ getTypeText(transactionInfo.type) }}
</div>
</div>
<van-cell-group>
<van-cell title="业务类型" :value="transactionInfo.businessType" />
<van-cell v-if="transactionInfo.fromWarehouse" title="源仓库" :value="transactionInfo.fromWarehouse" />
<van-cell v-if="transactionInfo.toWarehouse" title="目标仓库" :value="transactionInfo.toWarehouse" />
<van-cell title="申请人" :value="transactionInfo.applicant" />
<van-cell title="申请时间" :value="transactionInfo.applyTime" />
</van-cell-group>
</div>
<!-- 物料明细 -->
<div class="material-section">
<div class="section-title">物料明细</div>
<div
v-for="(item, index) in materialList"
:key="index"
class="material-item"
>
<div class="material-info">
<div class="material-name">{{ item.materialCode }} - {{ item.materialName }}</div>
<div class="material-spec">规格{{ item.specification }}</div>
<div class="material-location" v-if="item.fromLocation">
<span class="label">源库位</span>
<van-tag type="primary" size="small">{{ item.fromLocation }}</van-tag>
</div>
<div class="material-quantity">
申请数量{{ item.requestQuantity }} | 已处理{{ item.processedQuantity }}
</div>
</div>
<div class="process-input">
<van-stepper
v-model="item.currentProcess"
:min="0"
:max="item.requestQuantity - item.processedQuantity"
integer
/>
</div>
</div>
</div>
<!-- 目标库位 (调拨盘盈) -->
<div v-if="needTargetLocation" class="location-section">
<div class="section-title">目标库位</div>
<van-field
v-model="targetLocation"
label="库位"
placeholder="请选择或扫描目标库位"
readonly
is-link
@click="showLocationPicker = true"
>
<template #right-icon>
<van-icon name="scan" @click.stop="handleScanLocation" />
</template>
</van-field>
</div>
<!-- 原因说明 -->
<div class="reason-section">
<div class="section-title">原因说明</div>
<van-field
v-model="reasonInfo.reason"
label="原因"
placeholder="请选择原因"
readonly
is-link
@click="showReasonPicker = true"
/>
<van-field
v-model="reasonInfo.description"
label="详细说明"
type="textarea"
placeholder="请输入详细说明"
rows="3"
/>
</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="showLocationPicker" position="bottom">
<van-picker
:columns="locationColumns"
@confirm="onLocationConfirm"
@cancel="showLocationPicker = false"
/>
</van-popup>
<van-popup v-model="showReasonPicker" position="bottom">
<van-picker
:columns="reasonColumns"
@confirm="onReasonConfirm"
@cancel="showReasonPicker = false"
/>
</van-popup>
</div>
</template>
<script>
export default {
name: 'OtherTransactionExecute',
data() {
return {
transactionInfo: {
transactionNo: 'TR202401001',
type: 'transfer',
businessType: '仓库调拨',
fromWarehouse: '主仓库',
toWarehouse: '分仓库A',
applicant: '张三',
applyTime: '2024-01-15 10:30'
},
materialList: [
{
materialCode: 'MAT001',
materialName: '原材料A',
specification: '100*50*20mm',
fromLocation: 'A01-01-01',
requestQuantity: 100,
processedQuantity: 0,
currentProcess: 0
}
],
targetLocation: '',
reasonInfo: {
reason: '',
description: ''
},
remark: '',
submitting: false,
showLocationPicker: false,
showReasonPicker: false,
locationColumns: [
'B01-01-01',
'B01-01-02',
'B01-02-01',
'B01-02-02',
'C01-01-01'
],
reasonColumns: []
}
},
computed: {
needTargetLocation() {
return ['transfer', 'gain'].includes(this.transactionInfo.type)
}
},
mounted() {
this.loadTransactionData()
this.initReasonColumns()
},
methods: {
loadTransactionData() {
const transactionNo = this.$route.params.orderNo
console.log('加载出入库单据数据:', transactionNo)
},
initReasonColumns() {
const reasonMap = {
transfer: ['仓库调整', '库位优化', '业务需要'],
gain: ['盘点发现', '系统错误', '其他原因'],
loss: ['盘点发现', '损耗', '丢失'],
scrap: ['质量问题', '过期', '损坏', '其他'],
sample: ['客户样品', '测试样品', '展示样品']
}
this.reasonColumns = reasonMap[this.transactionInfo.type] || []
},
handleScanLocation() {
this.$toast('扫描库位功能开发中...')
},
onLocationConfirm(value) {
this.targetLocation = value
this.showLocationPicker = false
},
onReasonConfirm(value) {
this.reasonInfo.reason = value
this.showReasonPicker = false
},
async handleSubmit() {
//
const hasProcess = this.materialList.some(item => item.currentProcess > 0)
if (!hasProcess) {
this.$toast('请输入处理数量')
return
}
//
if (this.needTargetLocation && !this.targetLocation) {
this.$toast('请选择目标库位')
return
}
//
if (!this.reasonInfo.reason) {
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
}
},
getTypeText(type) {
const typeMap = {
transfer: '调拨',
gain: '盘盈',
loss: '盘亏',
scrap: '报废',
sample: '样品'
}
return typeMap[type] || '未知'
},
getTypeClass(type) {
return `type-${type}`
}
}
}
</script>
<style scoped>
.execute-container {
min-height: 100vh;
background-color: #f7f8fa;
padding-bottom: 80px;
}
.transaction-info {
background: white;
margin-bottom: 10px;
}
.info-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
border-bottom: 1px solid #ebedf0;
}
.transaction-no {
font-size: 18px;
font-weight: bold;
color: #323233;
}
.transaction-type {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
color: white;
}
.type-transfer {
background-color: #1989fa;
}
.type-gain {
background-color: #07c160;
}
.type-loss {
background-color: #ff976a;
}
.type-scrap {
background-color: #ee0a24;
}
.type-sample {
background-color: #9c26b0;
}
.material-section,
.location-section,
.reason-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;
}
.material-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
border-bottom: 1px solid #ebedf0;
}
.material-item:last-child {
border-bottom: none;
}
.material-info {
flex: 1;
}
.material-name {
font-size: 16px;
font-weight: bold;
color: #323233;
margin-bottom: 4px;
}
.material-spec {
font-size: 12px;
color: #969799;
margin-bottom: 6px;
}
.material-location {
display: flex;
align-items: center;
margin-bottom: 4px;
}
.material-location .label {
font-size: 12px;
color: #646566;
margin-right: 8px;
}
.material-quantity {
font-size: 14px;
color: #646566;
}
.process-input {
margin-left: 16px;
}
.bottom-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 16px;
background: white;
border-top: 1px solid #ebedf0;
}
</style>

394
src/views/modules/other-transaction/index.vue

@ -1,313 +1,203 @@
<template>
<div class="other-transaction-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>
<!-- 类型筛选 -->
<div class="filter-section">
<van-tabs v-model="activeTab" @change="handleTabChange">
<van-tab title="全部" name="all" />
<van-tab title="调拨" name="transfer" />
<van-tab title="盘盈" name="gain" />
<van-tab title="盘亏" name="loss" />
<van-tab title="报废" name="scrap" />
<van-tab title="样品" name="sample" />
</van-tabs>
<div class="pda-container">
<div class="header-bar">
<div class="header-left" @click="$router.back()">
<i class="el-icon-arrow-left"></i>
<span>其他出入库</span>
</div>
<div class="header-right" @click="$router.push({ path: '/' })">首页</div>
</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"
:class="{ disabled: btn.disabled }"
@click="handleButtonClick(btn)"
>
<div
v-for="item in transactionList"
:key="item.id"
class="transaction-item"
@click="handleTransactionClick(item)"
>
<div class="transaction-header">
<div class="transaction-no">{{ item.transactionNo }}</div>
<div class="transaction-type" :class="getTypeClass(item.type)">
{{ getTypeText(item.type) }}
</div>
</div>
<div class="transaction-info">
<div class="info-row">
<span class="label">业务类型</span>
<span class="value">{{ item.businessType }}</span>
</div>
<div class="info-row" v-if="item.fromWarehouse">
<span class="label">源仓库</span>
<span class="value">{{ item.fromWarehouse }}</span>
</div>
<div class="info-row" v-if="item.toWarehouse">
<span class="label">目标仓库</span>
<span class="value">{{ item.toWarehouse }}</span>
</div>
<div class="info-row">
<span class="label">数量</span>
<span class="value">{{ item.quantity }}</span>
</div>
<div class="info-row">
<span class="label">申请人</span>
<span class="value">{{ item.applicant }}</span>
</div>
<div class="info-row">
<span class="label">申请时间</span>
<span class="value">{{ item.applyTime }}</span>
</div>
</div>
<div class="transaction-status">
<van-tag :type="getStatusColor(item.status)" size="small">
{{ getStatusText(item.status) }}
</van-tag>
</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: 'OtherTransaction',
data() {
return {
searchValue: '',
activeTab: 'all',
refreshing: false,
loading: false,
finished: false,
transactionList: [
buttons: [
{
id: 1,
transactionNo: 'TR202401001',
type: 'transfer',
businessType: '仓库调拨',
fromWarehouse: '主仓库',
toWarehouse: '分仓库A',
quantity: 100,
applicant: '张三',
applyTime: '2024-01-15 10:30',
status: 0
icon: "scan",
label: "移库",
iconClass: "purchase",
to: "productionPicking",
disabled: true,
},
{
id: 2,
transactionNo: 'GA202401001',
type: 'gain',
businessType: '盘盈入库',
fromWarehouse: '',
toWarehouse: '主仓库',
quantity: 50,
applicant: '李四',
applyTime: '2024-01-14 09:20',
status: 1
icon: "records",
label: "Receive from Transit",
iconClass: "qualified",
to: "receiveFromTransit",
disabled: false,
},
{
id: 3,
transactionNo: 'LO202401001',
type: 'loss',
businessType: '盘亏出库',
fromWarehouse: '主仓库',
toWarehouse: '',
quantity: 20,
applicant: '王五',
applyTime: '2024-01-13 14:15',
status: 2
icon: "records",
label: "报废",
iconClass: "qualified",
to: "scrap",
disabled: false,
},
{
id: 4,
transactionNo: 'SC202401001',
type: 'scrap',
businessType: '报废出库',
fromWarehouse: '主仓库',
toWarehouse: '',
quantity: 10,
applicant: '赵六',
applyTime: '2024-01-12 11:30',
status: 0
}
]
}
},
mounted() {
this.loadData()
icon: "records",
label: "其它入库",
iconClass: "qualified",
to: "productionPicking",
disabled: false,
},
{
icon: "records",
label: "其他出库",
iconClass: "qualified",
to: "productionPicking",
disabled: false,
},
{
icon: "records",
label: "单独CALL料",
iconClass: "qualified",
to: "productionPicking",
disabled: false,
},
],
};
},
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()
},
handleTransactionClick(item) {
if (item.status === 0 || item.status === 1) {
this.$router.push(`/other-transaction/execute/${item.transactionNo}`)
handleButtonClick(btn) {
if (btn.disabled) {
this.$message.warning("正在开发中,敬请期待...");
} else {
this.$toast('该单据已完成处理')
this.$router.push(btn.to);
}
},
getTypeText(type) {
const typeMap = {
transfer: '调拨',
gain: '盘盈',
loss: '盘亏',
scrap: '报废',
sample: '样品'
}
return typeMap[type] || '未知'
},
getTypeClass(type) {
return `type-${type}`
},
getStatusText(status) {
const statusMap = {
0: '待执行',
1: '执行中',
2: '已完成'
}
return statusMap[status] || '未知'
},
getStatusColor(status) {
const colorMap = {
0: 'warning',
1: 'primary',
2: 'success'
}
return colorMap[status] || 'default'
}
}
}
},
};
</script>
<style scoped>
.other-transaction-container {
min-height: 100vh;
background-color: #f7f8fa;
}
.search-section {
padding: 10px 16px;
background: white;
}
.filter-section {
background: white;
border-bottom: 1px solid #ebedf0;
<style>
:root {
--columns: 3;
--button-size: calc(100vw / var(--columns) - 20px);
}
.transaction-item {
background: white;
margin: 10px 16px;
border-radius: 8px;
padding: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
position: relative;
}
.transaction-header {
/* 头部栏 */
.header-bar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding: 8px 16px;
background: #17b3a3;
color: white;
height: 40px;
min-height: 40px;
max-height: 40px;
}
.transaction-no {
.header-left {
display: flex;
align-items: center;
cursor: pointer;
font-size: 16px;
font-weight: bold;
color: #323233;
font-weight: 500;
}
.transaction-type {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
color: white;
margin-right: 110px;
.header-left i {
margin-right: 8px;
font-size: 18px;
}
.type-transfer {
background-color: #1989fa;
.header-right {
cursor: pointer;
font-size: 16px;
font-weight: 500;
}
.type-gain {
background-color: #07c160;
.menu-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
padding: 20px;
justify-content: center; /* 水平居中 */
align-content: center; /* 垂直居中 */
width: 100%; /* 确保占满容器宽度 */
}
.type-loss {
background-color: #ff976a;
.menu-item {
background: white;
border-radius: 12px;
padding: 12px 6px;
text-align: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.2s;
cursor: pointer;
}
.type-scrap {
background-color: #ee0a24;
.menu-item:active {
transform: scale(0.95);
}
.type-sample {
background-color: #9c26b0;
.menu-item.disabled {
opacity: 0.6;
position: relative;
}
.transaction-info {
font-size: 14px;
margin-bottom: 12px;
.menu-item.disabled::after {
content: "开发中";
position: absolute;
top: 8px;
right: 8px;
background: #ff9500;
color: white;
font-size: 8px;
padding: 2px 4px;
border-radius: 8px;
font-weight: bold;
}
.info-row {
.menu-icon {
width: 38px;
height: 38px;
border-radius: 50%;
display: flex;
margin-bottom: 6px;
align-items: center;
justify-content: center;
margin: 0 auto 6px;
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%);
}
.transaction-status {
position: absolute;
top: 16px;
right: 16px;
.menu-text {
font-size: 10px;
color: #333;
font-weight: bold; /* 加粗字体 */
white-space: nowrap; /* 防止文字换行 */
overflow: hidden;
text-overflow: ellipsis;
margin-top: 2px;
}
</style>

651
src/views/modules/other-transaction/receiveFromTransit.vue

@ -0,0 +1,651 @@
<template>
<div class="pda-container">
<!-- 头部栏 -->
<div class="header-bar">
<div class="header-left" @click="$router.back()">
<i class="el-icon-arrow-left"></i>
<span>Receive from Transit</span>
</div>
<div class="header-right" @click="$router.push({ path: '/' })">
首页
</div>
</div>
<!-- 搜索框 -->
<div class="search-container">
<el-input clearable class="compact-input"
v-model="transactionId"
placeholder="请输入Transaction ID"
prefix-icon="el-icon-search"
@keyup.enter.native="handleSearchTransaction"
ref="transactionInput"
/>
<el-button type="primary" class="big-button" @click="handleSearchTransaction" :loading="searching">
查询
</el-button>
</div>
<!-- 移库信息卡片 -->
<div class="material-info-card" v-if="transitInfo.transNo">
<div class="card-title">
<span class="title-label">移库单号</span>
<span class="title-value">{{ transitInfo.transNo }}</span>
</div>
<div class="card-details">
<div class="detail-item">
<div class="detail-label">移出仓库</div>
<div class="detail-value">{{ transitInfo.fromWarehouse }}</div>
</div>
<div class="detail-item">
<div class="detail-label">移入仓库</div>
<div class="detail-value">{{ transitInfo.toWarehouse }}</div>
</div>
<div class="detail-item">
<div class="detail-label">状态</div>
<div class="detail-value">
<span class="status-pending">{{ transitInfo.status }}</span>
</div>
</div>
</div>
</div>
<!-- 扫描区域 -->
<div class="section-title" v-if="transitInfo.transNo">
<div class="title-left">
<i class="el-icon-circle-check"></i>
<span>扫描箱/卷标签</span>
</div>
</div>
<!-- 扫描输入框 -->
<div class="scan-container" v-if="transitInfo.transNo">
<el-input clearable class="compact-input"
v-model="scanCode"
placeholder="请扫描箱/卷标签"
prefix-icon="el-icon-scan"
@keyup.enter.native="handleScan"
ref="scanInput"
/>
</div>
<!-- 标签列表 -->
<div class="label-list" v-if="transitInfo.transNo">
<div class="list-header">
<div class="col-no">NO.</div>
<div class="col-label">标签条码</div>
<div class="col-part">物料编码</div>
<div class="col-unit">单位</div>
<div class="col-qty">标签数量</div>
<div class="col-status">状态</div>
</div>
<div
v-for="(label, index) in labelList"
:key="label.id"
class="list-item"
>
<div class="col-no">{{ labelList.length - index }}</div>
<div class="col-label">{{ label.labelCode }}</div>
<div class="col-part">{{ label.partNo }}</div>
<div class="col-unit">{{ label.unit || '个' }}</div>
<div class="col-qty">{{ label.quantity }}</div>
<div class="col-status">
<span class="status-success">已接收</span>
</div>
</div>
<!-- 空状态 -->
<div v-if="labelList.length === 0" class="empty-labels">
<p>暂无扫描标签</p>
</div>
</div>
<!-- 底部操作按钮 -->
<div class="bottom-actions" v-if="transitInfo.transNo">
<button class="action-btn primary" @click="confirmReceive" :disabled="labelList.length === 0">
确认接收
</button>
<button class="action-btn secondary" @click="cancelReceive">
取消
</button>
</div>
<!-- 错误提示 -->
<div v-if="errorMessage" class="error-message">
<i class="el-icon-warning"></i>
<span>{{ errorMessage }}</span>
</div>
</div>
</template>
<script>
import { getTransitRecord, scanTransitLabel, confirmTransitReceive } from '@/api/other-transaction/transit';
export default {
data() {
return {
transactionId: '',
scanCode: '',
transitInfo: {},
labelList: [],
searching: false,
errorMessage: ''
};
},
methods: {
//
handleSearchTransaction() {
if (!this.transactionId.trim()) {
this.$message.warning('请输入Transaction ID');
return;
}
this.searching = true;
this.errorMessage = '';
const params = {
transactionId: this.transactionId.trim(),
site: this.$store.state.user.site
};
getTransitRecord(params).then(({ data }) => {
this.searching = false;
if (data && data.code === 0) {
this.transitInfo = data.data;
this.$message.success('查询成功');
//
this.$nextTick(() => {
if (this.$refs.scanInput) {
this.$refs.scanInput.focus();
}
});
} else {
this.$message.error(data.msg || '未找到移库记录');
this.transitInfo = {};
this.labelList = [];
}
}).catch(error => {
this.searching = false;
this.$message.error('查询失败');
this.transitInfo = {};
this.labelList = [];
});
},
//
handleScan() {
if (!this.scanCode.trim()) {
return;
}
this.validateAndAddLabel(this.scanCode.trim());
this.scanCode = '';
},
//
validateAndAddLabel(labelCode) {
const params = {
labelCode: labelCode,
transNo: this.transitInfo.transNo,
site: this.$store.state.user.site,
};
scanTransitLabel(params).then(({ data }) => {
if (data && data.code === 0) {
//
const exists = this.labelList.find(item => item.labelCode === labelCode);
if (exists) {
this.$message.warning('该标签已扫描,请勿重复扫描');
return;
}
//
this.labelList.push({
id: Date.now(),
labelCode: labelCode,
partNo: data.labelInfo.partNo,
quantity: data.labelInfo.quantity,
unit: data.labelInfo.unit,
batchNo: data.labelInfo.batchNo,
locationId: data.labelInfo.locationId
});
this.$message.success('扫描成功');
} else {
this.$message.error(data.msg || '该标签与移库单不符,请检查');
}
}).catch(error => {
this.$message.error('扫描失败');
});
},
//
confirmReceive() {
if (this.labelList.length === 0) {
this.$message.warning('请先扫描标签');
return;
}
this.$confirm('确认接收所有扫描的标签吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const params = {
site: this.transitInfo.site,
transNo: this.transitInfo.transNo,
labels: this.labelList.map(label => ({
labelCode: label.labelCode,
quantity: label.quantity,
batchNo: label.batchNo,
partNo: label.partNo,
locationId: label.locationId || this.transitInfo.toLocation
}))
};
confirmTransitReceive(params).then(({ data }) => {
if (data && data.code === 0) {
this.$message.success('接收成功');
this.$router.back();
} else {
this.$message.error(data.msg || '接收失败');
}
}).catch(error => {
console.error('接收确认失败:', error);
this.$message.error('接收失败');
});
}).catch(() => {
//
});
},
//
cancelReceive() {
if (this.labelList.length > 0) {
this.$confirm('取消后将清空已扫描的标签,确定取消吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '继续操作',
type: 'warning'
}).then(() => {
this.$router.back();
}).catch(() => {
//
});
} else {
this.$router.back();
}
}
},
mounted() {
// Transaction ID
this.$nextTick(() => {
if (this.$refs.transactionInput) {
this.$refs.transactionInput.focus();
}
});
}
};
</script>
<style scoped>
/* 复用productionPickingDetail.vue的样式 */
.pda-container {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
background: #f5f5f5;
}
/* 头部栏 */
.header-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 16px;
background: #17B3A3;
color: white;
height: 40px;
min-height: 40px;
}
.header-left {
display: flex;
align-items: center;
cursor: pointer;
font-size: 16px;
font-weight: 500;
}
.header-left i {
margin-right: 8px;
font-size: 18px;
}
.header-right {
cursor: pointer;
font-size: 16px;
font-weight: 500;
}
/* 搜索容器 */
.search-container {
padding: 12px 16px;
background: white;
display: flex;
align-items: center;
gap: 12px;
}
.search-container .el-input {
flex: 1;
margin-right: 12px;
}
.big-button {
height: 30px; /* 默认大概 36px,可以改大 */
font-size: 12px; /* 字体大一点 */
padding: 0 10px; /* 横向内边距 */
border-radius: 14px; /* 圆角按钮 */
}
/* 紧凑型输入框样式 */
.compact-input ::v-deep .el-input__inner {
height: 36px;
padding: 0 12px 0 35px;
font-size: 14px;
}
.compact-input ::v-deep .el-input__prefix {
left: 10px;
}
.compact-input ::v-deep .el-input__suffix {
right: 30px;
}
/* 扫描容器 */
.scan-container {
padding: 12px 16px;
background: white;
margin: 4px 16px;
border-radius: 8px;
}
/* 物料信息卡片 */
.material-info-card {
background: white;
margin: 4px 16px;
padding: 6px 20px;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border: 1px solid #f0f0f0;
}
.card-title {
margin-bottom: 16px;
}
.title-label {
font-size: 11px;
color: #999;
display: block;
margin-bottom: 6px;
font-weight: normal;
}
.title-value {
font-size: 18px;
font-weight: bold;
color: #333;
line-height: 1.2;
margin-left: 20px;
}
.card-details {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 4px;
}
.detail-item {
flex: 1;
text-align: center;
min-width: 60px;
max-width: 60px;
}
.detail-label {
font-size: 11px;
color: #999;
margin-bottom: 6px;
font-weight: normal;
line-height: 1.2;
margin-left: -12px;
}
.detail-value {
font-size: 13px;
color: #333;
font-weight: 500;
line-height: 1.2;
margin-left: -12px;
}
.status-pending {
color: #E6A23C;
font-weight: 500;
}
/* 区域标题 */
.section-title {
display: flex;
align-items: center;
justify-content: space-between;
padding: 6px 8px;
background: white;
margin: 0 16px;
margin-top: 4px;
border-radius: 8px 8px 0 0;
border-bottom: 2px solid #17B3A3;
}
.title-left {
display: flex;
align-items: center;
}
.title-left i {
color: #17B3A3;
font-size: 16px;
margin-right: 8px;
}
.title-left span {
color: #17B3A3;
font-size: 14px;
font-weight: 500;
}
/* 标签列表 */
.label-list {
background: white;
margin: 0 16px 12px;
border-radius: 0 0 8px 8px;
overflow: hidden;
}
.list-header {
display: flex;
background: #f8f9fa;
padding: 12px 8px;
border-bottom: 1px solid #e0e0e0;
font-size: 12px;
color: #666;
font-weight: 500;
}
.list-item {
display: flex;
padding: 12px 8px;
border-bottom: 1px solid #f0f0f0;
font-size: 12px;
color: #333;
}
.list-item:last-child {
border-bottom: none;
}
.col-no {
width: 20px;
text-align: center;
}
.col-label {
flex: 2;
text-align: center;
}
.col-part {
flex: 2;
text-align: center;
}
.col-unit {
width: 40px;
text-align: center;
}
.col-qty {
width: 60px;
text-align: center;
}
.col-status {
width: 60px;
text-align: center;
}
.status-success {
color: #67C23A;
font-weight: 500;
}
.empty-labels {
padding: 40px 20px;
text-align: center;
color: #999;
}
.empty-labels p {
margin: 0;
font-size: 14px;
}
/* 底部操作按钮 */
.bottom-actions {
display: flex;
padding: 16px;
gap: 20px;
background: white;
margin-top: auto;
}
.action-btn {
flex: 1;
padding: 12px;
border: 1px solid #17B3A3;
background: white;
color: #17B3A3;
border-radius: 20px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s ease;
}
.action-btn.primary {
background: #17B3A3;
color: white;
}
.action-btn:hover:not(:disabled) {
background: #17B3A3;
color: white;
}
.action-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.action-btn:active {
transform: scale(0.98);
}
/* 错误消息 */
.error-message {
display: flex;
align-items: center;
justify-content: center;
padding: 12px 16px;
background: #fef0f0;
color: #f56c6c;
margin: 0 16px;
border-radius: 4px;
font-size: 14px;
}
.error-message i {
margin-right: 8px;
font-size: 16px;
}
/* 响应式设计 */
@media (max-width: 360px) {
.header-bar {
padding: 8px 12px;
}
.search-container {
padding: 8px 12px;
}
.material-info-card {
margin: 4px 12px;
padding: 6px 16px;
}
.section-title {
margin: 0 12px;
margin-top: 4px;
}
.label-list {
margin: 0 12px 8px;
}
.card-details {
flex-wrap: wrap;
gap: 6px;
}
.detail-item {
flex: 0 0 48%;
margin-bottom: 6px;
min-width: 50px;
}
.list-header, .list-item {
font-size: 11px;
}
.col-label, .col-part {
flex: 1.5;
}
}
</style>

539
src/views/modules/other-transaction/scrap.vue

@ -0,0 +1,539 @@
<template>
<div class="pda-container">
<!-- 头部栏 -->
<div class="header-bar">
<div class="header-left" @click="$router.back()">
<i class="el-icon-arrow-left"></i>
<span>物料报废</span>
</div>
<div class="header-right" @click="$router.push({ path: '/' })">
首页
</div>
</div>
<!-- 扫描区域 -->
<div class="section-title">
<div class="title-left">
<i class="el-icon-scan"></i>
<span>扫描箱/卷标签</span>
</div>
</div>
<!-- 扫描输入框 -->
<div class="scan-container">
<el-input clearable class="compact-input"
v-model="scanCode"
placeholder="请扫描箱/卷标签"
prefix-icon="el-icon-scan"
@keyup.enter.native="handleScan"
ref="scanInput"
/>
</div>
<!-- 标签列表 -->
<div class="label-list" v-if="labelList.length > 0">
<div class="list-header">
<div class="col-no">NO.</div>
<div class="col-label">标签条码</div>
<div class="col-part">物料编码</div>
<div class="col-unit">单位</div>
<div class="col-qty">数量</div>
<div class="col-status">状态</div>
</div>
<div
v-for="(label, index) in labelList"
:key="label.id"
class="list-item"
>
<div class="col-no">{{ labelList.length - index }}</div>
<div class="col-label">{{ label.labelCode }}</div>
<div class="col-part">{{ label.partNo }}</div>
<div class="col-unit">{{ label.unit || '个' }}</div>
<div class="col-qty">{{ label.quantity }}</div>
<div class="col-status">
<span class="status-pending">待报废</span>
</div>
</div>
</div>
<!-- 报废原因选择 -->
<div class="section-title" v-if="labelList.length > 0">
<div class="title-left">
<i class="el-icon-warning"></i>
<span>选择报废原因</span>
</div>
</div>
<!-- 报废原因选择器 -->
<div class="reason-container" v-if="labelList.length > 0">
<el-select
v-model="selectedReason"
placeholder="请选择报废原因"
class="reason-select"
@change="handleReasonChange"
>
<el-option
v-for="reason in scrapReasons"
:key="reason.value"
:label="reason.label"
:value="reason.value"
/>
</el-select>
</div>
<!-- 底部操作按钮 -->
<div class="bottom-actions" v-if="labelList.length > 0">
<button class="action-btn primary" @click="confirmScrap" :disabled="!selectedReason">
确认报废
</button>
<button class="action-btn secondary" @click="cancelScrap">
取消
</button>
</div>
<!-- 错误提示 -->
<div v-if="errorMessage" class="error-message">
<i class="el-icon-warning"></i>
<span>{{ errorMessage }}</span>
</div>
</div>
</template>
<script>
import { scanScrapLabel, confirmScrap } from '@/api/other-transaction/scrap';
export default {
data() {
return {
scanCode: '',
labelList: [],
selectedReason: '',
scrapReasons: [
{ value: 'DAMAGED', label: '物料损坏' },
{ value: 'EXPIRED', label: '物料过期' },
{ value: 'QUALITY_ISSUE', label: '质量问题' },
{ value: 'OBSOLETE', label: '物料过时' },
{ value: 'PROCESS_DEFECT', label: '工艺缺陷' },
{ value: 'OTHER', label: '其他原因' }
],
errorMessage: ''
};
},
methods: {
//
handleScan() {
if (!this.scanCode.trim()) {
return;
}
this.validateAndAddLabel(this.scanCode.trim());
this.scanCode = '';
},
//
validateAndAddLabel(labelCode) {
//
const exists = this.labelList.find(item => item.labelCode === labelCode);
if (exists) {
this.$message.warning('该标签已扫描,请勿重复扫描');
return;
}
const params = {
labelCode: labelCode,
site: this.$store.state.user.site,
};
scanScrapLabel(params).then(({ data }) => {
if (data && data.code === 0) {
//
this.labelList.push({
id: Date.now(),
labelCode: labelCode,
partNo: data.labelInfo.partNo,
partDesc: data.labelInfo.partDesc,
quantity: data.labelInfo.quantity,
unit: data.labelInfo.unit,
batchNo: data.labelInfo.batchNo,
locationId: data.labelInfo.locationId,
warehouseId: data.labelInfo.warehouseId
});
this.$message.success('扫描成功');
} else {
this.$message.error(data.msg || '该标签无效,请检查');
}
}).catch(error => {
this.$message.error('扫描失败');
});
},
//
handleReasonChange(value) {
this.selectedReason = value;
},
//
confirmScrap() {
if (this.labelList.length === 0) {
this.$message.warning('请先扫描标签');
return;
}
if (!this.selectedReason) {
this.$message.warning('请选择报废原因');
return;
}
this.$confirm('确认报废所有扫描的标签吗?此操作不可撤销!', '警告', {
confirmButtonText: '确认报废',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const params = {
site: this.$store.state.user.site,
scrapReason: this.selectedReason,
labels: this.labelList.map(label => ({
labelCode: label.labelCode,
quantity: label.quantity,
batchNo: label.batchNo,
partNo: label.partNo,
locationId: label.locationId,
warehouseId: label.warehouseId
}))
};
confirmScrap(params).then(({ data }) => {
if (data && data.code === 0) {
this.$message.success('报废成功');
this.$router.back();
} else {
this.$message.error(data.msg || '报废失败');
}
}).catch(error => {
console.error('报废确认失败:', error);
this.$message.error('报废失败');
});
}).catch(() => {
//
});
},
//
cancelScrap() {
if (this.labelList.length > 0) {
this.$confirm('取消后将清空已扫描的标签,确定取消吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '继续操作',
type: 'warning'
}).then(() => {
this.$router.back();
}).catch(() => {
//
});
} else {
this.$router.back();
}
}
},
mounted() {
//
this.$nextTick(() => {
if (this.$refs.scanInput) {
this.$refs.scanInput.focus();
}
});
}
};
</script>
<style scoped>
/* 复用receiveFromTransit.vue的样式 */
.pda-container {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
background: #f5f5f5;
}
/* 头部栏 */
.header-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 16px;
background: #17b3a3;
color: white;
height: 40px;
min-height: 40px;
}
.header-left {
display: flex;
align-items: center;
cursor: pointer;
font-size: 16px;
font-weight: 500;
}
.header-left i {
margin-right: 8px;
font-size: 18px;
}
.header-right {
cursor: pointer;
font-size: 16px;
font-weight: 500;
}
/* 扫描容器 */
.scan-container {
padding: 12px 16px;
background: white;
margin: 4px 16px;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border: 1px solid #f0f0f0;
}
/* 紧凑型输入框样式 */
.compact-input ::v-deep .el-input__inner {
height: 36px;
padding: 0 12px 0 35px;
font-size: 14px;
border-radius: 18px;
border: 1px solid #e0e0e0;
transition: all 0.2s ease;
}
.compact-input ::v-deep .el-input__inner:focus {
border-color: #17b3a3;
box-shadow: 0 0 0 2px rgba(255, 76, 82, 0.1);
}
.compact-input ::v-deep .el-input__prefix {
left: 10px;
}
.compact-input ::v-deep .el-input__suffix {
right: 30px;
}
/* 区域标题 */
.section-title {
display: flex;
align-items: center;
justify-content: space-between;
padding: 6px 8px;
background: white;
margin: 0 16px;
margin-top: 4px;
border-radius: 8px 8px 0 0;
border-bottom: 2px solid #17b3a3;
}
.title-left {
display: flex;
align-items: center;
}
.title-left i {
color: #17b3a3;
font-size: 16px;
margin-right: 8px;
}
.title-left span {
color: #17b3a3;
font-size: 14px;
font-weight: 500;
}
/* 标签列表 */
.label-list {
background: white;
margin: 0 16px 12px;
border-radius: 0 0 8px 8px;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border: 1px solid #f0f0f0;
}
.list-header {
display: flex;
background: #f8f9fa;
padding: 12px 8px;
border-bottom: 1px solid #e0e0e0;
font-size: 12px;
color: #666;
font-weight: 500;
}
.list-item {
display: flex;
padding: 12px 8px;
border-bottom: 1px solid #f0f0f0;
font-size: 12px;
color: #333;
}
.list-item:last-child {
border-bottom: none;
}
.col-no {
width: 20px;
text-align: center;
}
.col-label {
flex: 2;
text-align: center;
}
.col-part {
flex: 2;
text-align: center;
}
.col-unit {
width: 40px;
text-align: center;
}
.col-qty {
width: 60px;
text-align: center;
}
.col-status {
width: 60px;
text-align: center;
}
.status-pending {
color: #E6A23C;
font-weight: 500;
}
/* 报废原因选择器 */
.reason-container {
padding: 12px 16px;
background: white;
margin: 4px 16px;
border-radius: 0 0 8px 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border: 1px solid #f0f0f0;
}
.reason-select {
width: 100%;
}
.reason-select ::v-deep .el-input__inner {
height: 36px;
border-radius: 18px;
border: 1px solid #e0e0e0;
transition: all 0.2s ease;
}
.reason-select ::v-deep .el-input__inner:focus {
border-color: #FF4C52;
box-shadow: 0 0 0 2px rgba(255, 76, 82, 0.1);
}
/* 底部操作按钮 */
.bottom-actions {
display: flex;
padding: 16px;
gap: 20px;
background: white;
margin-top: auto;
}
.action-btn {
flex: 1;
padding: 12px;
border: 1px solid #FF4C52;
background: white;
color: #FF4C52;
border-radius: 20px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s ease;
}
.action-btn.primary {
background: #FF4C52;
color: white;
}
.action-btn:hover:not(:disabled) {
background: #FF4C52;
color: white;
}
.action-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.action-btn:active {
transform: scale(0.98);
}
/* 错误消息 */
.error-message {
display: flex;
align-items: center;
justify-content: center;
padding: 12px 16px;
background: #fef0f0;
color: #f56c6c;
margin: 0 16px;
border-radius: 4px;
font-size: 14px;
}
.error-message i {
margin-right: 8px;
font-size: 16px;
}
/* 响应式设计 */
@media (max-width: 360px) {
.header-bar {
padding: 8px 12px;
}
.scan-container {
padding: 8px 12px;
margin: 4px 12px;
}
.reason-container {
margin: 4px 12px;
}
.section-title {
margin: 0 12px;
margin-top: 4px;
}
.label-list {
margin: 0 12px 8px;
}
.list-header, .list-item {
font-size: 11px;
}
.col-label, .col-part {
flex: 1.5;
}
}
</style>

597
src/views/modules/sales-return/sales-return-inbound.vue

@ -1,29 +1,44 @@
<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 class="header-bar">
<div class="header-left" @click="handleBack">
<i class="el-icon-arrow-left"></i>
<span>销售退货入库</span>
</div>
<div class="header-right" @click="$router.push({ path: '/' })">
首页
</div>
</div>
<!-- 搜索框 -->
<div class="search-container">
<el-input
v-model="scanRma"
placeholder="扫描RMA条码或输入RMA号"
prefix-icon="el-icon-search"
@keyup.enter.native="searchRmaList"
ref="scanRmaRef"
clearable
/>
</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">
<div class="list-title">选择RMA明细行号</div>
<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-row v-for="(rmaDetail, index) in rmaList[0].detailList" :key="index" class="rma-row">
<el-col :span="24">
<el-button type="primary" size="mini" @click="addToReturnList(rmaDetail)" :disabled="isInReturnList(rmaDetail)">添加到退货明细</el-button>
<div class="rma-item" @click="selectRmaDetail(rmaDetail)" :class="{ 'selected': selectedDetail && selectedDetail.partNo === rmaDetail.partNo }">
<div class="item-info">
<span class="part-no">{{ rmaDetail.partNo }}</span>
<span class="batch-qty">批号:{{ rmaDetail.batchNo }} | 数量:{{ rmaDetail.processQty }}</span>
</div>
<div class="item-status">
<i class="el-icon-check" v-if="isInReturnList(rmaDetail)"></i>
</div>
</div>
</el-col>
</el-row>
</el-form>
@ -37,34 +52,85 @@
<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="detail-info">
<div class="info-row">
<span class="info-label">物料:</span>
<span class="info-value">{{ detail.partNo }}</span>
</div>
<div class="info-row">
<span class="info-label">数量:</span>
<span class="info-value">{{ detail.processQty }}</span>
</div>
<div class="info-row">
<span class="info-label">批号:</span>
<span class="info-value">{{ detail.batchNo }}</span>
</div>
</div>
<!-- 包装单元和库位 -->
<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 class="pack-actions">
<!-- 创建包装单元 -->
<div class="action-group">
<div class="action-title">创建包装单元</div>
<el-row :gutter="6">
<el-col :span="10">
<el-input v-model="detail.newPackCode" placeholder="包装编码" size="small" />
</el-col>
<el-col :span="8">
<el-input v-model="detail.newPackQty" placeholder="数量" type="number" size="small" />
</el-col>
<el-col :span="6">
<el-button type="primary" size="small" @click="createPackUnit(detail)" :disabled="!detail.newPackCode || !detail.newPackQty">创建</el-button>
</el-col>
</el-row>
</div>
<!-- 扫描包装单元 -->
<div class="action-group" v-if="detail.packUnitList.length > 0">
<div class="action-title">扫描包装单元</div>
<el-row :gutter="6">
<el-col :span="18">
<el-input
v-model="detail.scanPackCode"
placeholder="扫描包装单元条码"
prefix-icon="el-icon-scan"
size="small"
@keyup.enter.native="scanPackUnit(detail)"
/>
</el-col>
<el-col :span="6">
<el-button type="primary" size="small" @click="scanPackUnit(detail)" :disabled="!detail.scanPackCode">扫描</el-button>
</el-col>
</el-row>
</div>
<!-- 库位指定 -->
<div class="action-group">
<div class="action-title">指定库位</div>
<el-input
v-model="detail.locationNo"
placeholder="请扫描或输入库位编码"
prefix-icon="el-icon-location"
size="small"
/>
</div>
</div>
<!-- 包装单元列表 -->
<div v-if="detail.packUnitList.length > 0" class="pack-list">
<div v-for="(pack, pIdx) in detail.packUnitList" :key="pIdx" class="pack-item">
{{ pack.code }} ({{ pack.qty }})
<span :class="pack.scanned ? 'status-ok' : 'status-wait'">
{{ pack.scanned ? '✓' : '○' }}
</span>
<el-button type="text" @click="removePackUnit(detail, pIdx)" class="delete-btn">删除</el-button>
</div>
</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>
<el-button type="success" class="submit-btn" @click="submitReturn">确认入库</el-button>
</div>
</div>
</div>
@ -78,9 +144,21 @@ export default {
return {
scanRma: "",
rmaList: [],
returnList: [] // 退
returnList: [], // 退
selectedDetail: null, // RMA
processType: "inbound" //
};
},
computed: {
processTypeText() {
const typeMap = {
'inbound': '入库',
'scrap': '报废',
'repair': '返修'
};
return typeMap[this.processType] || '处理';
}
},
methods: {
handleBack() {
this.$router.back();
@ -91,6 +169,15 @@ export default {
if (data.code === 0) this.rmaList = data.rows;
});
},
// RMA
selectRmaDetail(rmaDetail) {
this.selectedDetail = rmaDetail;
// 退
if (!this.isInReturnList(rmaDetail)) {
this.addToReturnList(rmaDetail);
}
this.$message.success(`已选择物料: ${rmaDetail.partNo}`);
},
addToReturnList(rmaDetail) {
//
if (this.isInReturnList(rmaDetail)) return;
@ -101,7 +188,10 @@ export default {
batchNo: rmaDetail.batchNo,
locationNo: "",
warehouseId: "",
packUnitList: []
packUnitList: [],
newPackCode: "",
newPackQty: "",
scanPackCode: ""
});
},
isInReturnList(rmaDetail) {
@ -112,6 +202,82 @@ export default {
removeDetail(idx) {
this.returnList.splice(idx, 1);
},
//
createPackUnit(detail) {
if (!detail.newPackCode || !detail.newPackQty) {
this.$message.warning('请输入包装编码和数量');
return;
}
//
const exists = detail.packUnitList.find(pack => pack.code === detail.newPackCode);
if (exists) {
this.$message.error('包装编码已存在');
return;
}
detail.packUnitList.push({
code: detail.newPackCode,
qty: parseFloat(detail.newPackQty),
scanned: false,
createTime: new Date()
});
//
detail.newPackCode = "";
detail.newPackQty = "";
this.$message.success('包装单元创建成功');
},
//
printLabel(detail) {
const unPrintedPacks = detail.packUnitList.filter(pack => !pack.printed);
if (unPrintedPacks.length === 0) {
this.$message.warning('没有需要打印的标签');
return;
}
this.$message.success(`正在打印 ${unPrintedPacks.length} 个标签...`);
// API
// printLabel({
// rmaNo: this.scanRma,
// partNo: detail.partNo,
// packCodes: unPrintedPacks.map(p => p.code)
// });
//
unPrintedPacks.forEach(pack => {
pack.printed = true;
});
},
//
scanPackUnit(detail) {
if (!detail.scanPackCode) {
this.$message.warning('请输入要扫描的包装单元条码');
return;
}
const pack = detail.packUnitList.find(p => p.code === detail.scanPackCode);
if (!pack) {
this.$message.error('未找到对应的包装单元');
return;
}
if (pack.scanned) {
this.$message.warning('该包装单元已经扫描过了');
return;
}
pack.scanned = true;
pack.scanTime = new Date();
detail.scanPackCode = "";
this.$message.success('扫描成功');
},
addPackUnit(detail) {
detail.packUnitList.push({code: "", qty: '', perQty: '', packageQty: ''});
},
@ -123,18 +289,66 @@ export default {
this.$message.error("请先扫描RMA号并选择退货明细");
return;
}
processReturn({
//
const missingLocation = this.returnList.some(detail => !detail.locationNo || !detail.locationNo.trim());
if (missingLocation) {
this.$message.error("请为每个明细指定库位");
return;
}
//
const hasUnscannedPacks = this.returnList.some(detail =>
detail.packUnitList.length > 0 && detail.packUnitList.some(pack => !pack.scanned)
);
if (hasUnscannedPacks) {
this.$message.error("请先扫描所有包装单元");
return;
}
const submitData = {
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);
processType: this.processType,
detailList: this.returnList.map(detail => ({
...detail,
packUnitList: detail.packUnitList.filter(pack => pack.scanned)
}))
};
this.$confirm(`确认执行${this.processTypeText}操作吗?`, '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
processReturn(submitData).then(({data}) => {
if (data.code === 0) {
this.$message.success(`${this.processTypeText}成功`);
this.resetForm();
} else {
this.$message.error(data.msg || `${this.processTypeText}失败`);
}
}).catch(error => {
console.error('提交失败:', error);
this.$message.error(`${this.processTypeText}失败`);
});
}).catch(() => {
//
});
},
//
resetForm() {
this.scanRma = "";
this.rmaList = [];
this.returnList = [];
this.selectedDetail = null;
this.processType = "inbound";
//
this.$nextTick(() => {
if (this.$refs.scanRmaRef) {
this.$refs.scanRmaRef.focus();
}
});
}
@ -149,24 +363,118 @@ export default {
.pda-container {
background: #f5f5f5;
min-height: 100vh;
padding-bottom: 20px;
}
.status-bar {
/* 头部栏 - 参考原有样式 */
.header-bar {
display: flex;
justify-content: space-between;
align-items: center;
background: #17b3a3;
color: #fff;
padding: 8px 12px;
padding: 12px 16px;
font-size: 16px;
}
.return-list-title {
.header-left {
display: flex;
align-items: center;
cursor: pointer;
}
.header-left i {
margin-right: 8px;
font-size: 18px;
}
.header-right {
cursor: pointer;
}
/* 搜索容器 */
.search-container {
padding: 12px 16px;
background: white;
}
.search-container .el-input {
font-size: 16px;
}
/* RMA明细选择 */
.rma-list {
padding: 0 16px;
}
.list-title {
font-size: 16px;
font-weight: bold;
color: #17b3a3;
margin: 12px 0 8px 0;
}
.rma-row {
margin-bottom: 8px;
}
.rma-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
background: white;
border-radius: 6px;
cursor: pointer;
border: 1px solid #e0e0e0;
min-height: 60px;
}
.rma-item.selected {
border-color: #17b3a3;
background: #f0f9ff;
}
.rma-item:active {
background: #e6f7ff;
}
.item-info {
flex: 1;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.part-no {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 4px;
}
.batch-qty {
font-size: 14px;
color: #666;
}
.item-status {
font-size: 20px;
color: #17b3a3;
}
/* 退货明细列表 */
.return-list-title {
font-size: 16px;
font-weight: bold;
color: #17b3a3;
margin: 12px 16px 8px 16px;
}
.detail-card {
margin: 0 16px 12px 16px;
}
.detail-header {
font-weight: bold;
font-size: 15px;
@ -175,11 +483,182 @@ export default {
padding-left: 8px;
}
/* 明细信息显示 */
.detail-info {
margin-bottom: 12px;
}
.info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 6px 0;
border-bottom: 1px solid #f0f0f0;
}
.info-row:last-child {
border-bottom: none;
}
.info-label {
font-size: 14px;
color: #666;
font-weight: 500;
}
.info-value {
font-size: 14px;
color: #333;
font-weight: 500;
}
/* 包装单元区域 */
.pack-unit-area {
margin-top: 0;
padding: 12px;
background: #f8f9fa;
border-radius: 6px;
}
.pack-actions {
margin-bottom: 8px;
}
.action-group {
margin-bottom: 10px;
}
.action-group:last-child {
margin-bottom: 0;
}
.action-title {
font-size: 13px;
color: #17b3a3;
font-weight: 500;
margin-bottom: 6px;
}
.action-group .el-input {
height: 32px;
}
.action-group .el-button {
height: 32px;
font-size: 12px;
padding: 8px 12px;
}
.pack-list {
margin-top: 8px;
}
.pack-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px;
margin-bottom: 6px;
background: white;
border-radius: 4px;
border: 1px solid #e0e0e0;
font-size: 13px;
}
.status-ok {
color: #67C23A;
font-weight: bold;
font-size: 16px;
}
.status-wait {
color: #E6A23C;
font-weight: bold;
font-size: 16px;
}
.delete-btn {
color: #F56C6C;
padding: 0;
font-size: 12px;
}
/* 库位区域 */
.location-section {
margin: 16px;
padding: 16px;
background: white;
border-radius: 6px;
}
.section-label {
font-size: 16px;
font-weight: bold;
color: #17b3a3;
margin-bottom: 12px;
}
.location-input {
font-size: 16px;
}
.location-input .el-input__inner {
height: 44px;
font-size: 16px;
}
/* 提交按钮 */
.submit-btn {
width: 100%;
width: calc(100% - 32px);
margin: 16px 16px 12px 16px;
height: 44px;
font-size: 16px;
margin-top: 18px;
background: #17b3a3;
color: #fff;
border-color: #17b3a3;
border-radius: 6px;
}
.submit-btn:hover {
background: #15a093;
border-color: #15a093;
}
/* PDA适配 - 增大触摸目标 */
.el-input__inner {
height: 44px;
font-size: 16px;
padding: 0 15px;
}
.el-button {
min-height: 40px;
padding: 10px 16px;
font-size: 14px;
}
.el-button--primary {
background-color: #17b3a3;
border-color: #17b3a3;
}
.el-button--primary:hover {
background-color: #15a093;
border-color: #15a093;
}
/* 表单项间距优化 */
.el-form-item {
margin-bottom: 12px;
}
.el-form-item__label {
font-size: 14px;
color: #333;
font-weight: 500;
}
/* 主内容区域 */
.main-content {
padding-bottom: 12px;
}
</style>

545
src/views/modules/sales-return/sales-return-scrap.vue

@ -1,24 +1,45 @@
<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 class="header-bar">
<div class="header-left" @click="handleBack">
<i class="el-icon-arrow-left"></i>
<span>销售退货报废</span>
</div>
<div class="header-right" @click="$router.push({ path: '/' })">
首页
</div>
</div>
<!-- 搜索框 -->
<div class="search-container">
<el-input
v-model="scanRma"
placeholder="扫描RMA条码或输入RMA号"
prefix-icon="el-icon-search"
@keyup.enter.native="searchRmaList"
ref="scanRmaRef"
clearable
/>
</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">
<div class="list-title">选择RMA明细行号</div>
<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-row v-for="(rmaDetail, index) in rmaList[0].detailList" :key="index" class="rma-row">
<el-col :span="24">
<el-button type="primary" size="mini" @click="addToReturnList(rmaDetail)" :disabled="isInReturnList(rmaDetail)">添加到退货明细</el-button>
<div class="rma-item" @click="selectRmaDetail(rmaDetail)" :class="{ 'selected': selectedDetail && selectedDetail.partNo === rmaDetail.partNo }">
<div class="item-info">
<span class="part-no">{{ rmaDetail.partNo }}</span>
<span class="batch-qty">批号:{{ rmaDetail.batchNo }} | 数量:{{ rmaDetail.processQty }}</span>
</div>
<div class="item-status">
<i class="el-icon-check" v-if="isInReturnList(rmaDetail)"></i>
</div>
</div>
</el-col>
</el-row>
</el-form>
@ -32,18 +53,86 @@
<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>
<div class="detail-info">
<div class="info-row">
<span class="info-label">物料:</span>
<span class="info-value">{{ detail.partNo }}</span>
</div>
<div class="info-row">
<span class="info-label">数量:</span>
<span class="info-value">{{ detail.processQty }}</span>
</div>
<div class="info-row">
<span class="info-label">批号:</span>
<span class="info-value">{{ detail.batchNo }}</span>
</div>
</div>
<!-- 包装单元和报废原因 -->
<div class="pack-unit-area">
<div class="pack-actions">
<!-- 创建包装单元 -->
<div class="action-group">
<div class="action-title">创建包装单元</div>
<el-row :gutter="6">
<el-col :span="10">
<el-input v-model="detail.newPackCode" placeholder="包装编码" size="small" />
</el-col>
<el-col :span="8">
<el-input v-model="detail.newPackQty" placeholder="数量" type="number" size="small" />
</el-col>
<el-col :span="6">
<el-button type="primary" size="small" @click="createPackUnit(detail)" :disabled="!detail.newPackCode || !detail.newPackQty">创建</el-button>
</el-col>
</el-row>
</div>
<!-- 扫描包装单元 -->
<div class="action-group" v-if="detail.packUnitList.length > 0">
<div class="action-title">扫描包装单元</div>
<el-row :gutter="6">
<el-col :span="18">
<el-input
v-model="detail.scanPackCode"
placeholder="扫描包装单元条码"
prefix-icon="el-icon-scan"
size="small"
@keyup.enter.native="scanPackUnit(detail)"
/>
</el-col>
<el-col :span="6">
<el-button type="primary" size="small" @click="scanPackUnit(detail)" :disabled="!detail.scanPackCode">扫描</el-button>
</el-col>
</el-row>
</div>
<!-- 报废原因选择 -->
<div class="action-group">
<div class="action-title">报废原因</div>
<el-select v-model="detail.scrapReason" placeholder="请选择报废原因" size="small" style="width: 100%">
<el-option label="物料损坏" value="DAMAGED"></el-option>
<el-option label="物料过期" value="EXPIRED"></el-option>
<el-option label="质量问题" value="QUALITY_ISSUE"></el-option>
<el-option label="物料过时" value="OBSOLETE"></el-option>
<el-option label="其他原因" value="OTHER"></el-option>
</el-select>
</div>
</div>
<!-- 包装单元列表 -->
<div v-if="detail.packUnitList.length > 0" class="pack-list">
<div v-for="(pack, pIdx) in detail.packUnitList" :key="pIdx" class="pack-item">
{{ pack.code }} ({{ pack.qty }})
<span :class="pack.scanned ? 'status-ok' : 'status-wait'">
{{ pack.scanned ? '✓' : '○' }}
</span>
<el-button type="text" @click="removePackUnit(detail, pIdx)" class="delete-btn">删除</el-button>
</div>
</div>
</div>
</el-card>
</div>
<el-button type="success" class="submit-btn" @click="submitReturn">提交</el-button>
<el-button type="success" class="submit-btn" @click="submitReturn">确认报废</el-button>
</div>
</div>
</div>
@ -57,7 +146,9 @@ export default {
return {
scanRma: "",
rmaList: [],
returnList: []
returnList: [], // 退
selectedDetail: null, // RMA
processType: "scrap" //
};
},
methods: {
@ -70,6 +161,15 @@ export default {
if (data.code === 0) this.rmaList = data.rows;
});
},
// RMA
selectRmaDetail(rmaDetail) {
this.selectedDetail = rmaDetail;
// 退
if (!this.isInReturnList(rmaDetail)) {
this.addToReturnList(rmaDetail);
}
this.$message.success(`已选择物料: ${rmaDetail.partNo}`);
},
addToReturnList(rmaDetail) {
if (this.isInReturnList(rmaDetail)) return;
this.returnList.push({
@ -77,8 +177,11 @@ export default {
partNo: rmaDetail.partNo,
processQty: rmaDetail.processQty,
batchNo: rmaDetail.batchNo,
locationNo: "",
warehouseId: ""
scrapReason: "",
packUnitList: [],
newPackCode: "",
newPackQty: "",
scanPackCode: ""
});
},
isInReturnList(rmaDetail) {
@ -89,23 +192,130 @@ export default {
removeDetail(idx) {
this.returnList.splice(idx, 1);
},
//
createPackUnit(detail) {
if (!detail.newPackCode || !detail.newPackQty) {
this.$message.warning('请输入包装编码和数量');
return;
}
//
const exists = detail.packUnitList.find(pack => pack.code === detail.newPackCode);
if (exists) {
this.$message.error('包装编码已存在');
return;
}
detail.packUnitList.push({
code: detail.newPackCode,
qty: parseFloat(detail.newPackQty),
scanned: false,
createTime: new Date()
});
//
detail.newPackCode = "";
detail.newPackQty = "";
this.$message.success('包装单元创建成功');
},
//
scanPackUnit(detail) {
if (!detail.scanPackCode) {
this.$message.warning('请输入要扫描的包装单元条码');
return;
}
const pack = detail.packUnitList.find(p => p.code === detail.scanPackCode);
if (!pack) {
this.$message.error('未找到对应的包装单元');
return;
}
if (pack.scanned) {
this.$message.warning('该包装单元已经扫描过了');
return;
}
pack.scanned = true;
pack.scanTime = new Date();
detail.scanPackCode = "";
this.$message.success('扫描成功');
},
//
removePackUnit(detail, idx) {
detail.packUnitList.splice(idx, 1);
this.$message.success('包装单元已移除');
},
submitReturn() {
if (!this.scanRma || this.returnList.length === 0) {
this.$message.error("请先扫描RMA号并选择退货明细");
return;
}
processReturn({
//
const missingReason = this.returnList.some(detail => !detail.scrapReason);
if (missingReason) {
this.$message.error("请为每个明细选择报废原因");
return;
}
//
const hasUnscannedPacks = this.returnList.some(detail =>
detail.packUnitList.length > 0 && detail.packUnitList.some(pack => !pack.scanned)
);
if (hasUnscannedPacks) {
this.$message.error("请先扫描所有包装单元");
return;
}
const submitData = {
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);
processType: this.processType,
detailList: this.returnList.map(detail => ({
...detail,
packUnitList: detail.packUnitList.filter(pack => pack.scanned)
}))
};
this.$confirm('确认执行报废操作吗?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
processReturn(submitData).then(({ data }) => {
if (data.code === 0) {
this.$message.success('报废成功');
this.resetForm();
} else {
this.$message.error(data.msg || '报废失败');
}
}).catch(error => {
console.error('提交失败:', error);
this.$message.error('报废失败');
});
}).catch(() => {
//
});
},
//
resetForm() {
this.scanRma = "";
this.rmaList = [];
this.returnList = [];
this.selectedDetail = null;
this.processType = "scrap";
//
this.$nextTick(() => {
if (this.$refs.scanRmaRef) {
this.$refs.scanRmaRef.focus();
}
});
}
@ -120,24 +330,118 @@ export default {
.pda-container {
background: #f5f5f5;
min-height: 100vh;
padding-bottom: 20px;
}
.status-bar {
/* 头部栏 */
.header-bar {
display: flex;
justify-content: space-between;
align-items: center;
background: #17b3a3;
color: #fff;
padding: 8px 12px;
padding: 12px 16px;
font-size: 16px;
}
.return-list-title {
.header-left {
display: flex;
align-items: center;
cursor: pointer;
}
.header-left i {
margin-right: 8px;
font-size: 18px;
}
.header-right {
cursor: pointer;
}
/* 搜索容器 */
.search-container {
padding: 12px 16px;
background: white;
}
.search-container .el-input {
font-size: 16px;
}
/* RMA明细选择 */
.rma-list {
padding: 0 16px;
}
.list-title {
font-size: 16px;
font-weight: bold;
color: #17b3a3;
margin: 12px 0 8px 0;
}
.rma-row {
margin-bottom: 8px;
}
.rma-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
background: white;
border-radius: 6px;
cursor: pointer;
border: 1px solid #e0e0e0;
min-height: 60px;
}
.rma-item.selected {
border-color: #17b3a3;
background: #f0f9ff;
}
.rma-item:active {
background: #e6f7ff;
}
.item-info {
flex: 1;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.part-no {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 4px;
}
.batch-qty {
font-size: 14px;
color: #666;
}
.item-status {
font-size: 20px;
color: #17b3a3;
}
/* 退货明细列表 */
.return-list-title {
font-size: 16px;
font-weight: bold;
color: #17b3a3;
margin: 12px 16px 8px 16px;
}
.detail-card {
margin: 0 16px 12px 16px;
}
.detail-header {
font-weight: bold;
font-size: 15px;
@ -146,11 +450,168 @@ export default {
padding-left: 8px;
}
/* 明细信息显示 */
.detail-info {
margin-bottom: 12px;
}
.info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 6px 0;
border-bottom: 1px solid #f0f0f0;
}
.info-row:last-child {
border-bottom: none;
}
.info-label {
font-size: 14px;
color: #666;
font-weight: 500;
}
.info-value {
font-size: 14px;
color: #333;
font-weight: 500;
}
/* 包装单元区域 */
.pack-unit-area {
margin-top: 0;
padding: 12px;
background: #f8f9fa;
border-radius: 6px;
}
.pack-actions {
margin-bottom: 8px;
}
.action-group {
margin-bottom: 10px;
}
.action-group:last-child {
margin-bottom: 0;
}
.action-title {
font-size: 13px;
color: #17b3a3;
font-weight: 500;
margin-bottom: 6px;
}
.action-group .el-input {
height: 32px;
}
.action-group .el-button {
height: 32px;
font-size: 12px;
padding: 8px 12px;
}
.pack-list {
margin-top: 8px;
}
.pack-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px;
margin-bottom: 6px;
background: white;
border-radius: 4px;
border: 1px solid #e0e0e0;
font-size: 13px;
}
.status-ok {
color: #67C23A;
font-weight: bold;
font-size: 16px;
}
.status-wait {
color: #E6A23C;
font-weight: bold;
font-size: 16px;
}
.delete-btn {
color: #F56C6C;
padding: 0;
font-size: 12px;
}
/* 提交按钮 */
.submit-btn {
width: 100%;
width: calc(100% - 32px);
margin: 16px 16px 12px 16px;
height: 44px;
font-size: 16px;
margin-top: 18px;
background: #17b3a3;
color: #fff;
border-color: #17b3a3;
border-radius: 6px;
}
.submit-btn:hover {
background: #15a093;
border-color: #15a093;
}
/* PDA适配 - 增大触摸目标 */
.el-input__inner {
height: 44px;
font-size: 16px;
padding: 0 15px;
}
.el-button {
min-height: 40px;
padding: 10px 16px;
font-size: 14px;
}
.el-button--primary {
background-color: #17b3a3;
border-color: #17b3a3;
}
.el-button--primary:hover {
background-color: #15a093;
border-color: #15a093;
}
.el-button--danger {
background-color: #17b3a3;
border-color: #17b3a3;
}
.el-button--danger:hover {
background-color: #15a093;
border-color: #15a093;
}
/* 表单项间距优化 */
.el-form-item {
margin-bottom: 12px;
}
.el-form-item__label {
font-size: 14px;
color: #333;
font-weight: 500;
}
/* 主内容区域 */
.main-content {
padding-bottom: 12px;
}
</style>
Loading…
Cancel
Save