feat: 新增装机绑定功能与权限、BOM工序配置
1. 新增装机绑定实体与相关CRUD逻辑,支持工件工序物料绑定/解绑 2. 为BOM物料新增装配工序字段,支持按工序校验绑定 3. 扩展权限表,新增父权限码字段支持菜单按钮关联 4. 统一各页面帮助弹窗参数,新增角色管理帮助文档 5. 新增公共格式化工具函数,优化侧边栏菜单展开逻辑 6. 新增工位终端绑定代理接口与MES内部绑定API 7. 修复主入口数据库连接与schema初始化逻辑,新增一键迁移工具
This commit is contained in:
@@ -44,7 +44,46 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
<el-alert v-else type="info" :closable="false" title="请选择工位、输入SN后点【载入工序步骤】;若提示未配置工序步骤,请到「工艺流程」为该工位启用流程并维护工序步骤" />
|
||||
|
||||
<!-- 装机绑定区:该工件在本工序应装什么料(BOM 装配工序配置)→ 扫码/手录绑定,齐套后才允许报工 -->
|
||||
<el-card v-if="bindPanel" shadow="never" style="margin-bottom:12px;border-color:var(--el-color-primary)">
|
||||
<div slot="header" style="display:flex;justify-content:space-between;align-items:center">
|
||||
<b>工序 {{ form.stationNo }} 装机绑定(装配物料)</b>
|
||||
<el-alert v-if="bindPanel.enabled && !bindPanel.complete" type="warning" :closable="false" show-icon style="flex:1;margin-left:16px"
|
||||
:title="'尚未绑齐:' + bindPanel.missing" />
|
||||
<el-alert v-else-if="bindPanel.enabled && bindPanel.complete" type="success" :closable="false" show-icon style="flex:1;margin-left:16px"
|
||||
title="装配物料已绑齐,可提交报工" />
|
||||
<el-alert v-else type="info" :closable="false" style="flex:1;margin-left:16px"
|
||||
title="该产品未在本工序配置需绑定物料(BOM「装配工序」为空),不校验" />
|
||||
</div>
|
||||
<el-table v-if="bindPanel.required && bindPanel.required.length" :data="bindPanel.required" border size="small">
|
||||
<el-table-column prop="materialCode" label="物料编码" min-width="110" />
|
||||
<el-table-column prop="materialName" label="物料名称" min-width="120" />
|
||||
<el-table-column prop="manageMode" label="管理方式" width="120">
|
||||
<template #default="{row}">{{ row.manageMode === '2' ? '精密件(SN)' : '结构件(批次)' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已绑/需绑" width="100" align="center">
|
||||
<template #default="{row}">
|
||||
<b :style="{color: row.complete ? 'var(--el-color-success)' : 'var(--el-color-danger)'}">{{ row.boundCount }}/{{ row.need }}</b>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已绑定值" min-width="170">
|
||||
<template #default="{row}">
|
||||
<el-tag v-for="b in row.bound" :key="b" size="small" style="margin-right:4px">{{ b }}</el-tag>
|
||||
<span v-if="!row.bound.length" style="color:#909399">未绑定</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="绑定操作" width="230">
|
||||
<template #default="{row}">
|
||||
<div style="display:flex;gap:4px">
|
||||
<el-input v-model="row._input" :placeholder="row.manageMode === '2' ? '扫码SN' : '扫码/输入批次号'" size="small" @keyup.enter="bindOne(row)" />
|
||||
<el-button size="small" type="primary" :loading="binding" @click="bindOne(row)">绑定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
<el-alert v-if="!steps.length && !bindPanel" type="info" :closable="false" title="请选择工位、输入SN后点【载入工序步骤】;若提示未配置工序步骤,请到「工艺流程」为该工位启用流程并维护工序步骤" />
|
||||
|
||||
<el-divider content-position="left">报工记录</el-divider>
|
||||
<el-form inline>
|
||||
@@ -62,7 +101,7 @@
|
||||
<el-table-column prop="time" label="时间" min-width="170" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
<PageHelp :data="helpScan" />
|
||||
<PageHelp :data="helpScan" page="Scan" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -77,6 +116,8 @@ const form = reactive({ stationNo: 1, sn: '' })
|
||||
const steps = ref([])
|
||||
const flowName = ref('')
|
||||
const saving = ref(false)
|
||||
const bindPanel = ref(null)
|
||||
const binding = ref(false)
|
||||
const query = reactive({ sn: '', orderNo: '' })
|
||||
const list = ref([])
|
||||
|
||||
@@ -95,6 +136,7 @@ function critText(c) {
|
||||
// 从后端加载该工位启用工艺流程的工序步骤(value 挂在 row 上,提交时收集)
|
||||
async function loadSteps() {
|
||||
if (!form.sn) return ElMessage.warning('请先输入工件SN')
|
||||
bindPanel.value = null
|
||||
try {
|
||||
const data = await request.get('/process-steps', { params: { stationNo: form.stationNo } }) || []
|
||||
steps.value = data.map(s => ({ ...s, value: '', text: '' }))
|
||||
@@ -102,12 +144,50 @@ async function loadSteps() {
|
||||
if (!steps.value.length) {
|
||||
ElMessage.warning(`工位${form.stationNo} 未配置启用的工艺流程,请到「工艺流程」维护`)
|
||||
}
|
||||
loadBindPanel()
|
||||
} catch { steps.value = [] }
|
||||
}
|
||||
|
||||
// 拉取本工件本工序的装配物料绑定面板(应绑清单 + 已绑情况)
|
||||
async function loadBindPanel() {
|
||||
if (!form.sn) return
|
||||
try {
|
||||
const p = await request.get('/bind-panel', { params: { sn: form.sn, processCode: form.stationNo } }) || null
|
||||
if (p?.required) {
|
||||
p.required.forEach((r) => { r._input = '' })
|
||||
}
|
||||
bindPanel.value = p
|
||||
} catch {
|
||||
bindPanel.value = null
|
||||
}
|
||||
}
|
||||
|
||||
// 扫/录单个物料 → 立即绑定落库并刷新齐套状态(防错即时反馈)
|
||||
async function bindOne(row) {
|
||||
const v = (row._input || '').trim()
|
||||
if (!v) return ElMessage.warning('请先输入绑定值(精密件扫码SN / 结构件批次号)')
|
||||
binding.value = true
|
||||
try {
|
||||
await request.post('/binds', {
|
||||
sn: form.sn,
|
||||
orderNo: '',
|
||||
processCode: form.stationNo,
|
||||
stationNo: form.stationNo,
|
||||
items: [{ materialCode: row.materialCode, bindValue: v }]
|
||||
})
|
||||
ElMessage.success('绑定成功')
|
||||
loadBindPanel()
|
||||
} catch { /* 错误已在拦截器提示 */ }
|
||||
binding.value = false
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
if (!form.sn) return ElMessage.warning('请输入SN')
|
||||
if (!steps.value.length) return ElMessage.warning('该工位未配置工序步骤,无法报工')
|
||||
// 报工前强校验:本工序装配物料需绑齐(后端 validateStationBinds)
|
||||
if (bindPanel.value?.enabled && !bindPanel.value?.complete) {
|
||||
return ElMessage.warning('装配物料未绑齐,请先完成装机绑定:' + (bindPanel.value.missing || ''))
|
||||
}
|
||||
const stepReq = steps.value
|
||||
.filter(s => s.collectType !== 'NONE' && (s.text !== '' || s.value !== ''))
|
||||
.map(s => ({
|
||||
@@ -125,6 +205,7 @@ async function submit() {
|
||||
})
|
||||
ElMessage.success('报工成功')
|
||||
steps.value = []
|
||||
bindPanel.value = null
|
||||
Object.assign(form, { sn: '' })
|
||||
load()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user