新增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

@@ -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>