Files
wms-ui/src/views/weightManage/index.vue
2026-03-03 17:59:37 +08:00

789 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="gi_page">
<div class="container">
<!-- 步骤导航 -->
<div class="step-nav">
<div class="step-item" :class="{ active: activeStep >= 1, completed: activeStep > 1 }">
<div class="step-circle">1</div>
<div class="step-title">扫码核验</div>
</div>
<div class="step-line"></div>
<div class="step-item" :class="{ active: activeStep >= 2, completed: activeStep > 2 }">
<div class="step-circle">2</div>
<div class="step-title">称重登记</div>
</div>
<div class="step-line"></div>
<div class="step-item" :class="{ active: activeStep >= 3, completed: activeStep > 3 }">
<div class="step-circle">3</div>
<div class="step-title">完成创建</div>
</div>
</div>
<!-- 步骤内容 -->
<!-- 扫码核验页面 -->
<div v-if="activeStep === 1" class="step-content">
<div class="main-content">
<!-- 左侧表单 -->
<div class="left-section">
<a-image v-if="!formData.photoUrl" :src="formData.photoUrl"/>
<img v-else :src="formData.photoUrl" class="sample-image square-image" alt="样图">
<a-form :model="formData" layout="vertical">
<div class="form-row">
<div class="form-item">
<a-form-item label="物料名称">
<a-input v-model="formData.materialName" placeholder="物料名称" disabled />
</a-form-item>
</div>
<div class="form-item">
<a-form-item label="物料规格">
<a-input v-model="formData.materialSpec" placeholder="物料规格" disabled />
</a-form-item>
</div>
</div>
<div class="form-row">
<div class="form-item">
<a-form-item label="物料编码">
<a-input v-model="formData.encoding" placeholder="物料编码" disabled />
</a-form-item>
</div>
<div class="form-item">
<a-form-item label="重量">
<a-input v-model="formData.unitWeight" placeholder="Kg" disabled />
</a-form-item>
</div>
</div>
<div class="form-row">
<div class="form-item">
<a-form-item label="物料编码">
<a-input
v-model="formData.inputMaterialCode"
placeholder="请使用扫码枪扫描物料编码"
@change="handleMaterialCodeChange"
/>
</a-form-item>
</div>
</div>
</a-form>
</div>
<!-- 右侧信息 -->
<div class="right-section">
<div class="camera-section">
<div class="image-placeholder square-image">实时画面 相机1</div>
<div class="image-placeholder square-image">实时画面 相机2</div>
</div>
<div class="info-section">
<div class="info-card">
<h4>识别信息</h4>
<div class="info-item">
<span class="label">物料名称:</span>
<span class="value">{{ formData.materialName || '-' }}</span>
</div>
<div class="info-item">
<span class="label">物料编码:</span>
<span class="value">{{ formData.encoding || '-' }}</span>
</div>
</div>
<div class="info-card">
<h4>比对结果</h4>
<div class="info-item">
<span class="label">比对结果:</span>
<span class="value match-result" :class="{
'match-success': formData.matchResult === 'success',
'match-failed': formData.matchResult === 'failed',
'match-pending': !formData.matchResult
}">
<icon-check-circle-fill v-if="formData.matchResult === 'success'" style="color: #52c41a; margin-right: 8px; font-size: 25px;"/>
<icon-close-circle-fill v-else-if="formData.matchResult === 'failed'" style="color: #ff4d4f; margin-right: 8px; font-size: 25px;"/>
{{ formData.matchResult === 'success' ? '成功' : formData.matchResult === 'failed' ? '失败' : '-' }}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 称重登记页面 -->
<div v-else-if="activeStep === 2" class="step-content">
<div class="weighing-content">
<!-- 左侧输入区域 -->
<div class="left-weighing-section">
<div class="form-row">
<div class="form-item">
<label>物料名称:</label>
<a-input v-model="formData.materialName" placeholder="物料名称" disabled />
</div>
</div>
<div class="form-row">
<div class="form-item">
<label>输入数量:</label>
<a-input v-model="inputQuantity" placeholder="请输入数量" @change="calculateWeight" />
</div>
</div>
<div class="form-row">
<div class="form-item">
<label>计算重量:</label>
<a-input v-model="calculatedWeight" placeholder="-" disabled />
</div>
</div>
<div class="form-row">
<div class="form-item">
<label>对应重量:</label>
<a-input v-model="inputWeight" placeholder="-" disabled/>
</div>
</div>
<div class="image-placeholder large-image">实时画面</div>
<div class="weighing-actions">
<a-button type="primary" @click="handleConfirm">确定</a-button>
<a-button style="margin-left: 12px;" @click="handleReset">重置</a-button>
</div>
</div>
<!-- 右侧表格区域 -->
<div class="right-weighing-section">
<div class="weighing-section">
<div class="section-header">
<h4>称重列表</h4>
<div class="table-actions">
<a-button>打印</a-button>
</div>
</div>
<a-table :columns="columns" :data="weighingList" bordered>
<template #action="{ record }">
<a-button type="text" status="danger" @click="handleDelete(record.key)">
删除
</a-button>
</template>
</a-table>
</div>
</div>
</div>
</div>
<!-- 完成创建页面 -->
<div v-else-if="activeStep === 3" class="step-content">
<div class="completion-content">
<div class="completion-icon">
<a-icon type="check-circle" :size="64" style="color: #52c41a;" />
</div>
<h2>创建完成</h2>
<p>任务已成功创建以下是任务详情</p>
<div class="completion-info">
<div class="info-item">
<span class="label">任务ID:</span>
<span class="value">{{ taskId }}</span>
</div>
<div class="info-item">
<span class="label">物料名称:</span>
<span class="value">{{ formData.materialName }}</span>
</div>
<div class="info-item">
<span class="label">物料编码:</span>
<span class="value">{{ formData.encoding }}</span>
</div>
<div class="info-item">
<span class="label">物料规格:</span>
<span class="value">{{ formData.materialSpec }}</span>
</div>
<div class="info-item">
<span class="label">重量:</span>
<span class="value">{{ formData.unitWeight }}</span>
</div>
</div>
<div class="completion-actions">
<a-button type="primary" @click="handleBackToFirst">返回首页</a-button>
</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="action-buttons">
<a-button
v-if="activeStep > 1 && activeStep < 3"
@click="handlePrevious"
class="previous-button"
>
上一步
</a-button>
<a-button
v-if="activeStep < 3"
type="primary"
@click="handleNext"
:disabled="activeStep === 1 && formData.matchResult !== 'success'"
class="next-button"
>
{{ activeStep === 2 ? '完成' : '下一步' }}
</a-button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed } from 'vue'
import { Modal } from '@arco-design/web-vue'
import { getMaterialDetail } from "@/apis/weightManage/weightManage";
// 当前步骤
const activeStep = ref(1)
// 表单数据
const formData = reactive({
inputMaterialCode: '', // 输入的物料编码
encoding: '', // 物料编码
materialName: '', // 物料名称
materialSpec: '', // 物料规格
unitWeight: 0, // 重量
photoUrl: '', // 样图URL
matchResult: '' // 比对结果
})
// 称重登记页面数据
const inputQuantity = ref('')
const inputWeight = ref('')
const calculatedWeight = ref('')
const weighingCount = ref(1)
// 称重列表数据
const weighingList = ref([
// 初始数据可以在这里添加
])
// 任务ID
const taskId = computed(() => {
const date = new Date().toISOString().slice(0, 10).replace(/-/g, '')
const random = Math.floor(1000 + Math.random() * 9000)
return `${date}${formData.encoding}${random}`
})
// 称重表格列
const columns = [
{
title: '称重次数',
dataIndex: 'count',
key: 'count'
},
{
title: '数量',
dataIndex: 'quantity',
key: 'quantity',
className: 'green-bg'
},
{
title: '重量',
dataIndex: 'weight',
key: 'weight',
className: 'green-bg'
},
{
title: '计算重量',
dataIndex: 'calculatedWeight',
key: 'calculatedWeight',
className: 'green-bg'
},
{
title: '抓拍图片',
dataIndex: 'image',
key: 'image',
className: 'green-bg'
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
slotName: 'action'
}
]
// 处理物料编码变化
const handleMaterialCodeChange = async () => {
if (formData.inputMaterialCode) {
try {
await fetchMaterialData(formData.inputMaterialCode)
} catch (error) {
console.error('获取物料数据失败:', error)
}
} else {
formData.encoding = "";
formData.materialName = "";
formData.materialSpec = "";
formData.unitWeight = 0;
formData.photoUrl = "";
formData.matchResult = "";
}
};
// 模拟调用后端接口
const fetchMaterialData = async (code: string) => {
getMaterialDetail(code).then(res => {
if (res.code == '0') {
// 更新表单数据
formData.encoding = res.data.encoding
formData.materialName = res.data.materialName
formData.materialSpec = res.data.materialSpec
formData.unitWeight = res.data.unitWeight
formData.photoUrl = res.data.photoUrl
// 假设后端返回比对结果
// formData.matchResult = res.data.matchResult || 'failed' // 这里根据实际接口返回调整
formData.matchResult = res.data.matchResult || 'success' // 这里根据实际接口返回调整
return true
}
});
}
// 处理下一步
const handleNext = () => {
if (activeStep.value < 3) {
if (activeStep.value === 2) {
// 当在称重登记页面点击完成时,显示确认弹框
Modal.confirm({
title: '确认完成',
content: '确定要完成称重登记吗?',
onOk: () => {
activeStep.value++
}
})
} else {
activeStep.value++
}
}
}
// 处理上一步
const handlePrevious = () => {
if (activeStep.value > 1) {
activeStep.value--
}
}
// 返回第一步
const handleBackToFirst = () => {
activeStep.value = 1
}
// 计算重量
const calculateWeight = () => {
if (inputQuantity.value && formData.unitWeight) {
const singleWeight = parseFloat(formData.unitWeight.toString())
const quantity = parseFloat(inputQuantity.value)
if (!isNaN(singleWeight) && !isNaN(quantity)) {
calculatedWeight.value = (singleWeight * quantity).toFixed(2) + 'g'
}
} else {
calculatedWeight.value = ''
}
}
// 处理确定
const handleConfirm = () => {
// 生成新的列表数据
const newItem = {
key: (weighingList.value.length + 1).toString(),
count: weighingCount.value,
name: formData.materialName,
quantity: inputQuantity.value,
unitWeight: inputWeight.value,
calculatedWeight: calculatedWeight.value,
image: '图片'
}
// 添加到列表
weighingList.value.push(newItem)
// 重置输入
inputQuantity.value = ''
inputWeight.value = ''
calculatedWeight.value = ''
// 称重次数累加
weighingCount.value = weighingList.value.length + 1
}
// 处理重置
const handleReset = () => {
inputQuantity.value = ''
inputWeight.value = ''
calculatedWeight.value = ''
}
// 处理删除
const handleDelete = (key) => {
// 过滤掉要删除的项
weighingList.value = weighingList.value.filter(item => item.key !== key)
// 重新排序称重次数
weighingList.value.forEach((item, index) => {
item.count = index + 1
})
// 更新当前称重次数
weighingCount.value = weighingList.value.length + 1
}
defineOptions({ name: 'WeightManage' })
</script>
<style scoped lang="scss">
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
/* 步骤导航 */
.step-nav {
display: flex;
align-items: center;
margin-bottom: 30px;
padding: 20px;
background-color: var(--color-bg-2);
border-radius: 4px;
}
.step-item {
display: flex;
flex-direction: column;
align-items: center;
z-index: 1;
}
.step-circle {
width: 24px;
height: 24px;
border-radius: 50%;
background-color: #e8e8e8;
color: #666;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: bold;
margin-bottom: 8px;
}
.step-title {
font-size: 14px;
color: #666;
}
.step-line {
flex: 1;
height: 2px;
background-color: #e8e8e8;
margin: 0 20px;
}
.step-item.active .step-circle {
background-color: #1677ff;
color: white;
}
.step-item.active .step-title {
color: #1677ff;
font-weight: bold;
}
.step-item.completed .step-circle {
background-color: #52c41a;
color: white;
}
.step-item.completed .step-title {
color: #52c41a;
}
.step-item.completed ~ .step-line {
background-color: #52c41a;
}
/* 步骤内容 */
.step-content {
margin-bottom: 30px;
}
/* 主内容区域 */
.main-content {
display: flex;
margin-bottom: 30px;
}
.left-section {
flex: 1;
margin-right: 30px;
}
.right-section {
flex: 1;
}
/* 称重登记页面 */
.weighing-content {
display: flex;
margin-bottom: 30px;
}
.left-weighing-section {
width: 400px;
margin-right: 30px;
}
.right-weighing-section {
flex: 1;
}
.weighing-section {
margin-bottom: 20px;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.section-header h4 {
margin: 0;
font-size: 16px;
font-weight: bold;
}
.large-image {
width: 100%;
height: 200px;
margin: 20px 0;
}
.input-placeholder {
width: 100%;
height: 32px;
background-color: #e8e8e8;
border-radius: 4px;
margin-top: 8px;
}
.weighing-actions {
margin-top: 20px;
}
.table-actions {
display: flex;
justify-content: flex-end;
margin-top: 20px;
}
/* 绿色背景列 */
:deep(.green-bg) {
background-color: #f6ffed;
}
/* 完成创建页面 */
.completion-content {
text-align: center;
padding: 60px 0;
}
.completion-icon {
margin-bottom: 20px;
}
.completion-content h2 {
margin-bottom: 20px;
color: #52c41a;
}
.completion-content p {
margin-bottom: 30px;
font-size: 16px;
}
.completion-info {
max-width: 400px;
margin: 0 auto 40px;
text-align: left;
background-color: var(--color-bg-2);
padding: 20px;
border-radius: 4px;
}
.info-item {
margin-bottom: 12px;
display: flex;
}
.info-item .label {
width: 100px;
font-weight: bold;
}
.info-item .value {
flex: 1;
}
.completion-actions {
margin-top: 40px;
}
/* 图片占位符 */
.image-placeholder {
width: 100%;
height: 150px;
background-color: #e8e8e8;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
border-radius: 4px;
}
/* 正方形图片 */
.square-image {
width: 200px;
height: 200px;
}
/* 样图 */
.sample-image {
object-fit: cover;
margin-bottom: 20px;
border-radius: 4px;
}
/* 相机区域 */
.camera-section {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.camera-section .image-placeholder {
width: calc(50% - 10px);
}
/* 表单区域 */
.form-section {
margin-top: 20px;
}
.form-row {
display: flex;
margin-bottom: 16px;
}
.form-item {
flex: 1;
margin-right: 20px;
}
.form-item.full-width {
flex: 1;
margin-right: 0;
}
/* 确保输入框宽度一致 */
:deep(.arco-input-wrapper) {
width: 100%;
height: 35px;
}
:deep(.arco-input) {
font-size: 16px;
}
.form-item label {
display: block;
margin-bottom: 8px;
font-size: 16px;
color: #666;
}
.form-actions {
margin-top: 20px;
}
/* 信息区域 */
.info-section {
margin-top: 20px;
}
.info-card {
background-color: var(--color-bg-2);
border-radius: 4px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.info-card h4 {
margin: 0 0 16px 0;
font-size: 16px;
font-weight: bold;
color: #333;
}
.info-item {
display: flex;
margin-bottom: 12px;
align-items: center;
}
.info-item .label {
width: 100px;
font-size: 14px;
color: #666;
font-weight: 500;
}
.info-item .value {
flex: 1;
font-size: 16px;
color: #333;
}
.match-result {
font-weight: 500;
display: flex;
align-items: center;
}
.match-success {
color: #52c41a;
}
.match-failed {
color: #ff4d4f;
}
.match-pending {
color: #d9d9d9;
}
.info-text {
margin-top: 20px;
font-size: 14px;
line-height: 1.5;
}
/* 操作按钮 */
.action-buttons {
display: flex;
justify-content: flex-end;
}
.next-button {
width: 120px;
height: 40px;
font-size: 14px;
}
.previous-button {
width: 120px;
height: 40px;
font-size: 14px;
margin-right: 12px;
}
</style>