Files
bj_power/bj_power_wms/frontend/src/pages/Semi.vue
T
SunYF 2544c6141d refactor: 合并原库房客户端到主WMS服务,退役8891端口
1.  将bj_power_wms_client的前端代码、配置及网关逻辑全部迁移到bj_power_wms主项目
2.  删除原库房客户端相关的所有文件与配置
3.  更新README与部署文档,说明合并后的服务架构
4.  新增Web配置项支持自动打开浏览器开关,统一服务端口为8890
2026-09-07 15:55:30 +08:00

231 lines
8.5 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.
<script setup>
defineOptions({ name: 'Semi' })
import { onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import request from '../utils/request'
import { fmtTime } from '../utils/format'
import { getRealName } from '../utils/auth'
import PageHelp from '../components/PageHelp.vue'
import MaterialSelect from '../components/MaterialSelect.vue'
import { helpSemi } from '../help'
/* ---------- 半成品/成品入库(携带已完成工序,连续扫码) ---------- */
// 物料下拉由 MaterialSelect 组件按需远程搜索(最近 100 条)
onMounted(() => {
loadList()
})
const operator = getRealName()
const inForm = reactive({ materialCode: '', zoneCode: '', orderNo: '', completedProcess: '' })
const snInput = ref('')
const snList = ref([])
const inbounding = ref(false)
function addSnLines() {
for (let raw of String(snInput.value).split(/\s+/)) {
const sn = raw.trim()
if (sn && !snList.value.includes(sn)) snList.value.push(sn)
}
snInput.value = ''
}
function removeSn(i) {
snList.value.splice(i, 1)
}
async function submitInbound() {
if (!inForm.materialCode) {
ElMessage.warning('请选择物料')
return
}
if (!snList.value.length) {
ElMessage.warning('请扫码录入 SN(回车追加)')
return
}
inbounding.value = true
let ok = 0
try {
for (const sn of snList.value) {
try {
await request.post('/semi/inbound', {
sn,
materialCode: inForm.materialCode,
completedProcess: inForm.completedProcess.trim(),
zoneCode: inForm.zoneCode || undefined,
orderNo: inForm.orderNo.trim() || undefined,
operator
})
ok++
} catch { /* 单条失败不中断后续 */ }
}
ElMessage.success(`半成品入库完成:成功 ${ok} / ${snList.value.length} 条`)
snList.value = []
snInput.value = ''
} finally {
inbounding.value = false
}
}
/* ---------- 半成品出库(重上线) ---------- */
const outForm = reactive({ sn: '' })
const outbounding = ref(false)
async function submitOutbound() {
const sn = outForm.sn.trim()
if (!sn) {
ElMessage.warning('请输入 SN')
return
}
outbounding.value = true
try {
await request.post('/semi/outbound', { sn, operator })
ElMessage.success(`半成品出库成功:${sn}`)
outForm.sn = ''
await loadList()
} finally {
outbounding.value = false
}
}
/* ---------- 半成品查询 ---------- */
const qForm = reactive({ materialCode: '', status: '' })
const list = ref([])
const total = ref(0)
const loading = ref(false)
const page = reactive({ current: 1, size: 10 })
async function loadList() {
loading.value = true
try {
const data = await request.get('/semi/query', {
params: {
materialCode: qForm.materialCode.trim(),
status: qForm.status,
page: page.current,
pageSize: page.size
}
})
list.value = data?.list || []
total.value = data?.total || 0
} finally {
loading.value = false
}
}
function search() {
page.current = 1
loadList()
}
</script>
<template>
<el-card shadow="never">
<el-tabs>
<el-tab-pane label="半成品/成品入库">
<el-form label-width="110px" style="max-width:680px">
<el-form-item label="物料">
<MaterialSelect v-model="inForm.materialCode" placeholder="选择物料编码" />
</el-form-item>
<el-form-item label="已完成工序">
<el-input v-model="inForm.completedProcess" placeholder="如:1,3,5(可空)" clearable />
</el-form-item>
<el-form-item label="工单号">
<el-input v-model="inForm.orderNo" placeholder="来源工单号(可空)" clearable />
</el-form-item>
<el-form-item label="区域">
<el-input v-model="inForm.zoneCode" placeholder="库区(可空)" clearable />
</el-form-item>
<el-form-item label="操作人">
<el-input :model-value="operator" disabled />
</el-form-item>
<el-form-item label="扫码录入">
<el-input v-model="snInput" type="textarea" :rows="3" autofocus
placeholder="连续扫描 SN,每次回车追加(可一次多条,空白分隔)"
@keydown.enter.prevent="addSnLines" />
</el-form-item>
</el-form>
<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="260"
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="220" />
<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 style="margin-top:12px">
<el-button type="primary" :loading="inbounding" @click="submitInbound">提交入库</el-button>
<el-button @click="snList = []">清空</el-button>
</div>
</el-tab-pane>
<el-tab-pane label="半成品出库">
<el-form label-width="110px" style="max-width:560px" @submit.prevent="submitOutbound">
<el-form-item label="SN">
<el-input v-model="outForm.sn" placeholder="扫描或输入 SN,回车出库" clearable autofocus
@keyup.enter="submitOutbound" />
</el-form-item>
<el-form-item label="操作人">
<el-input :model-value="operator" disabled />
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="outbounding" @click="submitOutbound">出库重上线</el-button>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="半成品/成品查询">
<el-form inline @submit.prevent="search">
<el-form-item label="物料编码">
<el-input v-model="qForm.materialCode" placeholder="物料编码" clearable style="width:200px" />
</el-form-item>
<el-form-item label="状态">
<el-select v-model="qForm.status" clearable placeholder="请选择状态" style="width:120px">
<el-option value="在库" label="在库" />
<el-option value="出库" label="出库" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="loading" @click="search">查询</el-button>
</el-form-item>
</el-form>
<el-table :data="list" border size="small" v-loading="loading" empty-text="暂无记录">
<el-table-column prop="id" label="ID" width="70" align="center" />
<el-table-column prop="sn" label="SN" min-width="200" />
<el-table-column prop="materialCode" label="物料编码" min-width="140" />
<el-table-column prop="completedProcess" label="已完成工序" min-width="120">
<template #default="{ row }">{{ row.completedProcess || '-' }}</template>
</el-table-column>
<el-table-column prop="zoneCode" label="区域" width="90" align="center">
<template #default="{ row }">{{ row.zoneCode || '-' }}</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="90" align="center">
<template #default="{ row }">
<el-tag :type="row.status === '在库' ? 'success' : 'info'" size="small">{{ row.status }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="orderNo" label="工单号" min-width="140">
<template #default="{ row }">{{ row.orderNo || '-' }}</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; loadList() }" />
</div>
</el-tab-pane>
</el-tabs>
</el-card>
<PageHelp :data="helpSemi" page="Semi" />
</template>
<style scoped>
.pager { display: flex; justify-content: flex-end; margin-top: 10px; }
</style>