feat: 新增装机绑定功能与权限、BOM工序配置
1. 新增装机绑定实体与相关CRUD逻辑,支持工件工序物料绑定/解绑 2. 为BOM物料新增装配工序字段,支持按工序校验绑定 3. 扩展权限表,新增父权限码字段支持菜单按钮关联 4. 统一各页面帮助弹窗参数,新增角色管理帮助文档 5. 新增公共格式化工具函数,优化侧边栏菜单展开逻辑 6. 新增工位终端绑定代理接口与MES内部绑定API 7. 修复主入口数据库连接与schema初始化逻辑,新增一键迁移工具
This commit is contained in:
@@ -1,178 +1,187 @@
|
||||
<template>
|
||||
<el-card>
|
||||
<el-form inline>
|
||||
<el-form-item label="工位号">
|
||||
<el-select v-model="query.stationNo" placeholder="全部" clearable style="width:140px" @change="loadFlows">
|
||||
<el-option v-for="i in 12" :key="i" :label="`工位${i}`" :value="i" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadFlows">查询</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button v-if="can('produce.processflow:add')" type="success" @click="openFlow()">新增流程</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-tabs v-model="activeTab">
|
||||
<!-- ============ 流程列表 ============ -->
|
||||
<el-tab-pane label="流程列表" name="list">
|
||||
<el-form inline>
|
||||
<el-form-item label="工位号">
|
||||
<el-select v-model="query.stationNo" placeholder="全部" clearable style="width:140px" @change="loadFlows">
|
||||
<el-option v-for="i in 12" :key="i" :label="`工位${i}`" :value="i" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadFlows">查询</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button v-if="can('produce.processflow:add')" type="success" @click="openFlow()">新增流程</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table :data="flows" border size="small">
|
||||
<el-table-column prop="id" label="ID" width="60" />
|
||||
<el-table-column prop="name" label="流程名" min-width="130" show-overflow-tooltip />
|
||||
<el-table-column prop="stationNo" label="工序编号" width="100" align="center" />
|
||||
<el-table-column label="PDF" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.pdfFile" link type="primary" @click="previewPdf(row.pdfFile)">预览</el-button>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === 'ACTIVE' ? 'success' : 'info'">{{ statusText(row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="绑定工位" min-width="150">
|
||||
<template #default="{ row }">
|
||||
<el-popover v-if="(row.stations || []).length" placement="top" :width="220" trigger="hover">
|
||||
<template #reference>
|
||||
<el-tag size="small" type="success">{{ (row.stations || []).length }} 个工位</el-tag>
|
||||
<el-table :data="flows" border size="small">
|
||||
<el-table-column prop="id" label="ID" width="60" />
|
||||
<el-table-column prop="name" label="流程名" min-width="130" show-overflow-tooltip />
|
||||
<el-table-column prop="stationNo" label="工序编号" width="100" align="center" />
|
||||
<el-table-column label="PDF" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.pdfFile" link type="primary" @click="previewPdf(row.pdfFile)">预览</el-button>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
<div style="line-height:1.9">{{ (row.stations || []).map(s => `工位${s}`).join('、') }}</div>
|
||||
</el-popover>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="步骤" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tooltip
|
||||
v-if="row.steps && row.steps.length"
|
||||
:content="row.steps.map(s => `${s.seq}.${s.name}`).join(' ')">
|
||||
<span>{{ row.steps.length }} 步</span>
|
||||
</el-tooltip>
|
||||
<span v-else>0 步</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="创建时间" width="150">
|
||||
<template #default="{ row }">{{ fmt(row.createdAt) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="220" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === 'ACTIVE' ? 'success' : 'info'">{{ statusText(row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="绑定工位" min-width="150">
|
||||
<template #default="{ row }">
|
||||
<el-popover v-if="(row.stations || []).length" placement="top" :width="220" trigger="hover">
|
||||
<template #reference>
|
||||
<el-tag size="small" type="success">{{ (row.stations || []).length }} 个工位</el-tag>
|
||||
</template>
|
||||
<div style="line-height:1.9">{{ (row.stations || []).map(s => `工位${s}`).join('、') }}</div>
|
||||
</el-popover>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="步骤" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tooltip
|
||||
v-if="row.steps && row.steps.length"
|
||||
:content="row.steps.map(s => `${s.seq}.${s.name}`).join(' ')">
|
||||
<span>{{ row.steps.length }} 步</span>
|
||||
</el-tooltip>
|
||||
<span v-else>0 步</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="创建时间" width="150">
|
||||
<template #default="{ row }">{{ fmt(row.createdAt) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="220" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-if="can('produce.processflow:add') || can('produce.processflow:edit')"
|
||||
size="small" @click="openFlow(row)">编辑</el-button>
|
||||
<el-button
|
||||
v-if="can('produce.processflow:edit')"
|
||||
size="small" :type="row.status === 'ACTIVE' ? 'danger' : 'success'" @click="toggleStatus(row)">
|
||||
{{ row.status === 'ACTIVE' ? '停用' : '启用' }}
|
||||
</el-button>
|
||||
<el-button v-if="can('produce.processflow:delete')" size="small" type="danger" @click="delFlow(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- ============ 流程配置(新增/编辑共用,替代原弹窗套弹窗) ============ -->
|
||||
<el-tab-pane label="流程配置" name="config">
|
||||
<el-alert
|
||||
v-if="!flowDlg.id && !flowDlg.name"
|
||||
type="info" :closable="false" show-icon
|
||||
title="从「流程列表」点「新增流程」或某行的「编辑」进入此处;填写后保存即生效。" />
|
||||
<el-form :model="flowDlg" label-width="90px" style="margin-top:12px">
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="流程名" required>
|
||||
<el-input v-model="flowDlg.name" placeholder="如 3号工位装配流程" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工序编号" required>
|
||||
<el-input-number v-model="flowDlg.stationNo" :min="1" :max="12" style="width:100%" />
|
||||
<div style="color:#909399;font-size:12px;line-height:1.4">该流程承载的工序编号(1~12)</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="绑定工位" required>
|
||||
<el-select v-model="flowDlg.stations" multiple collapse-tags placeholder="可多选工位:一个工位同一时刻只能绑一个启用流程,一个流程可绑多个工位" style="width:100%">
|
||||
<el-option v-for="i in 12" :key="i" :label="`工位${i}`" :value="i" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="flowDlg.status" placeholder="请选择状态" style="width:100%">
|
||||
<el-option label="启用" value="ACTIVE" />
|
||||
<el-option label="停用" value="INACTIVE" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="作业指导PDF">
|
||||
<el-button
|
||||
v-if="can('produce.processflow:upload')"
|
||||
type="primary" plain :loading="flowDlg.uploading" @click="pickPdf">
|
||||
上传 PDF
|
||||
</el-button>
|
||||
<span v-if="flowDlg.pdfFile" class="pdf-name">
|
||||
{{ flowDlg.pdfFile }}
|
||||
<el-button link type="primary" @click="previewPdf(flowDlg.pdfFile)">预览</el-button>
|
||||
</span>
|
||||
<input ref="pdfInput" type="file" accept="application/pdf" style="display:none" @change="onPdfChange" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="flowDlg.remark" placeholder="备注(可空)" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 工序步骤子表 -->
|
||||
<el-form-item label="工序步骤">
|
||||
<div style="width:100%">
|
||||
<el-table :data="flowDlg.steps" border size="small">
|
||||
<el-table-column label="步骤" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input-number v-model="row.seq" :min="1" size="small" controls-position="right" style="width:70px" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="步骤名称" min-width="140">
|
||||
<template #default="{ row }"><el-input v-model="row.name" placeholder="如 拧紧扭矩" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="采集方式" width="140">
|
||||
<template #default="{ row }">
|
||||
<el-select v-model="row.collectType" placeholder="请选择">
|
||||
<el-option value="AUTO" label="拧紧枪自动" />
|
||||
<el-option value="MANUAL" label="手填" />
|
||||
<el-option value="NONE" label="仅记录" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否拧紧" width="90" align="center">
|
||||
<template #default="{ row }"><el-switch v-model="row.isTorque" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" min-width="120">
|
||||
<template #default="{ row }"><el-input v-model="row.remark" placeholder="备注(可空)" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="考核标准" width="110" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" size="small" @click="openCriteria(row)">
|
||||
{{ (row.criteria || []).length }} 条
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="70" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="danger" size="small" @click="removeStep(row)">删</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-button size="small" style="margin-top:10px" @click="addStep">新增步骤</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div style="text-align:right;margin-top:8px">
|
||||
<el-button @click="activeTab = 'list'">取消</el-button>
|
||||
<el-button
|
||||
v-if="can('produce.processflow:add') || can('produce.processflow:edit')"
|
||||
size="small" @click="openFlow(row)">编辑</el-button>
|
||||
<el-button
|
||||
v-if="can('produce.processflow:edit')"
|
||||
size="small" :type="row.status === 'ACTIVE' ? 'danger' : 'success'" @click="toggleStatus(row)">
|
||||
{{ row.status === 'ACTIVE' ? '停用' : '启用' }}
|
||||
</el-button>
|
||||
<el-button v-if="can('produce.processflow:delete')" size="small" type="danger" @click="delFlow(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
type="primary" @click="saveFlow">保存</el-button>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<!-- ============ 工艺流程 新增/编辑 ============ -->
|
||||
<el-dialog v-model="flowDlg.show" :title="flowDlg.id ? '编辑工艺流程' : '新增工艺流程'" width="940px" top="6vh">
|
||||
<el-form :model="flowDlg" label-width="90px">
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="流程名" required>
|
||||
<el-input v-model="flowDlg.name" placeholder="如 3号工位装配流程" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工序编号" required>
|
||||
<el-input-number v-model="flowDlg.stationNo" :min="1" :max="12" style="width:100%" />
|
||||
<div style="color:#909399;font-size:12px;line-height:1.4">该流程承载的工序编号(1~12)</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="绑定工位" required>
|
||||
<el-select v-model="flowDlg.stations" multiple collapse-tags placeholder="可多选工位:一个工位同一时刻只能绑一个启用流程,一个流程可绑多个工位" style="width:100%">
|
||||
<el-option v-for="i in 12" :key="i" :label="`工位${i}`" :value="i" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="flowDlg.status" placeholder="请选择状态" style="width:100%">
|
||||
<el-option label="启用" value="ACTIVE" />
|
||||
<el-option label="停用" value="INACTIVE" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="作业指导PDF">
|
||||
<el-button
|
||||
v-if="can('produce.processflow:upload')"
|
||||
type="primary" plain :loading="flowDlg.uploading" @click="pickPdf">
|
||||
上传 PDF
|
||||
</el-button>
|
||||
<span v-if="flowDlg.pdfFile" class="pdf-name">
|
||||
{{ flowDlg.pdfFile }}
|
||||
<el-button link type="primary" @click="previewPdf(flowDlg.pdfFile)">预览</el-button>
|
||||
</span>
|
||||
<input ref="pdfInput" type="file" accept="application/pdf" style="display:none" @change="onPdfChange" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="flowDlg.remark" placeholder="备注(可空)" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 工序步骤子表 -->
|
||||
<el-form-item label="工序步骤">
|
||||
<div style="width:100%">
|
||||
<el-table :data="flowDlg.steps" border size="small">
|
||||
<el-table-column label="步骤" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input-number v-model="row.seq" :min="1" size="small" controls-position="right" style="width:70px" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="步骤名称" min-width="140">
|
||||
<template #default="{ row }"><el-input v-model="row.name" placeholder="如 拧紧扭矩" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="采集方式" width="140">
|
||||
<template #default="{ row }">
|
||||
<el-select v-model="row.collectType" placeholder="请选择">
|
||||
<el-option value="AUTO" label="拧紧枪自动" />
|
||||
<el-option value="MANUAL" label="手填" />
|
||||
<el-option value="NONE" label="仅记录" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否拧紧" width="90" align="center">
|
||||
<template #default="{ row }"><el-switch v-model="row.isTorque" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" min-width="120">
|
||||
<template #default="{ row }"><el-input v-model="row.remark" placeholder="备注(可空)" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="考核标准" width="110" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" size="small" @click="openCriteria(row)">
|
||||
{{ (row.criteria || []).length }} 条
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="70" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="danger" size="small" @click="removeStep(row)">删</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-button size="small" style="margin-top:10px" @click="addStep">新增步骤</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="flowDlg.show = false">取消</el-button>
|
||||
<el-button
|
||||
v-if="can('produce.processflow:add') || can('produce.processflow:edit')"
|
||||
type="primary" @click="saveFlow">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- ============ 考核标准编辑(每步骤独立弹窗,单独保存) ============ -->
|
||||
<!-- ============ 考核标准编辑(单层弹窗,从配置 tab 打开,不再嵌套在弹窗内) ============ -->
|
||||
<el-dialog v-model="critDlg.show" :title="`考核标准 - ${critDlg.stepName || ''}`" width="720px" top="10vh" append-to-body>
|
||||
<el-alert type="info" :closable="false" style="margin-bottom:12px"
|
||||
title="为「步骤」设置合格判定标准:报工时按此标准自动判定合格/不合格;未设标准则该步骤仅记录、不判定。" />
|
||||
@@ -223,7 +232,7 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
<PageHelp :data="helpProcessFlow" />
|
||||
<PageHelp :data="helpProcessFlow" page="ProcessFlow" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -233,6 +242,7 @@ import { helpProcessFlow } from '../help'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import request from '../utils/request'
|
||||
|
||||
const activeTab = ref('list')
|
||||
const flows = ref([])
|
||||
const query = reactive({ stationNo: undefined })
|
||||
const pdfInput = ref(null)
|
||||
@@ -306,8 +316,8 @@ async function onPdfChange(e) {
|
||||
}
|
||||
|
||||
const flowDlg = reactive({
|
||||
show: false, id: 0, name: '', stationNo: 1, stations: [], pdfFile: '', status: 'ACTIVE',
|
||||
remark: '', uploading: false, steps: []
|
||||
id: 0, name: '', stationNo: 1, stations: [], pdfFile: '', status: 'ACTIVE',
|
||||
remark: '', uploading: false, steps: [blankStep(1)]
|
||||
})
|
||||
|
||||
function openFlow(row) {
|
||||
@@ -334,7 +344,7 @@ function openFlow(row) {
|
||||
})
|
||||
}
|
||||
if (!flowDlg.steps.length) flowDlg.steps.push(blankStep(1))
|
||||
flowDlg.show = true
|
||||
activeTab.value = 'config'
|
||||
}
|
||||
|
||||
function addStep() {
|
||||
@@ -346,7 +356,7 @@ function removeStep(row) {
|
||||
if (i >= 0) flowDlg.steps.splice(i, 1)
|
||||
}
|
||||
|
||||
/* ---------- 考核标准(独立弹窗) ---------- */
|
||||
/* ---------- 考核标准(单层弹窗) ---------- */
|
||||
const critDlg = reactive({ show: false, stepName: '', criteria: [], _step: null })
|
||||
|
||||
const needsTarget = computed(() => critDlg.criteria.some((c) => c.logic && c.logic !== 'RANGE'))
|
||||
@@ -397,7 +407,7 @@ async function saveFlow() {
|
||||
}
|
||||
await request.post('/process-flows', body)
|
||||
ElMessage.success('保存成功')
|
||||
flowDlg.show = false
|
||||
activeTab.value = 'list'
|
||||
loadFlows()
|
||||
}
|
||||
|
||||
@@ -418,7 +428,8 @@ async function toggleStatus(row) {
|
||||
} else {
|
||||
await ElMessageBox.confirm(
|
||||
`确认启用「${row.name}」?启用后其绑定工位(${(row.stations || []).map(s => '工位' + s).join('、') || '-'})将恢复使用该流程。`,
|
||||
'提示', { type: 'warning' })
|
||||
'提示', { type: 'warning' }
|
||||
)
|
||||
}
|
||||
await request.post('/process-flows/status', { id: row.id, status: toStatus })
|
||||
ElMessage.success(`已${action}`)
|
||||
|
||||
Reference in New Issue
Block a user