10 changed files with 2149 additions and 2 deletions
-
19src/api/customerIssue/customer-issue.js
-
6src/router/index.js
-
11src/views/main.vue
-
170src/views/modules/customerIssue/customerIssue.vue
-
659src/views/modules/customerIssue/customerIssuePDA.vue
-
1078src/views/modules/customerIssue/customerIssuePDAIssueList.vue
-
163src/views/modules/customerIssue/customerIssuePDAList.vue
-
3src/views/modules/production-return/productionReturnPDA.vue
-
26src/views/modules/production-return/productionReturnPDAIssueList.vue
-
16src/views/modules/production-return/productionReturnPDAList.vue
@ -0,0 +1,19 @@ |
|||
import { createAPI } from "@/utils/httpRequest.js"; |
|||
|
|||
|
|||
export const getCustomerIssueNotifyHeaderInfo = data => createAPI(`/pda/customerIssue/getCustomerIssueNotifyHeaderInfo`,'post',data) |
|||
|
|||
// 获取客户发料申请单物料清单
|
|||
export const getCustomerIssueNotifyHeaderOrderMaterialList = data => createAPI(`/pda/customerIssue/getCustomerIssueNotifyHeaderOrderMaterialList`,'post',data) |
|||
|
|||
// 获取客户发料物料记录
|
|||
export const getCustomerIssueMatericalForShopOrder = data => createAPI(`/pda/customerIssue/getCustomerIssueMatericalForShopOrder`,'post',data) |
|||
|
|||
// 扫描客户发料物料标签
|
|||
export const scanCustomerIssueMaterialLabel = data => createAPI(`/pda/customerIssue/scanCustomerIssueMaterialLabel`,'post',data) |
|||
|
|||
// 客户发料确认
|
|||
export const customerIssueConfirm = data => createAPI(`/pda/customerIssue/customerIssueConfirm`,'post',data) |
|||
|
|||
// 获取库存物料信息
|
|||
export const getInventoryPart = data => createAPI(`/pda/customerIssue/getInventoryPart`,'post',data) |
|||
@ -0,0 +1,170 @@ |
|||
<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="menu-grid"> |
|||
<div |
|||
class="menu-item" |
|||
v-for="(btn, index) in buttons" |
|||
:key="index" |
|||
:class="{ 'disabled': btn.disabled }" |
|||
@click="handleButtonClick(btn)" |
|||
> |
|||
<div class="menu-icon" :class="btn.iconClass"> |
|||
<van-icon :name="btn.icon" size="24" /> |
|||
</div> |
|||
<div class="menu-text">{{ btn.label }}</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
buttons: [ |
|||
/* { icon: 'scan', label: '直接发料', iconClass: 'direct', to: 'customerIssuePicking', disabled: true }, |
|||
{ icon: 'records', label: '申请单发料', iconClass: 'request', to: 'customerIssuePDA', disabled: false }, |
|||
{ icon: 'logistics', label: '移库发料', iconClass: 'move', to: 'customerIssuePicking', disabled: true }, |
|||
{ icon: 'revoke', label: '发料撤销', iconClass: 'cancel', to: 'customerIssuePicking', disabled: true }, */ |
|||
{ icon: 'records', label: '申请单发料', iconClass: 'request', to: 'customerIssuePDA', disabled: false }, |
|||
] |
|||
} |
|||
}, |
|||
methods: { |
|||
handleButtonClick(btn) { |
|||
if (btn.disabled) { |
|||
this.$message.warning('正在开发中,敬请期待...'); |
|||
} else { |
|||
this.$router.push(btn.to); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
:root { |
|||
--columns: 3; |
|||
--button-size: calc(100vw / var(--columns) - 20px); |
|||
} |
|||
|
|||
/* 头部栏 */ |
|||
.header-bar { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 8px 16px; |
|||
background: #17B3A3; |
|||
color: white; |
|||
height: 40px; |
|||
min-height: 40px; |
|||
max-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; |
|||
} |
|||
|
|||
.menu-grid { |
|||
display: grid; |
|||
grid-template-columns: repeat(2, 1fr); |
|||
gap: 15px; |
|||
padding: 20px; |
|||
justify-content: center; |
|||
align-content: center; |
|||
width: 100%; |
|||
} |
|||
|
|||
.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; |
|||
} |
|||
|
|||
.menu-item:active { |
|||
transform: scale(0.95); |
|||
} |
|||
|
|||
.menu-item.disabled { |
|||
opacity: 0.6; |
|||
position: relative; |
|||
} |
|||
|
|||
.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; |
|||
} |
|||
|
|||
.menu-icon { |
|||
width: 38px; |
|||
height: 38px; |
|||
border-radius: 50%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin: 0 auto 6px; |
|||
color: white; |
|||
} |
|||
|
|||
.menu-icon.direct { |
|||
background: linear-gradient(135deg, #17b3a3 0%, #1dc5ef 100%); |
|||
} |
|||
|
|||
.menu-icon.request { |
|||
background: linear-gradient(135deg, #17b3a3 0%, #1dc5ef 100%); |
|||
} |
|||
|
|||
.menu-icon.move { |
|||
background: linear-gradient(135deg, #17b3a3 0%, #1dc5ef 100%); |
|||
} |
|||
|
|||
.menu-icon.cancel { |
|||
background: linear-gradient(135deg, #17b3a3 0%, #1dc5ef 100%); |
|||
} |
|||
|
|||
.menu-text { |
|||
font-size: 10px; |
|||
color: #333; |
|||
font-weight: bold; |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
margin-top: 2px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,659 @@ |
|||
<template> |
|||
<div class="pda-container"> |
|||
<!-- 头部栏 --> |
|||
<div class="header-bar"> |
|||
<div class="header-left" @click="goBack"> |
|||
<i class="el-icon-arrow-left"></i> |
|||
<span>{{ functionTitle }}</span> |
|||
</div> |
|||
<div class="header-right" @click="$router.push({ path: '/' })">首页</div> |
|||
</div> |
|||
|
|||
<!-- 申请单输入 --> |
|||
<div class="search-container"> |
|||
<el-input clearable v-model="requestIssueForm.requestNo" placeholder="请输入客户单号" prefix-icon="el-icon-search" |
|||
@keyup.enter.native="loadIssueRequestMaterials" ref="requestNoInput" /> |
|||
</div> |
|||
|
|||
<!-- 申请单物料列表 --> |
|||
<div class="work-order-list" v-if="issueRequestMaterials.length > 0 "> |
|||
<div v-for="material in displayIssueRequestMaterials" :key="`${material.partNo}-${material.itemNo}`" |
|||
:class="['work-order-card', { selected: selectedRequestMaterial && isSameRequestMaterial(selectedRequestMaterial, material) }]" @click="selectRequestMaterial(material)"> |
|||
<div class="card-title"> |
|||
<span class="title-label">申请单号:{{ material.notifyNo }} </span> |
|||
</div> |
|||
|
|||
<!-- 工单号单独一行 --> |
|||
<div class="part-desc-row"> |
|||
<span class="desc-text">客户订单号:{{ material.soorderNo }}</span> |
|||
</div> |
|||
|
|||
<div class="card-details"> |
|||
<div class="detail-item"> |
|||
<div class="detail-label">申请数量</div> |
|||
<div class="detail-value">{{ material.unissureQty }}</div> |
|||
</div> |
|||
<div class="detail-item"> |
|||
<div class="detail-label">状态</div> |
|||
<div class="detail-value">待发料</div> |
|||
</div> |
|||
<div class="detail-item"> |
|||
<div class="detail-label">单位</div> |
|||
<div class="detail-value">{{ material.uom || "个" }}</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- 材料列表(新增,仿 directIssue.vue) --> |
|||
<div |
|||
class="content-area" |
|||
v-if="selectedWorkOrder && materialList.length > 0" |
|||
> |
|||
<div |
|||
v-for="(material, index) in materialList" |
|||
:key="index" |
|||
class="material-card" |
|||
@click="openIssueDetail(material)" |
|||
> |
|||
<div class="card-title"> |
|||
<span class="title-label" |
|||
>物料编码:{{ material.componentPartNo }} 行号:{{ |
|||
material.bomItemNo |
|||
}}</span |
|||
> |
|||
</div> |
|||
|
|||
<!-- 物料描述单独一行 --> |
|||
<div class="part-desc-row"> |
|||
<span class="desc-text">{{ material.componentPartDesc }}</span> |
|||
</div> |
|||
|
|||
<div class="card-details"> |
|||
<div class="detail-item"> |
|||
<div class="detail-label">需求数量</div> |
|||
<div class="detail-value">{{ material.qtyToIssue }}</div> |
|||
</div> |
|||
<div class="detail-item"> |
|||
<div class="detail-label">已发数量</div> |
|||
<div class="detail-value">{{ material.qtyIssued || 0 }}</div> |
|||
</div> |
|||
<div class="detail-item"> |
|||
<div class="detail-label">单位</div> |
|||
<div class="detail-value">{{ material.uom || "个" }}</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 空状态 --> |
|||
<div |
|||
v-if="selectedWorkOrder && materialList.length === 0" |
|||
class="empty-state" |
|||
> |
|||
<i class="el-icon-box"></i> |
|||
<p>该申请单暂无材料清单</p> |
|||
</div> |
|||
|
|||
<!-- 加载状态 --> |
|||
<div v-if="loading" class="loading-state"> |
|||
<i class="el-icon-loading"></i> |
|||
<p>加载中...</p> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { |
|||
getCustomerIssueNotifyHeaderInfo, |
|||
getCustomerIssueNotifyHeaderOrderMaterialList, |
|||
} from '@/api/customerIssue/customer-issue' |
|||
import { getWorkOrderMaterials } from '@/api/production/production-issue' |
|||
|
|||
export default { |
|||
name: 'customerIssuePDA', |
|||
data() { |
|||
return { |
|||
loading: false, |
|||
loadingText: '', |
|||
message: '', |
|||
messageType: 'info', |
|||
|
|||
// 基于申请单发料 |
|||
requestIssueForm: { |
|||
site: localStorage.getItem('site'), |
|||
requestNo: '', |
|||
operatorName: 'PDA_USER', |
|||
issueReason: '', |
|||
targetLocation: '', |
|||
remark: '', |
|||
createLabel: false, |
|||
printerName: '', |
|||
}, |
|||
issueRequestMaterials: [], |
|||
selectedRequestMaterial: null, |
|||
selectedWorkOrder:'', |
|||
materialList: [], // 新增:材料清单 |
|||
showOnlySelected: false, |
|||
} |
|||
}, |
|||
computed: { |
|||
functionTitle() { |
|||
return '客户单发料' |
|||
}, |
|||
displayIssueRequestMaterials() { |
|||
if (this.showOnlySelected && this.selectedRequestMaterial) { |
|||
return [this.selectedRequestMaterial] |
|||
} |
|||
return this.issueRequestMaterials |
|||
} |
|||
}, |
|||
methods: { |
|||
goBack() { |
|||
this.$router.back() |
|||
}, |
|||
|
|||
goBackToMaterials() { |
|||
this.selectedRequestMaterial = null |
|||
}, |
|||
|
|||
resetAll() { |
|||
this.issueRequestMaterials = [] |
|||
this.selectedRequestMaterial = null |
|||
this.message = '' |
|||
}, |
|||
|
|||
// 基于申请单发料相关方法 |
|||
async loadIssueRequestMaterials() { |
|||
if (!this.requestIssueForm.requestNo) { |
|||
this.showMessage('请输入发料申请单号', 'error') |
|||
return |
|||
} |
|||
|
|||
this.loading = true |
|||
this.loadingText = '加载申请单物料...' |
|||
this.issueRequestMaterials = [] |
|||
this.materialList = [] |
|||
this.selectedRequestMaterial = null |
|||
this.showOnlySelected = false |
|||
|
|||
getCustomerIssueNotifyHeaderInfo({ |
|||
site: localStorage.getItem('site'), |
|||
notifyNo: this.requestIssueForm.requestNo, |
|||
}).then(({ data }) => { |
|||
if (data.code === 0) { |
|||
console.log(data) |
|||
|
|||
this.issueRequestMaterials = data.data || [] |
|||
if (this.issueRequestMaterials.length === 0) { |
|||
this.$message.warning('查询申请单不存在') |
|||
} |
|||
} else { |
|||
this.$message.error(data.msg, 'error') |
|||
} |
|||
}) |
|||
.finally(() => { |
|||
this.loading = false |
|||
}) |
|||
}, |
|||
|
|||
isSameRequestMaterial(a, b) { |
|||
if (!a || !b) return false |
|||
return ( |
|||
a.notifyNo === b.notifyNo && |
|||
a.itemNo === b.itemNo && |
|||
a.soorderNo === b.soorderNo |
|||
) |
|||
}, |
|||
selectRequestMaterial(material) { |
|||
if ( |
|||
this.showOnlySelected && |
|||
this.selectedRequestMaterial && |
|||
this.isSameRequestMaterial(this.selectedRequestMaterial, material) |
|||
) { |
|||
// 再次点击同一条,恢复显示所有主数据 |
|||
this.selectedRequestMaterial = null |
|||
this.selectedWorkOrder = '' |
|||
this.materialList = [] |
|||
this.showOnlySelected = false |
|||
return |
|||
} |
|||
|
|||
// 选择并仅显示当前申请单物料 |
|||
this.selectedRequestMaterial = material |
|||
this.selectedWorkOrder = material.notifyNo |
|||
this.showOnlySelected = true |
|||
this.getCustomerIssueNotifyHeaderOrderMaterialList(material) |
|||
}, |
|||
getCustomerIssueNotifyHeaderOrderMaterialList(material){ |
|||
let params = { |
|||
site: localStorage.getItem('site'), |
|||
notifyNo: material.notifyNo, |
|||
itemNo: material.itemNo, |
|||
soorderNo: material.soorderNo, |
|||
}; |
|||
getCustomerIssueNotifyHeaderOrderMaterialList(params).then(({ data }) => { |
|||
if (data.code === 0) { |
|||
console.log(data) |
|||
this.materialList = data.data || [] |
|||
if (this.materialList.length === 0) { |
|||
this.$message.warning('该申请单行号暂无材料清单') |
|||
} |
|||
} else { |
|||
this.$message.error(data.msg, 'error') |
|||
} |
|||
}).catch((error) => { |
|||
this.$message.error('获取材料清单失败: ' + error.message, 'error') |
|||
}); |
|||
|
|||
}, |
|||
|
|||
|
|||
// 打开材料列表页面(仿照 productionReturnPicking.vue 的 openIssueList) |
|||
openIssueDetail(material) { |
|||
this.$router.push({ |
|||
name: 'customerIssuePDAList', |
|||
query: { |
|||
notifyNo: this.selectedRequestMaterial.notifyNo, // 申请单号 |
|||
itemNo: this.selectedRequestMaterial.itemNo, // 申请单行号 |
|||
workOrderNo: this.selectedRequestMaterial.soorderNo, // 客户订单号 |
|||
partNo: material.componentPartNo, // 物料编码 |
|||
unissureQty: material.qtyToIssue, // 需求数量 |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
resetRequest() { |
|||
this.requestIssueForm.requestNo = '' |
|||
this.issueRequestMaterials = [] |
|||
this.selectedRequestMaterial = null |
|||
}, |
|||
|
|||
showMessage(text, type = 'info') { |
|||
this.message = text |
|||
this.messageType = type |
|||
setTimeout(() => { |
|||
this.message = '' |
|||
}, 3000) |
|||
}, |
|||
}, |
|||
created () { |
|||
this.resetRequest() |
|||
}, |
|||
mounted() { |
|||
// 聚焦申请单号输入框 |
|||
this.$nextTick(() => { |
|||
if (this.$refs.requestNoInput) { |
|||
this.$refs.requestNoInput.focus() |
|||
} |
|||
}) |
|||
}, |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.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; |
|||
} |
|||
|
|||
/* 工单列表 */ |
|||
.work-order-list { |
|||
overflow-y: auto; |
|||
padding: 12px 16px; |
|||
} |
|||
|
|||
/* 工单卡片 */ |
|||
.work-order-card { |
|||
background: white; |
|||
border-radius: 8px; |
|||
margin-bottom: 12px; |
|||
padding: 16px; |
|||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|||
cursor: pointer; |
|||
transition: all 0.2s ease; |
|||
border: 2px solid transparent; |
|||
} |
|||
|
|||
.work-order-card:hover { |
|||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); |
|||
transform: translateY(-1px); |
|||
} |
|||
|
|||
.work-order-card.selected { |
|||
border-color: #17b3a3; |
|||
background: #f0fffe; |
|||
} |
|||
|
|||
.work-order-card:active { |
|||
transform: translateY(0); |
|||
} |
|||
|
|||
/* 内容区域 */ |
|||
.content-area { |
|||
flex: 1; |
|||
overflow-y: auto; |
|||
padding: 12px 16px; |
|||
} |
|||
|
|||
/* 材料卡片 */ |
|||
.material-card { |
|||
background: white; |
|||
border-radius: 8px; |
|||
margin-bottom: 12px; |
|||
padding: 16px; |
|||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|||
cursor: pointer; |
|||
transition: all 0.2s ease; |
|||
border: 2px solid transparent; |
|||
} |
|||
|
|||
.material-card:hover { |
|||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); |
|||
transform: translateY(-1px); |
|||
} |
|||
|
|||
.material-card.selected { |
|||
border-color: #17b3a3; |
|||
background: #f0fffe; |
|||
} |
|||
|
|||
.material-card:active { |
|||
transform: translateY(0); |
|||
} |
|||
|
|||
/* 卡片标题 */ |
|||
.card-title { |
|||
margin-bottom: 12px; |
|||
} |
|||
|
|||
.title-label { |
|||
font-size: 12px; |
|||
color: #666; |
|||
display: block; |
|||
margin-bottom: 4px; |
|||
} |
|||
|
|||
.title-value { |
|||
font-size: 16px; |
|||
font-weight: bold; |
|||
color: #333; |
|||
margin-left: 16px; |
|||
} |
|||
|
|||
/* 物料描述行 */ |
|||
.part-desc-row { |
|||
margin-bottom: 12px; |
|||
padding: 0 4px; |
|||
} |
|||
|
|||
.desc-text { |
|||
font-size: 12px; |
|||
color: #666; |
|||
line-height: 1.3; |
|||
word-break: break-all; |
|||
} |
|||
|
|||
/* 卡片详情 */ |
|||
.card-details { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: flex-start; |
|||
gap: 4px; |
|||
} |
|||
|
|||
.detail-item { |
|||
flex: 1; |
|||
text-align: center; |
|||
min-width: 50px; |
|||
max-width: 70px; |
|||
} |
|||
|
|||
.detail-label { |
|||
font-size: 11px; |
|||
color: #666; |
|||
margin-bottom: 4px; |
|||
line-height: 1.2; |
|||
margin-left: -12px; |
|||
} |
|||
|
|||
.detail-value { |
|||
font-size: 13px; |
|||
color: #333; |
|||
line-height: 1.2; |
|||
margin-left: -12px; |
|||
} |
|||
|
|||
/* 区域头部 */ |
|||
.section-header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 12px; |
|||
padding: 12px 16px; |
|||
background: white; |
|||
border-radius: 8px; |
|||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.section-header span { |
|||
font-size: 14px; |
|||
font-weight: 500; |
|||
color: #333; |
|||
} |
|||
|
|||
.reset-btn { |
|||
background: #17b3a3; |
|||
color: white; |
|||
border: none; |
|||
padding: 6px 12px; |
|||
border-radius: 4px; |
|||
cursor: pointer; |
|||
font-size: 12px; |
|||
} |
|||
|
|||
.reset-btn:hover { |
|||
background: #13998c; |
|||
} |
|||
|
|||
/* 输入组 */ |
|||
.input-group { |
|||
margin-bottom: 12px; |
|||
} |
|||
|
|||
.input-with-scan { |
|||
display: flex; |
|||
gap: 8px; |
|||
align-items: center; |
|||
} |
|||
|
|||
.input-with-scan .el-input { |
|||
flex: 1; |
|||
} |
|||
|
|||
/* 复选框组 */ |
|||
.checkbox-group { |
|||
margin-bottom: 12px; |
|||
} |
|||
|
|||
/* 确认区域 */ |
|||
.confirm-section { |
|||
padding: 16px; |
|||
background: white; |
|||
border-radius: 8px; |
|||
margin-top: 12px; |
|||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
/* 空状态 */ |
|||
.empty-state { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 60px 20px; |
|||
color: #999; |
|||
} |
|||
|
|||
.empty-state i { |
|||
font-size: 48px; |
|||
margin-bottom: 16px; |
|||
} |
|||
|
|||
.empty-state p { |
|||
font-size: 14px; |
|||
margin: 0; |
|||
} |
|||
|
|||
/* 加载状态 */ |
|||
.loading-state { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 60px 20px; |
|||
color: #17b3a3; |
|||
} |
|||
|
|||
.loading-state i { |
|||
font-size: 24px; |
|||
margin-bottom: 12px; |
|||
animation: spin 1s linear infinite; |
|||
} |
|||
|
|||
@keyframes spin { |
|||
from { |
|||
transform: rotate(0deg); |
|||
} |
|||
to { |
|||
transform: rotate(360deg); |
|||
} |
|||
} |
|||
|
|||
.loading-state p { |
|||
font-size: 14px; |
|||
margin: 0; |
|||
} |
|||
|
|||
/* 消息提示 */ |
|||
.message { |
|||
position: fixed; |
|||
top: 20px; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
padding: 12px 20px; |
|||
border-radius: 6px; |
|||
font-weight: bold; |
|||
z-index: 1001; |
|||
max-width: 90%; |
|||
text-align: center; |
|||
} |
|||
|
|||
.message.success { |
|||
background: #d4edda; |
|||
color: #155724; |
|||
border: 1px solid #c3e6cb; |
|||
} |
|||
|
|||
.message.error { |
|||
background: #f8d7da; |
|||
color: #721c24; |
|||
border: 1px solid #f5c6cb; |
|||
} |
|||
|
|||
.message.warning { |
|||
background: #fff3cd; |
|||
color: #856404; |
|||
border: 1px solid #ffeaa7; |
|||
} |
|||
|
|||
.message.info { |
|||
background: #d1ecf1; |
|||
color: #0c5460; |
|||
border: 1px solid #bee5eb; |
|||
} |
|||
|
|||
/* 响应式设计 */ |
|||
@media (max-width: 360px) { |
|||
.header-bar { |
|||
padding: 8px 12px; |
|||
} |
|||
|
|||
.search-container { |
|||
padding: 8px 12px; |
|||
} |
|||
|
|||
.work-order-list { |
|||
padding: 8px 12px; |
|||
} |
|||
|
|||
.work-order-card { |
|||
padding: 12px; |
|||
} |
|||
|
|||
.content-area { |
|||
padding: 8px 12px; |
|||
} |
|||
|
|||
.material-card { |
|||
padding: 12px; |
|||
} |
|||
|
|||
.card-details { |
|||
flex-wrap: wrap; |
|||
gap: 6px; |
|||
} |
|||
|
|||
.detail-item { |
|||
flex: 0 0 48%; |
|||
margin-bottom: 6px; |
|||
min-width: 50px; |
|||
} |
|||
} |
|||
</style> |
|||
1078
src/views/modules/customerIssue/customerIssuePDAIssueList.vue
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,163 @@ |
|||
<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="search-container"> |
|||
<div class="card-title"> |
|||
<label class="title-label">客户订单号:{{ workOrderNo }}</label> |
|||
</div> |
|||
<div class="card-title"> |
|||
<label class="title-label">物料编码:{{ partNo }}</label> |
|||
</div> |
|||
<div class="card-title"> |
|||
<label class="title-label">发料数量:{{ unissureQty }}</label> |
|||
</div> |
|||
</div> |
|||
<div class="content-area"> |
|||
<div class="work-order-list" v-if="issueList.length > 0"> |
|||
<div |
|||
v-for="(item, index) in issueList" |
|||
:key="index" |
|||
class="material-card" |
|||
@click="goDetail(item)" |
|||
> |
|||
<div class="card-title"> |
|||
<span class="title-label"> |
|||
物料编码:{{ partNo }} 发料号:{{ item.TRANSACTION_ID }} |
|||
</span> |
|||
</div> |
|||
<div class="part-desc-row"> |
|||
<span class="desc-text">批次号:{{ item.LOT_BATCH_NO || '-' }}</span> |
|||
</div> |
|||
<div class="card-details"> |
|||
<div class="detail-item"> |
|||
<div class="detail-label">发料数量</div> |
|||
<div class="detail-value">{{ item.QUANTITY }}</div> |
|||
</div> |
|||
<div class="detail-item"> |
|||
<div class="detail-label">已发数量</div> |
|||
<div class="detail-value">{{ item.QTY_ISSUED || 0 }}</div> |
|||
</div> |
|||
<div class="detail-item"> |
|||
<div class="detail-label">单位</div> |
|||
<div class="detail-value">{{ item.uom || '个' }}</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div v-if="!loading && issueList.length === 0" class="empty-state"> |
|||
<i class="el-icon-box"></i> |
|||
<p>暂无发料记录</p> |
|||
</div> |
|||
|
|||
<div v-if="loading" class="loading-state"> |
|||
<i class="el-icon-loading"></i> |
|||
<p>加载中...</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { getCustomerIssueMatericalForShopOrder } from '@/api/customerIssue/customer-issue'; |
|||
import { notify } from 'node-notifier'; |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
workOrderNo: '', |
|||
partNo: '', |
|||
loading: false, |
|||
issueList: [], |
|||
unissureQty: 0, |
|||
itemNo: '', |
|||
}; |
|||
}, |
|||
methods: { |
|||
loadIssueList() { |
|||
if (!this.workOrderNo || !this.partNo) { |
|||
return; |
|||
} |
|||
this.loading = true; |
|||
const params = { |
|||
workOrderNo: this.workOrderNo, |
|||
site: localStorage.getItem('site'), |
|||
partNo: this.partNo, |
|||
}; |
|||
getCustomerIssueMatericalForShopOrder(params) |
|||
.then(({ data }) => { |
|||
this.loading = false; |
|||
if (data && data.code === 0) { |
|||
this.issueList = data.issueForShopOrder || []; |
|||
} else { |
|||
this.$message.error(data.msg || '获取发料记录失败'); |
|||
this.issueList = []; |
|||
} |
|||
}) |
|||
.catch(() => { |
|||
this.loading = false; |
|||
this.$message.error('获取发料记录失败'); |
|||
}); |
|||
}, |
|||
goDetail(item) { |
|||
this.$router.push({ |
|||
name: 'customerIssuePDAIssueList', |
|||
query: { |
|||
workOrderNo: this.workOrderNo, |
|||
material:{ |
|||
itemNo: this.itemNo, |
|||
partNo: this.partNo, |
|||
orderType: 'customerOrder', |
|||
ifsTransactionID: item.TRANSACTION_ID, |
|||
quantity: item.QUANTITY, |
|||
batchNo: item.LOT_BATCH_NO, |
|||
unissureQty: this.unissureQty, |
|||
ifsAccountingID:item.ACCOUNTING_ID, |
|||
qtyIssued:item.QTY_ISSUED || 0, |
|||
} |
|||
}, |
|||
}); |
|||
}, |
|||
}, |
|||
mounted() { |
|||
this.workOrderNo = this.$route.query.workOrderNo; |
|||
this.partNo = this.$route.query.partNo; |
|||
this.unissureQty = this.$route.query.unissureQty; |
|||
this.itemNo = this.$route.query.itemNo; |
|||
this.loadIssueList(); |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.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; } |
|||
.content-area { flex: 1; overflow-y: auto; } |
|||
.work-order-list { overflow-y: auto; padding: 12px 16px; } |
|||
.material-card { background: white; border-radius: 8px; margin-bottom: 12px; padding: 16px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); cursor: pointer; transition: all 0.2s ease; border: 2px solid transparent; } |
|||
.material-card:hover { box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); transform: translateY(-1px); } |
|||
.material-card:active { transform: translateY(0); } |
|||
.card-title { margin-bottom: 12px; } |
|||
.title-label { font-size: 12px; color: #666; display: block; margin-bottom: 4px; } |
|||
.part-desc-row { margin-bottom: 12px; padding: 0 4px; } |
|||
.desc-text { font-size: 12px; color: #666; line-height: 1.3; word-break: break-all; } |
|||
.card-details { display: flex; justify-content: space-between; align-items: flex-start; gap: 4px; } |
|||
.detail-item { flex: 1; text-align: center; min-width: 50px; max-width: 70px; } |
|||
.detail-label { font-size: 11px; color: #666; margin-bottom: 4px; line-height: 1.2; margin-left: -12px; } |
|||
.detail-value { font-size: 13px; color: #333; line-height: 1.2; margin-left: -12px; } |
|||
.empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px 20px; color: #999; } |
|||
.empty-state i { font-size: 48px; margin-bottom: 16px; } |
|||
.loading-state { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px 20px; color: #17B3A3; } |
|||
.loading-state i { font-size: 24px; margin-bottom: 12px; animation: spin 1s linear infinite; } |
|||
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } |
|||
</style> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue