Browse Source

2025-09-05 pda 生产退仓上架

master
fengyuan_yang 6 months ago
parent
commit
7760e06602
  1. 12
      src/api/production/production-return2.js
  2. 14
      src/router/index.js
  3. 8
      src/views/main.vue
  4. 166
      src/views/modules/production/production-return.vue
  5. 424
      src/views/modules/production/productionQualifiedReturn.vue
  6. 1325
      src/views/modules/production/productionReturnStorage.vue

12
src/api/production/production-return2.js

@ -0,0 +1,12 @@
import { createAPI } from "@/utils/httpRequest.js";
export const getQualifiedReturnList = data => createAPI(`productionReturn/getQualifiedReturnList`, 'post', data)
export const getReturnDetails = data => createAPI(`productionReturn/getReturnDetails`, 'post', data)
export const validateLabelWithReturn = data => createAPI(`productionReturn/validateLabelWithReturn`, 'post', data)
export const confirmReturnStorage = data => createAPI(`productionReturn/confirmReturnStorage`, 'post', data)
export const getMaterialList = data => createAPI(`productionReturn/getMaterialList`, 'post', data)

14
src/router/index.js

@ -62,6 +62,20 @@ const globalRoutes = [
component: resolve => require(["@/views/modules/production/productionInboundStorage.vue"], resolve), meta: { transition: 'instant', preload: true, keepAlive: true } component: resolve => require(["@/views/modules/production/productionInboundStorage.vue"], resolve), meta: { transition: 'instant', preload: true, keepAlive: true }
}, },
// 生产退仓
{
path: "/productionReturn", name: "productionReturn",
component: resolve => require(["@/views/modules/production/production-return.vue"], resolve), meta: { transition: 'instant', preload: true, keepAlive: true }
},
{
path: "/productionQualifiedReturn", name: "productionQualifiedReturn",
component: resolve => require(["@/views/modules/production/productionQualifiedReturn.vue"], resolve), meta: { transition: 'instant', preload: true, keepAlive: true }
},
{
path: "/productionReturnStorage/:buNo/:inboundNo", name: "productionReturnStorage",
component: resolve => require(["@/views/modules/production/productionReturnStorage.vue"], resolve), meta: { transition: 'instant', preload: true, keepAlive: true }
},
// 销售出库 // 销售出库
{ {
path: "/salesOutbound", name: "salesOutbound", path: "/salesOutbound", name: "salesOutbound",

8
src/views/main.vue

@ -45,8 +45,8 @@
</div> </div>
<div class="menu-text">采购入库</div> <div class="menu-text">采购入库</div>
</div> </div>
<!-- <div class="menu-item disabled" @click="navigateWithWarehouseCheck('productionReturn')">-->
<div class="menu-item disabled" @click="handleDisabledFeature('生产退仓')">
<div class="menu-item" @click="navigateWithWarehouseCheck('productionReturn')">
<!-- <div class="menu-item disabled" @click="handleDisabledFeature('生产退仓')">-->
<div class="menu-icon production-return"> <div class="menu-icon production-return">
<van-icon name="revoke" size="24" /> <van-icon name="revoke" size="24" />
</div> </div>
@ -231,6 +231,7 @@ export default {
closeWarehouseDropdown() { closeWarehouseDropdown() {
this.showWarehouseDropdown = false; this.showWarehouseDropdown = false;
}, },
// //
selectWarehouse(warehouse) { selectWarehouse(warehouse) {
this.selectedWarehouse = warehouse.warehouseid; this.selectedWarehouse = warehouse.warehouseid;
@ -239,6 +240,7 @@ export default {
this.showWarehouseDropdown = false; this.showWarehouseDropdown = false;
this.$message.success(`已切换到仓库:${warehouse.warehousename}`); this.$message.success(`已切换到仓库:${warehouse.warehousename}`);
}, },
// //
checkWarehouseSelection() { checkWarehouseSelection() {
if (!this.selectedWarehouse) { if (!this.selectedWarehouse) {
@ -247,6 +249,7 @@ export default {
} }
return true; return true;
}, },
// //
navigateWithWarehouseCheck(routeName) { navigateWithWarehouseCheck(routeName) {
if (this.checkWarehouseSelection()) { if (this.checkWarehouseSelection()) {
@ -261,7 +264,6 @@ export default {
message: `${featureName}正在开发中,敬请期待...`, message: `${featureName}正在开发中,敬请期待...`,
duration: 8000 // 5 duration: 8000 // 5
}); });
}, },
// 退 // 退

166
src/views/modules/production/production-return.vue

@ -0,0 +1,166 @@
<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: 'purchase', to: 'productionQualifiedReturn', disabled: true },
{ icon: 'records', label: '申请单退仓', iconClass: 'qualified', to: 'productionQualifiedReturn', 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(3, 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.purchase {
background: linear-gradient(135deg, #17b3a3 0%, #1dc5ef 100%);
}
.menu-icon.inspection {
background: linear-gradient(135deg, #17b3a3 0%, #1dc5ef 100%);
}
.menu-icon.qualified {
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>

424
src/views/modules/production/productionQualifiedReturn.vue

@ -0,0 +1,424 @@
<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">
<el-input clearable
v-model="searchCode"
placeholder="请扫描入库单或标签条码"
prefix-icon="el-icon-search"
@keyup.enter.native="handleSearch"
ref="searchInput"
/>
</div>
<!-- 物料列表 -->
<div class="content-area">
<div
v-for="(item, index) in qualifiedList"
:key="index"
class="inbound-card"
@click="goToInboundPage(item)"
>
<div class="card-details">
<div class="detail-item">
<div class="detail-label">生产订单</div>
<div class="detail-value">
<span class="qualified">{{ item.inboundNo }}</span>
</div>
</div>
<div class="detail-item">
<div class="detail-label">物料编码</div>
<div class="detail-value">
<span class="qualified">{{ item.partNo }}</span>
</div>
</div>
<div class="detail-item">
<div class="detail-label">物料名称</div>
<div class="detail-value">
<span class="qualified">{{ item.partDesc }}</span>
</div>
</div>
</div>
</div>
<!-- 空状态 -->
<div v-if="qualifiedList.length === 0 && !loading" 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 { getQualifiedReturnList } from "@/api/production/production-return2.js";
import { getCurrentWarehouse } from '@/utils'
import moment from 'moment';
export default {
data() {
return {
searchCode: '',
qualifiedList: [],
loading: false
};
},
methods: {
formatDate(date) {
return date ? moment(date).format('YYYY-MM-DD') : '';
},
//
handleSearch() {
if (this.searchCode.trim()) {
this.searchQualifiedList(this.searchCode.trim());
} else {
this.loadQualifiedList();
}
},
//
loadQualifiedList() {
const currentWarehouse = getCurrentWarehouse();
if (!currentWarehouse) {
this.$message.error('请先选择仓库');
return;
}
this.loading = true;
const params = {
warehouseId: currentWarehouse,
site:localStorage.getItem('site'),
status: '待入库',//
};
getQualifiedReturnList(params).then(({ data }) => {
this.loading = false;
if (data && data.code === 0) {
this.qualifiedList = data.data || [];
} else {
this.$message.error(data.msg || '获取数据失败');
}
}).catch(error => {
this.loading = false;
console.error('获取生产待入库列表失败:', error);
this.$message.error('获取数据失败');
});
},
//
searchQualifiedList(searchCode) {
const currentWarehouse = getCurrentWarehouse();
if (!currentWarehouse) {
this.$message.error('请先选择仓库');
return;
}
this.loading = true;
const params = {
warehouseId: currentWarehouse,
searchCode: searchCode,
site:localStorage.getItem('site'),
status: '待入库'
};
getQualifiedReturnList(params).then(({ data }) => {
this.loading = false;
if (data && data.code === 0) {
if (data.data.length === 0) {
this.$message.warning('未找到匹配的入库单');
}
this.qualifiedList = data.data || [];
} else {
this.$message.error(data.msg || '查询失败');
}
}).catch(error => {
this.loading = false;
console.error('搜索失败:', error);
this.$message.error('查询失败');
});
},
//
goToInboundPage(item) {
this.$router.push({
name: 'productionReturnStorage',
params: {
buNo: item.buNo,
inboundNo: item.inboundNo
}
});
}
},
mounted() {
//
this.$nextTick(() => {
if (this.$refs.searchInput) {
this.$refs.searchInput.focus();
}
});
//
this.loadQualifiedList();
}
};
</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;
}
.search-box {
position: relative;
display: flex;
align-items: center;
background: #f8f9fa;
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 0 12px;
}
.search-icon {
color: #999;
font-size: 16px;
margin-right: 8px;
}
.search-box input {
flex: 1;
border: none;
background: transparent;
padding: 12px 0;
font-size: 14px;
outline: none;
}
.search-box input::placeholder {
color: #999;
}
/* 内容区域 */
.content-area {
flex: 1;
overflow-y: auto;
padding: 12px 16px;
}
/* 入库卡片 */
.inbound-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;
}
.inbound-card:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
transform: translateY(-1px);
}
.inbound-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: 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: 13px;
color: #666;
margin-bottom: 4px;
line-height: 1.2;
margin-left: -12px;
}
.detail-value {
font-size: 13px;
color: #333;
line-height: 1.2;
}
.detail-value .qualified {
color: black;
font-weight: 500;
}
.detail-value .total {
color: #333;
font-weight: 500;
}
.detail-value .total::before {
content: '/';
color: #333;
}
/* 空状态 */
.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;
}
/* 响应式设计 */
@media (max-width: 360px) {
.header-bar {
padding: 8px 12px;
}
.search-container {
padding: 8px 12px;
}
.content-area {
padding: 8px 12px;
}
.inbound-card {
padding: 12px;
}
.card-details {
flex-wrap: wrap;
gap: 6px;
}
.detail-item {
flex: 0 0 48%;
margin-bottom: 6px;
min-width: 50px;
}
}
</style>

1325
src/views/modules/production/productionReturnStorage.vue
File diff suppressed because it is too large
View File

Loading…
Cancel
Save