feat: 添加扫码成功页面和实际库区选择功能

- 新增扫码成功页面,优化用户体验
- 添加实际库区选择组件和API接口
- 修改合并功能表单,增加实际库区选择
- 更新应用版本号和配置
- 优化首页跳转逻辑和错误处理
This commit is contained in:
砂糖
2025-11-04 13:07:06 +08:00
parent 610ca8f2d8
commit 196f55961a
12 changed files with 2889 additions and 2443 deletions

View File

@@ -6,7 +6,7 @@
export default { export default {
onLaunch: function() { onLaunch: function() {
this.initApp() this.initApp()
updateManager.checkUpdate(); // updateManager.checkUpdate();
}, },
methods: { methods: {
// 初始化应用 // 初始化应用
@@ -33,7 +33,7 @@
this.$tab.reLaunch('/pages/login') this.$tab.reLaunch('/pages/login')
return; return;
} }
this.$store.dispatch('GetInfo')
} }
} }
} }

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询实际库区/库位自关联列表
export function listActualWarehouse(query) {
return request({
url: '/wms/actualWarehouse/list',
method: 'get',
params: query
})
}
// 查询实际库区/库位自关联详细
export function getActualWarehouse(actualWarehouseId) {
return request({
url: '/wms/actualWarehouse/' + actualWarehouseId,
method: 'get'
})
}
// 新增实际库区/库位自关联
export function addActualWarehouse(data) {
return request({
url: '/wms/actualWarehouse',
method: 'post',
data: data
})
}
// 修改实际库区/库位自关联
export function updateActualWarehouse(data) {
return request({
url: '/wms/actualWarehouse',
method: 'put',
data: data
})
}
// 删除实际库区/库位自关联
export function delActualWarehouse(actualWarehouseId) {
return request({
url: '/wms/actualWarehouse/' + actualWarehouseId,
method: 'delete'
})
}

View File

@@ -0,0 +1,425 @@
<template>
<view>
<!-- 选择器触发按钮 -->
<view
class="picker-input"
@click="handleOpen"
:class="{ 'picker-input-disabled': disabled }"
>
<text class="picker-text" :class="{ 'picker-placeholder': !selectedName }">
{{ selectedName || placeholder }}
</text>
<text class="picker-arrow" v-if="!disabled"></text>
</view>
<!-- 弹窗内容 -->
<uni-popup ref="popup" type="bottom" @close="handlePopupClose">
<view class="warehouse-popup">
<!-- 弹窗头部 -->
<view class="popup-header">
<text class="popup-title">{{ title || (wareType === 'virtual' ? '选择逻辑库区' : '选择真实库区') }}</text>
<text class="popup-close" @click="handleClose"></text>
</view>
<!-- 加载状态 -->
<view class="loading-tip" v-if="loading">
<uni-loading type="circle" size="24"></uni-loading>
<text class="loading-text">加载库区中...</text>
</view>
<!-- 搜索框 -->
<view class="popup-search" v-if="!loading">
<input
v-model="searchKeyword"
@input="handleSearch"
placeholder="搜索库区名称"
class="search-input"
/>
</view>
<!-- 库区列表 -->
<scroll-view class="popup-body" scroll-y v-if="!loading">
<view
class="warehouse-item"
v-for="item in filteredList"
:key="getItemId(item)"
@click="handleSelect(item)"
>
<text class="warehouse-name">{{ getItemName(item) }}</text>
<text class="warehouse-check" v-if="getItemId(item) === selectedId"></text>
</view>
<view class="empty-tip" v-if="filteredList.length === 0">
<text>未找到匹配的库区</text>
</view>
</scroll-view>
<!-- 错误提示 -->
<view class="error-tip" v-if="error">
<text class="error-icon"></text>
<text class="error-text">{{ errorMsg || '加载库区失败' }}</text>
<button class="retry-btn" @click="loadWarehouses">重试</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import { listWarehouse } from '@/api/wms/warehouse.js'
import { listActualWarehouse } from '@/api/wms/actualWarehouse.js'
export default {
name: 'WarehousePicker',
props: {
// 已选中的库区ID用于回显
value: {
type: [String, Number],
default: ''
},
// 禁用状态
disabled: {
type: Boolean,
default: false
},
// 按钮占位文本
placeholder: {
type: String,
default: '请选择库区'
},
// 弹窗标题
title: {
type: String,
default: ''
},
// 库区类型virtual-逻辑库区actual-真实库区
wareType: {
type: String,
default: 'virtual',
validator: (value) => {
return ['virtual', 'actual'].includes(value)
}
}
},
data() {
return {
// 弹窗显示状态
showPopup: false,
// 所有库区列表
dataList: [],
// 过滤后的库区列表
filteredList: [],
// 搜索关键词
searchKeyword: '',
// 加载状态
loading: false,
// 错误状态
error: false,
// 错误信息
errorMsg: '',
// 选中的库区名称(用于显示)
selectedName: ''
}
},
computed: {
// 选中的库区ID双向绑定
selectedId: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
},
watch: {
// 监听选中值变化,更新显示名称
value: {
immediate: true,
handler(val) {
if (val && this.dataList.length) {
const matched = this.dataList.find(item => this.getItemId(item) === val)
this.selectedName = matched ? this.getItemName(matched) : ''
}
}
},
// 监听库区类型变化,重新加载数据
wareType: {
immediate: true,
handler() {
this.loadWarehouses()
}
}
},
methods: {
// 根据类型获取项目ID
getItemId(item) {
return this.wareType === 'virtual' ? item.warehouseId : item.actualWarehouseId
},
// 根据类型获取项目名称
getItemName(item) {
return this.wareType === 'virtual' ? item.warehouseName : item.actualWarehouseName
},
// 加载库区列表
async loadWarehouses() {
if (this.loading) return
this.loading = true
this.error = false
this.errorMsg = ''
try {
// 根据类型选择不同的API
const res = this.wareType === 'virtual'
? await listWarehouse({ pageNum: 1, pageSize: 1000 })
: await listActualWarehouse({ pageNum: 1, pageSize: 1000 })
if (res.code === 200) {
this.dataList = res[this.wareType === 'virtual' ? 'data' : 'rows'] || []
this.filteredList = [...this.dataList]
// 初始化选中项名称
this.updateSelectedName()
} else {
throw new Error(res.msg || `${this.wareType === 'virtual' ? '逻辑' : '真实'}库区数据加载失败`)
}
} catch (err) {
this.error = true
this.errorMsg = err.message
console.error(`${this.wareType === 'virtual' ? '逻辑' : '真实'}库区加载失败:`, err)
} finally {
this.loading = false
}
},
// 更新选中的库区名称
updateSelectedName() {
if (!this.selectedId) return
const matched = this.dataList.find(
item => this.getItemId(item) === this.selectedId
)
this.selectedName = matched ? this.getItemName(matched) : ''
},
// 搜索过滤
handleSearch() {
const keyword = this.searchKeyword.trim().toLowerCase()
if (!keyword) {
this.filteredList = [...this.dataList]
} else {
this.filteredList = this.dataList.filter(item =>
this.getItemName(item).toLowerCase().includes(keyword)
)
}
},
// 选择库区
handleSelect(item) {
this.selectedId = this.getItemId(item)
this.selectedName = this.getItemName(item)
// 通知父组件选中的完整信息
this.$emit('change', item)
this.handleClose()
},
// 打开弹窗
handleOpen() {
if (this.disabled) return
// 每次打开前重置搜索
this.searchKeyword = ''
this.filteredList = [...this.dataList]
this.showPopup = true
this.$refs.popup.open()
},
// 关闭弹窗
handleClose() {
this.showPopup = false
this.$refs.popup.close()
},
// 弹窗关闭回调
handlePopupClose() {
this.showPopup = false
}
}
}
</script>
<style scoped lang="scss">
/* 保持原有样式不变 */
.picker-input {
width: 100%;
height: 88rpx;
padding: 0 24rpx;
background: #f8f9fa;
border: 2rpx solid #e8e8e8;
border-radius: 12rpx;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
transition: all 0.3s;
&:active {
background: #fff;
border-color: #007aff;
}
&.picker-input-disabled {
background: #f5f5f5;
color: #999;
cursor: not-allowed;
}
.picker-text {
flex: 1;
font-size: 28rpx;
color: #333;
&.picker-placeholder {
color: #999;
}
}
.picker-arrow {
font-size: 24rpx;
color: #999;
margin-left: 10rpx;
}
}
.warehouse-popup {
background: #fff;
border-radius: 24rpx 24rpx 0 0;
max-height: 70vh;
}
.popup-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
.popup-title {
font-size: 32rpx;
color: #333;
font-weight: 600;
}
.popup-close {
font-size: 40rpx;
color: #999;
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
.loading-tip {
display: flex;
align-items: center;
justify-content: center;
padding: 60rpx 0;
gap: 16rpx;
.loading-text {
font-size: 28rpx;
color: #666;
}
}
.error-tip {
padding: 40rpx 30rpx;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 20rpx;
.error-icon {
font-size: 48rpx;
color: #ff4d4f;
}
.error-text {
font-size: 28rpx;
color: #ff4d4f;
max-width: 80%;
}
.retry-btn {
margin-top: 10rpx;
padding: 10rpx 30rpx;
background: #007aff;
color: #fff;
border-radius: 20rpx;
font-size: 26rpx;
}
}
.popup-search {
padding: 20rpx 30rpx;
border-bottom: 1rpx solid #f0f0f0;
.search-input {
width: 100%;
height: 80rpx;
padding: 0 20rpx;
background: #f8f9fa;
border: 2rpx solid #e8e8e8;
border-radius: 10rpx;
font-size: 28rpx;
color: #333;
box-sizing: border-box;
&:focus {
background: #fff;
border-color: #007aff;
}
}
}
.popup-body {
max-height: 400rpx;
.warehouse-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
&:active {
background: #f0f7ff;
}
.warehouse-name {
flex: 1;
font-size: 28rpx;
color: #333;
}
.warehouse-check {
font-size: 32rpx;
color: #007aff;
font-weight: bold;
}
}
.empty-tip {
text-align: center;
padding: 60rpx 0;
color: #999;
font-size: 28rpx;
}
}
</style>

