项目初始化

This commit is contained in:
liuhanqing
2025-10-16 14:37:22 +08:00
commit 69c2dc5cd5
1636 changed files with 306197 additions and 0 deletions

View File

@@ -0,0 +1,448 @@
<template>
<view class="container">
<view class="input-group">
<text class="input-label">{{ $t('inbound.backIn.rackCode') }}</text>
<uni-easyinput
v-model="rackCode"
:placeholder="$t('inbound.backIn.rackCodePlaceholder')"
:clearable="true"
@input="handleInput"
@clear="handleClear"
ref="rackCodeInput">
<template #right>
<text class="scan-icon" @click="handleScan">📷</text>
</template>
</uni-easyinput>
</view>
<view class="loading-container" v-if="loading">
<uni-load-more status="loading" :content-text="{contentdown: $t('inbound.backIn.loading'),contentrefresh: $t('inbound.backIn.loading'),contentnomore: $t('common.noData')}"></uni-load-more>
</view>
<view class="card-container" v-if="materialList.length > 0">
<uni-card v-for="(item, index) in materialList" :key="index" class="material-card">
<view class="card-content">
<view class="info-row">
<text class="label">{{ $t('inbound.backIn.materialCode') }}</text>
<text class="value">{{ item.productId }}</text>
</view>
<view class="info-row">
<text class="label">{{ $t('inbound.backIn.materialName') }}</text>
<text class="value">{{ item.productName }}</text>
</view>
<view class="info-row">
<text class="label">{{ $t('inbound.backIn.quantity') }}</text>
<uni-easyinput
v-model="item.editQuantity"
type="number"
:placeholder="String(item.quantity)"
class="quantity-input"
@input="handleQuantityChange(index)"
/>
</view>
</view>
</uni-card>
</view>
<view class="empty-state" v-if="!loading && materialList.length === 0 && rackCode">
<text>{{ $t('inbound.backIn.noMaterialInfo') }}</text>
</view>
<view class="button-container" v-if="materialList.length > 0">
<button class="submit-button" @click="handleSubmit">{{ $t('inbound.backIn.submit') }}</button>
</view>
<!-- 仓库选择弹窗 -->
<uni-popup ref="warehousePopup" type="center">
<view class="popup-content">
<view class="popup-title">{{ $t('inbound.backIn.selectWarehouse') }}</view>
<view class="popup-body">
<uni-data-select
v-model="selectedWarehouseId"
:localdata="warehouseList"
:clear="false"
:placeholder="$t('inbound.backIn.warehousePlaceholder')"
/>
</view>
<view class="popup-footer">
<button class="cancel-button" @click="closeWarehousePopup">{{ $t('inbound.backIn.cancel') }}</button>
<button class="confirm-button" @click="confirmSubmit">{{ $t('inbound.backIn.confirm') }}</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import { getContainerDetails, agvRequest } from '@/api/in/order.js'
import { getBasWarehouList } from '@/api/bas/bas.js'
export default {
data() {
return {
rackCode: '',
materialList: [],
loading: false,
submitting: false,
warehouseList: [],
selectedWarehouseId: '',
preparedSubmitData: null
}
},
onReady() {
setTimeout(() => {
this.$nextTick(() => {
this.$refs.rackCodeInput.onFocus()
})
}, 100)
// 获取仓库列表
this.getWarehouseList()
},
methods: {
// 获取仓库列表
async getWarehouseList() {
try {
const response = await getBasWarehouList({
pageNum: 1,
pageSize: 100,
typeData: ['2']
})
if (response.code === 200) {
this.warehouseList = response.rows.map(item => ({
value: item.warehouseId,
text: item.warehouseName,
type: item.warehouseType
}))
}
} catch (error) {
console.error('获取仓库列表失败:', error)
uni.showToast({
title: this.$t('inbound.backIn.getWarehouseListFailed'),
icon: 'none'
})
}
},
// 处理输入事件
handleInput(value) {
if (value) {
this.fetchRackInfo(value)
}
},
// 处理清除事件
handleClear() {
this.materialList = []
},
// 处理扫码事件
handleScan() {
uni.scanCode({
success: (res) => {
this.rackCode = res.result
this.fetchRackInfo(res.result)
}
})
},
// 获取料架信息
async fetchRackInfo(rackCode) {
this.loading = true
try {
const response = await getContainerDetails({
"containerId":rackCode,
"pageNum":1,
"pageSize":100
})
if (response.code === 200) {
if (response.rows && response.rows.length > 0) {
this.materialList = response.rows.map(item => {
return {
...item,
editQuantity: String(item.quantity)
}
})
} else {
this.materialList = []
uni.showToast({
title: this.$t('inbound.backIn.noMaterialInfo'),
icon: 'none'
})
}
} else {
this.materialList = []
uni.showToast({
title: response.msg || this.$t('inbound.backIn.getRackInfoFailed'),
icon: 'none'
})
}
} catch (error) {
this.materialList = []
uni.showToast({
title: this.$t('inbound.backIn.getRackInfoFailed'),
icon: 'none'
})
} finally {
this.loading = false
}
},
// 处理数量变更
handleQuantityChange(index) {
// 确保输入的是有效数字
const value = this.materialList[index].editQuantity
if (value === '' || isNaN(Number(value))) {
this.materialList[index].editQuantity = '0'
}
},
// 打开仓库选择弹窗
openWarehousePopup() {
this.$refs.warehousePopup.open()
},
// 关闭仓库选择弹窗
closeWarehousePopup() {
this.$refs.warehousePopup.close()
this.submitting = false
},
// 处理提交
async handleSubmit() {
if (this.submitting) return
if (this.materialList.length === 0) {
uni.showToast({
title: this.$t('inbound.backIn.noSubmitMaterial'),
icon: 'none'
})
return
}
if(!this.rackCode){
uni.showToast({
title: this.$t('inbound.backIn.enterRackCode'),
icon: 'none'
})
return
}
// 验证输入
let isValid = true
this.materialList.forEach(item => {
if (item.editQuantity === '' || isNaN(Number(item.editQuantity)) || Number(item.editQuantity) < 0) {
isValid = false
}
})
if (!isValid) {
uni.showToast({
title: this.$t('inbound.backIn.enterValidQuantity'),
icon: 'none'
})
return
}
this.submitting = true
// 准备提交数据
const submitData = this.materialList.map(item => {
return {
id: item.id,
productId: item.productId,
quantity: Number(item.editQuantity)
}
})
// 检查是否有数量不为0的物料
const hasNonZeroQuantity = submitData.some(item => item.quantity > 0)
if (hasNonZeroQuantity) {
// 保存提交数据,打开仓库选择弹窗
this.preparedSubmitData = submitData
this.openWarehousePopup()
} else {
// 直接提交
await this.submitData(submitData)
}
},
// 确认提交(选择仓库后)
async confirmSubmit() {
if (!this.selectedWarehouseId) {
uni.showToast({
title: this.$t('inbound.backIn.selectWarehouse'),
icon: 'none'
})
return
}
this.closeWarehousePopup()
await this.submitData(this.preparedSubmitData, this.selectedWarehouseId)
},
// 提交数据
async submitData(submitData, warehouseId = null) {
try {
const requestData = {
"details": submitData,
"containerId": this.rackCode
}
// 如果有仓库ID,添加到请求数据中
if (warehouseId) {
requestData.spare1 = warehouseId
}
const response = await agvRequest(requestData)
if (response.code === 200) {
uni.showToast({
title: this.$t('inbound.backIn.submitSuccess'),
icon: 'success'
})
// 更新本地数据
this.materialList.forEach(item => {
item.quantity = Number(item.editQuantity)
})
} else {
uni.showToast({
title: response.msg || this.$t('inbound.backIn.submitFailed'),
icon: 'none'
})
}
} catch (error) {
uni.showToast({
title: this.$t('inbound.backIn.submitFailed'),
icon: 'none'
})
console.error(error)
} finally {
this.submitting = false
}
}
}
}
</script>
<style lang="scss">
.container {
padding: 20rpx;
background-color: #f8f9fc;
}
.input-group {
margin-bottom: 20rpx;
display: flex;
align-items: center;
}
.input-label {
width: 180rpx;
font-size: 28rpx;
}
.scan-icon {
font-size: 40rpx;
padding: 0 20rpx;
}
.card-container {
margin-top: 30rpx;
}
.material-card {
margin-bottom: 20rpx;
}
.card-content {
padding: 10rpx;
}
.info-row {
display: flex;
margin-bottom: 15rpx;
}
.label {
width: 180rpx;
font-size: 28rpx;
color: #666;
}
.value {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
.empty-state {
margin-top: 100rpx;
display: flex;
justify-content: center;
align-items: center;
color: #999;
font-size: 28rpx;
}
.loading-container {
margin-top: 50rpx;
display: flex;
justify-content: center;
}
.quantity-input {
flex: 1;
margin-left: 10rpx;
}
.button-container {
margin-top: 50rpx;
padding: 0 30rpx;
}
.submit-button {
background-color: #007aff;
color: #fff;
border-radius: 8rpx;
font-size: 32rpx;
height: 80rpx;
line-height: 80rpx;
}
/* 弹窗样式 */
.popup-content {
width: 600rpx;
background-color: #fff;
border-radius: 16rpx;
overflow: hidden;
}
.popup-title {
font-size: 32rpx;
font-weight: bold;
padding: 30rpx;
text-align: center;
border-bottom: 1rpx solid #eee;
}
.popup-body {
padding: 30rpx;
}
.popup-footer {
display: flex;
border-top: 1rpx solid #eee;
}
.cancel-button, .confirm-button {
flex: 1;
height: 80rpx;
line-height: 80rpx;
text-align: center;
font-size: 28rpx;
}
.cancel-button {
background-color: #f2f2f2;
color: #666;
}
.confirm-button {
background-color: #007aff;
color: #fff;
}
</style>

View File

@@ -0,0 +1,727 @@
<template>
<view class="container">
<view class="input-group">
<text class="input-label">{{ $t('inbound.bindMsg.trayCode') }}</text>
<uni-easyinput
v-model="trayCode"
:placeholder="$t('inbound.bindMsg.trayCodePlaceholder')"
:clearable="true"
@input="handleInput"
@clear="handleClear"
ref="trayCodeInput"
>
<template #right>
<text class="scan-icon" @click="handleScan">📷</text>
</template>
</uni-easyinput>
</view>
<view class="input-group">
<text class="input-label">{{ $t('inbound.bindMsg.subOrder') }}</text>
<uni-easyinput
v-model="stockinDetailId"
:placeholder="$t('inbound.bindMsg.subOrderPlaceholder')"
:clearable="true"
@input="handleSubOrderInput"
@clear="handleSubOrderClear"
ref="subOrderInput"
>
</uni-easyinput>
</view>
<!-- 子单据数据弹窗 -->
<uni-popup ref="subOrderPopup" type="center">
<view class="popup-content">
<view class="popup-title">{{ $t('inbound.bindMsg.subOrderInfo') }}</view>
<view class="popup-body">
<view v-if="subOrderInfo" class="info-item">
<view class="info-row">
<text class="info-label">{{ $t('inbound.bindMsg.warehouse') }}</text>
<text class="info-value">{{ subOrderInfo.warehouseName }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ $t('inbound.bindMsg.orderNumber') }}</text>
<text class="info-value">{{ subOrderInfo.stockinId }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ $t('inbound.bindMsg.materialCode') }}</text>
<text class="info-value">{{ subOrderInfo.productId }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ $t('inbound.bindMsg.materialName') }}</text>
<text class="info-value">{{ subOrderInfo.extraField.materialDesc }}</text>
</view>
<view class="info-row quantity-row">
<text class="info-label">{{ $t('inbound.bindMsg.quantity') }}</text>
<uni-easyinput
v-model="inQuantity"
type="number"
:maxlength="String(subOrderInfo.quantity).length"
:placeholder="$t('inbound.bindMsg.maxQuantity') + subOrderInfo.quantity"
@input="handleQuantityInput"
class="quantity-input"
/>
</view>
</view>
<view v-else class="no-data">{{ $t('inbound.bindMsg.noData') }}</view>
</view>
<view class="popup-buttons">
<button class="popup-btn confirm-btn" @click="handleBindSubOrder" :disabled="!subOrderInfo || subOrderInfo.quantity <= 0" :class="{'disabled-btn': !subOrderInfo || subOrderInfo.quantity <= 0}">{{ $t('inbound.bindMsg.bind') }}</button>
<button class="popup-btn cancel-btn" @click="handleCancelSubOrder">{{ $t('inbound.bindMsg.cancel') }}</button>
</view>
</view>
</uni-popup>
<view class="table-container" v-if="materialList.length > 0">
<uni-table border stripe :emptyText="$t('inbound.bindMsg.noData')">
<uni-tr>
<uni-th align="center">{{ $t('inbound.bindMsg.warehouseColumn') }}</uni-th>
<uni-th align="center">{{ $t('inbound.bindMsg.materialNameColumn') }}</uni-th>
<uni-th align="center">{{ $t('inbound.bindMsg.quantityColumn') }}</uni-th>
<uni-th align="center">{{ $t('inbound.bindMsg.operationColumn') }}</uni-th>
</uni-tr>
<uni-tr v-for="(item, index) in materialList" :key="index">
<uni-td align="center">{{ item.warehouseName }}</uni-td>
<uni-td align="center">{{ item.productName }}</uni-td>
<uni-td align="center">{{ item.quantity }}</uni-td>
<uni-td align="center">
<button class="unbind-btn" @click="handleUnbind(item.stockinDetailId)">{{ $t('inbound.bindMsg.unbind') }}</button>
</uni-td>
</uni-tr>
</uni-table>
</view>
<view class="button-group" v-if="materialList.length > 0">
<button class="confirm-button" @click="handleConfirm">{{ $t('inbound.bindMsg.confirmInbound') }}</button>
</view>
<!-- 货位选择弹出框 -->
<uni-popup ref="cargoSpacePopup" type="center">
<view class="popup-content">
<view class="popup-title">{{ $t('inbound.bindMsg.selectCargoSpace') }}</view>
<view class="popup-body">
<view class="input-group cargo-space-input">
<text class="input-label">{{ $t('inbound.bindMsg.cargoSpace') }}</text>
<uni-easyinput
v-model="cargoSpaceName"
:placeholder="$t('inbound.bindMsg.cargoSpacePlaceholder')"
:clearable="true"
@input="handleCargoSpaceInput"
>
<template #right>
<button class="recommend-btn" @click="handleRecommendCargoSpace">{{ $t('inbound.bindMsg.recommendCargoSpace') }}</button>
</template>
</uni-easyinput>
</view>
<view v-if="cargoSpaceHeight" class="cargo-space-height">
<text>{{ $t('inbound.bindMsg.cargoSpaceHeight') }} {{ cargoSpaceHeight }}{{ $t('inbound.bindMsg.meter') }}</text>
</view>
</view>
<view class="popup-buttons">
<button class="popup-btn confirm-btn" @click="handleConfirmCargoSpace">{{ $t('inbound.bindMsg.confirm') }}</button>
<button class="popup-btn cancel-btn" @click="handleCancelCargoSpace">{{ $t('inbound.bindMsg.cancel') }}</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import { getTrayInfo,addInJob,getOrderGoods ,bindTray, unbindTray} from '@/api/in/order.js'
import { getBasWarehouList, getCargoSpaceList } from '@/api/bas/bas.js'
export default {
data() {
return {
trayCode: '',
stockinDetailId: '',
subOrderInfo: null,
inQuantity:'',
materialList: [],
// currentWarehouseType: '',
cargoSpaceId: '',
cargoSpaceName: '',
cargoSpaceList: [],
cargoSpaceHeight: null,
}
},
onReady() {
setTimeout(() => {
this.$nextTick(() => {
this.$refs.trayCodeInput.onFocus()
})
}, 100)
},
methods: {
// 处理货位选择
async handleRecommendCargoSpace() {
// try {
const response = await getCargoSpaceList({ warehouseId: this.materialList[0].warehouseId, status: 1 })
if (response.code === 200 && response.rows.length > 0) {
// 获取第一个推荐货位
this.cargoSpaceId = response.rows[0].cargoSpaceId
this.cargoSpaceName = response.rows[0].cargoSpaceName
// 手动触发handleCargoSpaceInput方法获取货位高度信息
await this.handleCargoSpaceInput(response.rows[0].cargoSpaceName)
} else {
uni.showToast({
title: this.$t('inbound.bindMsg.noAvailableCargoSpace'),
icon: 'none'
})
}
// } catch (error) {
// uni.showToast({
// title: '获取推荐货位失败',
// icon: 'none'
// })
// }
},
// 处理货位选择
async handleCargoSpaceInput(value) {
if (value) {
try {
const response = await getCargoSpaceList({ cargoSpaceName: value, warehouseId: this.materialList[0].warehouseId })
if (response.code === 200 && response.rows.length > 0) {
this.cargoSpaceId = response.rows[0].cargoSpaceId
this.cargoSpaceHeight = response.rows[0].cargoHight
} else {
uni.showToast({
title: this.$t('inbound.bindMsg.getCargoSpaceInfoFailed'),
icon: 'none'
})
this.cargoSpaceId = ''
this.cargoSpaceHeight = null
}
} catch (error) {
uni.showToast({
title: this.$t('inbound.bindMsg.getCargoSpaceInfoFailed'),
icon: 'none'
})
this.cargoSpaceId = ''
this.cargoSpaceHeight = null
}
} else {
this.cargoSpaceId = ''
this.cargoSpaceHeight = null
}
},
// 带货位信息提交入库
async submitWithCargoSpace() {
if (!this.cargoSpaceId) {
uni.showToast({
title: this.$t('inbound.bindMsg.selectCargoSpace'),
icon: 'none'
})
return
}
try {
const response = await addInJob({
cargoSpaceId: this.cargoSpaceId,
trayCode: this.trayCode,
warehouseId: this.materialList[0].warehouseId
})
if (response.code === 200) {
uni.showToast({
title: this.$t('inbound.bindMsg.inboundSuccess'),
icon: 'success'
})
// 清空数据
this.trayCode = ''
this.materialList = []
this.cargoSpaceId = ''
this.cargoSpaceName = ''
this.cargoSpaceHeight=''
// this.currentWarehouseType = ''
} else {
uni.showToast({
title: response.msg || this.$t('inbound.bindMsg.inboundFailed'),
icon: 'none'
})
}
} catch (error) {
uni.showToast({
title: this.$t('inbound.bindMsg.inboundFailed'),
icon: 'none'
})
}
},
// 处理输入事件
handleInput(value) {
if (value) {
this.fetchTrayInfo(value)
}
},
// 处理清除事件
handleClear() {
this.materialList = []
},
// 处理扫码事件
handleScan() {
uni.scanCode({
success: (res) => {
this.trayCode = res.result
this.fetchTrayInfo(res.result)
}
})
},
// 获取托盘信息
async fetchTrayInfo(trayCode) {
try {
const response = await getTrayInfo(trayCode)
if (response.code===200) {
if(response.data.length>0){
this.materialList = response.data
}else{
this.materialList=[]
}
} else {
uni.showToast({
title: response.msg || this.$t('inbound.bindMsg.getTrayInfoFailed'),
icon: 'none'
})
}
} catch (error) {
uni.showToast({
title: this.$t('inbound.bindMsg.getTrayInfoFailed'),
icon: 'none'
})
}
},
// 处理确认入库事件
async handleConfirm() {
if (!this.trayCode || this.materialList.length === 0) {
uni.showToast({
title: this.$t('inbound.bindMsg.scanTrayFirst'),
icon: 'none'
})
return
}
const warehouseType = this.materialList[0].warehouseType
if (warehouseType === '1') {
// 显示货位选择弹出框
this.$refs.cargoSpacePopup.open()
} else {
// 非货位类型仓库,直接调用入库接口
try {
const response = await addInJob({
trayCode: this.trayCode,
warehouseId: this.materialList[0].warehouseId
})
if (response.code === 200) {
uni.showToast({
title: this.$t('inbound.bindMsg.inboundSuccess'),
icon: 'success'
})
// 清空数据
this.trayCode = ''
this.materialList = []
this.stockinDetailId=''
// this.cargoSpaceId = ''
} else {
uni.showToast({
title: response.msg || this.$t('inbound.bindMsg.inboundFailed'),
icon: 'none'
})
}
} catch (error) {
uni.showToast({
title: this.$t('inbound.bindMsg.inboundFailed'),
icon: 'none'
})
}
}
},
// 处理货位选择
handleConfirmCargoSpace() {
if (!this.cargoSpaceId) {
uni.showToast({
title: this.$t('inbound.bindMsg.selectCargoSpaceOrScan'),
icon: 'none'
})
return
}
this.$refs.cargoSpacePopup.close()
this.submitWithCargoSpace()
},
// 处理取消货位选择
handleCancelCargoSpace() {
this.$refs.cargoSpacePopup.close()
this.cargoSpaceId = ''
this.cargoSpaceName = ''
this.cargoSpaceHeight=''
},
// 处理子单据输入事件
async handleSubOrderInput(value) {
if (value) {
// 调用获取子单据信息
const goodsResponse = await getOrderGoods({stockinDetailId:value})
if (goodsResponse.length===0) {
uni.showToast({
title: this.$t('inbound.bindMsg.materialNotExistOrNoPermission'),
icon: 'none'
})
return
}
this.subOrderInfo= goodsResponse
console.log(this.subOrderInfo)
if (this.subOrderInfo) {
this.$refs.subOrderPopup.open()
}
}
},
// 处理子单据清除事件
handleSubOrderClear() {
// this.stockinDetailId = ''
this.subOrderInfo = null
},
handleQuantityInput(value) {
const numValue = Number(value)
if (numValue <= 0) {
this.inQuantity = ''
uni.showToast({
title: this.$t('inbound.bindMsg.quantityGreaterThanZero'),
icon: 'none'
})
return
}
if (numValue > this.subOrderInfo.quantity) {
this.inQuantity = String(this.subOrderInfo.quantity)
uni.showToast({
title: this.$t('inbound.bindMsg.notExceedMaxQuantity'),
icon: 'none'
})
return
}
this.inQuantity = String(numValue)
},
handleQuantityInput(value) {
const numValue = Number(value)
if (numValue <= 0) {
this.inQuantity = ''
uni.showToast({
title: this.$t('inbound.bindMsg.quantityGreaterThanZero'),
icon: 'none'
})
return
}
if (numValue > this.subOrderInfo.quantity) {
this.inQuantity = String(this.subOrderInfo.quantity)
uni.showToast({
title: this.$t('inbound.bindMsg.notExceedMaxQuantity'),
icon: 'none'
})
return
}
this.inQuantity = String(numValue)
},
// 处理绑定子单据事件
async handleBindSubOrder() {
// 验证必填信息
if (!this.trayCode) {
uni.showToast({
title: this.$t('inbound.bindMsg.enterTrayCode'),
icon: 'none'
})
return
}
if (!this.inQuantity || Number(this.inQuantity) <= 0) {
uni.showToast({
title: this.$t('inbound.bindMsg.enterValidQuantity'),
icon: 'none'
})
return
}
// 确保提交的数量不超过最大可用数量
const submitQuantity = Number(this.inQuantity)
if (submitQuantity > this.subOrderInfo.quantity && this.subOrderInfo.quantity > 0) {
this.inQuantity = String(this.subOrderInfo.quantity)
uni.showToast({
title: this.$t('inbound.bindMsg.autoAdjustMaxQuantity'),
icon: 'none'
})
}
const response = await bindTray({
trayCode: this.trayCode,
stockinDetailId: this.stockinDetailId,
inQuantity:this.inQuantity
})
if (response.code === 200) {
uni.showToast({
title: this.$t('inbound.bindMsg.bindSuccess'),
icon: 'success'
})
this.$refs.subOrderPopup.close()
this.stockinDetailId = ''
this.subOrderInfo = null
this.inQuantity=''
this.fetchTrayInfo(this.trayCode)
} else {
uni.showToast({
title: response.msg || this.$t('inbound.bindMsg.bindFailed'),
icon: 'none'
})
}
},
// 处理取消子单据事件
handleCancelSubOrder() {
if (this.$refs.subOrderPopup) {
this.$refs.subOrderPopup.close()
}
this.stockinDetailId = ''
this.subOrderInfo = null
this.inQuantity = ''
},
// 处理解绑事件
async handleUnbind(stockinDetailId) {
try {
const response = await unbindTray({
trayCode: this.trayCode,
stockinDetailId: stockinDetailId
})
if (response.code === 200) {
uni.showToast({
title: this.$t('inbound.bindMsg.unbindSuccess'),
icon: 'success'
})
// 刷新托盘信息
this.fetchTrayInfo(this.trayCode)
} else {
uni.showToast({
title: response.msg || this.$t('inbound.bindMsg.unbindFailed'),
icon: 'none'
})
}
} catch (error) {
uni.showToast({
title: this.$t('inbound.bindMsg.unbindFailed'),
icon: 'none'
})
}
}
}
}
</script>
<style>
.unbind-btn {
background-color: #ff4d4f;
color: #ffffff;
border: none;
border-radius: 4rpx;
padding: 10rpx 20rpx;
font-size: 24rpx;
cursor: pointer;
}
.unbind-btn:active {
background-color: #cf1322;
}
.container {
padding: 20rpx;
}
.input-group {
margin-bottom: 30rpx;
}
.input-label {
display: block;
margin-bottom: 10rpx;
font-size: 28rpx;
color: #333;
}
.scan-icon {
font-size: 40rpx;
padding: 0 20rpx;
}
.table-container {
background-color: #ffffff;
border-radius: 8rpx;
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
}
.cargo-space-container {
margin-bottom: 30rpx;
}
.cargo-space-input {
display: flex;
align-items: center;
}
.recommend-btn {
background-color: #409eff;
color: #ffffff;
border-radius: 4rpx;
padding: 0 20rpx;
height: 60rpx;
line-height: 60rpx;
font-size: 28rpx;
margin-left: 20rpx;
}
.button-group {
margin-top: 30rpx;
padding: 0 20rpx;
}
.confirm-button {
background-color: #409eff;
color: #ffffff;
border-radius: 8rpx;
padding: 20rpx 0;
font-size: 32rpx;
}
.popup-content {
background-color: #fff;
border-radius: 10rpx;
padding: 40rpx;
width: 85%;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
max-height: 80vh;
overflow-y: auto;
}
.popup-title {
font-size: 36rpx;
font-weight: bold;
text-align: center;
margin-bottom: 40rpx;
color: #333;
border-bottom: 1px solid #eee;
padding-bottom: 20rpx;
}
.popup-body {
padding: 20rpx 10rpx;
max-height: 60vh;
overflow-y: auto;
}
.popup-buttons {
display: flex;
justify-content: space-around;
margin-top: 40rpx;
padding-top: 20rpx;
border-top: 1px solid #eee;
}
.popup-btn {
padding: 20rpx 50rpx;
border-radius: 8rpx;
font-size: 28rpx;
transition: all 0.3s;
}
.confirm-btn {
background-color: #007aff;
color: #fff;
font-weight: 500;
}
.confirm-btn:active {
background-color: #0062cc;
transform: scale(0.98);
}
.cancel-btn {
background-color: #f2f2f2;
color: #666;
border: 1px solid #ddd;
}
.cancel-btn:active {
background-color: #e6e6e6;
transform: scale(0.98);
}
.disabled-btn {
background-color: #ccc;
color: #fff;
cursor: not-allowed;
}
.cargo-space-height {
margin-top: 10rpx;
padding: 10rpx;
color: #666;
font-size: 24rpx;
background-color: #f8f8f8;
border-radius: 6rpx;
text-align: center;
}
.info-item {
padding: 15rpx;
background-color: #f9f9f9;
border-radius: 8rpx;
}
.info-row {
margin-bottom: 15rpx;
display: flex;
align-items: center;
}
.info-label {
width: 180rpx;
font-size: 28rpx;
color: #666;
font-weight: 500;
}
.info-value {
flex: 1;
font-size: 28rpx;
color: #333;
word-break: break-all;
}
.quantity-row {
align-items: flex-start;
}
.quantity-input {
width: 200rpx;
display: inline-block;
background-color: #fff;
border-radius: 4rpx;
}
.no-data {
text-align: center;
padding: 30rpx;
color: #999;
font-size: 28rpx;
}
</style>

View File

@@ -0,0 +1,317 @@
<template>
<view class="container">
<view class="input-group">
<uni-easyinput
v-model="formData.trayCode"
placeholder="请输入或扫码输入托盘条码"
:clearable="true"
@clear="handleClear"
@confirm="handleConfirm"
ref="trayCodeInput"
auto-focus
>
<template #right>
<text class="scan-icon" @click="handleScan">📷</text>
</template>
</uni-easyinput>
</view>
<view class="info-group">
<view class="info-item">
<text class="info-label">物料名称:</text>
<text class="info-value">{{productInfo.name}}</text>
</view>
<!-- <view class="info-item">
<text class="info-label">批号:</text>
<text class="info-value">{{productInfo.lotNo}}</text>
</view> -->
<view class="info-item">
<text class="info-label">数量:</text>
<uni-easyinput
v-model="formData.inQuantity"
type="number"
:maxlength="String(productInfo.quantity).length"
:placeholder="'最大可输入' + productInfo.quantity"
@input="handleQuantityInput"
ref="quantityInput"
/>
<!-- <text class="info-value" style="margin-left: 10rpx;">/{{productInfo.quantity}}</text> -->
</view>
</view>
<view class="button-group">
<button class="bind-button" @click="handleBind" :disabled="productInfo.quantity == 0" :class="{'bind-button-disabled': productInfo.quantity == 0}">绑定托盘</button>
</view>
</view>
</template>
<script>
import { getOrderGoods, bindTray } from '@/api/in/order.js'
export default {
onReady() {
setTimeout(() => {
this.$nextTick(() => {
// console.log(this.$refs.trayCodeInput)
this.$refs.trayCodeInput.onFocus()
})
}, 100)
},
data() {
return {
formData: {
trayCode: '',
stockinDetailId: '',
inQuantity:''
},
productInfo: {
name: '',
productId:'',
quantity: 0
}
}
},
async onLoad(options) {
if (options.stockinDetailId) {
this.formData.stockinDetailId = options.stockinDetailId
try {
const response = await getOrderGoods({
stockinDetailId: options.stockinDetailId
})
const product = response[0]
console.log(product)
// if (product) {
this.productInfo = {
name: product.extraField.materialDesc || '',
productId: product.extraField.productId || '',
quantity: product.quantity || 0
// }
}
} catch (error) {
console.error('获取物料信息失败:', error)
uni.showToast({
title: '获取物料信息失败',
icon: 'none'
})
}
}
},
methods: {
handleClear() {
this.formData.trayCode = ''
},
handleQuantityInput(value) {
const numValue = Number(value)
if (numValue <= 0) {
this.formData.inQuantity = ''
uni.showToast({
title: '数量必须大于0',
icon: 'none'
})
return
}
if (numValue > this.productInfo.quantity) {
this.formData.inQuantity = String(this.productInfo.quantity)
uni.showToast({
title: '不能超过最大数量',
icon: 'none'
})
return
}
this.formData.inQuantity = String(numValue)
},
handleConfirm() {
// 处理确认事件
console.log('确认输入:', this.formData)
// 将焦点转移到数量输入框
this.$refs.quantityInput.focus()
},
handleScan() {
// 调用扫码功能
uni.scanCode({
success: (res) => {
this.formData.trayCode = res.result
}
})
},
async handleBind() {
// 验证必填信息
if (!this.formData.trayCode) {
uni.showToast({
title: '请输入托盘条码',
icon: 'none'
})
return
}
if (!this.formData.inQuantity || Number(this.formData.inQuantity) <= 0) {
uni.showToast({
title: '请输入大于0的数量',
icon: 'none'
})
return
}
// 确保提交的数量不超过最大可用数量
const submitQuantity = Number(this.formData.inQuantity)
if (submitQuantity > this.productInfo.quantity) {
this.formData.inQuantity = String(this.productInfo.quantity)
uni.showToast({
title: '已自动调整为最大可用数量',
icon: 'none'
})
}
// try {
const response = await bindTray(this.formData)
console.log(response)
if (response.code === 200) {
uni.showToast({
title: '绑定成功',
icon: 'success'
})
// 返回上一页并传递刷新标记
setTimeout(() => {
const pages = getCurrentPages()
const prevPage = pages[pages.length - 2]
if (prevPage) {
prevPage.$vm.needRefresh = true
}
uni.navigateBack()
}, 1500)
} else {
uni.showToast({
title: response.msg || '绑定失败',
icon: 'none'
})
}
// } catch (error) {
// // console.error('绑定托盘失败:', error)
// uni.showToast({
// title: '绑定托盘失败',
// icon: 'none'
// })
// }
}
}
}
</script>
<style>
.container {
padding: 20rpx;
background-color: #f5f7fa;
min-height: 100vh;
}
.input-group {
margin-bottom: 20rpx;
background-color: #fff;
padding: 20rpx;
border-radius: 12rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
}
.scan-icon {
font-size: 40rpx;
padding: 0 20rpx;
color: #409eff;
transition: opacity 0.3s ease;
}
.scan-icon:active {
opacity: 0.7;
}
.info-group {
background-color: #fff;
padding: 30rpx;
border-radius: 12rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
}
.info-item {
margin-bottom: 24rpx;
display: flex;
align-items: center;
}
.info-item:last-child {
margin-bottom: 0;
}
.info-label {
color: #606266;
margin-right: 16rpx;
font-size: 28rpx;
min-width: 140rpx;
}
.info-value {
color: #303133;
font-weight: 500;
font-size: 28rpx;
flex: 1;
}
:deep(.uni-easyinput__content) {
background-color: #f5f7fa;
border-radius: 8rpx;
border: 2rpx solid #dcdfe6;
transition: all 0.3s ease;
}
:deep(.uni-easyinput__content-input) {
font-size: 28rpx;
}
:deep(.is-input-border) {
border-color: #dcdfe6 !important;
}
:deep(.uni-easyinput__content:hover) {
border-color: #c0c4cc;
}
:deep(.uni-easyinput__content.is-focus) {
border-color: #409eff;
}
:deep(.is-disabled) {
background-color: #f5f7fa;
border-color: #e4e7ed;
}
.button-group {
margin-top: 40rpx;
padding: 0 20rpx;
}
.bind-button {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background: linear-gradient(90deg, #409eff, #007aff);
color: #fff;
font-size: 32rpx;
border-radius: 44rpx;
border: none;
}
.bind-button:active {
opacity: 0.8;
}
.bind-button-disabled {
background: linear-gradient(90deg, #a0cfff, #8cc5ff);
cursor: not-allowed;
}
</style>

View File

@@ -0,0 +1,436 @@
<template>
<view class="container">
<view class="search-box">
<uni-easyinput
v-model="stockinId"
:placeholder="$t('inbound.inorder.searchPlaceholder')"
:clearable="true"
@clear="handleClear"
@confirm="handleSearch"
@input="handleSearch"
ref="detailIdInput">
<template #right>
<text class="scan-icon" @click="handleScan">📷</text>
</template>
</uni-easyinput>
</view>
<view class="card-list">
<view v-if="orderList && orderList.length > 0">
<view v-for="(order, index) in orderList" :key="index" class="order-card">
<uni-card>
<view class="card-content">
<view class="order-header" @click="handleOrderClick(order)">
<view class="info-row">
<text class="label">{{ $t('inbound.inorder.orderNumber') }}</text>
<text class="value">{{ order.stockinId }}</text>
</view>
<view class="info-row">
<text class="label">{{ $t('inbound.inorder.createTime') }}</text>
<text class="value">{{ order.createDate }}</text>
</view>
<view class="info-row">
<text class="label">{{ $t('inbound.inorder.supplier') }}</text>
<text class="value">{{ order.supplierName }}</text>
</view>
</view>
<!-- 展开时显示物料信息 -->
<view v-if="order.expanded && order.goodsList" class="goods-list" @click.stop>
<view class="goods-title">{{ $t('inbound.inorder.goodsInfo') }}</view>
<view class="goods-table">
<view class="table-header">
<text class="header-cell" style="display: none;">{{ $t('inbound.inorder.productCode') }}</text>
<text class="header-cell">{{ $t('inbound.inorder.productName') }}</text>
<text class="header-cell">{{ $t('inbound.inorder.planQuantity') }}</text>
<text class="header-cell">{{ $t('inbound.inorder.inboundQuantity') }}</text>
</view>
<view v-for="(goods, goodsIndex) in order.goodsList" :key="goodsIndex" class="table-row">
<text class="table-cell" style="display: none;">{{ goods.productId }}</text>
<text class="table-cell material-name">{{ goods.extraField.materialDesc }}</text>
<text class="table-cell">{{ goods.quantity }}</text>
<view class="table-cell">
<uni-easyinput
v-model="goods.inQuantity"
type="number"
:maxlength="String(goods.quantity-goods.assignNum).length"
:max="goods.quantity-goods.assignNum"
@input="handleInQuantityChange(goods)"
:min="0"
style="width: 180rpx; display: inline-block;"
/>
</view>
<view class="table-cell">
<button class="operate-btn" @click.stop="handleInStock(goods)" :class="{'operate-btn-disabled': !isValidQuantity(goods)}">
{{ $t('inbound.inorder.inbound') }}
</button>
</view>
</view>
</view>
</view>
</view>
</uni-card>
</view>
</view>
<view v-else class="no-data">{{ $t('inbound.inorder.noOrderInfo') }}</view>
</view>
</view>
</template>
<script>
import { getInOrderList, getInOrderDetail, pkIn } from '@/api/in/order'
export default {
data() {
return {
stockinId: "",
orderList: [],
needRefresh: false
}
},
onReady() {
setTimeout(() => {
this.$nextTick(() => {
this.$refs.detailIdInput.onFocus()
})
}, 100)
},
onLoad() {
this.getOrderList()
},
onShow() {
if (this.needRefresh) {
this.getOrderList()
this.needRefresh = false
}
},
methods: {
// 获取入库单列表
async getOrderList() {
try {
const response = await getInOrderList({"stockinId":this.stockinId})
this.orderList = response.map(order => ({
...order,
expanded: false,
goodsList: null
}))
} catch (error) {
console.error('获取入库单列表失败:', error)
uni.showToast({
title: this.$t('inbound.inorder.getOrderListFailed'),
icon: 'none'
})
}
},
// 获取物品列表
async getGoodsList(order) {
try {
const goodsResponse = await getInOrderDetail({
stockinId: order.stockinId,
pageSize:100,
pageNum:1,
status:1
})
order.goodsList = goodsResponse.rows.map(item => ({
...item,
inQuantity: item.quantity-item.assignNum
}))
} catch (error) {
console.error('获取物品信息失败:', error)
uni.showToast({
title: this.$t('inbound.inorder.getItemInfoFailed'),
icon: 'none'
})
}
},
// 处理入库单点击
async handleOrderClick(order) {
// 切换展开状态
order.expanded = !order.expanded
// 如果展开且还没有加载物品列表,则加载物品列表
if (order.expanded && !order.goodsList) {
await this.getGoodsList(order)
}
},
// 处理搜索
handleSearch(value) {
if (value !== undefined) {
this.stockinId = value
}
this.getOrderList()
},
// 处理清除
handleClear() {
this.stockinId = ""
this.getOrderList()
},
// 处理扫码
handleScan() {
uni.scanCode({
success: (res) => {
this.stockinId = res.result
this.getOrderList()
}
})
},
// 验证入库数量是否有效
isValidQuantity(goods) {
const inQuantity = Number(goods.inQuantity);
return inQuantity > 0 && inQuantity <= (goods.quantity - goods.assignNum);
},
// 处理入库数量变化
handleInQuantityChange(goods) {
const maxQuantity = goods.quantity - goods.assignNum;
if (Number(goods.inQuantity) > maxQuantity) {
goods.inQuantity = maxQuantity;
uni.showToast({
title: this.$t('inbound.inorder.exceedInboundQuantity'),
icon: 'none'
});
}
},
// 处理入库操作
async handleInStock(goods) {
if (!this.isValidQuantity(goods)) {
uni.showToast({
title: this.$t('inbound.inorder.enterValidQuantity'),
icon: 'none'
})
return
}
try {
await pkIn({
stockinDetailId: goods.stockinDetailId,
inQuantity: goods.inQuantity
})
uni.showToast({
title: this.$t('inbound.inorder.inboundSuccess'),
icon: 'success'
})
// 刷新列表
this.getOrderList()
} catch (error) {
console.error('入库操作失败:', error)
uni.showToast({
title: this.$t('inbound.inorder.inboundFailed'),
icon: 'none'
})
}
}
}
}
</script>
<style lang="scss">
.container {
padding: 20rpx;
background-color: #f8f9fc;
}
.search-box {
margin-bottom: 20rpx;
position: relative;
background-color: #fff;
border-radius: 8rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
padding: 20rpx;
:deep(.uni-easyinput__content) {
background-color: #f8f9fc;
border-radius: 6rpx;
border: 2rpx solid #e8e8e8;
transition: all 0.3s ease;
&:hover, &:focus-within {
border-color: #409eff;
}
}
.scan-icon {
padding: 0 20rpx;
font-size: 40rpx;
line-height: 70rpx;
color: #409eff;
cursor: pointer;
transition: opacity 0.3s ease;
&:hover {
opacity: 0.8;
}
}
}
.card-list {
.order-card {
margin-bottom: 20rpx;
transition: all 0.3s ease;
:deep(.uni-card) {
background-color: #fff;
border-radius: 8rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
border: none;
overflow: hidden;
}
&:hover {
transform: translateY(-2rpx);
:deep(.uni-card) {
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
}
}
}
.card-content {
.info-row {
display: flex;
margin-bottom: 16rpx;
align-items: center;
&:last-child {
margin-bottom: 0;
}
.label {
color: #909399;
width: 160rpx;
font-size: 28rpx;
}
.value {
color: #303133;
flex: 1;
font-size: 28rpx;
}
}
}
.goods-list {
margin-top: 20rpx;
padding-top: 20rpx;
border-top: 2rpx solid #ebeef5;
.goods-title {
font-size: 28rpx;
color: #606266;
margin-bottom: 16rpx;
font-weight: bold;
}
.goods-table {
width: 100%;
border-radius: 6rpx;
overflow: hidden;
background-color: #f8f9fc;
.table-header {
display: flex;
background-color: #f2f3f5;
padding: 16rpx;
.header-cell {
flex: 1;
color: #606266;
font-size: 26rpx;
font-weight: bold;
text-align: center;
&:nth-child(1) {
flex: 2;
}
&:nth-child(2), &:nth-child(3) {
flex: 0.8;
}
&:nth-child(4) {
flex: 1.2;
}
}
}
.table-row {
display: flex;
padding: 16rpx;
border-bottom: 2rpx solid #ebeef5;
&:last-child {
border-bottom: none;
}
.table-cell {
flex: 1;
color: #303133;
font-size: 26rpx;
text-align: center;
padding: 0 8rpx;
display: flex;
align-items: center;
justify-content: center;
&:nth-child(1) {
flex: 2;
}
&:nth-child(2), &:nth-child(3) {
flex: 0.8;
}
&:nth-child(4) {
flex: 1.2;
}
&.material-name {
overflow: visible;
white-space: normal;
word-break: break-word;
justify-content: flex-start;
}
.operate-btn {
background-color: #409eff;
color: #fff;
border: none;
padding: 4rpx 20rpx;
border-radius: 4rpx;
font-size: 24rpx;
cursor: pointer;
&:hover {
background-color: #66b1ff;
}
&:active {
background-color: #3a8ee6;
}
}
}
}
}
.no-goods {
text-align: center;
color: #909399;
font-size: 26rpx;
padding: 30rpx 0;
}
}
.operate-btn-disabled {
background-color: #c0c4cc !important;
cursor: not-allowed !important;
opacity: 0.6 !important;
&:hover {
background-color: #c0c4cc !important;
}
}
</style>

View File

@@ -0,0 +1,282 @@
<template>
<view class="container">
<view class="input-group">
<text class="input-label">料箱条码:</text>
<uni-easyinput
v-model="formData.trayCode"
placeholder="请输入或扫码输入料箱条码"
:clearable="true"
@clear="handleClear"
@confirm="handleConfirm"
ref="trayCodeInput"
>
<template #right>
<text class="scan-icon" @click="handleScan">📷</text>
</template>
</uni-easyinput>
</view>
<view class="input-group">
<text class="input-label">仓库</text>
<uni-data-select
v-model="formData.warehouseId"
:localdata="warehouseList"
:clear="false"
placeholder="请选择仓库"
/>
</view>
<view class="input-group">
<text class="input-label">入口</text>
<uni-data-select
v-model="formData.entranceId"
:localdata="entranceIdList"
:clear="false"
placeholder="请选择入口"
/>
</view>
<view class="button-group">
<button class="submit-button" @click="handleSubmit">空料箱入库</button>
</view>
</view>
</template>
<script>
import { emptyBoxIn } from '@/api/in/ktpin.js'
import { getBasWarehouList } from '@/api/bas/bas.js'
export default {
data() {
return {
formData: {
trayCode: '',
entranceId: '',
warehouseId: ''
},
entranceIdList: [],
warehouseList: []
}
},
onReady() {
setTimeout(() => {
this.$nextTick(() => {
this.$refs.trayCodeInput.onFocus()
})
}, 100)
this.getWarehouseList()
},
watch: {
'formData.warehouseId': {
handler(newVal) {
if (newVal) {
this.getEntranceList(newVal)
} else {
this.entranceIdList = []
this.formData.entranceId = ''
}
}
}
},
methods: {
// 获取仓库列表
async getWarehouseList() {
try {
const response = await getBasWarehouList({warehouseType:'2'})
if (response.code === 200) {
this.warehouseList = response.rows.map(item => ({
value: item.warehouseId,
text: item.warehouseName
}))
}
} catch (error) {
console.error('获取仓库列表失败:', error)
uni.showToast({
title: '获取仓库列表失败',
icon: 'none'
})
}
},
// 获取入口列表
async getEntranceList(warehouseId) {
try {
// 这里需要根据实际API调整,暂时模拟不同仓库的入口数据
// const response = await getWarehouseEntrances(warehouseId)
const mockData = {
'02': [
{ value: 1, text: '东入口' },
{ value: 2, text: '西入口' }
],
'06': [
{ value: 3, text: '南入口' },
{ value: 4, text: '北入口' }
]
}
this.entranceIdList = mockData[warehouseId] || []
this.formData.entranceId = ''
} catch (error) {
console.error('获取入口列表失败:', error)
uni.showToast({
title: '获取入口列表失败',
icon: 'none'
})
}
},
handleClear() {
this.formData.trayCode = ''
},
handleConfirm() {
// 处理确认事件
},
handleScan() {
// 调用扫码功能
uni.scanCode({
success: (res) => {
this.formData.trayCode = res.result
}
})
},
async handleSubmit() {
// 表单验证
if (!this.formData.trayCode) {
uni.showToast({
title: '请扫描或输入托盘条码',
icon: 'none'
})
return
}
if (!this.formData.entranceId) {
uni.showToast({
title: '请选择入口',
icon: 'none'
})
return
}
if (!this.formData.warehouseId) {
uni.showToast({
title: '请选择仓库',
icon: 'none'
})
return
}
// try {
const response = await emptyBoxIn(this.formData)
if (response.code === 200) {
uni.showToast({
title: '空料箱入库成功',
icon: 'success'
})
// 清空表单
this.formData = {
trayCode: '',
warehouseId:'',
entranceId: ''
}
// 重新聚焦到托盘条码输入框
setTimeout(() => {
this.$nextTick(() => {
this.$refs.trayCodeInput.onFocus()
})
}, 100)
} else {
uni.showToast({
title: response.msg || '入库操作失败',
icon: 'none'
})
}
// } catch (error) {
// console.error('入库失败:', error)
// uni.showToast({
// title: '入库失败',
// icon: 'none'
// })
// }
}
}
}
</script>
<style lang="scss">
.container {
padding: 30rpx;
background-color: #f8f9fc;
min-height: 100vh;
}
.input-group {
margin-bottom: 30rpx;
display: flex;
align-items: center;
.input-label {
font-size: 28rpx;
color: #333;
font-weight: 500;
width: 160rpx;
flex-shrink: 0;
}
:deep(.uni-easyinput__content) {
background-color: #fff;
border-radius: 12rpx;
border: 2rpx solid #e8e8e8;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
transition: all 0.3s ease;
&:focus-within {
border-color: #2979ff;
box-shadow: 0 4rpx 16rpx rgba(41, 121, 255, 0.1);
transform: translateY(-2rpx);
}
}
:deep(.uni-easyinput__content-input) {
height: 88rpx;
padding: 0 30rpx;
font-size: 28rpx;
}
}
.scan-icon {
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
font-size: 40rpx;
color: #2979ff;
transition: all 0.3s ease;
&:active {
transform: scale(0.9);
}
}
.button-group {
padding: 30rpx;
margin-top: 20rpx;
.submit-button {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background-color: #2979ff;
color: #fff;
font-size: 32rpx;
border-radius: 12rpx;
box-shadow: 0 4rpx 16rpx rgba(41, 121, 255, 0.2);
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
box-shadow: 0 2rpx 8rpx rgba(41, 121, 255, 0.2);
}
}
}
</style>

View File

@@ -0,0 +1,459 @@
<template>
<view class="container">
<view class="input-group">
<text class="input-label">{{ $t('inbound.emptyPalletBox.emptyPallet.trayCode') }}</text>
<uni-easyinput
v-model="formData.trayCode"
:placeholder="$t('inbound.emptyPalletBox.emptyPallet.trayCodePlaceholder')"
:clearable="true"
@clear="handleClear"
@confirm="handleConfirm"
ref="trayCodeInput"
>
<template #right>
<text class="scan-icon" @click="handleScan">📷</text>
</template>
</uni-easyinput>
</view>
<view class="input-group">
<text class="input-label">{{ $t('inbound.emptyPalletBox.emptyPallet.warehouse') }}</text>
<uni-data-select
v-model="formData.warehouseId"
:localdata="warehouseList"
:clear="false"
:placeholder="$t('inbound.emptyPalletBox.emptyPallet.warehousePlaceholder')"
@change="handleWarehouseChange"
/>
</view>
<view class="input-group" v-if="currentWarehouseType == '1'">
<text class="input-label">{{ $t('inbound.emptyPalletBox.emptyPallet.cargoSpace') }}</text>
<view class="cargo-input-group">
<uni-easyinput
v-model="formData.cargoSpaceName"
:placeholder="$t('inbound.emptyPalletBox.emptyPallet.cargoSpacePlaceholder')"
:clearable="true"
@input="handleCargoSpaceInput"
/>
<button class="recommend-btn" @click="handleRecommendCargoSpace">{{ $t('inbound.emptyPalletBox.emptyPallet.recommendCargoSpace') }}</button>
</view>
</view>
<view v-if="currentWarehouseType == '1' && cargoSpaceHeight" class="cargo-space-info">
<text class="cargo-space-height">{{ $t('inbound.emptyPalletBox.emptyPallet.cargoSpaceHeight') }}{{ cargoSpaceHeight }}{{ $t('inbound.emptyPalletBox.emptyPallet.meter') }}</text>
</view>
<view class="button-group">
<button class="submit-button" @click="handleSubmit">{{ $t('inbound.emptyPalletBox.emptyPallet.submit') }}</button>
</view>
</view>
</template>
<script>
import { emptyTrayIn } from '@/api/in/ktpin.js'
import { getBasWarehouList,getCargoSpaceList } from '@/api/bas/bas.js'
export default {
data() {
return {
formData: {
trayCode: '',
warehouseId: '',
cargoSpaceId: '',
cargoSpaceName:'',
},
warehouseList: [],
cargoSpaceId: '',
cargoSpaceList: [],
currentWarehouseType: null,
cargoSpaceHeight:''
}
},
onReady() {
setTimeout(() => {
this.$nextTick(() => {
this.$refs.trayCodeInput.onFocus()
})
}, 100)
// 获取仓库列表
this.getWarehouseList()
},
methods: {
// 获取仓库列表
async getWarehouseList() {
try {
const response = await getBasWarehouList({
pageNum:1,
pageSize:100,
typeData:['1','2']
})
if (response.code === 200) {
this.warehouseList = response.rows.map(item => ({
value: item.warehouseId,
text: item.warehouseName,
type: item.warehouseType
}))
}
} catch (error) {
console.error('获取仓库列表失败:', error)
uni.showToast({
title: this.$t('inbound.emptyPalletBox.emptyPallet.getWarehouseListFailed'),
icon: 'none'
})
}
},
handleClear() {
this.formData.trayCode = ''
},
handleConfirm() {
// 处理确认事件
},
handleScan() {
// 调用扫码功能
uni.scanCode({
success: (res) => {
this.formData.trayCode = res.result
}
})
},
handleWarehouseChange(warehouseId) {
if (!warehouseId) return
const selectedWarehouse = this.warehouseList.find(item => item.value === warehouseId)
this.currentWarehouseType = selectedWarehouse ? selectedWarehouse.type : null
},
// 处理货位选择
async handleRecommendCargoSpace() {
// try {
const response = await getCargoSpaceList({ warehouseId: this.formData.warehouseId, status: 1 })
if (response.code === 200 && response.rows.length > 0) {
// 获取第一个推荐货位
this.formData.cargoSpaceId = response.rows[0].cargoSpaceId
this.formData.cargoSpaceName = response.rows[0].cargoSpaceName
// 手动触发handleCargoSpaceInput方法获取货位高度信息
await this.handleCargoSpaceInput(response.rows[0].cargoSpaceName)
} else {
uni.showToast({
title: this.$t('inbound.emptyPalletBox.emptyPallet.noAvailableCargoSpace'),
icon: 'none'
})
}
// } catch (error) {
// uni.showToast({
// title: '获取推荐货位失败',
// icon: 'none'
// })
// }
},
// 处理货位选择
async handleCargoSpaceInput(value) {
if (value) {
try {
const response = await getCargoSpaceList({ cargoSpaceName: value, warehouseId: this.formData.warehouseId })
if (response.code === 200 && response.rows.length > 0) {
this.formData.cargoSpaceId = response.rows[0].cargoSpaceId
this.cargoSpaceHeight = response.rows[0].cargoHight
console.log(this.formData.cargoSpaceId)
} else {
uni.showToast({
title: this.$t('inbound.emptyPalletBox.emptyPallet.getCargoSpaceInfoFailed'),
icon: 'none'
})
this.formData.cargoSpaceId = ''
this.cargoSpaceHeight = null
}
} catch (error) {
uni.showToast({
title: this.$t('inbound.emptyPalletBox.emptyPallet.getCargoSpaceInfoFailed'),
icon: 'none'
})
this.formData.cargoSpaceId = ''
this.cargoSpaceHeight = null
}
} else {
this.formData.cargoSpaceId = ''
this.cargoSpaceHeight = null
}
},
async handleSubmit() {
if (!this.formData.trayCode) {
uni.showToast({
title: this.$t('inbound.emptyPalletBox.emptyPallet.enterTrayCode'),
icon: 'none'
})
return
}
if (!this.formData.warehouseId) {
uni.showToast({
title: this.$t('inbound.emptyPalletBox.emptyPallet.selectWarehouse'),
icon: 'none'
})
return
}
if (this.currentWarehouseType === '1' && (!this.formData.cargoSpaceId || this.formData.cargoSpaceId === null)) {
uni.showToast({
title: this.$t('inbound.emptyPalletBox.emptyPallet.selectCargoSpace'),
icon: 'none'
})
return
}
await emptyTrayIn(this.formData).then(response => {
if (response.code === 200) {
uni.showToast({
title: this.$t('inbound.emptyPalletBox.emptyPallet.inboundSuccess'),
icon: 'success'
})
// 清空表单
this.formData = {
trayCode: '',
warehouseId: '',
cargoSpaceId: '',
cargoSpaceName: ''
}
this.cargoSpaceHeight=''
this.currentWarehouseType=null
// 重新聚焦到托盘条码输入框
setTimeout(() => {
this.$nextTick(() => {
this.$refs.trayCodeInput.onFocus()
})
}, 100)
} else {
uni.showToast({
title: response.msg || this.$t('inbound.emptyPalletBox.emptyPallet.inboundOperationFailed'),
icon: 'none'
})
}
}).catch(error => {
console.error('入库失败:', error)
uni.showToast({
title: this.$t('inbound.emptyPalletBox.emptyPallet.inboundFailed'),
icon: 'none'
})
})
}
}
}
</script>
<style lang="scss">
.container {
padding: 30rpx;
background-color: #f8f9fc;
min-height: 100vh;
}
.input-group {
margin-bottom: 30rpx;
display: flex;
align-items: center;
.input-label {
font-size: 28rpx;
color: #333;
font-weight: 500;
width: 160rpx;
flex-shrink: 0;
}
:deep(.uni-easyinput__content) {
background-color: #fff;
border-radius: 12rpx;
border: 2rpx solid #e8e8e8;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
transition: all 0.3s ease;
&:focus-within {
border-color: #2979ff;
box-shadow: 0 4rpx 16rpx rgba(41, 121, 255, 0.1);
transform: translateY(-2rpx);
}
}
:deep(.uni-easyinput__content-input) {
height: 88rpx;
padding: 0 30rpx;
font-size: 28rpx;
}
}
.scan-icon {
display: flex;
align-items: center;
justify-content: center;
width: 88rpx;
height: 88rpx;
font-size: 40rpx;
color: #2979ff;
transition: all 0.3s ease;
&:active {
transform: scale(0.9);
}
}
.button-group {
padding: 30rpx;
margin-top: 20rpx;
.submit-button {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background-color: #2979ff;
color: #fff;
font-size: 32rpx;
border-radius: 12rpx;
box-shadow: 0 4rpx 16rpx rgba(41, 121, 255, 0.2);
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
box-shadow: 0 2rpx 8rpx rgba(41, 121, 255, 0.2);
}
}
}
.cargo-info {
padding: 0 30rpx;
margin-top: 20rpx;
}
.cargo-content {
display: flex;
align-items: center;
padding: 20rpx;
}
.cargo-label {
font-size: 28rpx;
color: #666;
margin-right: 20rpx;
}
.cargo-value {
font-size: 32rpx;
color: #333;
font-weight: 500;
}
.table-container {
margin: 20rpx 30rpx;
background-color: #fff;
border-radius: 12rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
overflow: hidden;
}
.selected-row {
background-color: #e6f0ff !important;
}
:deep(.uni-table-tr) {
cursor: pointer;
transition: all 0.3s ease;
&:hover {
background-color: #f5f7fa;
}
}
.cargo-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20rpx;
padding: 20rpx;
}
.cargo-item {
background-color: #fff;
padding: 30rpx 20rpx;
text-align: center;
border-radius: 12rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
transition: all 0.3s ease;
cursor: pointer;
&:active {
transform: scale(0.98);
}
}
.selected-item {
background-color: #e6f0ff;
border: 2rpx solid #2979ff;
transform: translateY(-2rpx);
box-shadow: 0 4rpx 16rpx rgba(41, 121, 255, 0.1);
}
.cargo-input-group {
flex: 1;
display: flex;
align-items: center;
gap: 20rpx;
:deep(.uni-easyinput__content) {
flex: 1;
}
}
.recommend-btn {
padding: 0 30rpx;
height: 88rpx;
line-height: 88rpx;
background-color: #2979ff;
color: #fff;
font-size: 28rpx;
border-radius: 12rpx;
box-shadow: 0 2rpx 8rpx rgba(41, 121, 255, 0.2);
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
}
}
.popup-content {
background-color: #fff;
border-radius: 12rpx;
width: 600rpx;
padding: 30rpx;
}
.popup-title {
font-size: 32rpx;
font-weight: 500;
color: #333;
text-align: center;
margin-bottom: 30rpx;
}
.popup-footer {
display: flex;
justify-content: flex-end;
gap: 20rpx;
margin-top: 30rpx;
button {
padding: 0 40rpx;
height: 80rpx;
line-height: 80rpx;
font-size: 28rpx;
border-radius: 8rpx;
}
.cancel-btn {
background-color: #f5f5f5;
color: #666;
}
.confirm-btn {
background-color: #2979ff;
color: #fff;
}
}
</style>

