新增MES库区管理功能,包含免密接口、数据处理逻辑及相关控制器、服务和实体的实现。支持库区的增删改查操作,优化用户体验并增强系统的实时数据同步能力。

This commit is contained in:
geht
2026-05-12 14:06:07 +08:00
parent cffe32d896
commit b737dddb2a
74 changed files with 4937 additions and 174 deletions

View File

@@ -92,6 +92,7 @@
</div>
<MesXslWarehouseModal @register="registerModal" @success="handleSuccess" />
<MesXslWarehouseSysCategoryModal @register="registerCategoryModal" @success="onCategorySuccess" />
<MesXslWarehouseAreaBatchAddModal @register="registerBatchAreaModal" @success="handleSuccess" />
</div>
</template>
@@ -106,6 +107,7 @@
import { defHttp } from '/@/utils/http/axios';
import MesXslWarehouseModal from './components/MesXslWarehouseModal.vue';
import MesXslWarehouseSysCategoryModal from './components/MesXslWarehouseSysCategoryModal.vue';
import MesXslWarehouseAreaBatchAddModal from './components/MesXslWarehouseAreaBatchAddModal.vue';
import { columns, searchFormSchema, superQuerySchema, WH_CATEGORY_CUSTOMER_CODE, WH_CATEGORY_SUPPLIER_CODE } from './MesXslWarehouse.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl, updateStatus } from './MesXslWarehouse.api';
import { loadTreeData as loadCategoryTreeRoot } from '/@/views/system/category/category.api';
@@ -310,6 +312,7 @@
const [registerModal, { openModal }] = useModal();
const [registerCategoryModal, { openModal: openCategoryModal }] = useModal();
const [registerBatchAreaModal, { openModal: openBatchAreaModal }] = useModal();
function handleAddCategory() {
const rootId = warehouseCategoryRootId.value;
@@ -507,8 +510,15 @@
];
}
function handleBatchAddArea(record: Recordable) {
openBatchAreaModal(true, { record });
}
function getDropDownAction(record) {
return [{ label: '详情', onClick: handleDetail.bind(null, record) }];
return [
{ label: '详情', onClick: handleDetail.bind(null, record) },
{ label: '批量添加库区', onClick: handleBatchAddArea.bind(null, record) },
];
}
</script>

View File

@@ -0,0 +1,208 @@
<template>
<BasicModal
v-bind="$attrs"
@register="registerModal"
destroyOnClose
:title="title"
:width="700"
:confirmLoading="submitting"
@ok="handleSubmit"
>
<div style="margin-bottom: 10px; display: flex; justify-content: space-between; align-items: center">
<span style="color: #666; font-size: 13px"> {{ rows.length }} </span>
<a-button type="primary" size="small" preIcon="ant-design:plus-outlined" @click="addRow">新增行</a-button>
</div>
<a-table
:columns="tableColumns"
:data-source="rows"
:pagination="false"
size="small"
bordered
row-key="__key"
:scroll="{ y: 380 }"
>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'seq'">
{{ index + 1 }}
</template>
<template v-else-if="column.key === 'areaCode'">
<a-input
v-model:value="record.areaCode"
placeholder="库区编码(必填)"
size="small"
:status="record.__codeError ? 'error' : ''"
@change="onAreaCodeChange(record)"
@blur="validateCode(record)"
/>
<div v-if="record.__codeError" style="color: #ff4d4f; font-size: 12px; margin-top: 2px">
{{ record.__codeError }}
</div>
</template>
<template v-else-if="column.key === 'areaName'">
<a-input v-model:value="record.areaName" placeholder="默认同库区编码" size="small" />
</template>
<template v-else-if="column.key === 'maxCapacity'">
<a-input-number
v-model:value="record.maxCapacity"
:min="0"
:precision="0"
placeholder="最大存放量"
size="small"
style="width: 100%"
/>
</template>
<template v-else-if="column.key === 'action'">
<a-button danger type="link" size="small" @click="removeRow(index)">删除</a-button>
</template>
</template>
</a-table>
<div v-if="rows.length === 0" style="text-align: center; color: #999; padding: 24px 0; font-size: 13px">
暂无库区明细点击新增行添加
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { useMessage } from '/@/hooks/web/useMessage';
import { batchAddAreas } from '/@/views/xslmes/mesXslWarehouseArea/MesXslWarehouseArea.api';
const { createMessage } = useMessage();
const emit = defineEmits(['register', 'success']);
const warehouseId = ref('');
const warehouseName = ref('');
const warehouseCategory = ref<string | undefined>(undefined);
const tenantId = ref<number | undefined>(undefined);
const submitting = ref(false);
let _rowKey = 0;
interface AreaRow {
__key: number;
__codeError: string;
__prevCode: string;
areaCode: string;
areaName: string;
maxCapacity: number | undefined;
}
const rows = ref<AreaRow[]>([]);
const title = computed(() =>
warehouseName.value ? `批量添加库区 — ${warehouseName.value}` : '批量添加库区'
);
const tableColumns = [
{ title: '序号', key: 'seq', width: 52, align: 'center' },
{ title: '库区编码 *', key: 'areaCode', width: 180 },
{ title: '库区名称', key: 'areaName', width: 180 },
{ title: '最大存放量', key: 'maxCapacity', width: 130 },
{ title: '操作', key: 'action', width: 60, align: 'center' },
];
const [registerModal, { setModalProps, closeModal }] = useModalInner((data) => {
rows.value = [];
_rowKey = 0;
warehouseId.value = data?.record?.id ?? '';
warehouseName.value = data?.record?.warehouseName ?? '';
warehouseCategory.value = data?.record?.warehouseCategory ?? undefined;
tenantId.value = data?.record?.tenantId ?? undefined;
addRow();
});
function addRow() {
rows.value.push({
__key: _rowKey++,
__codeError: '',
__prevCode: '',
areaCode: '',
areaName: '',
maxCapacity: undefined,
});
}
function removeRow(index: number) {
rows.value.splice(index, 1);
}
function onAreaCodeChange(record: AreaRow) {
if (!record.areaName || record.areaName === record.__prevCode) {
record.areaName = record.areaCode;
}
record.__prevCode = record.areaCode;
record.__codeError = '';
}
function validateCode(record: AreaRow) {
if (!record.areaCode || !record.areaCode.trim()) {
record.__codeError = '库区编码不能为空';
} else {
record.__codeError = '';
}
}
async function handleSubmit() {
if (rows.value.length === 0) {
createMessage.warning('请至少添加一条库区记录');
return;
}
// Validate all rows
let hasError = false;
const codeSet = new Set<string>();
for (const row of rows.value) {
const code = (row.areaCode || '').trim();
if (!code) {
row.__codeError = '库区编码不能为空';
hasError = true;
continue;
}
if (codeSet.has(code)) {
row.__codeError = '库区编码重复';
hasError = true;
continue;
}
codeSet.add(code);
row.__codeError = '';
}
if (hasError) {
createMessage.error('请修正红色标记的错误后再提交');
return;
}
const payload = rows.value.map((row) => ({
areaCode: row.areaCode.trim(),
areaName: (row.areaName || row.areaCode).trim() || row.areaCode.trim(),
maxCapacity: row.maxCapacity ?? undefined,
warehouseId: warehouseId.value,
warehouseName: warehouseName.value,
warehouseCategory: warehouseCategory.value,
tenantId: tenantId.value,
status: '0',
}));
try {
submitting.value = true;
setModalProps({ confirmLoading: true });
await batchAddAreas(payload);
createMessage.success(`批量添加成功,共创建 ${payload.length} 个库区!`);
closeModal();
emit('success');
} catch {
// error handled by global interceptor
} finally {
submitting.value = false;
setModalProps({ confirmLoading: false });
}
}
</script>