完善机组车台功能,并导入机组车台 / 车间班次数据

一、机组车台功能完善
- 车间下拉改为只取「前缫」职责类型的部门(新增接口 /api/jizuchetai/qianxian-deps)
- 补齐校验:车间、机组号、开始车台号必填;结束车台号不得小于开始车台号;同车间同机组不可重复
- 前端页面同步调整:车间改为下拉选择、增加必填提示、表格加 row-key

二、数据导入(新增 ProdSeedData,幂等导入器)
- biz_prod_qs_jzct:机组车台 35 条(其中 11 条已删除)→ 有效 24 条
- biz_prod_qs_cjbc:车间班次 7 条(其中 1 条已删除)→ 有效 6 条
- F9 的部门 Id 通过部门名称映射到本系统部门;已删除的数据不导入;
  已存在且一致的数据不重复写入,缺失的自动补回
This commit is contained in:
yanpeng200212
2026-10-14 09:42:06 +08:00
parent 0e6d4dce53
commit 8c4c464362
9 changed files with 817 additions and 44 deletions
+98 -44
View File
@@ -1,61 +1,103 @@
<script setup>
import { ref, reactive, onMounted } from 'vue';
import request from '../../../utils/request';
import { buildDeptTree } from '../../../utils/dept';
import { ElMessage, ElMessageBox } from 'element-plus';
const list = ref([]);
const total = ref(0);
const loading = ref(false);
const deptTree = ref([]);
const query = reactive({ pageIndex: 1, pageSize: 20, keyword: '' });
// 车间下拉:只取职责类型为「前缫」的部门(后端接口)
const deptOptions = ref([]);
const dialogVisible = ref(false);
const dialogTitle = ref('新增机组车台');
const isEdit = ref(false);
const editId = ref(null);
const form = reactive({ departmentId: null, jizu: 0, chetaiStart: 0, chetaiEnd: 0 });
const form = reactive({ departmentId: 0, jizu: 0, chetaiStart: 0, chetaiEnd: 0 });
async function load() {
loading.value = true;
try {
const res = await request.get('/jizuchetai', { params: query });
list.value = res.data.items;
total.value = res.data.total;
list.value = res.data.items || [];
total.value = res.data.total || 0;
} finally {
loading.value = false;
}
}
async function loadDepts() {
const res = await request.get('/sys/department');
deptTree.value = buildDeptTree(res.data);
try {
const res = await request.get('/jizuchetai/qianxian-deps');
deptOptions.value = res.data || [];
} catch (e) {
deptOptions.value = [];
}
}
// 分页组件挂载时会触发一次 current-change:页码未变化时忽略,避免首次打开重复请求
function handlePageChange(p) {
if (p === query.pageIndex) return;
query.pageIndex = p;
load();
}
function handleSearch() {
query.pageIndex = 1;
load();
}
function openCreate() {
isEdit.value = false;
dialogTitle.value = '新增机组车台';
Object.assign(form, { departmentId: null, jizu: 0, chetaiStart: 0, chetaiEnd: 0 });
Object.assign(form, {
departmentId: Number(deptOptions.value[0]?.id) || 0,
jizu: 0,
chetaiStart: 0,
chetaiEnd: 0
});
dialogVisible.value = true;
}
function openEdit(row) {
isEdit.value = true;
editId.value = row.id;
dialogTitle.value = '编辑机组车台';
Object.assign(form, { departmentId: row.departmentId, jizu: row.jizu, chetaiStart: row.chetaiStart, chetaiEnd: row.chetaiEnd });
dialogTitle.value = '修改机组车台';
Object.assign(form, {
departmentId: Number(row.departmentId),
jizu: Number(row.jizu),
chetaiStart: Number(row.chetaiStart),
chetaiEnd: Number(row.chetaiEnd)
});
dialogVisible.value = true;
}
async function save() {
if (!form.departmentId) { ElMessage.warning('请选择车间'); return; }
if (!form.departmentId) {
ElMessage.warning('请选择车间');
return;
}
if (!form.jizu || form.jizu <= 0) {
ElMessage.warning('机组号必须大于 0');
return;
}
if (!form.chetaiStart || form.chetaiStart <= 0) {
ElMessage.warning('开始车台号必须大于 0');
return;
}
if (form.chetaiEnd < form.chetaiStart) {
ElMessage.warning('结束车台号不能小于开始车台号');
return;
}
try {
if (isEdit.value) {
await request.put(`/jizuchetai/${editId.value}`, form);
ElMessage.success('更新成功');
ElMessage.success('修改成功');
} else {
await request.post('/jizuchetai', form);
ElMessage.success('创建成功');
ElMessage.success('新增成功');
}
dialogVisible.value = false;
load();
@@ -63,7 +105,7 @@ async function save() {
}
async function del(row) {
await ElMessageBox.confirm(`确定删除机组「${row.jizu}」吗?`, '提示', { type: 'warning' });
await ElMessageBox.confirm(`确定删除「${row.departmentName} · 机组${row.jizu}」吗?`, '提示', { type: 'warning' });
try {
await request.delete(`/jizuchetai/${row.id}`);
ElMessage.success('删除成功');
@@ -71,13 +113,10 @@ async function del(row) {
} catch (e) {}
}
function handlePageChange(p) {
// 分页组件挂载时会触发一次 current-change,页码未变化时忽略,避免首次打开重复请求
if (p === query.pageIndex) return;
query.pageIndex = p;
onMounted(() => {
loadDepts();
load();
}
onMounted(() => { load(); loadDepts(); });
});
</script>
<template>
@@ -90,40 +129,55 @@ onMounted(() => { load(); loadDepts(); });
</template>
<div class="search-bar">
<el-input v-model="query.keyword" placeholder="车间/机组号" clearable style="width: 200px" @keyup.enter="query.pageIndex=1;load()" />
<el-button type="primary" @click="query.pageIndex=1;load()">搜索</el-button>
<el-input
v-model="query.keyword"
placeholder="车间 / 机组号"
clearable
style="width: 220px"
@keyup.enter="handleSearch"
/>
<el-button type="primary" @click="handleSearch">查询</el-button>
</div>
<el-table v-loading="loading" :data="list" border stripe>
<el-table v-loading="loading" :data="list" row-key="id" border stripe>
<el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column prop="departmentName" label="车间" min-width="200" />
<el-table-column prop="jizu" label="机组号" width="120" />
<el-table-column prop="chetaiStart" label="开始车台号" width="120" />
<el-table-column prop="chetaiEnd" label="结束车台号" width="120" />
<el-table-column label="操作" width="140" fixed="right">
<el-table-column prop="chetaiStart" label="开始车台号" width="130" />
<el-table-column prop="chetaiEnd" label="结束车台号" width="130" />
<el-table-column label="操作" width="150" fixed="right">
<template #default="{ row }">
<el-button size="small" type="primary" @click="openEdit(row)">编辑</el-button>
<el-button size="small" type="danger" @click="del(row)">删除</el-button>
<el-button size="small" type="primary" link @click="openEdit(row)">编辑</el-button>
<el-button size="small" type="danger" link @click="del(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination class="pagination" :current-page="query.pageIndex" :page-size="query.pageSize" :total="total" layout="total, prev, pager, next" @current-change="handlePageChange" />
<el-pagination
class="pagination"
:current-page="query.pageIndex"
:page-size="query.pageSize"
:total="total"
layout="total, prev, pager, next"
@current-change="handlePageChange"
/>
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="480px">
<el-form :model="form" label-width="100px">
<el-form-item label="车间">
<el-tree-select
v-model="form.departmentId"
:data="deptTree"
:props="{ label: 'name', value: 'id', children: 'children' }"
check-strictly
placeholder="选择车间"
style="width: 100%"
/>
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="520px">
<el-form :model="form" label-width="110px">
<el-form-item label="车间" required>
<el-select v-model="form.departmentId" placeholder="请选择车间" style="width: 100%">
<el-option v-for="d in deptOptions" :key="d.id" :label="d.name" :value="Number(d.id)" />
</el-select>
</el-form-item>
<el-form-item label="机组号" required>
<el-input-number v-model="form.jizu" :min="1" :precision="0" style="width: 100%" />
</el-form-item>
<el-form-item label="开始车台号" required>
<el-input-number v-model="form.chetaiStart" :min="1" :precision="0" style="width: 100%" />
</el-form-item>
<el-form-item label="结束车台号" required>
<el-input-number v-model="form.chetaiEnd" :min="1" :precision="0" style="width: 100%" />
</el-form-item>
<el-form-item label="机组号"><el-input-number v-model="form.jizu" :min="0" /></el-form-item>
<el-form-item label="开始车台号"><el-input-number v-model="form.chetaiStart" :min="0" /></el-form-item>
<el-form-item label="结束车台号"><el-input-number v-model="form.chetaiEnd" :min="0" /></el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
@@ -135,6 +189,6 @@ onMounted(() => { load(); loadDepts(); });
<style scoped>
.card-header { display: flex; justify-content: space-between; align-items: center; }
.search-bar { display: flex; gap: 12px; margin-bottom: 16px; }
.search-bar { display: flex; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
.pagination { margin-top: 16px; justify-content: flex-end; }
</style>