4 changed files with 415 additions and 0 deletions
-
3src/api/inventory/label.js
-
2src/router/index.js
-
6src/views/main.vue
-
404src/views/modules/inventory/label-query.vue
@ -0,0 +1,3 @@ |
|||
import { createAPI } from "@/utils/httpRequest.js"; |
|||
|
|||
export const queryLabelInfo = data => createAPI(`/pda/label/query`,'post',data) |
|||
@ -0,0 +1,404 @@ |
|||
<template> |
|||
<div> |
|||
<div class="pda-container"> |
|||
<!-- 头部栏 --> |
|||
<div class="header-bar"> |
|||
<div class="header-left" @click="handleBack"> |
|||
<i class="el-icon-arrow-left"></i> |
|||
<span>标签查询</span> |
|||
</div> |
|||
<div class="header-right" @click="$router.push({ path: '/' })"> |
|||
首页 |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="table-body" style="max-height: 500px; overflow-y: auto;"> |
|||
<div class="main-content form-section"> |
|||
<!-- 标签扫描输入框 --> |
|||
<div class="input-group"> |
|||
<label class="input-label">标签编码</label> |
|||
<el-input |
|||
v-model="labelCode" |
|||
placeholder="请扫描标签编码" |
|||
class="form-input" |
|||
clearable |
|||
inputmode="none" |
|||
autocomplete="off" |
|||
autocorrect="off" |
|||
spellcheck="false" |
|||
@keyup.enter.native="handleLabelScan" |
|||
ref="labelInput" |
|||
/> |
|||
</div> |
|||
|
|||
<!-- 标签信息显示 (扫描后显示) --> |
|||
<div v-if="labelInfo" class="info-section"> |
|||
<div class="info-title"> |
|||
<i class="el-icon-document"></i> |
|||
<span>标签信息</span> |
|||
</div> |
|||
|
|||
<div class="info-row"> |
|||
<span class="info-label">标签编码:</span> |
|||
<span class="info-value">{{ labelInfo.unitId || '-' }}</span> |
|||
</div> |
|||
|
|||
<div class="info-row"> |
|||
<span class="info-label">物料编码:</span> |
|||
<span class="info-value">{{ labelInfo.partNo || '-' }}</span> |
|||
</div> |
|||
|
|||
<div class="info-row"> |
|||
<span class="info-label">数量:</span> |
|||
<span class="info-value">{{ labelInfo.qty || '0' }}</span> |
|||
</div> |
|||
|
|||
<div class="info-row"> |
|||
<span class="info-label">批次号:</span> |
|||
<span class="info-value">{{ labelInfo.batchNo || '-' }}</span> |
|||
</div> |
|||
|
|||
<div class="info-row"> |
|||
<span class="info-label">仓库:</span> |
|||
<span class="info-value">{{ labelInfo.warehouseId || '-' }}</span> |
|||
</div> |
|||
|
|||
<div class="info-row"> |
|||
<span class="info-label">库位:</span> |
|||
<span class="info-value">{{ labelInfo.locationId || '-' }}</span> |
|||
</div> |
|||
|
|||
<div class="info-row"> |
|||
<span class="info-label">WDR:</span> |
|||
<span class="info-value">{{ labelInfo.wdr || '-' }}</span> |
|||
</div> |
|||
|
|||
|
|||
<div class="info-row"> |
|||
<span class="info-label">创建时间:</span> |
|||
<span class="info-value">{{ formatDate(labelInfo.createdDate) }}</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 底部操作按钮 --> |
|||
<div v-if="labelInfo" class="bottom-actions"> |
|||
<button |
|||
class="action-btn secondary" |
|||
@click="clearData" |
|||
> |
|||
清空 |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { queryLabelInfo } from '@/api/inventory/label' |
|||
|
|||
export default { |
|||
name: 'LabelQuery', |
|||
|
|||
data() { |
|||
return { |
|||
site: localStorage.getItem('site'), |
|||
labelCode: '', |
|||
labelInfo: null, |
|||
loading: false |
|||
}; |
|||
}, |
|||
|
|||
methods: { |
|||
/** |
|||
* 返回上一页 |
|||
*/ |
|||
handleBack() { |
|||
this.$router.back(); |
|||
}, |
|||
|
|||
/** |
|||
* 处理标签扫描 |
|||
*/ |
|||
handleLabelScan() { |
|||
if (!this.labelCode.trim()) { |
|||
this.$message.error('请扫描有效的标签编码'); |
|||
return; |
|||
} |
|||
|
|||
this.loading = true; |
|||
|
|||
queryLabelInfo({ |
|||
site: this.site, |
|||
labelCode: this.labelCode.trim() |
|||
}).then(({ data }) => { |
|||
this.loading = false; |
|||
|
|||
if (data && data.code === 0) { |
|||
this.labelInfo = data.data; |
|||
this.$message.success('查询成功'); |
|||
} else { |
|||
this.$message.error(data.msg || '标签不存在'); |
|||
this.labelCode = ''; |
|||
this.labelInfo = null; |
|||
this.focusLabelInput(); |
|||
} |
|||
}).catch(error => { |
|||
this.loading = false; |
|||
console.error('查询标签失败:', error); |
|||
this.$message.error('查询异常'); |
|||
this.labelCode = ''; |
|||
this.labelInfo = null; |
|||
this.focusLabelInput(); |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* 清空数据 |
|||
*/ |
|||
clearData() { |
|||
this.labelCode = ''; |
|||
this.labelInfo = null; |
|||
this.focusLabelInput(); |
|||
}, |
|||
|
|||
/** |
|||
* 聚焦标签输入框 |
|||
*/ |
|||
focusLabelInput() { |
|||
this.$nextTick(() => { |
|||
if (this.$refs.labelInput) { |
|||
this.$refs.labelInput.focus(); |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* 格式化日期 |
|||
*/ |
|||
formatDate(date) { |
|||
if (!date) return '-'; |
|||
|
|||
const d = new Date(date); |
|||
const year = d.getFullYear(); |
|||
const month = String(d.getMonth() + 1).padStart(2, '0'); |
|||
const day = String(d.getDate()).padStart(2, '0'); |
|||
const hours = String(d.getHours()).padStart(2, '0'); |
|||
const minutes = String(d.getMinutes()).padStart(2, '0'); |
|||
|
|||
return `${year}-${month}-${day} ${hours}:${minutes}`; |
|||
}, |
|||
|
|||
/** |
|||
* 获取状态标签类型 |
|||
*/ |
|||
getStatusType(inStockFlag) { |
|||
return inStockFlag === 'Y' ? 'success' : 'danger'; |
|||
} |
|||
}, |
|||
|
|||
mounted() { |
|||
// 页面加载后自动聚焦标签输入框 |
|||
this.focusLabelInput(); |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
/* PDA容器样式 */ |
|||
.pda-container { |
|||
width: 100vw; |
|||
height: 120vh; |
|||
display: flex; |
|||
flex-direction: column; |
|||
background: #f5f5f5; |
|||
font-family: 'Arial', sans-serif; |
|||
} |
|||
|
|||
/* 头部栏样式 */ |
|||
.header-bar { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 8px 16px; |
|||
background: #17B3A3; |
|||
color: white; |
|||
height: 40px; |
|||
min-height: 40px; |
|||
max-height: 40px; |
|||
} |
|||
|
|||
.header-left { |
|||
display: flex; |
|||
align-items: center; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.header-left i { |
|||
margin-right: 8px; |
|||
font-size: 18px; |
|||
} |
|||
|
|||
.header-left span { |
|||
font-size: 16px; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.header-right { |
|||
cursor: pointer; |
|||
font-size: 14px; |
|||
padding: 4px 8px; |
|||
border-radius: 4px; |
|||
} |
|||
|
|||
/* 主要内容区 */ |
|||
.table-body { |
|||
flex: 1; |
|||
overflow-y: auto; |
|||
} |
|||
|
|||
.main-content { |
|||
padding: 16px; |
|||
} |
|||
|
|||
/* 输入组样式 */ |
|||
|
|||
.input-label { |
|||
display: block; |
|||
margin-bottom: 8px; |
|||
font-size: 14px; |
|||
font-weight: 500; |
|||
color: #333; |
|||
} |
|||
|
|||
.form-input { |
|||
width: 100%; |
|||
height: 44px; |
|||
} |
|||
|
|||
/* 信息展示区 */ |
|||
.info-section { |
|||
background: white; |
|||
border-radius: 8px; |
|||
padding: 16px; |
|||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.info-title { |
|||
display: flex; |
|||
align-items: center; |
|||
font-size: 16px; |
|||
font-weight: bold; |
|||
color: #17B3A3; |
|||
margin-bottom: 16px; |
|||
padding-bottom: 12px; |
|||
border-bottom: 2px solid #17B3A3; |
|||
} |
|||
|
|||
.info-title i { |
|||
margin-right: 8px; |
|||
font-size: 18px; |
|||
} |
|||
|
|||
.info-row { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: flex-start; |
|||
padding: 10px 0; |
|||
border-bottom: 1px solid #f0f0f0; |
|||
} |
|||
|
|||
.info-row:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.info-label { |
|||
font-size: 14px; |
|||
color: #666; |
|||
min-width: 90px; |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.info-value { |
|||
font-size: 14px; |
|||
font-weight: 500; |
|||
color: #333; |
|||
flex: 1; |
|||
text-align: right; |
|||
word-break: break-all; |
|||
} |
|||
|
|||
/* 底部按钮区 */ |
|||
.bottom-actions { |
|||
display: flex; |
|||
gap: 12px; |
|||
padding-top: 16px; |
|||
} |
|||
|
|||
.action-btn { |
|||
flex: 1; |
|||
padding: 12px 24px; |
|||
border: none; |
|||
border-radius: 6px; |
|||
font-size: 16px; |
|||
font-weight: 500; |
|||
cursor: pointer; |
|||
transition: all 0.2s; |
|||
min-height: 44px; |
|||
} |
|||
|
|||
.action-btn.primary { |
|||
background: #17B3A3; |
|||
color: white; |
|||
} |
|||
|
|||
.action-btn.primary:hover { |
|||
background: #15a394; |
|||
} |
|||
|
|||
.action-btn.primary:disabled { |
|||
background: #ccc; |
|||
cursor: not-allowed; |
|||
} |
|||
|
|||
.action-btn.secondary { |
|||
background: #f5f5f5; |
|||
color: #333; |
|||
border: 1px solid #ddd; |
|||
} |
|||
|
|||
.action-btn.secondary:hover { |
|||
background: #e8e8e8; |
|||
} |
|||
|
|||
/* 响应式设计 */ |
|||
@media screen and (max-width: 480px) { |
|||
.header-bar { |
|||
padding: 8px 12px; |
|||
} |
|||
|
|||
.main-content { |
|||
padding: 12px; |
|||
} |
|||
|
|||
.info-section { |
|||
padding: 2px; |
|||
} |
|||
|
|||
.info-label { |
|||
font-size: 13px; |
|||
min-width: 80px; |
|||
} |
|||
|
|||
.info-value { |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.action-btn { |
|||
padding: 10px 16px; |
|||
font-size: 14px; |
|||
} |
|||
} |
|||
</style> |
|||
|
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue