feat: 完成区域管理、装箱功能优化与接口标准化
- 新增区域状态字段与增删改查接口,支持区域启用/停用 - 重构实体字段JSON标签为camelCase格式统一接口规范 - 优化入库、盘点、装箱流程的交互与提示文案 - 新增装箱管理功能,支持合同号关联与装箱编辑 - 调整前端菜单与帮助文档适配业务场景变更
This commit is contained in:
@@ -1,11 +1,6 @@
|
||||
<template>
|
||||
<!-- 页面左下角 "?" 帮助按钮:点击弹出当前页面整体介绍 + 字段说明 -->
|
||||
<div class="page-help">
|
||||
<el-tooltip content="本页操作说明" placement="left">
|
||||
<el-button class="help-fab" circle @click="open">?</el-button>
|
||||
</el-tooltip>
|
||||
|
||||
<el-drawer v-model="show" :title="data.title || '操作说明'" size="520px" append-to-body class="ph-drawer">
|
||||
<!-- 帮助内容通过右上角「帮助」按钮触发(MainLayout 派发 wms:open-page-help 事件) -->
|
||||
<el-drawer v-model="show" :title="data.title || '操作说明'" size="520px" append-to-body class="ph-drawer">
|
||||
<div class="ph-inner">
|
||||
<div class="ph-banner">
|
||||
<div class="ph-banner-title">{{ data.title || '操作说明' }}</div>
|
||||
@@ -49,10 +44,9 @@
|
||||
|
||||
<!-- 既无顶层字段也无分组 -->
|
||||
<el-empty v-if="!data.fields && !(data.sections && data.sections.length)"
|
||||
description="暂无说明" :image-size="70" />
|
||||
description="该页面暂未编写操作说明,请先完成基础数据维护后查看效果" :image-size="70" />
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
@@ -14,7 +14,7 @@ export const helpInbound = {
|
||||
{ name: '物料', source: '下拉选择。数据来自 WMS"物料档案"里类型为"结构件"的物料。', purpose: '入库的是什么物料;档案里必须存在才能选到', fill: '选择物料编码,如 SCREW-M3;选不到=还没建该物料档案' },
|
||||
{ name: '批次号', source: '留空系统自动生成(日期+序号);也可手工填。', purpose: '区别不同到货批次,实现先进先出(FIFO)', fill: '默认留空自动生成;供应商自带批号时可手填' },
|
||||
{ name: '数量', source: '手工填写整数。', purpose: '本批到货数量', fill: '整数 ≥1' },
|
||||
{ name: '区域', source: '下拉选择。数据来自库区字典。', purpose: '放到哪个库区(待检/合格/不合格…)', fill: '新到货一般先放"待检"区,检验合格后再转"合格"区(Z02)' },
|
||||
{ name: '区域', source: '下拉选择(必填)。数据来自"基础数据-区域维护"。', purpose: '放到哪个库区(待检/合格/不合格…)', fill: '必填;新到货一般先放"待检"区,检验合格后再转"合格"区' },
|
||||
{ name: '生产日期', source: '手动选择日期。', purpose: '生产时间,用于时效和批次管理', fill: '选择日期' },
|
||||
{ name: '供应商', source: '手工填写。', purpose: '来料来源', fill: '供应商名称,可空' }
|
||||
]
|
||||
@@ -23,8 +23,8 @@ export const helpInbound = {
|
||||
title: 'Tab2 精密件 SN 入库(逐件)',
|
||||
overview: '适用于芯片、器件等需要单件追溯的来料,一件一个 SN。',
|
||||
fields: [
|
||||
{ name: '物料', source: '下拉选择。来自"物料档案"类型为"精密件"的物料。', purpose: '入库的精密件物料', fill: '选择物料编码' },
|
||||
{ name: '区域', source: '下拉选择。来自库区字典。', purpose: '放到哪个库区', fill: '可选,空则默认待检区' },
|
||||
{ name: '物料', source: '下拉选择(必填)。来自"物料档案"类型为"精密件"的物料。', purpose: '入库的精密件物料', fill: '选择物料编码' },
|
||||
{ name: '区域', source: '下拉选择(必填)。来自"基础数据-区域维护"。', purpose: '放到哪个库区', fill: '必填;新到货一般先放"待检"区' },
|
||||
{ name: '扫码录入', source: '扫码枪连续扫码。来自每颗器件自带的 SN 条码。', purpose: '逐件登记 SN,实现单件追溯', fill: '扫入/粘贴 SN 后回车追加,可一次连续多条' }
|
||||
]
|
||||
},
|
||||
@@ -82,20 +82,21 @@ export const helpStocktake = {
|
||||
{ name: '操作人', source: '登录账号自动带出。', purpose: '发起盘点人', fill: '自动' },
|
||||
{ name: '发起盘点', source: '按钮操作。', purpose: '冻结当前库存快照,生成盘点单', fill: '点按钮发起' },
|
||||
{ name: '差异写回库存', source: '开关。', purpose: '完成后是否用实盘差异修正账面库存', fill: '开=写回;关=仅记录差异' },
|
||||
{ name: '目标编号', source: '扫码枪。来自批次号/SN条码。', purpose: '要盘点的批次号或 SN', fill: '扫批次号/SN,回车提交' },
|
||||
{ name: '批次号 / SN 序列号', source: '扫码枪。来自批次号/SN条码。', purpose: '要盘点的批次号(结构件)或 SN(精密件)', fill: '扫批次号/SN,回车提交' },
|
||||
{ name: '实盘数量', source: '扫码/手输。', purpose: '实际数到数量', fill: '非负整数;0=盘亏为零' }
|
||||
]
|
||||
}
|
||||
|
||||
export const helpPackage = {
|
||||
title: '包装绑定(箱号 ↔ SN)',
|
||||
title: '装箱管理(箱号 ↔ SN)',
|
||||
overview:
|
||||
'把若干精密件 SN 绑定到一个箱号,形成包装箱,用于发货/入库整箱追溯。\n数据链路:拣选出的 SN → 绑到箱号 → 一个箱号代表一箱货。',
|
||||
'把若干成品/精密件 SN 装入同一个箱号,形成可追溯的包装箱,用于发货、入库、整箱追溯。\n数据链路:拣选出待包装的 SN → 扫进同一箱号 → 一个箱号关联多个 SN → 后续按箱号出库/发货/追溯。',
|
||||
fields: [
|
||||
{ name: '箱号', source: '扫码/手输。', purpose: '包装箱唯一号', fill: '扫描或手输箱号' },
|
||||
{ name: '物料', source: '下拉选择(可空)。来自物料档案。', purpose: '箱内物料类型', fill: '可选' },
|
||||
{ name: '操作人', source: '登录账号自动带出。', purpose: '绑定人', fill: '自动' },
|
||||
{ name: 'SN 录入', source: '扫码枪连续扫码。来自器件 SN 条码。', purpose: '装箱的 SN 清单', fill: '扫入 SN 回车追加' }
|
||||
{ name: '箱号', source: '扫码枪/手动输入,箱子上的条码或手贴码。', purpose: '包装箱唯一标识,一箱一个号', fill: '扫描或手输箱号;同一箱号不可重复使用' },
|
||||
{ name: '物料', source: '下拉选择(可空)。来自物料档案。', purpose: '箱内物料的类型;建议同一箱只装一种物料', fill: '可选;选择后建议只扫该物料 SN' },
|
||||
{ name: '合同号', source: '手动填写(选填)。', purpose: '关联销售/采购合同,便于按合同追溯', fill: '可空;按合同装箱时填写' },
|
||||
{ name: '操作人', source: '登录账号自动带出。', purpose: '装箱人,追溯用', fill: '自动' },
|
||||
{ name: 'SN 录入', source: '扫码枪连续扫码。来自成品/精密件 SN 条码。', purpose: '装进箱内的 SN 清单', fill: '扫入 SN 后点【录入到列表】加入清单,回车只是换行;支持逗号/分号/顿号/空格/回车分隔' }
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ const menus = [
|
||||
{ path: '/inspection', title: '质量检验', icon: CircleCheck },
|
||||
{ path: '/stocktake', title: '库存盘点', icon: List },
|
||||
{ path: '/semi', title: '半成品/成品', icon: Box },
|
||||
{ path: '/package', title: '包装绑定', icon: Box },
|
||||
{ path: '/package', title: '装箱管理', icon: Box },
|
||||
{ path: '/ledger', title: '备料台账', icon: Tickets },
|
||||
{ path: '/base-data', title: '基础数据', icon: EditPen }
|
||||
]
|
||||
|
||||
@@ -1,32 +1,69 @@
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import request from '../utils/request'
|
||||
import PageHelp from '../components/PageHelp.vue'
|
||||
import { helpBaseData } from '../help'
|
||||
|
||||
/* ---------- Tab1 区域维护 ---------- */
|
||||
const zones = ref([])
|
||||
const zoneTotal = ref(0)
|
||||
const zoneLoading = ref(false)
|
||||
const zoneKeyword = ref('')
|
||||
const zonePage = reactive({ current: 1, size: 10 })
|
||||
|
||||
const zoneDialog = ref(false)
|
||||
const zoneEditingId = ref(0)
|
||||
const zoneForm = reactive({ zoneCode: '', zoneName: '', description: '' })
|
||||
const zoneSaving = ref(false)
|
||||
|
||||
async function loadZones() {
|
||||
const data = await request.get('/zone/list')
|
||||
zones.value = Array.isArray(data) ? data : data?.list || []
|
||||
zoneLoading.value = true
|
||||
try {
|
||||
const data = await request.get('/zone/list', {
|
||||
params: { keyword: zoneKeyword.value.trim(), page: zonePage.current, pageSize: zonePage.size }
|
||||
})
|
||||
zones.value = data?.list || []
|
||||
zoneTotal.value = data?.total || 0
|
||||
} finally {
|
||||
zoneLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function addZone() {
|
||||
function searchZones() {
|
||||
zonePage.current = 1
|
||||
loadZones()
|
||||
}
|
||||
|
||||
function openZoneCreate() {
|
||||
zoneEditingId.value = 0
|
||||
Object.assign(zoneForm, { zoneCode: '', zoneName: '', description: '' })
|
||||
zoneDialog.value = true
|
||||
}
|
||||
|
||||
function openZoneEdit(row) {
|
||||
zoneEditingId.value = row.id
|
||||
Object.assign(zoneForm, {
|
||||
zoneCode: row.zoneCode, zoneName: row.zoneName, description: row.description || ''
|
||||
})
|
||||
zoneDialog.value = true
|
||||
}
|
||||
|
||||
async function saveZone() {
|
||||
if (!zoneForm.zoneCode || !zoneForm.zoneName) {
|
||||
ElMessage.warning('区域编码和区域名称必填')
|
||||
return
|
||||
}
|
||||
zoneSaving.value = true
|
||||
try {
|
||||
await request.post('/zone/create', { ...zoneForm })
|
||||
ElMessage.success('区域新增成功')
|
||||
zoneForm.zoneCode = ''
|
||||
zoneForm.zoneName = ''
|
||||
zoneForm.description = ''
|
||||
if (zoneEditingId.value) {
|
||||
await request.post('/zone/update', { id: zoneEditingId.value, ...zoneForm })
|
||||
ElMessage.success('区域修改成功')
|
||||
} else {
|
||||
await request.post('/zone/create', { ...zoneForm })
|
||||
ElMessage.success('区域新增成功')
|
||||
}
|
||||
zoneDialog.value = false
|
||||
await loadZones()
|
||||
} finally {
|
||||
zoneSaving.value = false
|
||||
@@ -37,18 +74,29 @@ async function addZone() {
|
||||
const materials = ref([])
|
||||
const materialTotal = ref(0)
|
||||
const materialLoading = ref(false)
|
||||
const materialKeyword = ref('')
|
||||
const materialTypeFilter = ref('')
|
||||
const matPage = reactive({ current: 1, size: 10 })
|
||||
|
||||
const matDialog = ref(false)
|
||||
const mEditingId = ref(0)
|
||||
const mForm = reactive({
|
||||
code: '', name: '', shortName: '', spec: '', unit: '',
|
||||
manageMode: 1, materialType: '', templateCode: '', description: ''
|
||||
})
|
||||
const mSaving = ref(false)
|
||||
// 是否编辑模式
|
||||
const editingId = ref(0)
|
||||
|
||||
async function loadMaterials() {
|
||||
materialLoading.value = true
|
||||
try {
|
||||
const data = await request.get('/material/query', { params: { page: 1, pageSize: 200 } })
|
||||
const data = await request.get('/material/query', {
|
||||
params: {
|
||||
keyword: materialKeyword.value.trim(),
|
||||
materialType: materialTypeFilter.value,
|
||||
page: matPage.current,
|
||||
pageSize: matPage.size
|
||||
}
|
||||
})
|
||||
materials.value = data?.list || []
|
||||
materialTotal.value = data?.total || 0
|
||||
} finally {
|
||||
@@ -56,22 +104,33 @@ async function loadMaterials() {
|
||||
}
|
||||
}
|
||||
|
||||
function searchMaterials() {
|
||||
matPage.current = 1
|
||||
loadMaterials()
|
||||
}
|
||||
|
||||
function resetMForm() {
|
||||
editingId.value = 0
|
||||
mEditingId.value = 0
|
||||
Object.assign(mForm, {
|
||||
code: '', name: '', shortName: '', spec: '', unit: '',
|
||||
manageMode: 1, materialType: '', templateCode: '', description: ''
|
||||
})
|
||||
}
|
||||
|
||||
function startEdit(row) {
|
||||
editingId.value = row.id
|
||||
function openMatCreate() {
|
||||
resetMForm()
|
||||
matDialog.value = true
|
||||
}
|
||||
|
||||
function openMatEdit(row) {
|
||||
mEditingId.value = row.id
|
||||
Object.assign(mForm, {
|
||||
code: row.code, name: row.name, shortName: row.shortName || '',
|
||||
spec: row.spec || '', unit: row.unit || '', manageMode: row.manageMode,
|
||||
materialType: row.materialType || '', templateCode: row.templateCode || '',
|
||||
description: row.description || ''
|
||||
})
|
||||
matDialog.value = true
|
||||
}
|
||||
|
||||
async function saveMaterial() {
|
||||
@@ -81,18 +140,18 @@ async function saveMaterial() {
|
||||
}
|
||||
mSaving.value = true
|
||||
try {
|
||||
if (editingId.value) {
|
||||
if (mEditingId.value) {
|
||||
await request.post('/material/update', {
|
||||
id: editingId.value, name: mForm.name, shortName: mForm.shortName,
|
||||
id: mEditingId.value, name: mForm.name, shortName: mForm.shortName,
|
||||
spec: mForm.spec, unit: mForm.unit, description: mForm.description,
|
||||
manageMode: mForm.manageMode
|
||||
})
|
||||
ElMessage.success('物料更新成功')
|
||||
ElMessage.success('物料修改成功')
|
||||
} else {
|
||||
await request.post('/material/create', { ...mForm })
|
||||
ElMessage.success('物料新增成功')
|
||||
}
|
||||
resetMForm()
|
||||
matDialog.value = false
|
||||
await loadMaterials()
|
||||
} finally {
|
||||
mSaving.value = false
|
||||
@@ -108,55 +167,51 @@ onMounted(() => {
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<el-tabs>
|
||||
<el-tab-pane label="区域维护">
|
||||
<el-form inline style="margin-bottom:14px">
|
||||
<el-form-item label="区域编码">
|
||||
<el-input v-model="zoneForm.zoneCode" placeholder="如 Z02" clearable style="width:170px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="区域名称">
|
||||
<el-input v-model="zoneForm.zoneName" placeholder="如 合格区" clearable style="width:170px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="说明">
|
||||
<el-input v-model="zoneForm.description" placeholder="备注(可空)" clearable style="width:220px" />
|
||||
<el-tab-pane :label="`区域维护(${zoneTotal})`">
|
||||
<el-form inline style="margin-bottom:14px" @submit.prevent="searchZones">
|
||||
<el-form-item label="关键字">
|
||||
<el-input v-model="zoneKeyword" placeholder="区域编码/名称" clearable style="width:200px"
|
||||
@keyup.enter="searchZones" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="zoneSaving" @click="addZone">新增区域</el-button>
|
||||
<el-button type="primary" :loading="zoneLoading" @click="searchZones">查询</el-button>
|
||||
<el-button type="success" @click="openZoneCreate">新增区域</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="zones" border size="small" empty-text="暂无区域,请先在上方新增">
|
||||
<el-table :data="zones" border size="small" v-loading="zoneLoading" empty-text="暂无区域,请点击【新增区域】">
|
||||
<el-table-column prop="zoneCode" label="区域编码" min-width="140" />
|
||||
<el-table-column prop="zoneName" label="区域名称" min-width="160" />
|
||||
<el-table-column label="状态" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === '停用' ? 'info' : 'success'" size="small">
|
||||
{{ row.status || '启用' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="description" label="说明" min-width="200">
|
||||
<template #default="{ row }">{{ row.description || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" size="small" @click="openZoneEdit(row)">编辑</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pager">
|
||||
<el-pagination background layout="total, prev, pager, next" :total="zoneTotal"
|
||||
:current-page="zonePage.current" :page-size="zonePage.size"
|
||||
@current-change="(p) => { zonePage.current = p; loadZones() }" />
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane :label="`物料档案(${materialTotal})`">
|
||||
<el-form label-width="100px" inline style="margin-bottom:14px">
|
||||
<el-form-item label="物料编码">
|
||||
<el-input v-model="mForm.code" placeholder="如 SCREW-M3" clearable style="width:160px" :disabled="!!editingId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="名称">
|
||||
<el-input v-model="mForm.name" placeholder="如 螺丝 M3" clearable style="width:160px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="简称">
|
||||
<el-input v-model="mForm.shortName" placeholder="简称(可空)" clearable style="width:130px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="规格">
|
||||
<el-input v-model="mForm.spec" placeholder="规格(可空)" clearable style="width:130px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="单位">
|
||||
<el-input v-model="mForm.unit" placeholder="如 个/套" clearable style="width:100px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="类型">
|
||||
<el-select v-model="mForm.manageMode" placeholder="请选择" style="width:150px">
|
||||
<el-option :value="1" label="结构件(批次管理)" />
|
||||
<el-option :value="2" label="精密件(SN 管理)" />
|
||||
</el-select>
|
||||
<el-form inline style="margin-bottom:14px" @submit.prevent="searchMaterials">
|
||||
<el-form-item label="关键字">
|
||||
<el-input v-model="materialKeyword" placeholder="物料编码/名称" clearable style="width:200px"
|
||||
@keyup.enter="searchMaterials" />
|
||||
</el-form-item>
|
||||
<el-form-item label="物料类型">
|
||||
<el-select v-model="mForm.materialType" placeholder="请选择" clearable style="width:130px">
|
||||
<el-select v-model="materialTypeFilter" placeholder="全部" clearable style="width:130px">
|
||||
<el-option label="标准件" value="标准件" />
|
||||
<el-option label="电子件" value="电子件" />
|
||||
<el-option label="包装件" value="包装件" />
|
||||
@@ -165,13 +220,12 @@ onMounted(() => {
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="mSaving" @click="saveMaterial">
|
||||
{{ editingId ? '保存修改' : '新增物料' }}
|
||||
</el-button>
|
||||
<el-button v-if="editingId" @click="resetMForm">取消编辑</el-button>
|
||||
<el-button type="primary" :loading="materialLoading" @click="searchMaterials">查询</el-button>
|
||||
<el-button type="success" @click="openMatCreate">新增物料</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="materials" border size="small" v-loading="materialLoading" empty-text="暂无物料,请先在上方新增">
|
||||
<el-table :data="materials" border size="small" v-loading="materialLoading"
|
||||
empty-text="暂无物料,请点击【新增物料】">
|
||||
<el-table-column prop="code" label="物料编码" min-width="120" />
|
||||
<el-table-column prop="name" label="名称" min-width="120" />
|
||||
<el-table-column prop="spec" label="规格" min-width="90">
|
||||
@@ -192,12 +246,86 @@ onMounted(() => {
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" size="small" @click="startEdit(row)">编辑</el-button>
|
||||
<el-button link type="primary" size="small" @click="openMatEdit(row)">编辑</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pager">
|
||||
<el-pagination background layout="total, sizes, prev, pager, next" :total="materialTotal"
|
||||
:current-page="matPage.current" :page-size="matPage.size" :page-sizes="[10, 20, 50, 100]"
|
||||
@current-change="(p) => { matPage.current = p; loadMaterials() }"
|
||||
@size-change="(s) => { matPage.size = s; matPage.current = 1; loadMaterials() }" />
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<!-- 区域弹窗 -->
|
||||
<el-dialog v-model="zoneDialog" :title="zoneEditingId ? '编辑区域' : '新增区域'" width="460px"
|
||||
append-to-body destroy-on-close>
|
||||
<el-form label-width="90px">
|
||||
<el-form-item label="区域编码" required>
|
||||
<el-input v-model="zoneForm.zoneCode" placeholder="如 Z05" :disabled="!!zoneEditingId" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="区域名称" required>
|
||||
<el-input v-model="zoneForm.zoneName" placeholder="如 待检区" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="说明">
|
||||
<el-input v-model="zoneForm.description" type="textarea" :rows="2" placeholder="备注(可空)" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="zoneDialog = false">取消</el-button>
|
||||
<el-button type="primary" :loading="zoneSaving" @click="saveZone">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 物料弹窗 -->
|
||||
<el-dialog v-model="matDialog" :title="mEditingId ? '编辑物料' : '新增物料'" width="560px"
|
||||
append-to-body destroy-on-close>
|
||||
<el-form label-width="90px">
|
||||
<el-form-item label="物料编码" required>
|
||||
<el-input v-model="mForm.code" placeholder="如 SCREW-M3" :disabled="!!mEditingId" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="名称" required>
|
||||
<el-input v-model="mForm.name" placeholder="如 螺丝 M3" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="简称">
|
||||
<el-input v-model="mForm.shortName" placeholder="简称(可空)" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="规格">
|
||||
<el-input v-model="mForm.spec" placeholder="规格(可空)" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="单位">
|
||||
<el-input v-model="mForm.unit" placeholder="如 个/套" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="类型">
|
||||
<el-select v-model="mForm.manageMode" placeholder="请选择" style="width:100%">
|
||||
<el-option :value="1" label="结构件(批次管理)" />
|
||||
<el-option :value="2" label="精密件(SN 管理)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="物料类型">
|
||||
<el-select v-model="mForm.materialType" placeholder="请选择" clearable style="width:100%">
|
||||
<el-option label="标准件" value="标准件" />
|
||||
<el-option label="电子件" value="电子件" />
|
||||
<el-option label="包装件" value="包装件" />
|
||||
<el-option label="半成品" value="半成品" />
|
||||
<el-option label="成品" value="成品" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="说明">
|
||||
<el-input v-model="mForm.description" type="textarea" :rows="2" placeholder="备注(可空)" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="matDialog = false">取消</el-button>
|
||||
<el-button type="primary" :loading="mSaving" @click="saveMaterial">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
<PageHelp :data="helpBaseData" />
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.pager { display: flex; justify-content: flex-end; margin-top: 10px; }
|
||||
</style>
|
||||
|
||||
@@ -34,7 +34,7 @@ const entries = [
|
||||
{ path: '/inspection', title: '质量检验', icon: CircleCheck },
|
||||
{ path: '/stocktake', title: '库存盘点', icon: List },
|
||||
{ path: '/semi', title: '半成品/成品', icon: Box },
|
||||
{ path: '/package', title: '包装绑定', icon: Tickets },
|
||||
{ path: '/package', title: '装箱管理', icon: Tickets },
|
||||
{ path: '/ledger', title: '备料台账', icon: Tickets },
|
||||
{ path: '/base-data', title: '基础数据', icon: EditPen },
|
||||
{ path: '/display', title: '免登录大屏', icon: Monitor }
|
||||
|
||||
@@ -11,7 +11,7 @@ const materials = ref([])
|
||||
const zones = ref([])
|
||||
|
||||
onMounted(async () => {
|
||||
const [ms, zs] = await Promise.all([request.get('/material/list'), request.get('/zone/list')])
|
||||
const [ms, zs] = await Promise.all([request.get('/material/list'), request.get('/zone/picker')])
|
||||
materials.value = Array.isArray(ms) ? ms : ms?.list || []
|
||||
zones.value = Array.isArray(zs) ? zs : zs?.list || []
|
||||
})
|
||||
@@ -26,6 +26,7 @@ const form1 = reactive({
|
||||
})
|
||||
const rules1 = {
|
||||
materialCode: [{ required: true, message: '请选择物料', trigger: 'change' }],
|
||||
zoneCode: [{ required: true, message: '请选择入库区域', trigger: 'change' }],
|
||||
quantity: [{ required: true, message: '请输入数量', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
@@ -86,8 +87,12 @@ async function submitSn() {
|
||||
ElMessage.warning('请选择物料')
|
||||
return
|
||||
}
|
||||
if (!form2.zoneCode) {
|
||||
ElMessage.warning('请选择入库区域')
|
||||
return
|
||||
}
|
||||
if (!snList.value.length) {
|
||||
ElMessage.warning('请先扫码录入 SN(输入后回车追加)')
|
||||
ElMessage.warning('请先扫码录入 SN(输入后点击【录入到列表】)')
|
||||
return
|
||||
}
|
||||
submitting2.value = true
|
||||
@@ -163,8 +168,8 @@ async function importExcel() {
|
||||
<el-form-item label="数量" prop="quantity">
|
||||
<el-input-number v-model="form1.quantity" :min="1" :step="1" step-strictly style="width:100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="区域">
|
||||
<el-select v-model="form1.zoneCode" placeholder="选择库区" clearable style="width:100%">
|
||||
<el-form-item label="区域" prop="zoneCode">
|
||||
<el-select v-model="form1.zoneCode" placeholder="请选择入库区域(必填)" clearable style="width:100%">
|
||||
<el-option v-for="z in zones" :key="z.id" :value="z.zoneCode"
|
||||
:label="`${z.zoneCode} ${z.zoneName || ''}`" />
|
||||
</el-select>
|
||||
@@ -189,14 +194,14 @@ async function importExcel() {
|
||||
|
||||
<el-tab-pane :label="`精密件 SN 入库${snList.length ? `(已扫 ${snList.length})` : ''}`">
|
||||
<el-form label-width="110px" style="max-width:680px">
|
||||
<el-form-item label="物料">
|
||||
<el-select v-model="form2.materialCode" filterable placeholder="选择物料编码" style="width:100%">
|
||||
<el-form-item label="物料" required>
|
||||
<el-select v-model="form2.materialCode" filterable placeholder="请选择物料(必填)" style="width:100%">
|
||||
<el-option v-for="m in materials" :key="m.id" :value="m.code"
|
||||
:label="`${m.code} ${m.name || ''}`" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="区域">
|
||||
<el-select v-model="form2.zoneCode" placeholder="选择库区(可空)" clearable style="width:100%">
|
||||
<el-form-item label="区域" required>
|
||||
<el-select v-model="form2.zoneCode" placeholder="请选择入库区域(必填)" clearable style="width:100%">
|
||||
<el-option v-for="z in zones" :key="z.id" :value="z.zoneCode"
|
||||
:label="`${z.zoneCode} ${z.zoneName || ''}`" />
|
||||
</el-select>
|
||||
|
||||
@@ -18,14 +18,47 @@ onMounted(async () => {
|
||||
await loadBoxes()
|
||||
})
|
||||
|
||||
/* ---------- 箱号绑定(连续扫码 SN,箱号 ↔ SN) ---------- */
|
||||
const bindForm = reactive({ boxNo: '', materialCode: '' })
|
||||
/* ---------- 装箱弹窗(新增 / 编辑) ---------- */
|
||||
const dialogVisible = ref(false)
|
||||
const editingId = ref(0)
|
||||
const bindForm = reactive({ boxNo: '', materialCode: '', contractNo: '', remark: '' })
|
||||
const snInput = ref('')
|
||||
const snList = ref([])
|
||||
const binding = ref(false)
|
||||
const saving = ref(false)
|
||||
|
||||
function resetForm() {
|
||||
editingId.value = 0
|
||||
Object.assign(bindForm, { boxNo: '', materialCode: '', contractNo: '', remark: '' })
|
||||
snInput.value = ''
|
||||
snList.value = []
|
||||
}
|
||||
|
||||
function openCreate() {
|
||||
resetForm()
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
function openEdit(row) {
|
||||
resetForm()
|
||||
editingId.value = row.id
|
||||
bindForm.boxNo = row.boxNo
|
||||
bindForm.materialCode = row.materialCode || ''
|
||||
bindForm.contractNo = row.contractNo || ''
|
||||
bindForm.remark = row.remark || ''
|
||||
try {
|
||||
const arr = JSON.parse(row.snList || '[]')
|
||||
snList.value = Array.isArray(arr) ? arr : []
|
||||
} catch {
|
||||
snList.value = row.snList ? String(row.snList).split(/[,,\s]+/).filter(Boolean) : []
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
// 支持多种分隔符:中英文逗号、分号、顿号、空格、回车、制表符
|
||||
const SN_SEP = /[,,;;、\s]+/
|
||||
|
||||
function addSnLines() {
|
||||
for (let raw of String(snInput.value).split(/\s+/)) {
|
||||
for (let raw of String(snInput.value).split(SN_SEP)) {
|
||||
const sn = raw.trim()
|
||||
if (sn && !snList.value.includes(sn)) snList.value.push(sn)
|
||||
}
|
||||
@@ -36,36 +69,41 @@ function removeSn(i) {
|
||||
snList.value.splice(i, 1)
|
||||
}
|
||||
|
||||
async function bind() {
|
||||
async function save() {
|
||||
if (!bindForm.boxNo.trim()) {
|
||||
ElMessage.warning('请输入箱号')
|
||||
return
|
||||
}
|
||||
if (!snList.value.length) {
|
||||
ElMessage.warning('请扫码录入 SN(回车追加)')
|
||||
ElMessage.warning('请扫码录入至少 1 个 SN')
|
||||
return
|
||||
}
|
||||
binding.value = true
|
||||
saving.value = true
|
||||
try {
|
||||
await request.post('/package/bind', {
|
||||
boxNo: bindForm.boxNo.trim(),
|
||||
const payload = {
|
||||
materialCode: bindForm.materialCode || undefined,
|
||||
contractNo: bindForm.contractNo.trim() || undefined,
|
||||
remark: bindForm.remark.trim() || undefined,
|
||||
snList: [...snList.value],
|
||||
operator
|
||||
})
|
||||
ElMessage.success(`绑定成功:箱号 ${bindForm.boxNo.trim()} 共 ${snList.value.length} 个 SN`)
|
||||
snList.value = []
|
||||
snInput.value = ''
|
||||
bindForm.boxNo = ''
|
||||
}
|
||||
if (editingId.value) {
|
||||
await request.post('/package/update', { id: editingId.value, ...payload })
|
||||
ElMessage.success(`装箱更新成功:${bindForm.boxNo.trim()}`)
|
||||
} else {
|
||||
await request.post('/package/bind', { boxNo: bindForm.boxNo.trim(), ...payload })
|
||||
ElMessage.success(`装箱成功:${bindForm.boxNo.trim()} 共 ${snList.value.length} 个 SN`)
|
||||
}
|
||||
dialogVisible.value = false
|
||||
page.current = 1
|
||||
await loadBoxes()
|
||||
} finally {
|
||||
binding.value = false
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- 包装查询 ---------- */
|
||||
const boxKeyword = ref('')
|
||||
/* ---------- 装箱查询(多条件) ---------- */
|
||||
const filters = reactive({ boxNo: '', contractNo: '', operator: '', materialCode: '', dateRange: [] })
|
||||
const boxes = ref([])
|
||||
const total = ref(0)
|
||||
const loading = ref(false)
|
||||
@@ -83,9 +121,19 @@ function parseSn(jsonStr) {
|
||||
async function loadBoxes() {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await request.get('/package/query', {
|
||||
params: { boxNo: boxKeyword.value.trim(), page: page.current, pageSize: page.size }
|
||||
})
|
||||
const params = {
|
||||
boxNo: filters.boxNo.trim(),
|
||||
contractNo: filters.contractNo.trim(),
|
||||
operator: filters.operator.trim(),
|
||||
materialCode: filters.materialCode.trim(),
|
||||
page: page.current,
|
||||
pageSize: page.size
|
||||
}
|
||||
if (Array.isArray(filters.dateRange) && filters.dateRange.length === 2) {
|
||||
params.startAt = new Date(filters.dateRange[0]).getTime()
|
||||
params.endAt = new Date(filters.dateRange[1]).getTime() + 86399999
|
||||
}
|
||||
const data = await request.get('/package/query', { params })
|
||||
boxes.value = data?.list || []
|
||||
total.value = data?.total || 0
|
||||
} finally {
|
||||
@@ -97,84 +145,144 @@ function search() {
|
||||
page.current = 1
|
||||
loadBoxes()
|
||||
}
|
||||
|
||||
function resetSearch() {
|
||||
Object.assign(filters, { boxNo: '', contractNo: '', operator: '', materialCode: '', dateRange: [] })
|
||||
search()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<el-card shadow="never" class="mb12" header="箱号绑定(连续扫码 SN)">
|
||||
<el-card shadow="never" class="mb12" header="装箱管理">
|
||||
<el-form inline label-width="90px" @submit.prevent>
|
||||
<el-form-item label="箱号">
|
||||
<el-input v-model="bindForm.boxNo" placeholder="扫描或输入箱号" clearable style="width:200px" />
|
||||
<el-form-item>
|
||||
<el-button type="primary" :icon="'Plus'" @click="openCreate">新增装箱</el-button>
|
||||
<span style="margin-left:10px;color:#909399;font-size:12px">装箱:将多个成品/精密件 SN 装入一个箱号,用于发货、入库、整箱追溯</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-card shadow="never" header="装箱查询" class="inner-card">
|
||||
<el-form inline @submit.prevent="search">
|
||||
<el-form-item label="箱号">
|
||||
<el-input v-model="filters.boxNo" placeholder="按箱号模糊查询" clearable style="width:170px" @keyup.enter="search" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同号">
|
||||
<el-input v-model="filters.contractNo" placeholder="按合同号查询" clearable style="width:150px" @keyup.enter="search" />
|
||||
</el-form-item>
|
||||
<el-form-item label="操作人">
|
||||
<el-input v-model="filters.operator" placeholder="操作人" clearable style="width:130px" @keyup.enter="search" />
|
||||
</el-form-item>
|
||||
<el-form-item label="物料">
|
||||
<el-select v-model="filters.materialCode" filterable clearable placeholder="物料" style="width:180px">
|
||||
<el-option v-for="m in materials" :key="m.id" :value="m.code"
|
||||
:label="`${m.code} ${m.name || ''}`" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="装箱时间">
|
||||
<el-date-picker v-model="filters.dateRange" type="daterange" value-format="YYYY-MM-DD"
|
||||
range-separator="至" start-placeholder="开始" end-placeholder="结束"
|
||||
style="width:240px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="loading" @click="search">查询</el-button>
|
||||
<el-button @click="resetSearch">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="boxes" border size="small" v-loading="loading" empty-text="暂无装箱记录">
|
||||
<el-table-column prop="boxNo" label="箱号" min-width="140" />
|
||||
<el-table-column label="SN 列表" min-width="280">
|
||||
<template #default="{ row }">{{ parseSn(row.snList) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="quantity" label="SN 数量" width="90" align="center" />
|
||||
<el-table-column prop="materialCode" label="物料编码" min-width="120">
|
||||
<template #default="{ row }">{{ row.materialCode || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="contractNo" label="合同号" min-width="110">
|
||||
<template #default="{ row }">{{ row.contractNo || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operator" label="操作人" width="100" align="center">
|
||||
<template #default="{ row }">{{ row.operator || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="装箱时间" width="150" align="center">
|
||||
<template #default="{ row }">{{ fmtTime(row.createdAt) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" size="small" @click="openEdit(row)">编辑</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pager">
|
||||
<el-pagination background layout="total, sizes, prev, pager, next" :total="total"
|
||||
:current-page="page.current" :page-size="page.size" :page-sizes="[10, 20, 50, 100]"
|
||||
@current-change="(p) => { page.current = p; loadBoxes() }"
|
||||
@size-change="(s) => { page.size = s; page.current = 1; loadBoxes() }" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-card>
|
||||
|
||||
<!-- 新增/编辑装箱 弹窗 -->
|
||||
<el-dialog v-model="dialogVisible" :title="editingId ? '编辑装箱' : '新增装箱'" width="640px"
|
||||
append-to-body destroy-on-close @closed="resetForm">
|
||||
<el-form label-width="90px">
|
||||
<el-form-item label="箱号" required>
|
||||
<el-input v-model="bindForm.boxNo" placeholder="扫描或输入箱号" :disabled="!!editingId"
|
||||
style="width:100%" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="物料">
|
||||
<el-select v-model="bindForm.materialCode" filterable clearable placeholder="请选择物料"
|
||||
style="width:240px">
|
||||
<el-select v-model="bindForm.materialCode" filterable clearable placeholder="请选择物料(可空,同一箱建议装同一物料)"
|
||||
style="width:100%">
|
||||
<el-option v-for="m in materials" :key="m.id" :value="m.code"
|
||||
:label="`${m.code} ${m.name || ''}`" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同号">
|
||||
<el-input v-model="bindForm.contractNo" placeholder="合同号(选填)" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="操作人">
|
||||
<el-input :model-value="operator" disabled style="width:140px" />
|
||||
<el-input :model-value="operator" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="SN 录入">
|
||||
<div style="width:100%">
|
||||
<el-input v-model="snInput" type="textarea" :rows="3"
|
||||
placeholder="连续扫描 SN,支持 逗号/分号/顿号/空格/回车 分隔,一次可录入多条" />
|
||||
<div style="margin-top:6px">
|
||||
<el-button type="primary" plain :disabled="!snInput.trim()" @click="addSnLines">录入到列表</el-button>
|
||||
<span style="margin-left:8px;color:#909399;font-size:12px">点【录入到列表】加入下方清单,回车只是换行</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="待装 SN">
|
||||
<div style="width:100%">
|
||||
<div style="margin-bottom:6px">共 <b>{{ snList.length }}</b> 条</div>
|
||||
<el-table :data="snList.map((v, i) => ({ i, v }))" size="small" border max-height="200"
|
||||
empty-text="暂无 SN" style="width:100%">
|
||||
<el-table-column type="index" label="#" width="56" align="center" />
|
||||
<el-table-column prop="v" label="SN 序列号" min-width="200" />
|
||||
<el-table-column label="操作" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="danger" size="small" @click="removeSn(row.i)">移除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="bindForm.remark" type="textarea" :rows="2" placeholder="备注(可空)" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-input v-model="snInput" type="textarea" :rows="3" autofocus
|
||||
placeholder="连续扫描 SN,每次回车追加(可一次多条,空白分隔)"
|
||||
style="max-width:560px;margin-bottom:8px"
|
||||
@keydown.enter.prevent="addSnLines" />
|
||||
|
||||
<div style="margin-bottom:8px">待绑定 SN:<b>{{ snList.length }}</b> 条</div>
|
||||
<el-table :data="snList.map((v, i) => ({ i, v }))" size="small" border max-height="240"
|
||||
empty-text="暂无 SN" style="max-width:760px">
|
||||
<el-table-column type="index" label="#" width="56" align="center" />
|
||||
<el-table-column prop="v" label="SN 序列号" min-width="200" />
|
||||
<el-table-column label="操作" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="danger" size="small" @click="removeSn(row.i)">移除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-button type="primary" class="mt12" :loading="binding" @click="bind">确认绑定</el-button>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" header="包装查询">
|
||||
<el-form inline @submit.prevent="search">
|
||||
<el-form-item label="箱号">
|
||||
<el-input v-model="boxKeyword" placeholder="按箱号模糊查询" clearable style="width:220px"
|
||||
@keyup.enter="search" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="loading" @click="search">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="boxes" border size="small" v-loading="loading" empty-text="暂无包装记录">
|
||||
<el-table-column prop="boxNo" label="箱号" min-width="150" />
|
||||
<el-table-column label="SN 列表" min-width="300">
|
||||
<template #default="{ row }">{{ parseSn(row.snList) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="quantity" label="SN 数量" width="90" align="center" />
|
||||
<el-table-column prop="materialCode" label="物料编码" min-width="130">
|
||||
<template #default="{ row }">{{ row.materialCode || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operator" label="操作人" width="100" align="center">
|
||||
<template #default="{ row }">{{ row.operator || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" width="160" align="center">
|
||||
<template #default="{ row }">{{ fmtTime(row.createdAt) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pager">
|
||||
<el-pagination background layout="total, prev, pager, next" :total="total"
|
||||
:current-page="page.current" :page-size="page.size"
|
||||
@current-change="(p) => { page.current = p; loadBoxes() }" />
|
||||
</div>
|
||||
</el-card>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="saving" @click="save">{{ editingId ? '保存修改' : '确认装箱' }}</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<PageHelp :data="helpPackage" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.mb12 { margin-bottom: 12px; }
|
||||
.mt12 { margin-top: 12px; }
|
||||
.inner-card { border: none; box-shadow: none; padding: 0; }
|
||||
.pager { display: flex; justify-content: flex-end; margin-top: 10px; }
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -38,7 +38,7 @@ async function submitRecord() {
|
||||
}
|
||||
const targetId = recordForm.targetId.trim()
|
||||
if (!targetId) {
|
||||
ElMessage.warning('请扫入目标编号(批次号或 SN)')
|
||||
ElMessage.warning('请扫入批次号(结构件)或 SN 序列号(精密件)')
|
||||
return
|
||||
}
|
||||
const qty = Number(recordForm.scanQty)
|
||||
@@ -152,8 +152,8 @@ async function loadHistory() {
|
||||
</el-input>
|
||||
</template>
|
||||
<el-form inline @submit.prevent="submitRecord">
|
||||
<el-form-item label="目标编号">
|
||||
<el-input ref="idRef" v-model="recordForm.targetId" clearable autofocus placeholder="批次号 / SN"
|
||||
<el-form-item label="批次号/SN">
|
||||
<el-input ref="idRef" v-model="recordForm.targetId" clearable autofocus placeholder="批次号(结构件) / SN(精密件)"
|
||||
style="width:220px" @keyup.enter="submitRecord" />
|
||||
</el-form-item>
|
||||
<el-form-item label="实盘数量">
|
||||
@@ -164,7 +164,7 @@ async function loadHistory() {
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="records" border size="small" max-height="300" empty-text="尚无扫码记录">
|
||||
<el-table-column prop="targetId" label="目标编号" min-width="170" />
|
||||
<el-table-column prop="targetId" label="批次号 / SN 序列号" min-width="180" />
|
||||
<el-table-column prop="bookQty" label="账面数" width="90" align="center" />
|
||||
<el-table-column prop="scannedQty" label="实盘数" width="90" align="center" />
|
||||
<el-table-column label="差异" width="90" align="center">
|
||||
|
||||
@@ -16,7 +16,7 @@ const routes = [
|
||||
{ path: 'inspection', name: 'Inspection', component: () => import('../pages/Inspection.vue'), meta: { title: '质量检验' } },
|
||||
{ path: 'stocktake', name: 'Stocktake', component: () => import('../pages/Stocktake.vue'), meta: { title: '库存盘点' } },
|
||||
{ path: 'semi', name: 'Semi', component: () => import('../pages/Semi.vue'), meta: { title: '半成品/成品' } },
|
||||
{ path: 'package', name: 'Package', component: () => import('../pages/Package.vue'), meta: { title: '包装绑定' } },
|
||||
{ path: 'package', name: 'Package', component: () => import('../pages/Package.vue'), meta: { title: '装箱管理' } },
|
||||
{ path: 'ledger', name: 'Ledger', component: () => import('../pages/Ledger.vue'), meta: { title: '备料台账' } },
|
||||
{ path: 'base-data', name: 'BaseData', component: () => import('../pages/BaseData.vue'), meta: { title: '基础数据' } },
|
||||
{ path: 'change-password', name: 'ChangePassword', component: () => import('../pages/ChangePassword.vue'), meta: { title: '修改密码' } }
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>库房客户端</title>
|
||||
<script type="module" crossorigin src="/assets/index-BytlUM1G.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Bc2zCoxT.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user