View File

@@ -0,0 +1,159 @@
<template>
<view class="container">
<view class="function-list">
<view class="function-item" @click="navigateTo('/pages/in/qualityCheck')">
<view class="icon-box blue">
<image src="/static/images/tabbar/tray121.png" mode="aspectFit" class="icon-image" style="width: 40rpx; height: 40rpx;"></image>
</view>
<view class="function-text">
<text class="title">{{ $t('inbound.qualityCheck.title') }}</text>
<text class="desc">{{ $t('inbound.qualityCheck.desc') }}</text>
</view>
</view>
<!-- <view class="function-item" @click="navigateTo('/pages/in/klxin')">
<view class="icon-box blue">
<image src="/static/images/tabbar/tray121.png" mode="aspectFit" class="icon-image" style="width: 40rpx; height: 40rpx;"></image>
</view>
<view class="function-text">
<text class="title">空料箱入库</text>
<text class="desc">空料箱收货入库</text>
</view>
</view> -->
<view class="function-item" @click="navigateTo('/pages/in/ktpin')">
<view class="icon-box blue">
<image src="/static/images/tabbar/tray121.png" mode="aspectFit" class="icon-image" style="width: 40rpx; height: 40rpx;"></image>
</view>
<view class="function-text">
<text class="title">{{ $t('inbound.emptyPalletBox.title') }}</text>
<text class="desc">{{ $t('inbound.emptyPalletBox.desc') }}</text>
</view>
</view>
<view class="function-item" @click="navigateTo('/pages/in/inorder')">
<view class="icon-box blue">
<image src="/static/images/tabbar/dingdandanjuwenjian-2.png" mode="aspectFit" class="icon-image" style="width: 40rpx; height: 40rpx;"></image>
</view>
<view class="function-text">
<text class="title">{{ $t('inbound.inorder.title') }}</text>
<text class="desc">{{ $t('inbound.inorder.desc') }}</text>
</view>
</view>
<view class="function-item" @click="navigateTo('/pages/in/bindMsg')">
<view class="icon-box blue">
<image src="/static/images/tabbar/list.png" mode="aspectFit" class="icon-image" style="width: 40rpx; height: 40rpx;"></image>
</view>
<view class="function-text">
<text class="title">{{ $t('inbound.bindMsg.title') }}</text>
<text class="desc">{{ $t('inbound.bindMsg.desc') }}</text>
</view>
</view>
<view class="function-item" @click="navigateTo('/pages/in/backIn')">
<view class="icon-box blue">
<image src="/static/images/tabbar/list.png" mode="aspectFit" class="icon-image" style="width: 40rpx; height: 40rpx;"></image>
</view>
<view class="function-text">
<text class="title">{{ $t('inbound.backIn.title') }}</text>
<text class="desc">{{ $t('inbound.backIn.desc') }}</text>
</view>
</view>
</view>
</view>
</template>
<script>
import tab from '@/plugins/tab'
export default {
data() {
return {}
},
methods: {
navigateTo(url) {
tab.navigateTo(url)
}
}
}
</script>
<style lang="scss" scoped>
.container {
padding: 20rpx;
background-color: #f5f7fa;
min-height: 100vh;
}
.function-list {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.function-item {
display: flex;
align-items: center;
background-color: #fff;
padding: 32rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
&:hover {
transform: translateY(-4rpx);
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.12);
}
&:active {
transform: translateY(0);
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
}
.icon-box {
width: 88rpx;
height: 88rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
margin-right: 32rpx;
transition: all 0.3s ease;
&.blue {
background: linear-gradient(135deg, #409eff, #3a8ee6);
box-shadow: 0 6rpx 16rpx rgba(64, 158, 255, 0.25);
}
&:hover {
transform: rotate(15deg) scale(1.1);
}
}
.icon-image {
width: 44rpx;
height: 44rpx;
transition: all 0.3s ease;
}
.iconfont {
color: #fff;
font-size: 44rpx;
transition: all 0.3s ease;
}
.function-text {
flex: 1;
.title {
font-size: 34rpx;
color: #2c3e50;
font-weight: 600;
margin-bottom: 10rpx;
letter-spacing: 1rpx;
}
.desc {
font-size: 26rpx;
color: #7f8c8d;
letter-spacing: 0.5rpx;
}
}
</style>

View File

@@ -0,0 +1,429 @@
<template>
<view class="container">
<!-- 单据列表 -->
<view class="order-list" v-if="orderList.length > 0">
<uni-card v-for="(item, index) in orderList" :key="index" class="order-card">
<view class="order-info" @click="handleOrderClick(item)">
<view class="info-row">
<text class="label">{{ $t('inbound.qualityCheck.orderNumber') }}</text>
<text class="value">{{ item.stockinId }}</text>
</view>
<view class="info-row">
<text class="label">{{ $t('inbound.qualityCheck.supplier') }}</text>
<text class="value">{{ item.supplierName }}</text>
</view>
<view class="info-row">
<text class="label">{{ $t('inbound.qualityCheck.warehouse') }}</text>
<text class="value">{{ item.warehouseName }}</text>
</view>
<view class="info-row">
<text class="label">{{ $t('inbound.qualityCheck.createTime') }}</text>
<text class="value">{{ item.createDate }}</text>
</view>
<view class="expand-icon" :class="{'expanded': item.isExpanded}">
<text>{{ item.isExpanded ? $t('inbound.qualityCheck.collapse') : $t('inbound.qualityCheck.expand') }}</text>
</view>
</view>
<!-- 物料详情 -->
<view class="material-detail" v-if="item.isExpanded && item.materials && item.materials.length > 0">
<view class="material-header">
<button class="check-all-button" @click="handleCheckAll(index)">{{ $t('inbound.qualityCheck.checkAll') }}</button>
</view>
<view class="material-list">
<view v-for="(material, mIndex) in item.materials" :key="mIndex" class="material-item">
<view class="material-row" :class="{'checked': material.stockStatus === '1'}">
<!-- <text class="material-code">{{ material.productId }}</text> -->
<text class="material-name">{{ material.extraField.materialDesc }}</text>
<view class="material-quantity">
<text>{{ $t('inbound.qualityCheck.quantity') }}</text>
<uni-easyinput
v-model="material.quantity"
type="number"
@input="handleQuantityChange(index, mIndex, $event)"
style="width: 200rpx; display: inline-block;"
/>
</view>
<text class="material-status" :class="{'status-checked': material.stockStatus == '1'}">
{{ material.stockStatus == '1' ? $t('inbound.qualityCheck.checked') : $t('inbound.qualityCheck.unchecked') }}
</text>
<button class="check-button" @click="handleQualityCheck(index, mIndex)">{{ $t('inbound.qualityCheck.check') }}</button>
</view>
</view>
</view>
</view>
</uni-card>
</view>
<view v-else class="no-data">
<text>{{ $t('inbound.qualityCheck.noOrders') }}</text>
</view>
</view>
</template>
<script>
import { getQualityCheckOrders, getOrderMaterials,updateReceiveStockinStatus,updateAllReceiveStockinStatus } from '@/api/in/order.js'
export default {
data() {
return {
orderList: []
}
},
onReady() {
this.fetchOrderList()
},
methods: {
// 获取质检单据列表
async fetchOrderList() {
try {
const response = await getQualityCheckOrders({status:'0'})
if (response.code === 200) {
this.orderList = response.rows.map(order => ({
...order,
isExpanded: false,
materials: []
}))
} else {
uni.showToast({
title: response.msg || this.$t('inbound.qualityCheck.getOrdersFailed'),
icon: 'none'
})
}
} catch (error) {
console.error('获取单据列表失败:', error)
uni.showToast({
title: this.$t('inbound.qualityCheck.getOrdersFailed'),
icon: 'none'
})
}
},
// 点击单据卡片
async handleOrderClick(order) {
const index = this.orderList.findIndex(item => item.stockinId === order.stockinId)
if (index === -1) return
// 切换展开状态
this.$set(this.orderList[index], 'isExpanded', !this.orderList[index].isExpanded)
// 如果是展开状态且还没有加载物料信息,则获取物料信息
if (this.orderList[index].isExpanded && this.orderList[index].materials.length === 0) {
try {
const response = await getOrderMaterials({
stockinId: order.stockinId,
status: '0'
})
if (response.code === 200) {
this.$set(this.orderList[index], 'materials', response.rows)
} else {
uni.showToast({
title: response.msg || this.$t('inbound.qualityCheck.getMaterialsFailed'),
icon: 'none'
})
}
} catch (error) {
console.error('获取物料信息失败:', error)
uni.showToast({
title: this.$t('inbound.qualityCheck.getMaterialsFailed'),
icon: 'none'
})
}
}
},
// 全部质检
async handleCheckAll(index) {
const order = this.orderList[index]
if (!order.materials || order.materials.length === 0) {
uni.showToast({
title: this.$t('inbound.qualityCheck.noMaterials'),
icon: 'none'
})
return
}
// 收集所有未质检物料的信息
const materials = order.materials
.map(material => ({
stockinDetailId: material.stockinDetailId,
quantity: material.quantity
}))
if (materials.length === 0) {
uni.showToast({
title: this.$t('inbound.qualityCheck.allChecked'),
icon: 'none'
})
return
}
try {
const response = await updateAllReceiveStockinStatus({
stockinGuid: order.stockinGuid,
list: materials
})
if (response.code === 200) {
uni.showToast({
title: this.$t('inbound.qualityCheck.batchCheckSuccess'),
icon: 'success'
})
// 重新获取当前单据的物料列表
// const materialsResponse = await getOrderMaterials({
// stockinId: order.stockinId,
// status: '0'
// })
// if (materialsResponse.code === 200) {
// this.$set(this.orderList[index], 'materials', materialsResponse.rows)
// }
this.fetchOrderList()
} else {
uni.showToast({
title: response.msg || this.$t('inbound.qualityCheck.batchCheckFailed'),
icon: 'none'
})
}
} catch (error) {
console.error('批量质检失败:', error)
uni.showToast({
title: this.$t('inbound.qualityCheck.batchCheckFailed'),
icon: 'none'
})
}
},
// 质检操作
async handleQualityCheck(index, mIndex) {
const material = this.orderList[index].materials[mIndex]
const response = await updateReceiveStockinStatus({
stockinDetailId: material.stockinDetailId,
quantity: material.quantity,
stockinGuid:material.stockinGuid,
stockStatus: '1'
})
if (response.code === 200) {
uni.showToast({
title: `${material.extraField.materialDesc} ${this.$t('inbound.qualityCheck.checkSuccess')}`,
icon: 'success'
})
// 重新获取当前单据的物料列表
const materialsResponse = await getOrderMaterials({
stockinId: this.orderList[index].stockinId,
status: '0'
})
if (materialsResponse.code === 200) {
this.$set(this.orderList[index], 'materials', materialsResponse.rows)
}
} else {
uni.showToast({
title: response.msg || this.$t('inbound.qualityCheck.checkFailed'),
icon: 'none'
})
}
},
// 在methods中添加数量变化处理方法
async handleQuantityChange(index, mIndex, value) {
const material = this.orderList[index].materials[mIndex]
const newQuantity = Number(value)
// 验证输入值
if (isNaN(newQuantity) || newQuantity < 0) {
uni.showToast({
title: this.$t('inbound.qualityCheck.invalidQuantity'),
icon: 'none'
})
material.quantity = material.quantity
return
}
// TODO: 调用后端接口更新数量
// 这里可以添加调用后端接口的逻辑
},
}
}
</script>
<style lang="scss">
.container {
padding: 20rpx;
.order-list {
.order-card {
margin-bottom: 20rpx;
background: #fff;
border-radius: 12rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
.order-info {
position: relative;
padding: 24rpx 100rpx 24rpx 24rpx;
.info-row {
display: flex;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
.label {
color: #909399;
width: 160rpx;
font-size: 28rpx;
}
.value {
color: #303133;
flex: 1;
font-size: 28rpx;
}
}
.expand-icon {
position: absolute;
right: 24rpx;
top: 50%;
transform: translateY(-50%);
color: #409EFF;
font-size: 26rpx;
padding: 12rpx 20rpx;
border-radius: 6rpx;
transition: all 0.3s ease;
&.expanded {
color: #909399;
transform: translateY(-50%) rotate(180deg);
}
}
}
.material-detail {
margin: 0 24rpx 24rpx;
transition: all 0.3s ease;
max-height: 600rpx;
overflow-y: auto;
.material-header {
padding: 20rpx 0;
border-bottom: 1px solid #EBEEF5;
.check-all-button {
background-color: #409EFF;
color: #fff;
border: none;
border-radius: 4rpx;
padding: 12rpx 24rpx;
font-size: 26rpx;
cursor: pointer;
&:active {
background-color: #3a8ee6;
}
}
}
.material-list {
.material-item {
border-bottom: 1px solid #EBEEF5;
.material-row {
display: flex;
align-items: center;
padding: 20rpx 0;
gap: 20rpx;
flex-wrap: nowrap;
.material-code {
color: #909399;
font-size: 24rpx;
width: 160rpx;
}
.material-name {
flex: 1;
font-size: 28rpx;
color: #303133;
min-width: 200rpx;
word-break: break-word;
white-space: normal;
overflow: hidden;
}
.material-quantity {
font-size: 26rpx;
color: #606266;
width: 250rpx;
display: flex;
align-items: center;
gap: 10rpx;
}
.check-button {
background-color: #409EFF;
color: #fff;
border: none;
border-radius: 4rpx;
padding: 12rpx 24rpx;
font-size: 26rpx;
cursor: pointer;
min-width: 100rpx;
&:active {
background-color: #3a8ee6;
}
&.button-disabled {
background-color: #c0c4cc !important;
cursor: not-allowed;
opacity: 0.7;
&:active {
background-color: #c0c4cc !important;
}
}
}
}
}
}
}
}
}
.no-data {
text-align: center;
padding: 60rpx;
color: #909399;
font-size: 28rpx;
}
}
.material-row {
&.checked {
background-color: #f5f7fa;
}
.material-status {
font-size: 26rpx;
padding: 4rpx 12rpx;
border-radius: 4rpx;
background-color: #e6a23c;
color: #fff;
&.status-checked {
background-color: #67c23a;
}
}
.check-button {
&.button-disabled {
background-color: #c0c4cc;
cursor: not-allowed;
&:active {
background-color: #c0c4cc;
}
}
}
}
</style>