View File

@@ -15,7 +15,8 @@
<view class="card-title"> <view class="card-title">
<text class="title-dot"></text> <text class="title-dot"></text>
<text class="title-text">原钢卷信息</text> <text class="title-text">原钢卷信息</text>
<view class="more-btn" @click.stop="showBomDialog" v-if="coilDetail.bomItemList && coilDetail.bomItemList.length > 0"> <view class="more-btn" @click.stop="showBomDialog"
v-if="coilDetail.bomItemList && coilDetail.bomItemList.length > 0">
<text class="icon-more"></text> <text class="icon-more"></text>
<text class="more-text">参数</text> <text class="more-text">参数</text>
</view> </view>
@@ -49,19 +50,13 @@
<view class="form-item"> <view class="form-item">
<text class="form-label">分卷数量</text> <text class="form-label">分卷数量</text>
<view class="split-count-selector"> <view class="split-count-selector">
<view <view class="count-btn" :class="{ 'count-btn-disabled': splitCoils.length <= 2 }"
class="count-btn" @click="changeSplitCount(-1)">
:class="{ 'count-btn-disabled': splitCoils.length <= 2 }"
@click="changeSplitCount(-1)"
>
<text>-</text> <text>-</text>
</view> </view>
<text class="count-value">{{ splitCoils.length }}</text> <text class="count-value">{{ splitCoils.length }}</text>
<view <view class="count-btn" :class="{ 'count-btn-disabled': splitCoils.length >= 10 }"
class="count-btn" @click="changeSplitCount(1)">
:class="{ 'count-btn-disabled': splitCoils.length >= 10 }"
@click="changeSplitCount(1)"
>
<text>+</text> <text>+</text>
</view> </view>
</view> </view>
@@ -69,51 +64,45 @@
<!-- 分卷信息列表 --> <!-- 分卷信息列表 -->
<view class="split-list"> <view class="split-list">
<view <view class="split-item" v-for="(item, index) in splitCoils" :key="index">
class="split-item"
v-for="(item, index) in splitCoils"
:key="index"
>
<view class="split-header"> <view class="split-header">
<text class="split-title">分卷 {{ index + 1 }}</text> <text class="split-title">分卷 {{ index + 1 }}</text>
</view> </view>
<view class="split-body"> <view class="split-body">
<view class="split-field"> <view class="split-field">
<text class="field-label">新钢卷号</text> <text class="field-label">新钢卷号</text>
<input <input v-model="item.currentCoilNo" placeholder="请输入新钢卷号" class="field-input" />
v-model="item.currentCoilNo"
placeholder="请输入新钢卷号"
class="field-input"
/>
</view> </view>
<view class="split-field"> <view class="split-field">
<text class="field-label">班组</text> <text class="field-label">班组</text>
<input <input v-model="item.team" placeholder="请输入班组名称" class="field-input" />
v-model="item.team"
placeholder="请输入班组名称"
class="field-input"
/>
</view> </view>
<view class="split-field"> <view class="split-field">
<text class="field-label-optional">目标库</text> <text class="field-label-optional">目标库</text>
<view <klp-warehouse-picker v-model="item.warehouseId" placeholder="请选择目标库区" />
class="picker-input" <!-- <view class="picker-input" @click="showWarehousePickerForItem(index)">
@click="showWarehousePickerForItem(index)"
>
<text class="picker-text" :class="{ 'picker-placeholder': !item.warehouseName }"> <text class="picker-text" :class="{ 'picker-placeholder': !item.warehouseName }">
{{ item.warehouseName || '请选择目标库区' }} {{ item.warehouseName || '请选择目标库区' }}
</text> </text>
<text class="picker-arrow"></text> <text class="picker-arrow"></text>
</view> -->
</view> </view>
<view class="split-field">
<text class="field-label-optional">实际库区</text>
<klp-warehouse-picker v-model="item.actualWarehouseId" placeholder="请选择实际库区" ware-type="actual" />
<!-- <view class="picker-input" @click="showWarehousePickerForItem(index)">
<text class="picker-text" :class="{ 'picker-placeholder': !item.warehouseName }">
{{ item.warehouseName || '请选择目标库区' }}
</text>
<text class="picker-arrow"></text>
</view> -->
</view> </view>
<!-- 物品类型选择 --> <!-- 物品类型选择 -->
<view class="split-field"> <view class="split-field">
<text class="field-label-optional">物品类型</text> <text class="field-label-optional">物品类型</text>
<view <view class="picker-input" @click="showItemTypePickerForItem(index)">
class="picker-input"
@click="showItemTypePickerForItem(index)"
>
<text class="picker-text" :class="{ 'picker-placeholder': !item.itemType }"> <text class="picker-text" :class="{ 'picker-placeholder': !item.itemType }">
{{ item.itemType === 'product' ? '成品' : item.itemType === 'raw_material' ? '原料' : '请选择物品类型' }} {{ item.itemType === 'product' ? '成品' : item.itemType === 'raw_material' ? '原料' : '请选择物品类型' }}
</text> </text>
@@ -124,10 +113,7 @@
<!-- 产品选择仅当选择了成品类型时显示 --> <!-- 产品选择仅当选择了成品类型时显示 -->
<view class="split-field" v-if="item.itemType === 'product'"> <view class="split-field" v-if="item.itemType === 'product'">
<text class="field-label-optional">选择产品</text> <text class="field-label-optional">选择产品</text>
<view <view class="picker-input" @click="showProductPickerForItem(index)">
class="picker-input"
@click="showProductPickerForItem(index)"
>
<text class="picker-text" :class="{ 'picker-placeholder': !item.productName }"> <text class="picker-text" :class="{ 'picker-placeholder': !item.productName }">
{{ item.productName || '请选择产品' }} {{ item.productName || '请选择产品' }}
</text> </text>
@@ -138,10 +124,7 @@
<!-- 原材料选择仅当选择了原料类型时显示 --> <!-- 原材料选择仅当选择了原料类型时显示 -->
<view class="split-field" v-if="item.itemType === 'raw_material'"> <view class="split-field" v-if="item.itemType === 'raw_material'">
<text class="field-label-optional">选择原材料</text> <text class="field-label-optional">选择原材料</text>
<view <view class="picker-input" @click="showRawMaterialPickerForItem(index)">
class="picker-input"
@click="showRawMaterialPickerForItem(index)"
>
<text class="picker-text" :class="{ 'picker-placeholder': !item.rawMaterialName }"> <text class="picker-text" :class="{ 'picker-placeholder': !item.rawMaterialName }">
{{ item.rawMaterialName || '请选择原材料' }} {{ item.rawMaterialName || '请选择原材料' }}
</text> </text>
@@ -151,21 +134,11 @@
<view class="split-field"> <view class="split-field">
<text class="field-label-optional">毛重 ()</text> <text class="field-label-optional">毛重 ()</text>
<input <input v-model="item.grossWeight" type="digit" placeholder="请输入毛重(选填)" class="field-input" />
v-model="item.grossWeight"
type="digit"
placeholder="请输入毛重(选填)"
class="field-input"
/>
</view> </view>
<view class="split-field"> <view class="split-field">
<text class="field-label-optional">净重 ()</text> <text class="field-label-optional">净重 ()</text>
<input <input v-model="item.netWeight" type="digit" placeholder="请输入净重(选填)" class="field-input" />
v-model="item.netWeight"
type="digit"
placeholder="请输入净重(选填)"
class="field-input"
/>
</view> </view>
</view> </view>
</view> </view>
@@ -186,38 +159,6 @@
</view> </view>
</view> </view>
<!-- 库区选择弹窗 -->
<uni-popup ref="warehousePopup" type="bottom">
<view class="warehouse-popup">
<view class="popup-header">
<text class="popup-title">选择库区</text>
<text class="popup-close" @click="closeWarehousePickerForItem"></text>
</view>
<view class="popup-search">
<input
v-model="warehouseSearchKeyword"
@input="filterWarehousesInPicker"
placeholder="搜索库区名称"
class="search-input"
/>
</view>
<scroll-view class="popup-body" scroll-y>
<view
class="warehouse-item"
v-for="warehouse in filteredWarehousesInPicker"
:key="warehouse.warehouseId"
@click="selectWarehouseFromPicker(warehouse)"
>
<text class="warehouse-name">{{ warehouse.warehouseName }}</text>
<text class="warehouse-check" v-if="currentPickerItemIndex !== -1 && splitCoils[currentPickerItemIndex].warehouseId === warehouse.warehouseId"></text>
</view>
<view class="empty-tip" v-if="!filteredWarehousesInPicker || filteredWarehousesInPicker.length === 0">
<text>未找到匹配的库区</text>
</view>
</scroll-view>
</view>
</uni-popup>
<!-- 产品选择弹窗 --> <!-- 产品选择弹窗 -->
<uni-popup ref="productPopup" type="bottom"> <uni-popup ref="productPopup" type="bottom">
<view class="warehouse-popup"> <view class="warehouse-popup">
@@ -226,22 +167,15 @@
<text class="popup-close" @click="closeProductPickerForItem"></text> <text class="popup-close" @click="closeProductPickerForItem"></text>
</view> </view>
<view class="popup-search"> <view class="popup-search">
<input <input v-model="productSearchKeyword" @input="filterProductsInPicker" placeholder="搜索产品名称"
v-model="productSearchKeyword" class="search-input" />
@input="filterProductsInPicker"
placeholder="搜索产品名称"
class="search-input"
/>
</view> </view>
<scroll-view class="popup-body" scroll-y> <scroll-view class="popup-body" scroll-y>
<view <view class="warehouse-item" v-for="product in filteredProductsInPicker" :key="product.productId"
class="warehouse-item" @click="selectProductFromPicker(product)">
v-for="product in filteredProductsInPicker"
:key="product.productId"
@click="selectProductFromPicker(product)"
>
<text class="warehouse-name">{{ product.productName }}</text> <text class="warehouse-name">{{ product.productName }}</text>
<text class="warehouse-check" v-if="currentPickerItemIndex !== -1 && splitCoils[currentPickerItemIndex].itemId === product.productId"></text> <text class="warehouse-check"
v-if="currentPickerItemIndex !== -1 && splitCoils[currentPickerItemIndex].itemId === product.productId"></text>
</view> </view>
<view class="empty-tip" v-if="!filteredProductsInPicker || filteredProductsInPicker.length === 0"> <view class="empty-tip" v-if="!filteredProductsInPicker || filteredProductsInPicker.length === 0">
<text>未找到匹配的产品</text> <text>未找到匹配的产品</text>
@@ -258,22 +192,15 @@
<text class="popup-close" @click="closeRawMaterialPickerForItem"></text> <text class="popup-close" @click="closeRawMaterialPickerForItem"></text>
</view> </view>
<view class="popup-search"> <view class="popup-search">
<input <input v-model="rawMaterialSearchKeyword" @input="filterRawMaterialsInPicker" placeholder="搜索原材料名称"
v-model="rawMaterialSearchKeyword" class="search-input" />
@input="filterRawMaterialsInPicker"
placeholder="搜索原材料名称"
class="search-input"
/>
</view> </view>
<scroll-view class="popup-body" scroll-y> <scroll-view class="popup-body" scroll-y>
<view <view class="warehouse-item" v-for="material in filteredRawMaterialsInPicker" :key="material.rawMaterialId"
class="warehouse-item" @click="selectRawMaterialFromPicker(material)">
v-for="material in filteredRawMaterialsInPicker"
:key="material.rawMaterialId"
@click="selectRawMaterialFromPicker(material)"
>
<text class="warehouse-name">{{ material.rawMaterialName }}</text> <text class="warehouse-name">{{ material.rawMaterialName }}</text>
<text class="warehouse-check" v-if="currentPickerItemIndex !== -1 && splitCoils[currentPickerItemIndex].itemId === material.rawMaterialId"></text> <text class="warehouse-check"
v-if="currentPickerItemIndex !== -1 && splitCoils[currentPickerItemIndex].itemId === material.rawMaterialId"></text>
</view> </view>
<view class="empty-tip" v-if="!filteredRawMaterialsInPicker || filteredRawMaterialsInPicker.length === 0"> <view class="empty-tip" v-if="!filteredRawMaterialsInPicker || filteredRawMaterialsInPicker.length === 0">
<text>未找到匹配的原材料</text> <text>未找到匹配的原材料</text>
@@ -292,11 +219,13 @@
<scroll-view class="popup-body" scroll-y> <scroll-view class="popup-body" scroll-y>
<view class="warehouse-item" @click="selectItemType('product')"> <view class="warehouse-item" @click="selectItemType('product')">
<text class="warehouse-name">成品</text> <text class="warehouse-name">成品</text>
<text class="warehouse-check" v-if="currentPickerItemIndex !== -1 && splitCoils[currentPickerItemIndex].itemType === 'product'"></text> <text class="warehouse-check"
v-if="currentPickerItemIndex !== -1 && splitCoils[currentPickerItemIndex].itemType === 'product'"></text>
</view> </view>
<view class="warehouse-item" @click="selectItemType('raw_material')"> <view class="warehouse-item" @click="selectItemType('raw_material')">
<text class="warehouse-name">原料</text> <text class="warehouse-name">原料</text>
<text class="warehouse-check" v-if="currentPickerItemIndex !== -1 && splitCoils[currentPickerItemIndex].itemType === 'raw_material'"></text> <text class="warehouse-check"
v-if="currentPickerItemIndex !== -1 && splitCoils[currentPickerItemIndex].itemType === 'raw_material'"></text>
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
@@ -333,11 +262,23 @@
</template> </template>
<script> <script>
import { getGenerateRecord } from '@/api/wms/code.js' import {
import { updateMaterialCoil, getMaterialCoil, getMaterialCoilTrace } from '@/api/wms/coil.js' getGenerateRecord
import { listWarehouse } from '@/api/wms/warehouse.js' } from '@/api/wms/code.js'
import { listProduct } from '@/api/wms/product.js' import {
import { listRawMaterial } from '@/api/wms/rawMaterial.js' updateMaterialCoil,
getMaterialCoil,
getMaterialCoilTrace
} from '@/api/wms/coil.js'
import {
listWarehouse
} from '@/api/wms/warehouse.js'
import {
listProduct
} from '@/api/wms/product.js'
import {
listRawMaterial
} from '@/api/wms/rawMaterial.js'
export default { export default {
data() { data() {
@@ -347,12 +288,12 @@ export default {
hasMergeSplit: 1 // 1表示分卷 hasMergeSplit: 1 // 1表示分卷
}, },
coilDetail: {}, coilDetail: {},
splitCoils: [ splitCoils: [{
{
currentCoilNo: '', currentCoilNo: '',
team: '', team: '',
hasMergeSplit: 1, hasMergeSplit: 1,
warehouseId: undefined, warehouseId: undefined,
actualWarehouseId: undefined,
warehouseName: '', warehouseName: '',
warehouseKeyword: '', warehouseKeyword: '',
filteredWarehouses: [], filteredWarehouses: [],
@@ -369,6 +310,7 @@ export default {
team: '', team: '',
hasMergeSplit: 1, hasMergeSplit: 1,
warehouseId: undefined, warehouseId: undefined,
actualWarehouseId: undefined,
warehouseName: '', warehouseName: '',
warehouseKeyword: '', warehouseKeyword: '',
filteredWarehouses: [], filteredWarehouses: [],
@@ -402,45 +344,24 @@ export default {
}, },
onLoad() { onLoad() {
this.loadWarehouses();
this.loadProducts(); this.loadProducts();
this.loadRawMaterials(); this.loadRawMaterials();
}, },
mounted() { mounted() {
this.loadWarehouses();
this.loadProducts(); this.loadProducts();
this.loadRawMaterials(); this.loadRawMaterials();
}, },
methods: { methods: {
// 加载库区列表
async loadWarehouses() {
console.log('开始加载库区...');
try {
const res = await listWarehouse({ pageNum: 1, pageSize: 1000 });
console.log("库区返回值", res);
if (res.code === 200) {
this.warehouses = res.data || [];
console.log('库区加载成功,数量:', this.warehouses.length);
// 为每个分卷初始化库区列表
this.splitCoils.forEach(item => {
item.filteredWarehouses = [...this.warehouses];
});
console.log('分卷库区列表初始化完成');
} else {
console.error('库区加载失败:', res.msg);
}
} catch (err) {
console.error('加载库区异常:', err);
}
},
// 加载产品列表 // 加载产品列表
async loadProducts() { async loadProducts() {
console.log('开始加载产品列表...'); console.log('开始加载产品列表...');
try { try {
const res = await listProduct({ pageNum: 1, pageSize: 1000 }); const res = await listProduct({
pageNum: 1,
pageSize: 1000
});
console.log("产品返回值", res); console.log("产品返回值", res);
if (res.code === 200) { if (res.code === 200) {
this.products = res.rows || res.data || []; this.products = res.rows || res.data || [];
@@ -458,7 +379,10 @@ export default {
async loadRawMaterials() { async loadRawMaterials() {
console.log('开始加载原材料列表...'); console.log('开始加载原材料列表...');
try { try {
const res = await listRawMaterial({ pageNum: 1, pageSize: 1000 }); const res = await listRawMaterial({
pageNum: 1,
pageSize: 1000
});
console.log("原材料返回值", res); console.log("原材料返回值", res);
if (res.code === 200) { if (res.code === 200) {
this.rawMaterials = res.rows || res.data || []; this.rawMaterials = res.rows || res.data || [];
@@ -472,32 +396,6 @@ export default {
} }
}, },
// 过滤库区(在选择器中)
filterWarehousesInPicker() {
const keyword = this.warehouseSearchKeyword.trim().toLowerCase();
if (!keyword) {
this.filteredWarehousesInPicker = [...this.warehouses];
} else {
this.filteredWarehousesInPicker = this.warehouses.filter(warehouse => {
const name = (warehouse.warehouseName || '').toLowerCase();
return name.includes(keyword);
});
}
},
// 从选择器中选择库区
async selectWarehouseFromPicker(warehouse) {
if (this.currentPickerItemIndex === -1) return;
const item = this.splitCoils[this.currentPickerItemIndex];
// 使用 $set 确保响应式更新
this.$set(item, 'warehouseId', warehouse.warehouseId);
this.$set(item, 'warehouseName', warehouse.warehouseName);
this.closeWarehousePickerForItem();
},
// 显示物品类型选择器 // 显示物品类型选择器
showItemTypePickerForItem(index) { showItemTypePickerForItem(index) {
this.currentPickerItemIndex = index; this.currentPickerItemIndex = index;
@@ -544,20 +442,6 @@ export default {
this.$refs.bomPopup.close(); this.$refs.bomPopup.close();
}, },
// 显示库区选择器(为特定分卷)
showWarehousePickerForItem(index) {
this.currentPickerItemIndex = index;
this.warehouseSearchKeyword = '';
this.filteredWarehousesInPicker = [...this.warehouses];
this.$refs.warehousePopup.open();
},
// 关闭库区选择器
closeWarehousePickerForItem() {
this.$refs.warehousePopup.close();
this.currentPickerItemIndex = -1;
},
// 显示产品选择器(为特定分卷) // 显示产品选择器(为特定分卷)
showProductPickerForItem(index) { showProductPickerForItem(index) {
this.currentPickerItemIndex = index; this.currentPickerItemIndex = index;
@@ -730,7 +614,8 @@ export default {
// 3. 通过追溯接口获取钢卷信息 // 3. 通过追溯接口获取钢卷信息
const traceRes = await getMaterialCoilTrace(enterCoilNo, currentCoilNo); const traceRes = await getMaterialCoilTrace(enterCoilNo, currentCoilNo);
if (traceRes.code !== 200 || !traceRes.data || !traceRes.data.records || traceRes.data.records.length === 0) { if (traceRes.code !== 200 || !traceRes.data || !traceRes.data.records || traceRes.data.records
.length === 0) {
throw new Error('未找到钢卷信息'); throw new Error('未找到钢卷信息');
} }
@@ -808,6 +693,7 @@ export default {
team: '', team: '',
hasMergeSplit: 1, hasMergeSplit: 1,
warehouseId: undefined, warehouseId: undefined,
actualWarehouseId: undefined,
warehouseName: '', warehouseName: '',
warehouseKeyword: '', warehouseKeyword: '',
filteredWarehouses: this.warehouses, filteredWarehouses: this.warehouses,
@@ -837,12 +723,12 @@ export default {
hasMergeSplit: 1 hasMergeSplit: 1
}; };
this.coilDetail = {}; this.coilDetail = {};
this.splitCoils = [ this.splitCoils = [{
{
currentCoilNo: '', currentCoilNo: '',
team: '', team: '',
hasMergeSplit: 1, hasMergeSplit: 1,
warehouseId: undefined, warehouseId: undefined,
actualWarehouseId: undefined,
warehouseName: '', warehouseName: '',
warehouseKeyword: '', warehouseKeyword: '',
filteredWarehouses: this.warehouses, filteredWarehouses: this.warehouses,
@@ -859,6 +745,7 @@ export default {
team: '', team: '',
hasMergeSplit: 1, hasMergeSplit: 1,
warehouseId: undefined, warehouseId: undefined,
actualWarehouseId: undefined,
warehouseName: '', warehouseName: '',
warehouseKeyword: '', warehouseKeyword: '',
filteredWarehouses: this.warehouses, filteredWarehouses: this.warehouses,
@@ -922,6 +809,7 @@ export default {
itemType: item.itemType || this.coilDetail.itemType, // 优先使用分卷的itemType itemType: item.itemType || this.coilDetail.itemType, // 优先使用分卷的itemType
itemId: item.itemId || this.coilDetail.itemId, // 优先使用分卷的itemId itemId: item.itemId || this.coilDetail.itemId, // 优先使用分卷的itemId
warehouseId: item.warehouseId || this.coilDetail.warehouseId, // 使用分卷的库区或原库区 warehouseId: item.warehouseId || this.coilDetail.warehouseId, // 使用分卷的库区或原库区
actualWarehouseId: item.actualWarehouseId || this.coilDetail.actualWarehouseId,
grossWeight: item.grossWeight ? Number(item.grossWeight) : null, grossWeight: item.grossWeight ? Number(item.grossWeight) : null,
netWeight: item.netWeight ? Number(item.netWeight) : null netWeight: item.netWeight ? Number(item.netWeight) : null
})) }))

View File

@@ -71,18 +71,26 @@
<!-- 目标库区 --> <!-- 目标库区 -->
<view class="form-item form-item-optional"> <view class="form-item form-item-optional">
<text class="form-label-optional">目标库</text> <text class="form-label-optional">目标库</text>
<view <view
class="picker-input" class="picker-input"
@click="showWarehousePicker()" @click="showWarehousePicker()"
> >
<text class="picker-text" :class="{ 'picker-placeholder': !warehouseName }"> <text class="picker-text" :class="{ 'picker-placeholder': !warehouseName }">
{{ warehouseName || '请选择目标库' }} {{ warehouseName || '请选择目标库' }}
</text> </text>
<text class="picker-arrow"></text> <text class="picker-arrow"></text>
</view> </view>
</view> </view>
<!-- 实际库区 -->
<view class="form-item form-item-optional">
<text class="form-label-optional">实际库区</text>
<klp-warehouse-picker v-model="actualWarehouseId" placeholder="请选择目标库区"
ware-type="actual" />
</view>
<!-- 物品类型选择 --> <!-- 物品类型选择 -->
<view class="form-item form-item-optional"> <view class="form-item form-item-optional">
<text class="form-label-optional">物品类型</text> <text class="form-label-optional">物品类型</text>
@@ -299,6 +307,7 @@ export default {
mergedCoilNo: '', mergedCoilNo: '',
team: '', team: '',
warehouseId: undefined, warehouseId: undefined,
actualWarehouseId: undefined,
warehouseName: '', warehouseName: '',
warehouseKeyword: '', warehouseKeyword: '',
warehouses: [], warehouses: [],
@@ -686,6 +695,7 @@ export default {
this.mergedCoilNo = ''; this.mergedCoilNo = '';
this.team = ''; this.team = '';
this.warehouseId = undefined; this.warehouseId = undefined;
this.actualWarehouseId = undefined;
this.warehouseName = ''; this.warehouseName = '';
this.warehouseKeyword = ''; this.warehouseKeyword = '';
this.itemType = ''; this.itemType = '';
@@ -752,6 +762,7 @@ export default {
itemType: this.itemType || this.scannedCoils[0].itemType, // 优先使用选择的itemType itemType: this.itemType || this.scannedCoils[0].itemType, // 优先使用选择的itemType
itemId: this.itemId || this.scannedCoils[0].itemId, // 优先使用选择的itemId itemId: this.itemId || this.scannedCoils[0].itemId, // 优先使用选择的itemId
warehouseId: this.warehouseId || this.scannedCoils[0].warehouseId, // 使用选择的库区或第一个钢卷的库区 warehouseId: this.warehouseId || this.scannedCoils[0].warehouseId, // 使用选择的库区或第一个钢卷的库区
actualWarehouseId: this.actualWarehouseId || this.scannedCoils[0].actualWarehouseId
grossWeight: this.grossWeight ? Number(this.grossWeight) : null, grossWeight: this.grossWeight ? Number(this.grossWeight) : null,
netWeight: this.netWeight ? Number(this.netWeight) : null, netWeight: this.netWeight ? Number(this.netWeight) : null,
newCoils: this.scannedCoils.map(coil => ({ newCoils: this.scannedCoils.map(coil => ({

View File

@@ -59,50 +59,35 @@
<!-- 当前钢卷号 --> <!-- 当前钢卷号 -->
<view class="form-item"> <view class="form-item">
<text class="form-label">当前钢卷号</text> <text class="form-label">当前钢卷号</text>
<input <input v-model="form.currentCoilNo" placeholder="请输入当前钢卷号" class="form-input"
v-model="form.currentCoilNo" :disabled="coilDetail.dataType === 0" :class="{ 'form-input-disabled': coilDetail.dataType === 0 }" />
placeholder="请输入当前钢卷号"
class="form-input"
:disabled="coilDetail.dataType === 0"
:class="{ 'form-input-disabled': coilDetail.dataType === 0 }"
/>
</view> </view>
<!-- 班组 --> <!-- 班组 -->
<view class="form-item"> <view class="form-item">
<text class="form-label">班组</text> <text class="form-label">班组</text>
<input <input v-model="form.team" placeholder="请输入班组名称" class="form-input" :disabled="coilDetail.dataType === 0"
v-model="form.team" :class="{ 'form-input-disabled': coilDetail.dataType === 0 }" />
placeholder="请输入班组名称"
class="form-input"
:disabled="coilDetail.dataType === 0"
:class="{ 'form-input-disabled': coilDetail.dataType === 0 }"
/>
</view> </view>
<!-- 库区选择 --> <!-- 库区选择 -->
<view class="form-item form-item-optional"> <view class="form-item form-item-optional">
<text class="form-label-optional">目标库</text> <text class="form-label-optional">目标库</text>
<view <klp-warehouse-picker v-model="form.warehouseId" :disabled="coilDetail.dataType === 0" placeholder="请选择目标库区"
class="picker-input" @change="handleWarehouseChange" />
@click="coilDetail.dataType !== 0 && showWarehousePicker()"
:class="{ 'picker-input-disabled': coilDetail.dataType === 0 }"
>
<text class="picker-text" :class="{ 'picker-placeholder': !currentWarehouseName }">
{{ currentWarehouseName || '请选择目标库区' }}
</text>
<text class="picker-arrow" v-if="coilDetail.dataType !== 0"></text>
</view> </view>
<view class="form-item form-item-optional">
<text class="form-label-optional">真实库区</text>
<klp-warehouse-picker v-model="form.actualWarehouseId" :disabled="coilDetail.dataType === 0" placeholder="请选择目标库区"
ware-type="actual" />
</view> </view>
<!-- 物品类型选择 --> <!-- 物品类型选择 -->
<view class="form-item form-item-optional"> <view class="form-item form-item-optional">
<text class="form-label-optional">物品类型</text> <text class="form-label-optional">物品类型</text>
<view <view class="picker-input" @click="coilDetail.dataType !== 0 && showItemTypePicker()"
class="picker-input" :class="{ 'picker-input-disabled': coilDetail.dataType === 0 }">
@click="coilDetail.dataType !== 0 && showItemTypePicker()"
:class="{ 'picker-input-disabled': coilDetail.dataType === 0 }"
>
<text class="picker-text" :class="{ 'picker-placeholder': !form.itemType }"> <text class="picker-text" :class="{ 'picker-placeholder': !form.itemType }">
{{ form.itemType === 'product' ? '成品' : form.itemType === 'raw_material' ? '原料' : '请选择物品类型' }} {{ form.itemType === 'product' ? '成品' : form.itemType === 'raw_material' ? '原料' : '请选择物品类型' }}
</text> </text>
@@ -113,11 +98,8 @@
<!-- 产品选择仅当选择了成品类型时显示 --> <!-- 产品选择仅当选择了成品类型时显示 -->
<view class="form-item form-item-optional" v-if="form.itemType === 'product'"> <view class="form-item form-item-optional" v-if="form.itemType === 'product'">
<text class="form-label-optional">选择产品</text> <text class="form-label-optional">选择产品</text>
<view <view class="picker-input" @click="coilDetail.dataType !== 0 && showProductPicker()"
class="picker-input" :class="{ 'picker-input-disabled': coilDetail.dataType === 0 }">
@click="coilDetail.dataType !== 0 && showProductPicker()"
:class="{ 'picker-input-disabled': coilDetail.dataType === 0 }"
>
<text class="picker-text" :class="{ 'picker-placeholder': !selectedProductName }"> <text class="picker-text" :class="{ 'picker-placeholder': !selectedProductName }">
{{ selectedProductName || '请选择产品' }} {{ selectedProductName || '请选择产品' }}
</text> </text>
@@ -128,11 +110,8 @@
<!-- 原材料选择仅当选择了原料类型时显示 --> <!-- 原材料选择仅当选择了原料类型时显示 -->
<view class="form-item form-item-optional" v-if="form.itemType === 'raw_material'"> <view class="form-item form-item-optional" v-if="form.itemType === 'raw_material'">
<text class="form-label-optional">选择原材料</text> <text class="form-label-optional">选择原材料</text>
<view <view class="picker-input" @click="coilDetail.dataType !== 0 && showRawMaterialPicker()"
class="picker-input" :class="{ 'picker-input-disabled': coilDetail.dataType === 0 }">
@click="coilDetail.dataType !== 0 && showRawMaterialPicker()"
:class="{ 'picker-input-disabled': coilDetail.dataType === 0 }"
>
<text class="picker-text" :class="{ 'picker-placeholder': !selectedRawMaterialName }"> <text class="picker-text" :class="{ 'picker-placeholder': !selectedRawMaterialName }">
{{ selectedRawMaterialName || '请选择原材料' }} {{ selectedRawMaterialName || '请选择原材料' }}
</text> </text>
@@ -143,27 +122,15 @@
<!-- 毛重 --> <!-- 毛重 -->
<view class="form-item form-item-optional"> <view class="form-item form-item-optional">
<text class="form-label-optional">毛重 ()</text> <text class="form-label-optional">毛重 ()</text>
<input <input v-model="form.grossWeight" type="digit" placeholder="请输入毛重(选填)" class="form-input"
v-model="form.grossWeight" :disabled="coilDetail.dataType === 0" :class="{ 'form-input-disabled': coilDetail.dataType === 0 }" />
type="digit"
placeholder="请输入毛重(选填)"
class="form-input"
:disabled="coilDetail.dataType === 0"
:class="{ 'form-input-disabled': coilDetail.dataType === 0 }"
/>
</view> </view>
<!-- 净重 --> <!-- 净重 -->
<view class="form-item form-item-optional"> <view class="form-item form-item-optional">
<text class="form-label-optional">净重 ()</text> <text class="form-label-optional">净重 ()</text>
<input <input v-model="form.netWeight" type="digit" placeholder="请输入净重(选填)" class="form-input"
v-model="form.netWeight" :disabled="coilDetail.dataType === 0" :class="{ 'form-input-disabled': coilDetail.dataType === 0 }" />
type="digit"
placeholder="请输入净重(选填)"
class="form-input"
:disabled="coilDetail.dataType === 0"
:class="{ 'form-input-disabled': coilDetail.dataType === 0 }"
/>
</view> </view>
<!-- 操作者信息 --> <!-- 操作者信息 -->
@@ -174,50 +141,13 @@
<!-- 操作按钮 --> <!-- 操作按钮 -->
<view class="action-buttons"> <view class="action-buttons">
<button class="btn btn-secondary" @click="handleReset">重新扫码</button> <button class="btn btn-secondary" @click="handleReScan">重新扫码</button>
<button <button v-if="coilDetail.dataType === 1" class="btn btn-primary" @click="handleConfirm" :disabled="loading">
v-if="coilDetail.dataType === 1"
class="btn btn-primary"
@click="handleConfirm"
:disabled="loading"
>
{{ loading ? '提交中...' : '保存' }} {{ loading ? '提交中...' : '保存' }}
</button> </button>
</view> </view>
</view> </view>
<!-- 库区选择弹窗 -->
<uni-popup ref="warehousePopup" type="bottom">
<view class="warehouse-popup">
<view class="popup-header">
<text class="popup-title">选择库区</text>
<text class="popup-close" @click="closeWarehousePicker"></text>
</view>
<view class="popup-search">
<input
v-model="warehouseSearchKeyword"
@input="filterWarehousesInPicker"
placeholder="搜索库区名称"
class="search-input"
/>
</view>
<scroll-view class="popup-body" scroll-y>
<view
class="warehouse-item"
v-for="warehouse in filteredWarehousesInPicker"
:key="warehouse.warehouseId"
@click="selectWarehouseFromPicker(warehouse)"
>
<text class="warehouse-name">{{ warehouse.warehouseName }}</text>
<text class="warehouse-check" v-if="form.warehouseId === warehouse.warehouseId"></text>
</view>
<view class="empty-tip" v-if="!filteredWarehousesInPicker || filteredWarehousesInPicker.length === 0">
<text>未找到匹配的库区</text>
</view>
</scroll-view>
</view>
</uni-popup>
<!-- 产品选择弹窗 --> <!-- 产品选择弹窗 -->
<uni-popup ref="productPopup" type="bottom"> <uni-popup ref="productPopup" type="bottom">
<view class="warehouse-popup"> <view class="warehouse-popup">
@@ -226,20 +156,12 @@
<text class="popup-close" @click="closeProductPicker"></text> <text class="popup-close" @click="closeProductPicker"></text>
</view> </view>
<view class="popup-search"> <view class="popup-search">
<input <input v-model="productSearchKeyword" @input="filterProductsInPicker" placeholder="搜索产品名称"
v-model="productSearchKeyword" class="search-input" />
@input="filterProductsInPicker"
placeholder="搜索产品名称"
class="search-input"
/>
</view> </view>
<scroll-view scroll-y class="popup-body"> <scroll-view scroll-y class="popup-body">
<view <view class="warehouse-item" v-for="product in filteredProductsInPicker" :key="product.productId"
class="warehouse-item" @click="selectProductFromPicker(product)">
v-for="product in filteredProductsInPicker"
:key="product.productId"
@click="selectProductFromPicker(product)"
>
<text class="warehouse-name">{{ product.productName }}</text> <text class="warehouse-name">{{ product.productName }}</text>
<text class="warehouse-check" v-if="form.itemId === product.productId"></text> <text class="warehouse-check" v-if="form.itemId === product.productId"></text>
</view> </view>
@@ -258,20 +180,12 @@
<text class="popup-close" @click="closeRawMaterialPicker"></text> <text class="popup-close" @click="closeRawMaterialPicker"></text>
</view> </view>
<view class="popup-search"> <view class="popup-search">
<input <input v-model="rawMaterialSearchKeyword" @input="filterRawMaterialsInPicker" placeholder="搜索原材料名称"
v-model="rawMaterialSearchKeyword" class="search-input" />
@input="filterRawMaterialsInPicker"
placeholder="搜索原材料名称"
class="search-input"
/>
</view> </view>
<scroll-view scroll-y class="popup-body"> <scroll-view scroll-y class="popup-body">
<view <view class="warehouse-item" v-for="material in filteredRawMaterialsInPicker" :key="material.rawMaterialId"
class="warehouse-item" @click="selectRawMaterialFromPicker(material)">
v-for="material in filteredRawMaterialsInPicker"
:key="material.rawMaterialId"
@click="selectRawMaterialFromPicker(material)"
>
<text class="warehouse-name">{{ material.rawMaterialName }}</text> <text class="warehouse-name">{{ material.rawMaterialName }}</text>
<text class="warehouse-check" v-if="form.itemId === material.rawMaterialId"></text> <text class="warehouse-check" v-if="form.itemId === material.rawMaterialId"></text>
</view> </view>
@@ -333,11 +247,24 @@
</template> </template>
<script> <script>
import { getGenerateRecord } from '@/api/wms/code.js' import {
import { updateMaterialCoil, getMaterialCoil, getMaterialCoilTrace } from '@/api/wms/coil.js' getGenerateRecord
import { listWarehouse } from '@/api/wms/warehouse.js' } from '@/api/wms/code.js'
import { getRawMaterial, listRawMaterial } from '@/api/wms/rawMaterial.js' import {
import { listProduct } from '@/api/wms/product.js' updateMaterialCoil,
getMaterialCoil,
getMaterialCoilTrace
} from '@/api/wms/coil.js'
import {
listWarehouse
} from '@/api/wms/warehouse.js'
import {
getRawMaterial,
listRawMaterial
} from '@/api/wms/rawMaterial.js'
import {
listProduct
} from '@/api/wms/product.js'
export default { export default {
data() { data() {
@@ -349,9 +276,10 @@ import { listProduct } from '@/api/wms/product.js'
team: '', team: '',
currentCoilNo: '', currentCoilNo: '',
warehouseId: undefined, warehouseId: undefined,
actualWarehouseId: undefined,
warehouseName: '', warehouseName: '',
grossWeight: '', grossWeight: '',
netWeight: '' netWeight: '',
}, },
coilDetail: {}, coilDetail: {},
materialDetail: null, materialDetail: null,
@@ -384,41 +312,24 @@ import { listProduct } from '@/api/wms/product.js'
}, },
onLoad() { onLoad() {
this.loadWarehouses();
this.loadProducts(); this.loadProducts();
this.loadRawMaterials(); this.loadRawMaterials();
}, },
mounted() { mounted() {
this.loadWarehouses();
this.loadProducts(); this.loadProducts();
this.loadRawMaterials(); this.loadRawMaterials();
}, },
methods: { methods: {
// 加载库区列表
async loadWarehouses() {
console.log('开始加载库区...');
try {
const res = await listWarehouse({ pageNum: 1, pageSize: 1000 });
console.log("库区返回值", res);
if (res.code === 200) {
this.warehouses = res.data || [];
this.filteredWarehouses = this.warehouses;
console.log('库区加载成功,数量:', this.warehouses.length);
} else {
console.error('库区加载失败:', res.msg);
}
} catch (err) {
console.error('加载库区异常:', err);
}
},
// 加载产品列表 // 加载产品列表
async loadProducts() { async loadProducts() {
console.log('开始加载产品列表...'); console.log('开始加载产品列表...');
try { try {
const res = await listProduct({ pageNum: 1, pageSize: 1000 }); const res = await listProduct({
pageNum: 1,
pageSize: 1000
});
console.log("产品返回值", res); console.log("产品返回值", res);
if (res.code === 200) { if (res.code === 200) {
this.products = res.rows || res.data || []; this.products = res.rows || res.data || [];
@@ -436,7 +347,10 @@ import { listProduct } from '@/api/wms/product.js'
async loadRawMaterials() { async loadRawMaterials() {
console.log('开始加载原材料列表...'); console.log('开始加载原材料列表...');
try { try {
const res = await listRawMaterial({ pageNum: 1, pageSize: 1000 }); const res = await listRawMaterial({
pageNum: 1,
pageSize: 1000
});
console.log("原材料返回值", res); console.log("原材料返回值", res);
if (res.code === 200) { if (res.code === 200) {
this.rawMaterials = res.rows || res.data || []; this.rawMaterials = res.rows || res.data || [];
@@ -526,65 +440,12 @@ import { listProduct } from '@/api/wms/product.js'
this.closeRawMaterialPicker(); this.closeRawMaterialPicker();
}, },
// 过滤库区 // 处理库区选择变化(可选,如需获取完整库区信息)
filterWarehouses() { handleWarehouseChange(warehouse) {
console.log('过滤库区,关键词:', this.warehouseKeyword); console.log('选中的库区信息:', warehouse)
console.log('当前库区列表:', this.warehouses); // 可在这里更新库区名称等信息
const keyword = this.warehouseKeyword.trim().toLowerCase(); this.form.warehouseName = warehouse.warehouseName
if (!keyword) { this.currentWarehouseName = warehouse.warehouseName
this.filteredWarehouses = this.warehouses;
} else {
this.filteredWarehouses = this.warehouses.filter(item => {
const name = (item.warehouseName || '').toLowerCase();
return name.includes(keyword);
});
}
console.log('过滤后库区数量:', this.filteredWarehouses.length);
this.showWarehouseList = true;
},
// 选择库区
selectWarehouse(warehouse) {
this.form.warehouseId = warehouse.warehouseId;
this.form.warehouseName = warehouse.warehouseName;
this.warehouseKeyword = warehouse.warehouseName;
// 关闭搜索结果列表
this.$nextTick(() => {
this.showWarehouseList = false;
});
},
// 显示库区选择器
showWarehousePicker() {
this.warehouseSearchKeyword = '';
this.filteredWarehousesInPicker = [...this.warehouses];
this.$refs.warehousePopup.open();
},
// 关闭库区选择器
closeWarehousePicker() {
this.$refs.warehousePopup.close();
},
// 在选择器中过滤库区
filterWarehousesInPicker() {
const keyword = this.warehouseSearchKeyword.trim().toLowerCase();
if (!keyword) {
this.filteredWarehousesInPicker = [...this.warehouses];
} else {
this.filteredWarehousesInPicker = this.warehouses.filter(warehouse => {
const name = (warehouse.warehouseName || '').toLowerCase();
return name.includes(keyword);
});
}
},
// 从选择器中选择库区
async selectWarehouseFromPicker(warehouse) {
this.form.warehouseId = warehouse.warehouseId;
this.form.warehouseName = warehouse.warehouseName;
this.currentWarehouseName = warehouse.warehouseName;
this.closeWarehousePicker();
}, },
// 显示物品类型选择器 // 显示物品类型选择器
@@ -656,7 +517,8 @@ import { listProduct } from '@/api/wms/product.js'
// 4. 通过入场钢卷号查询钢卷追溯信息 // 4. 通过入场钢卷号查询钢卷追溯信息
const traceRes = await getMaterialCoilTrace(enterCoilNo, currentCoilNo); const traceRes = await getMaterialCoilTrace(enterCoilNo, currentCoilNo);
if (traceRes.code !== 200 || !traceRes.data || !traceRes.data.records || traceRes.data.records.length === 0) { if (traceRes.code !== 200 || !traceRes.data || !traceRes.data.records || traceRes.data.records
.length === 0) {
throw new Error('未找到钢卷信息'); throw new Error('未找到钢卷信息');
} }
@@ -693,6 +555,7 @@ import { listProduct } from '@/api/wms/product.js'
this.form.itemType = coilData.itemType || ''; this.form.itemType = coilData.itemType || '';
this.form.itemId = coilData.itemId; this.form.itemId = coilData.itemId;
this.form.warehouseId = coilData.warehouseId; this.form.warehouseId = coilData.warehouseId;
this.form.actualWarehouseId = coilData.actualWarehouseId;
this.form.grossWeight = coilData.grossWeight || ''; this.form.grossWeight = coilData.grossWeight || '';
this.form.netWeight = coilData.netWeight || ''; this.form.netWeight = coilData.netWeight || '';
@@ -750,12 +613,18 @@ import { listProduct } from '@/api/wms/product.js'
this.showWarehouseList = false; this.showWarehouseList = false;
}, },
// 重新扫码 handleReScan() {
handleReset() {
uni.showModal({ uni.showModal({
title: '确认重新扫码', title: '确认重新扫码',
content: '是否要清空当前数据并重新扫码?', content: '是否要清空当前数据并重新扫码?',
success: (res) => { success: (res) => {
this.handleReset()
}
});
},
// 重新扫码
handleReset() {
if (res.confirm) { if (res.confirm) {
this.form = { this.form = {
coilId: undefined, coilId: undefined,
@@ -764,6 +633,7 @@ import { listProduct } from '@/api/wms/product.js'
team: '', team: '',
currentCoilNo: '', currentCoilNo: '',
warehouseId: undefined, warehouseId: undefined,
actualWarehouseId: undefined,
warehouseName: '', warehouseName: '',
grossWeight: '', grossWeight: '',
netWeight: '' netWeight: ''
@@ -777,25 +647,32 @@ import { listProduct } from '@/api/wms/product.js'
this.filteredWarehouses = this.warehouses; this.filteredWarehouses = this.warehouses;
this.qrcodeStatus = 1; // 重置二维码状态 this.qrcodeStatus = 1; // 重置二维码状态
} }
}
});
}, },
// 提交 // 提交
handleConfirm() { handleConfirm() {
// 历史数据不允许修改 // 历史数据不允许修改
if (this.coilDetail.dataType === 0) { if (this.coilDetail.dataType === 0) {
uni.showToast({ title: '历史数据不允许修改', icon: 'none' }); uni.showToast({
title: '历史数据不允许修改',
icon: 'none'
});
return; return;
} }
// 验证必填项 // 验证必填项
if (!this.form.currentCoilNo) { if (!this.form.currentCoilNo) {
uni.showToast({ title: '请输入当前钢卷号', icon: 'none' }); uni.showToast({
title: '请输入当前钢卷号',
icon: 'none'
});
return; return;
} }
if (!this.form.team) { if (!this.form.team) {
uni.showToast({ title: '请输入班组', icon: 'none' }); uni.showToast({
title: '请输入班组',
icon: 'none'
});
return; return;
} }
@@ -809,19 +686,23 @@ import { listProduct } from '@/api/wms/product.js'
itemId: this.form.itemId, itemId: this.form.itemId,
team: this.form.team, team: this.form.team,
warehouseId: this.form.warehouseId, warehouseId: this.form.warehouseId,
actualWarehouseId: this.form.actualWarehouseId,
grossWeight: this.form.grossWeight ? Number(this.form.grossWeight) : null, grossWeight: this.form.grossWeight ? Number(this.form.grossWeight) : null,
netWeight: this.form.netWeight ? Number(this.form.netWeight) : null netWeight: this.form.netWeight ? Number(this.form.netWeight) : null
}; };
updateMaterialCoil(submitData).then(res => { updateMaterialCoil(submitData).then(res => {
if (res.code === 200) { if (res.code === 200) {
uni.showToast({ // uni.showToast({
title: '保存成功', // title: '保存成功',
icon: 'success' // icon: 'success'
}); // });
setTimeout(() => { // setTimeout(() => {
this.handleReset(); this.handleReset();
}, 1500); // }, 1500);
uni.navigateTo({
url: '/pages/scansuccess/scansuccess'
})
} else { } else {
uni.showToast({ uni.showToast({
title: res.msg || '保存失败', title: res.msg || '保存失败',

View File

@@ -1,14 +1,14 @@
// 应用全局配置 // 应用全局配置
module.exports = { module.exports = {
baseUrl: 'http://192.168.31.116:8080', // baseUrl: 'http://192.168.31.116:8080',
// baseUrl: 'http://140.143.206.120:8080', baseUrl: 'http://140.143.206.120:8080',
// baseUrl: 'http://localhost:8080', // baseUrl: 'http://localhost:8080',
// 应用信息 // 应用信息
appInfo: { appInfo: {
// 应用名称 // 应用名称
name: "ruoyi-app", name: "ruoyi-app",
// 应用版本 // 应用版本
version: "1.2.0", version: "1.3.5",
// 应用logo // 应用logo
logo: "/static/logo.jpg", logo: "/static/logo.jpg",
// 官方网站 // 官方网站

View File

@@ -2,7 +2,7 @@
"name" : "科伦普", "name" : "科伦普",
"appid" : "__UNI__E781B49", "appid" : "__UNI__E781B49",
"description" : "", "description" : "",
"versionName" : "3.4", "versionName" : "3.5",
"versionCode" : 1, "versionCode" : 1,
"transformPx" : false, "transformPx" : false,
"app-plus" : { "app-plus" : {

View File

@@ -48,6 +48,13 @@
"navigationBarTitleText" : "产线监控", "navigationBarTitleText" : "产线监控",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
},
{
"path" : "pages/scansuccess/scansuccess",
"style" :
{
"navigationBarTitleText" : "扫码结果"
}
} }
// { // {
// "path": "pages/register", // "path": "pages/register",

View File

@@ -137,17 +137,20 @@
uni.hideLoading(); uni.hideLoading();
console.log('=== 扫码流程完成 ==='); console.log('=== 扫码流程完成 ===');
uni.showToast({ uni.navigateTo({
title: '创建成功', url: '/pages/scansuccess/scansuccess'
icon: 'success', })
duration: 2000 // uni.showToast({
}); // title: '创建成功',
// icon: 'success',
// duration: 2000
// });
// 延迟后返回或跳转 // // 延迟后返回或跳转
setTimeout(() => { // setTimeout(() => {
// 可以跳转到待操作列表或返回上一页 // // 可以跳转到待操作列表或返回上一页
uni.navigateBack(); // uni.navigateBack();
}, 2000); // }, 2000);
} catch (err) { } catch (err) {
console.error('=== 扫码处理失败 ==='); console.error('=== 扫码处理失败 ===');

View File

@@ -1,93 +1,139 @@
<template> <template>
<!-- <view class="production-page"> <!-- 模板内容保持不变注释部分可根据需求保留 -->
<klp-header @lineChange="setActive" class="line-header"></klp-header>
<view class="content-wrapper">
<Acidity v-if="active == 0"/>
<Paint v-else-if="active == 1"/>
<Zinc1 v-else-if="active == 2"></Zinc1>
<Zinc2 v-else-if="active == 3"></Zinc2>
<Zinc3 v-else-if="active == 4"></Zinc3>
</view>
</view> -->
</template> </template>
<script> <script>
// 根据不同的全责跳转到不同的页面
// 如果是工人跳转到扫码页面
// 如果是管理员跳转到产线
export default { export default {
created() { data() {
return {
hasJumped: false // 防止重复跳转的标记
}
},
onShow() {
// 已跳转过则不再执行逻辑
if (this.hasJumped) return;
// 显示加载状态,提升用户感知
uni.showLoading({
title: '验证身份中...',
mask: true // 防止用户重复操作
});
// 检查用户角色 // 检查用户角色
this.$store.dispatch('GetInfo').then(res => { this.$store.dispatch('GetInfo')
.then(res => {
uni.hideLoading(); // 关闭加载提示
console.log('获取身份信息内容', res.data, )
// 验证返回数据格式
if (!res || !res.data || !Array.isArray(res.data.roles)) {
throw new Error('用户角色信息格式错误');
}
console.log('用户角色信息', res.data.roles)
const roles = res.data.roles; const roles = res.data.roles;
if (roles.includes('admin')) { if (roles.includes('admin')) {
// 管理员角色跳转到产线页面 // 管理员角色跳转
uni.switchTab({ uni.switchTab({
url: '/pages/line/line' url: '/pages/line/line',
success: () => {
this.hasJumped = true; // 标记已跳转
},
fail: (err) => {
console.error('管理员页面跳转失败:', err);
uni.showToast({
title: '跳转产线页面失败',
icon: 'none',
duration: 2000
});
}
}); });
} else if (roles.includes('worker')) { } else if (roles.includes('worker')) {
// 工人角色跳转到扫码页面 // 工人角色跳转
uni.navigateTo({ uni.navigateTo({
url: '/pages/easycode/easycode' url: '/pages/easycode/easycode',
success: () => {
this.hasJumped = true; // 标记已跳转
},
fail: (err) => {
console.error('工人页面跳转失败:', err);
uni.showToast({
title: '跳转扫码页面失败',
icon: 'none',
duration: 2000
}); });
} }
// else { });
// // 其他角色,跳转到扫码页面 } else {
// uni.navigateTo({ // 处理未定义角色(默认角色)
// url: '/pages/easycode/easycode' uni.showToast({
// }); title: '检测到未知角色,将跳转至默认页面',
// } icon: 'none',
duration: 2000
});
// 延迟跳转,确保提示被用户看到
setTimeout(() => {
uni.navigateTo({
url: '/pages/easycode/easycode',
success: () => {
this.hasJumped = true;
},
fail: (err) => {
console.error('默认角色页面跳转失败:', err);
uni.showToast({
title: '跳转默认页面失败',
icon: 'none',
duration: 2000
});
}
});
}, 2000);
}
}) })
.catch(err => {
uni.reLaunch({
url: '/pages/login'
})
// uni.hideLoading(); // 关闭加载提示
// console.error('用户信息获取失败:', err);
// // 区分错误类型,给出更精准提示
// const errorMsg = err.message || '网络异常,请检查网络后重试';
// uni.showToast({
// title: errorMsg,
// icon: 'none',
// duration: 3000
// });
// // 提供重试入口
// setTimeout(() => {
// uni.showModal({
// title: '加载失败',
// content: '是否重新登录?',
// success: (res) => {
// if (res.confirm) {
// uni.reLaunch({
// url: '/pages/login'
// })
// }
// }
// });
// }, 3000);
});
} }
} }
// import Acidity from '@/components/lines/acidity.vue'
// import Paint from '@/components/lines/paint.vue'
// import Zinc1 from '@/components/lines/zinc1.vue'
// import Zinc2 from '@/components/lines/zinc2.vue'
// import Zinc3 from '@/components/lines/zinc3.vue'
// export default {
// components: {
// Acidity,
// Paint,
// Zinc1,
// Zinc2,
// Zinc3
// },
// data() {
// return {
// active: 0
// }
// },
// methods: {
// next() {
// if (this.active >= 5) {
// this.active = 0
// } else {
// this.active += 1
// }
// },
// setActive({ index, line }) {
// this.active = index;
// }
// }
// }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
/* 主容器 - 简洁背景 */ /* 样式保持不变 */
.production-page { .production-page {
min-height: 100vh; min-height: 100vh;
background: #f6f6f6; background: #f6f6f6;
} }
/* 顶部装饰 */
.page-header { .page-header {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -124,7 +170,6 @@ export default {
background: #fff; background: #fff;
} }
/* 内容容器 */
.content-wrapper { .content-wrapper {
padding: 0; padding: 0;
} }

View File

@@ -0,0 +1,142 @@
<template>
<view class="scan-success-page">
<!-- 成功图标 -->
<view class="success-icon">
<view class="icon-circle">
<view class="icon-check"></view>
</view>
</view>
<!-- 成功提示文字 -->
<view class="success-text">
<text class="main-text">扫码成功</text>
<text class="sub-text">信息已验证通过</text>
</view>
<!-- 返回按钮 -->
<button class="back-btn" @click="handleBack">
返回
</button>
</view>
</template>
<script>
export default {
methods: {
// 处理返回逻辑
handleBack() {
// 返回上一页如果是从首页跳转可改为switchTab
uni.navigateBack({
delta: 1,
fail: () => {
// 若返回失败则改用switchTab跳转
uni.switchTab({
url: '/pages/code/code'
});
}
});
}
}
};
</script>
<style scoped lang="scss">
.scan-success-page {
min-height: 100vh;
background-color: #ffffff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 40rpx;
}
// 成功图标样式
.success-icon {
margin-bottom: 60rpx;
.icon-circle {
width: 180rpx;
height: 180rpx;
border-radius: 50%;
background-color: #eaffea;
display: flex;
align-items: center;
justify-content: center;
animation: circleScale 0.5s ease-out;
.icon-check {
width: 100rpx;
height: 50rpx;
border-left: 10rpx solid #00b42a;
border-bottom: 10rpx solid #00b42a;
transform: rotate(-45deg);
animation: checkShow 0.3s ease-out 0.2s backwards;
}
}
}
// 文字提示样式
.success-text {
text-align: center;
margin-bottom: 100rpx;
.main-text {
font-size: 36rpx;
color: #333333;
font-weight: 600;
display: block;
margin-bottom: 20rpx;
}
.sub-text {
font-size: 28rpx;
color: #666666;
}
}
// 返回按钮样式
.back-btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
background-color: #007aff;
color: #ffffff;
font-size: 32rpx;
border-radius: 45rpx;
margin-top: 40rpx;
box-shadow: 0 4rpx 10rpx rgba(0, 122, 255, 0.3);
transition: all 0.2s ease;
&:active {
background-color: #0066cc;
transform: scale(0.98);
}
}
// 动画定义
@keyframes circleScale {
0% {
transform: scale(0);
opacity: 0;
}
70% {
transform: scale(1.1);
opacity: 1;
}
100% {
transform: scale(1);
}
}
@keyframes checkShow {
0% {
opacity: 0;
transform: rotate(-45deg) scale(0.5);
}
100% {
opacity: 1;
transform: rotate(-45deg) scale(1);
}
}
</style>