将MES模块的仓库管理提取为独立的一级菜单"仓储物流",并实现:
- ERP采购入库审核 → MES库存同步增加
- ERP销售出库审核 → MES库存同步减少
- 仓库级别审批流程配置(每个仓库可独立启用/禁用审批)
# 1. 菜单调整(将仓库管理提取为一级菜单)
sql/mysql/wls_menu_init.sql
# 2. 数据库初始化(审批配置表 + 单据BPM字段)
sql/mysql/wls_database_init.sql
# 3. ERP仓库与MES仓库映射表
sql/mysql/erp_mes_warehouse_mapping.sql
仓储物流(一级菜单,id=5780)
├── 仓库设置
├── 库存现有量
├── 采购入库
├── 到货通知
├── 采购退货
├── 生产领料
├── 生产退料
├── 产品入库
├── 发货通知
├── 销售出库
├── 销售退货
├── 转移调拨
├── 库存盘点
├── 装箱管理
├── 条码配置
├── 赋能管理
├── SN码
├── 外协发料
├── 外协入库
├── 杂项入库
├── 杂项出库
├── 审批配置(新增)
└── 仓库映射(新增,在ERP菜单下)
方案一:路径别名(推荐)
// vite.config.js
export default defineConfig({
resolve: {
alias: {
'@/views/wls': path.resolve(__dirname, 'src/views/mes/wm')
}
}
})
方案二:复制组件
将 src/views/mes/wm 目录复制为 src/views/wls
路径:views/wls/approval/config/index.vue
功能:
1. 仓库列表展示
2. 每个仓库可配置入库/出库/调拨/盘点是否启用审批
3. 选择审批流程(从BPM流程列表)
<template>
<div class="app-container">
<!-- 搜索栏 -->
<el-form :inline="true">
<el-form-item label="仓库">
<el-select v-model="queryParams.warehouseId" placeholder="请选择仓库" clearable>
<el-option v-for="warehouse in warehouseList" :key="warehouse.id"
:label="warehouse.warehouseName" :value="warehouse.id" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery">搜索</el-button>
</el-form-item>
</el-form>
<!-- 配置表格 -->
<el-table :data="configList" v-loading="loading">
<el-table-column prop="warehouseName" label="仓库名称" width="150" />
<el-table-column label="入库审批" width="120">
<template #default="{ row }">
<el-switch v-model="row.inboundEnabled"
@change="handleApprovalChange(row, 'INBOUND', $event)" />
</template>
</el-table-column>
<el-table-column label="出库审批" width="120">
<template #default="{ row }">
<el-switch v-model="row.outboundEnabled"
@change="handleApprovalChange(row, 'OUTBOUND', $event)" />
</template>
</el-table-column>
<el-table-column label="调拨审批" width="120">
<template #default="{ row }">
<el-switch v-model="row.transferEnabled"
@change="handleApprovalChange(row, 'TRANSFER', $event)" />
</template>
</el-table-column>
<el-table-column label="盘点审批" width="120">
<template #default="{ row }">
<el-switch v-model="row.checkEnabled"
@change="handleApprovalChange(row, 'CHECK', $event)" />
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template #default="{ row }">
<el-button link type="primary" @click="handleConfigProcess(row)">配置流程</el-button>
</template>
</el-table-column>
</el-table>
<!-- 流程配置弹窗 -->
<el-dialog v-model="processDialogVisible" title="配置审批流程" width="500px">
<el-form label-width="100px">
<el-form-item label="业务类型">
<el-select v-model="currentConfig.bizType">
<el-option label="入库" value="INBOUND" />
<el-option label="出库" value="OUTBOUND" />
<el-option label="调拨" value="TRANSFER" />
<el-option label="盘点" value="CHECK" />
</el-select>
</el-form-item>
<el-form-item label="审批流程">
<el-select v-model="currentConfig.processDefinitionKey" placeholder="请选择流程">
<el-option v-for="process in processList" :key="process.key"
:label="process.name" :value="process.key" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="processDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSaveProcessConfig">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import * as ApprovalApi from '@/api/wms/approval'
const warehouseList = ref([])
const configList = ref([])
const processList = ref([])
const loading = ref(false)
const queryParams = ref({ warehouseId: null })
const processDialogVisible = ref(false)
const currentConfig = ref({ warehouseId: null, bizType: null, processDefinitionKey: null })
// 加载仓库列表(从仓库设置模块获取)
const loadWarehouseList = async () => {
// 调用仓库设置接口获取列表
}
// 加载审批配置
const loadConfigList = async (warehouseId) => {
if (!warehouseId) return
loading.value = true
try {
configList.value = await ApprovalApi.getApprovalConfigList(warehouseId)
} finally {
loading.value = false
}
}
// 切换审批开关
const handleApprovalChange = async (row, bizType, enabled) => {
await ApprovalApi.saveApprovalConfig({
warehouseId: row.warehouseId,
bizType: bizType,
approvalEnabled: enabled
})
}
// 配置流程
const handleConfigProcess = async (row) => {
currentConfig.value = { warehouseId: row.warehouseId, bizType: null, processDefinitionKey: null }
// 加载可用流程列表
processList.value = await ApprovalApi.getAvailableProcessList(row.warehouseId, 'INBOUND')
processDialogVisible.value = true
}
// 保存流程配置
const handleSaveProcessConfig = async () => {
await ApprovalApi.saveApprovalConfig(currentConfig.value)
processDialogVisible.value = false
loadConfigList(queryParams.value.warehouseId)
}
onMounted(() => {
loadWarehouseList()
})
</script>
路径:views/erp/warehouse/mapping/index.vue(放在ERP仓库管理下)
功能:
1. 配置ERP仓库与MES仓库的映射关系
2. 支持新增、修改、删除映射
<template>
<div class="app-container">
<!-- 搜索栏 -->
<el-form :inline="true">
<el-form-item label="ERP仓库">
<el-select v-model="queryParams.erpWarehouseId" placeholder="请选择ERP仓库" clearable>
<el-option v-for="warehouse in erpWarehouseList" :key="warehouse.id"
:label="warehouse.name" :value="warehouse.id" />
</el-select>
</el-form-item>
<el-form-item label="MES仓库">
<el-select v-model="queryParams.mesWarehouseId" placeholder="请选择MES仓库" clearable>
<el-option v-for="warehouse in mesWarehouseList" :key="warehouse.id"
:label="warehouse.warehouseName" :value="warehouse.id" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery">搜索</el-button>
<el-button type="primary" @click="handleAdd">新增</el-button>
</el-form-item>
</el-form>
<!-- 映射表格 -->
<el-table :data="mappingList" v-loading="loading">
<el-table-column prop="erpWarehouseName" label="ERP仓库" />
<el-table-column prop="mesWarehouseName" label="MES仓库" />
<el-table-column prop="status" label="状态">
<template #default="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
{{ row.status === 1 ? '启用' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="150">
<template #default="{ row }">
<el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
<el-button link type="danger" @click="handleDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination v-model:current-page="queryParams.pageNo" v-model:page-size="queryParams.pageSize"
:total="total" @change="handleQuery" />
<!-- 新增/编辑弹窗 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="500px">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
<el-form-item label="ERP仓库" prop="erpWarehouseId">
<el-select v-model="formData.erpWarehouseId" placeholder="请选择ERP仓库">
<el-option v-for="warehouse in erpWarehouseList" :key="warehouse.id"
:label="warehouse.name" :value="warehouse.id" />
</el-select>
</el-form-item>
<el-form-item label="MES仓库" prop="mesWarehouseId">
<el-select v-model="formData.mesWarehouseId" placeholder="请选择MES仓库">
<el-option v-for="warehouse in mesWarehouseList" :key="warehouse.id"
:label="warehouse.warehouseName" :value="warehouse.id" />
</el-select>
</el-form-item>
<el-form-item label="状态">
<el-radio-group v-model="formData.status">
<el-radio :value="1">启用</el-radio>
<el-radio :value="0">禁用</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import * as MappingApi from '@/api/erp/warehouseMapping'
import { ElMessage, ElMessageBox } from 'element-plus'
const loading = ref(false)
const total = ref(0)
const mappingList = ref([])
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
erpWarehouseId: null,
mesWarehouseId: null
})
const dialogVisible = ref(false)
const dialogTitle = ref('')
const formRef = ref()
const formData = reactive({
id: null,
erpWarehouseId: null,
mesWarehouseId: null,
status: 1
})
const formRules = {
erpWarehouseId: [{ required: true, message: '请选择ERP仓库', trigger: 'change' }],
mesWarehouseId: [{ required: true, message: '请选择MES仓库', trigger: 'change' }]
}
// ERP仓库列表(从ERP仓库接口获取)
const erpWarehouseList = ref([])
// MES仓库列表(从MES仓库接口获取)
const mesWarehouseList = ref([])
// 加载映射列表
const loadMappingList = async () => {
loading.value = true
try {
const res = await MappingApi.getMappingPage(queryParams)
mappingList.value = res.list
total.value = res.total
} finally {
loading.value = false
}
}
// 新增
const handleAdd = () => {
dialogTitle.value = '新增仓库映射'
Object.assign(formData, { id: null, erpWarehouseId: null, mesWarehouseId: null, status: 1 })
dialogVisible.value = true
}
// 编辑
const handleEdit = (row) => {
dialogTitle.value = '编辑仓库映射'
Object.assign(formData, row)
dialogVisible.value = true
}
// 提交
const handleSubmit = async () => {
await formRef.value.validate()
if (formData.id) {
await MappingApi.updateMapping(formData)
ElMessage.success('更新成功')
} else {
await MappingApi.createMapping(formData)
ElMessage.success('创建成功')
}
dialogVisible.value = false
loadMappingList()
}
// 删除
const handleDelete = async (id) => {
await ElMessageBox.confirm('确定删除该映射?', '提示', { type: 'warning' })
await MappingApi.deleteMapping(id)
ElMessage.success('删除成功')
loadMappingList()
}
onMounted(() => {
loadMappingList()
// 加载仓库列表
})
</script>
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /mes/wms/approval/config/get | 获取单个审批配置 |
| GET | /mes/wms/approval/config/list | 获取仓库所有审批配置 |
| POST | /mes/wms/approval/config/save | 保存审批配置 |
| GET | /mes/wms/approval/process-list | 获取可用审批流程 |
请求参数详情:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| warehouseId | Long | 是 | 仓库ID |
| bizType | String | 是 | 业务类型(INBOUND/OUTBOUND/TRANSFER/CHECK) |
响应:
{
"code": 0,
"data": {
"id": 1,
"warehouseId": 100,
"bizType": "INBOUND",
"approvalEnabled": true,
"processDefinitionKey": "wms_inbound_approve",
"categoryCode": "wms_approve"
}
}
请求体:
{
"warehouseId": 100,
"bizType": "INBOUND",
"approvalEnabled": true,
"processDefinitionKey": "wms_inbound_approve"
}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| warehouseId | Long | 是 | 仓库ID |
| bizType | String | 是 | 业务类型 |
响应:
{
"code": 0,
"data": [
{ "key": "wms_inbound_approve", "name": "入库审批流程" },
{ "key": "wms_common_approve", "name": "通用审批流程" }
]
}
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /erp/warehouse-mapping/page | 分页查询映射列表 |
| GET | /erp/warehouse-mapping/get | 获取单个映射 |
| POST | /erp/warehouse-mapping/create | 新增映射 |
| PUT | /erp/warehouse-mapping/update | 更新映射 |
| DELETE | /erp/warehouse-mapping/delete | 删除映射 |
请求参数详情:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| pageNo | Integer | 是 | 页码 |
| pageSize | Integer | 是 | 每页数量 |
| erpWarehouseId | Long | 否 | ERP仓库ID |
| mesWarehouseId | Long | 否 | MES仓库ID |
| status | Integer | 否 | 状态 |
响应:
{
"code": 0,
"data": {
"list": [
{
"id": 1,
"erpWarehouseId": 1,
"erpWarehouseName": "主仓库",
"mesWarehouseId": 100,
"mesWarehouseName": "总仓",
"status": 1
}
],
"total": 1
}
}
请求体:
{
"erpWarehouseId": 1,
"mesWarehouseId": 100,
"status": 1
}
创建文件:src/api/wms/approval/index.js
import request from '@/utils/request'
// 获取审批配置
export function getApprovalConfig(warehouseId, bizType) {
return request({
url: '/mes/wms/approval/config/get',
method: 'get',
params: { warehouseId, bizType }
})
}
// 获取仓库所有审批配置
export function getApprovalConfigList(warehouseId) {
return request({
url: '/mes/wms/approval/config/list',
method: 'get',
params: { warehouseId }
})
}
// 保存审批配置
export function saveApprovalConfig(data) {
return request({
url: '/mes/wms/approval/config/save',
method: 'post',
data: data
})
}
// 获取可用审批流程列表
export function getAvailableProcessList(warehouseId, bizType) {
return request({
url: '/mes/wms/approval/process-list',
method: 'get',
params: { warehouseId, bizType }
})
}
创建文件:src/api/erp/warehouseMapping/index.js
import request from '@/utils/request'
// 分页查询映射列表
export function getMappingPage(params) {
return request({
url: '/erp/warehouse-mapping/page',
method: 'get',
params: params
})
}
// 获取单个映射
export function getMapping(id) {
return request({
url: '/erp/warehouse-mapping/get',
method: 'get',
params: { id }
})
}
// 新增映射
export function createMapping(data) {
return request({
url: '/erp/warehouse-mapping/create',
method: 'post',
data: data
})
}
// 更新映射
export function updateMapping(data) {
return request({
url: '/erp/warehouse-mapping/update',
method: 'put',
data: data
})
}
// 删除映射
export function deleteMapping(id) {
return request({
url: '/erp/warehouse-mapping/delete',
method: 'delete',
params: { id }
})
}
通过条码(barCode)关联:
- ERP产品的barCode字段值 = MDM物料的barCode字段值
- 系统自动通过barCode匹配,无需额外配置表
需要在仓库映射页面配置映射关系:
| ERP仓库 | MES仓库 | 说明 |
|---|---|---|
| 主仓库(ID=1) | 总仓(ID=100) | 默认映射 |
注意:ERP仓库必须配置映射后,ERP采购入库/销售出库审核才能同步MES库存。
ERP采购入库单创建
↓
ERP采购入库单审核
↓
调用 WmsStockApi.purchaseInbound()
↓
查找ERP仓库 → MES仓库映射
↓
查找ERP产品(barCode) → MDM物料(barCode)
↓
创建MES库存事务记录
↓
MES库存增加
ERP销售出库单创建
↓
ERP销售出库单审核
↓
调用 WmsStockApi.salesOutbound()
↓
查找仓库映射 + 产品映射
↓
创建MES库存事务记录(数量为负)
↓
MES库存减少
MES入库单创建(草稿)
↓
检查仓库审批配置 → 是否需要审批?
↓ (需要审批)
提交审批 → BPM流程启动
↓
审批通过 → 单据状态更新 → 执行入库
↓ (不需要审批)
直接执行入库
mes:wm-warehouse:query、mes:wm-warehouse:updateerp:warehouse:query、erp:warehouse:update、erp:warehouse:delete