<template>
|
<div class="app-container">
|
<div class="search_form">
|
<el-form :model="searchForm"
|
:inline="true">
|
<el-form-item label="车间:">
|
<el-select v-model="searchForm.workshop"
|
placeholder="请选择"
|
clearable
|
style="width: 160px;"
|
@change="handleQuery">
|
<el-option label="车间1"
|
value="1" />
|
<el-option label="车间2"
|
value="2" />
|
<el-option label="车间3"
|
value="3" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="状态:">
|
<el-select v-model="searchForm.status"
|
placeholder="请选择"
|
clearable
|
style="width: 160px;"
|
@change="handleQuery">
|
<el-option label="待处理"
|
value="pending" />
|
<el-option label="进行中"
|
value="processing" />
|
<el-option label="已完成"
|
value="completed" />
|
</el-select>
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary"
|
@click="handleQuery">搜索</el-button>
|
</el-form-item>
|
</el-form>
|
<div>
|
<el-button type="primary"
|
@click="handleMerge">和并下发</el-button>
|
<el-button type="info"
|
@click="showCategorySummaryDialog = true">产品类别汇总</el-button>
|
<!-- <el-button type="danger"
|
@click="handleDelete">删除</el-button> -->
|
</div>
|
</div>
|
<div class="table_list">
|
<PIMTable rowKey="id"
|
:column="tableColumn"
|
:tableData="tableData"
|
:page="page"
|
height="calc(100vh - 350px)"
|
:tableLoading="tableLoading"
|
:isSelection="true"
|
:selectable="isSelectable"
|
@selection-change="handleSelectionChange"
|
@pagination="pagination">
|
</PIMTable>
|
</div>
|
<!-- 合并下发弹窗 -->
|
<el-dialog v-model="isShowNewModal"
|
title="合并下发"
|
width="500px">
|
<el-form :model="mergeForm"
|
label-width="120px">
|
<el-form-item label="序列号">
|
<el-input v-model="mergeForm.serialNo"
|
disabled />
|
</el-form-item>
|
<el-form-item label="生产计划数量">
|
<el-input-number v-model="mergeForm.totalquantity"
|
:min="1"
|
:step="1"
|
style="width: 100%" />
|
</el-form-item>
|
<el-form-item label="备注">
|
<el-input v-model="mergeForm.remark"
|
type="textarea" />
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="isShowNewModal = false">取消</el-button>
|
<el-button type="primary"
|
@click="handleMergeSubmit">确定下发</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
<!-- 产品类别汇总弹窗 -->
|
<el-dialog v-model="showCategorySummaryDialog"
|
title="产品类别汇总统计"
|
width="400px">
|
<el-table :data="categorySummary"
|
border
|
style="width: 100%">
|
<el-table-column prop="materialCategory"
|
label="产品类别"
|
align="center"
|
width="150" />
|
<el-table-column prop="totalquantity"
|
label="总制造数量"
|
align="center" />
|
</el-table>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="showCategorySummaryDialog = false">关闭</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
<!-- 追踪进度弹窗 -->
|
<el-dialog v-model="showTrackProgressDialog"
|
:title="`追踪进度 - ${trackProgressForm.serialNo || ''}`"
|
width="600px">
|
<el-form :model="trackProgressForm"
|
label-width="120px">
|
<el-form-item label="序列号">
|
<el-input v-model="trackProgressForm.serialNo"
|
disabled />
|
</el-form-item>
|
<el-form-item label="当前状态">
|
<el-select v-model="trackProgressForm.currentStatus"
|
placeholder="请选择状态">
|
<el-option label="待处理"
|
value="pending" />
|
<el-option label="进行中"
|
value="processing" />
|
<el-option label="已完成"
|
value="completed" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="完成进度">
|
<el-progress :percentage="trackProgressForm.completionRate"
|
:status="trackProgressForm.completionRate === 100 ? 'success' : ''" />
|
</el-form-item>
|
<el-form-item label="进度详情">
|
<el-table :data="trackProgressForm.progressDetails"
|
border
|
style="width: 100%">
|
<el-table-column prop="step"
|
label="步骤"
|
align="center"
|
width="100" />
|
<el-table-column prop="status"
|
label="状态"
|
align="center"
|
width="100">
|
<template #default="scope">
|
<el-tag :type="scope.row.status === 'completed' ? 'success' : scope.row.status === 'processing' ? 'warning' : 'info'">
|
{{ scope.row.status === 'completed' ? '已完成' : scope.row.status === 'processing' ? '进行中' : '待开始' }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column prop="startTime"
|
label="开始时间"
|
align="center"
|
width="180" />
|
<el-table-column prop="endTime"
|
label="结束时间"
|
align="center"
|
width="180" />
|
</el-table>
|
</el-form-item>
|
<el-form-item label="备注">
|
<el-input v-model="trackProgressForm.remark"
|
type="textarea" />
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<span class="dialog-footer">
|
<el-button @click="showTrackProgressDialog = false">关闭</el-button>
|
<el-button type="primary"
|
@click="handleUpdateProgress">更新进度</el-button>
|
</span>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { onMounted, ref } from "vue";
|
import { ElMessage } from "element-plus";
|
import dayjs from "dayjs";
|
import { productionPlanListPage } from "@/api/productionPlan/productionPlan.js";
|
import PIMTable from "./components/PIMTable.vue";
|
|
const tableColumn = ref([
|
{
|
label: "来源",
|
prop: "source",
|
width: "100px",
|
},
|
{
|
label: "状态",
|
prop: "status",
|
width: "80px",
|
},
|
{
|
label: "审核状态",
|
prop: "auditStatus",
|
width: "100px",
|
},
|
{
|
label: "订单号",
|
prop: "orderNo",
|
width: "120px",
|
},
|
{
|
label: "序列号",
|
prop: "serialNo",
|
width: "140px",
|
},
|
{
|
label: "零件号",
|
prop: "partNo",
|
width: "120px",
|
},
|
{
|
label: "零件",
|
prop: "partName",
|
width: "120px",
|
},
|
{
|
label: "产品类别",
|
prop: "materialCategory",
|
width: "100px",
|
},
|
{
|
label: "工艺文件号",
|
prop: "processFileNo",
|
width: "140px",
|
},
|
{
|
label: "销售数量",
|
prop: "salesQuantity",
|
width: "100px",
|
align: "right",
|
},
|
{
|
label: "制造数量",
|
prop: "quantity",
|
width: "100px",
|
align: "right",
|
},
|
{
|
label: "零件单位",
|
prop: "partUnit",
|
width: "80px",
|
},
|
{
|
label: "主计划需求日期",
|
prop: "mainPlanDemandDate",
|
formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
|
width: "140px",
|
},
|
{
|
label: "承诺日期",
|
prop: "commitmentDate",
|
formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
|
width: "120px",
|
},
|
{
|
label: "制造属性",
|
prop: "manufactureProperty",
|
width: "100px",
|
},
|
{
|
label: "备注",
|
prop: "remark",
|
width: "150px",
|
},
|
{
|
label: "更新时间",
|
prop: "updateTime",
|
formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
|
width: "120px",
|
},
|
{
|
label: "更新人",
|
prop: "updateBy",
|
width: "100px",
|
},
|
{
|
label: "创建时间",
|
prop: "createTime",
|
formatData: val => (val ? dayjs(val).format("YYYY-MM-DD") : ""),
|
width: "120px",
|
},
|
{
|
label: "创建人",
|
prop: "createBy",
|
width: "100px",
|
},
|
{
|
dataType: "action",
|
label: "操作",
|
align: "center",
|
fixed: "right",
|
width: 200,
|
operation: [
|
{
|
name: "下发",
|
type: "text",
|
clickFun: row => {
|
// 单独下发操作
|
// 设置表单数据
|
mergeForm.serialNo = row.serialNo;
|
mergeForm.totalquantity = row.quantity;
|
mergeForm.remark = "";
|
|
// 打开弹窗
|
isShowNewModal.value = true;
|
},
|
},
|
{
|
name: "追踪进度",
|
type: "text",
|
clickFun: row => {
|
handleTrackProgress(row);
|
},
|
},
|
],
|
},
|
]);
|
const tableData = ref([]);
|
const tableLoading = ref(false);
|
const page = reactive({
|
current: 1,
|
size: 100,
|
total: 0,
|
});
|
const selectedRows = ref([]);
|
|
// 产品类别汇总统计数据
|
const categorySummary = ref([]);
|
// 产品类别汇总弹窗控制
|
const showCategorySummaryDialog = ref(false);
|
|
// 合并下发弹窗控制
|
const isShowNewModal = ref(false);
|
// 合并下发表单数据
|
const mergeForm = reactive({
|
serialNo: "",
|
totalquantity: 0,
|
remark: "",
|
});
|
|
// 追踪进度弹窗控制
|
const showTrackProgressDialog = ref(false);
|
// 追踪进度表单数据
|
const trackProgressForm = reactive({
|
serialNo: "",
|
currentStatus: "",
|
completionRate: 0,
|
progressDetails: [],
|
remark: "",
|
});
|
|
// 处理追踪进度按钮点击
|
const handleTrackProgress = row => {
|
// 设置表单数据
|
trackProgressForm.serialNo = row.serialNo;
|
trackProgressForm.currentStatus = row.status;
|
|
// 生成模拟进度数据
|
trackProgressForm.progressDetails = generateProgressDetails(row.status);
|
|
// 计算完成率
|
trackProgressForm.completionRate = calculateCompletionRate(
|
trackProgressForm.progressDetails
|
);
|
trackProgressForm.remark = "";
|
|
// 打开弹窗
|
showTrackProgressDialog.value = true;
|
};
|
|
// 生成模拟进度详情数据
|
const generateProgressDetails = status => {
|
const details = [
|
{
|
step: "计划确认",
|
status: "completed",
|
startTime: "2026-03-01 09:00:00",
|
endTime: "2026-03-01 10:00:00",
|
},
|
{
|
step: "物料准备",
|
status:
|
status === "completed"
|
? "completed"
|
: status === "processing"
|
? "completed"
|
: "pending",
|
startTime:
|
status === "completed" || status === "processing"
|
? "2026-03-01 10:30:00"
|
: "",
|
endTime:
|
status === "completed" || status === "processing"
|
? "2026-03-02 16:00:00"
|
: "",
|
},
|
{
|
step: "生产加工",
|
status:
|
status === "completed"
|
? "completed"
|
: status === "processing"
|
? "processing"
|
: "pending",
|
startTime:
|
status === "completed" || status === "processing"
|
? "2026-03-03 08:00:00"
|
: "",
|
endTime: status === "completed" ? "2026-03-08 17:00:00" : "",
|
},
|
{
|
step: "质量检验",
|
status: status === "completed" ? "completed" : "pending",
|
startTime: status === "completed" ? "2026-03-09 09:00:00" : "",
|
endTime: status === "completed" ? "2026-03-09 15:00:00" : "",
|
},
|
{
|
step: "入库",
|
status: status === "completed" ? "completed" : "pending",
|
startTime: status === "completed" ? "2026-03-10 10:00:00" : "",
|
endTime: status === "completed" ? "2026-03-10 11:00:00" : "",
|
},
|
];
|
return details;
|
};
|
|
// 计算完成率
|
const calculateCompletionRate = details => {
|
const completedSteps = details.filter(
|
step => step.status === "completed"
|
).length;
|
return Math.round((completedSteps / details.length) * 100);
|
};
|
|
// 处理进度更新
|
const handleUpdateProgress = () => {
|
// 这里可以添加更新进度的逻辑
|
ElMessage.success("进度更新成功");
|
showTrackProgressDialog.value = false;
|
};
|
|
const data = reactive({
|
searchForm: {
|
customerName: "",
|
salesContractNo: "",
|
projectName: "",
|
materialCategory: "",
|
specificationModel: "",
|
},
|
});
|
const { searchForm } = toRefs(data);
|
|
// 查询列表
|
/** 搜索按钮操作 */
|
const handleQuery = () => {
|
page.current = 1;
|
getList();
|
};
|
const pagination = obj => {
|
page.current = obj.page;
|
page.size = obj.limit;
|
getList();
|
};
|
// 计算产品类别汇总统计
|
const calculateCategorySummary = () => {
|
const summary = {};
|
|
// 遍历表格数据,按产品类别汇总
|
tableData.value.forEach(row => {
|
const category = row.materialCategory;
|
if (!summary[category]) {
|
summary[category] = {
|
materialCategory: category,
|
totalquantity: 0,
|
};
|
}
|
summary[category].totalquantity += row.quantity;
|
});
|
|
// 转换为数组格式
|
categorySummary.value = Object.values(summary);
|
};
|
|
const getList = () => {
|
tableLoading.value = true;
|
// 构造一个新的对象,不包含entryDate字段
|
const params = { ...searchForm.value, ...page };
|
params.entryDate = undefined;
|
// tableData.value = [
|
// {
|
// id: 1,
|
// source: "销售订单",
|
// status: "待处理",
|
// auditStatus: "已审核",
|
// orderNo: "SO20260301001",
|
// serialNo: "PP20260301001",
|
// partNo: "P001",
|
// partName: "零件A",
|
// materialCategory: "类别1",
|
// processFileNo: "PF20260301001",
|
// salesQuantity: 100,
|
// quantity: 105,
|
// partUnit: "个",
|
// mainPlanDemandDate: "2026-03-15",
|
// commitmentDate: "2026-03-10",
|
// manufactureProperty: "常规",
|
// remark: "",
|
// updateTime: "2026-03-01",
|
// updateBy: "admin",
|
// createTime: "2026-03-01",
|
// createBy: "admin",
|
// },
|
// {
|
// id: 2,
|
// source: "销售订单",
|
// status: "待处理",
|
// auditStatus: "已审核",
|
// orderNo: "SO20260301002",
|
// serialNo: "PP20260301001",
|
// partNo: "P002",
|
// partName: "零件B",
|
// materialCategory: "类别1",
|
// processFileNo: "PF20260301002",
|
// salesQuantity: 200,
|
// quantity: 210,
|
// partUnit: "个",
|
// mainPlanDemandDate: "2026-03-15",
|
// commitmentDate: "2026-03-10",
|
// manufactureProperty: "常规",
|
// remark: "",
|
// updateTime: "2026-03-01",
|
// updateBy: "admin",
|
// createTime: "2026-03-01",
|
// createBy: "admin",
|
// },
|
// {
|
// id: 3,
|
// source: "销售订单",
|
// status: "进行中",
|
// auditStatus: "已审核",
|
// orderNo: "SO20260301003",
|
// serialNo: "PP20260301002",
|
// partNo: "P003",
|
// partName: "零件C",
|
// materialCategory: "类别2",
|
// processFileNo: "PF20260301003",
|
// salesQuantity: 150,
|
// quantity: 155,
|
// partUnit: "个",
|
// mainPlanDemandDate: "2026-03-20",
|
// commitmentDate: "2026-03-15",
|
// manufactureProperty: "常规",
|
// remark: "",
|
// updateTime: "2026-03-01",
|
// updateBy: "admin",
|
// createTime: "2026-03-01",
|
// createBy: "admin",
|
// },
|
// {
|
// id: 4,
|
// source: "销售订单",
|
// status: "进行中",
|
// auditStatus: "已审核",
|
// orderNo: "SO20260301004",
|
// serialNo: "PP20260301002",
|
// partNo: "P004",
|
// partName: "零件D",
|
// materialCategory: "类别2",
|
// processFileNo: "PF20260301004",
|
// salesQuantity: 300,
|
// quantity: 315,
|
// partUnit: "个",
|
// mainPlanDemandDate: "2026-03-20",
|
// commitmentDate: "2026-03-15",
|
// manufactureProperty: "常规",
|
// remark: "",
|
// updateTime: "2026-03-01",
|
// updateBy: "admin",
|
// createTime: "2026-03-01",
|
// createBy: "admin",
|
// },
|
// {
|
// id: 5,
|
// source: "销售订单",
|
// status: "已完成",
|
// auditStatus: "已审核",
|
// orderNo: "SO20260301005",
|
// serialNo: "PP20260301003",
|
// partNo: "P005",
|
// partName: "零件E",
|
// materialCategory: "类别3",
|
// processFileNo: "PF20260301005",
|
// salesQuantity: 250,
|
// quantity: 260,
|
// partUnit: "个",
|
// mainPlanDemandDate: "2026-03-10",
|
// commitmentDate: "2026-03-05",
|
// manufactureProperty: "常规",
|
// remark: "",
|
// updateTime: "2026-03-01",
|
// updateBy: "admin",
|
// createTime: "2026-03-01",
|
// createBy: "admin",
|
// },
|
// ];
|
// tableLoading.value = false;
|
// page.total = tableData.value.length;
|
// // 计算产品类别汇总统计
|
// calculateCategorySummary();
|
productionPlanListPage(params)
|
.then(res => {
|
tableLoading.value = false;
|
|
tableData.value = res.data.records;
|
page.total = res.data.total;
|
// 计算产品类别汇总统计
|
calculateCategorySummary();
|
})
|
.catch(() => {
|
tableLoading.value = false;
|
});
|
};
|
|
// 选中的序列号
|
const selectedserialNo = ref("");
|
|
// 表格选择数据
|
const handleSelectionChange = selection => {
|
selectedRows.value = selection;
|
// 如果有选中的行,记录第一个选中行的序列号
|
if (selection.length > 0) {
|
selectedserialNo.value = selection[0].serialNo;
|
} else {
|
// 如果没有选中的行,清空序列号
|
selectedserialNo.value = "";
|
}
|
};
|
|
// 判断行是否可选择
|
const isSelectable = row => {
|
// 如果没有选中的行,所有行都可选择
|
if (!selectedserialNo.value) {
|
return true;
|
}
|
// 如果有选中的行,只有序列号相同的行才可选择
|
return row.serialNo === selectedserialNo.value;
|
};
|
|
// 处理合并下发按钮点击
|
const handleMerge = () => {
|
if (selectedRows.value.length === 0) {
|
ElMessage.warning("请选择要合并下发的生产计划");
|
return;
|
}
|
|
// 计算总制造数量
|
const totalQuantity = selectedRows.value.reduce((sum, row) => {
|
return sum + row.quantity;
|
}, 0);
|
|
// 设置表单数据
|
mergeForm.serialNo = selectedserialNo.value;
|
mergeForm.totalquantity = totalQuantity;
|
mergeForm.remark = "";
|
|
// 打开弹窗
|
isShowNewModal.value = true;
|
};
|
|
// 处理合并下发提交
|
const handleMergeSubmit = () => {
|
// 这里可以添加下发逻辑
|
ElMessage.success("合并下发成功");
|
isShowNewModal.value = false;
|
// 可以选择刷新列表或其他操作
|
};
|
|
onMounted(() => {
|
getList();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.app-container {
|
padding: 24px;
|
background-color: #f0f2f5;
|
min-height: calc(100vh - 48px);
|
}
|
|
.search_form {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 24px;
|
padding: 20px;
|
background-color: #ffffff;
|
border-radius: 6px;
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
transition: all 0.3s ease;
|
|
&:hover {
|
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.08);
|
}
|
}
|
|
.table_list {
|
// margin-bottom: 24px;
|
background-color: #ffffff;
|
border-radius: 6px;
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
overflow: hidden;
|
height: calc(100vh - 250px);
|
}
|
|
:deep(.el-table) {
|
border: none;
|
border-radius: 6px;
|
overflow: hidden;
|
|
.el-table__header-wrapper {
|
background-color: #fafafa;
|
|
th {
|
background-color: #fafafa;
|
font-weight: 600;
|
color: #303133;
|
border-bottom: 1px solid #ebeef5;
|
padding: 14px 0;
|
}
|
}
|
|
.el-table__body-wrapper {
|
tr {
|
transition: all 0.3s ease;
|
|
&:hover {
|
background-color: #f5f7fa;
|
}
|
|
td {
|
border-bottom: 1px solid #ebeef5;
|
padding: 12px 0;
|
}
|
}
|
|
tr.current-row {
|
background-color: #ecf5ff;
|
}
|
}
|
|
.el-table__empty-block {
|
padding: 40px 0;
|
}
|
}
|
|
.pagination-container {
|
display: flex;
|
justify-content: flex-end;
|
padding: 16px 20px;
|
background-color: #ffffff;
|
border-top: 1px solid #ebeef5;
|
border-radius: 0 0 12px 12px;
|
}
|
|
:deep(.el-button) {
|
transition: all 0.3s ease;
|
|
&:hover {
|
transform: translateY(-1px);
|
}
|
}
|
|
:deep(.el-dialog) {
|
border-radius: 6px;
|
overflow: hidden;
|
|
.el-dialog__header {
|
background-color: #fafafa;
|
border-bottom: 1px solid #ebeef5;
|
padding: 20px 24px;
|
|
.el-dialog__title {
|
font-size: 16px;
|
font-weight: 600;
|
color: #303133;
|
}
|
}
|
|
.el-dialog__body {
|
padding: 24px;
|
}
|
|
.el-dialog__footer {
|
padding: 16px 24px;
|
border-top: 1px solid #ebeef5;
|
background-color: #fafafa;
|
}
|
}
|
|
:deep(.el-form) {
|
.el-form-item {
|
margin-bottom: 20px;
|
|
.el-form-item__label {
|
font-weight: 500;
|
color: #303133;
|
}
|
|
.el-input,
|
.el-select,
|
.el-date-picker,
|
.el-input-number {
|
width: 100%;
|
|
// .el-input__inner {
|
// border-radius: 6px;
|
// border: 1px solid #dcdfe6;
|
// transition: all 0.3s ease;
|
|
// &:focus {
|
// border-color: #409eff;
|
// box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
|
// }
|
// }
|
}
|
}
|
}
|
|
:deep(.el-tag) {
|
border-radius: 4px;
|
padding: 2px 8px;
|
font-size: 12px;
|
}
|
|
@media (max-width: 768px) {
|
.app-container {
|
padding: 16px;
|
}
|
|
.search_form {
|
flex-direction: column;
|
align-items: flex-start;
|
gap: 12px;
|
|
.el-form {
|
width: 100%;
|
|
.el-form-item {
|
width: 100%;
|
}
|
}
|
|
> div {
|
width: 100%;
|
display: flex;
|
gap: 12px;
|
|
.el-button {
|
flex: 1;
|
}
|
}
|
}
|
|
:deep(.el-table) {
|
th,
|
td {
|
padding: 10px 0;
|
font-size: 12px;
|
}
|
}
|
|
:deep(.el-dialog) {
|
width: 90% !important;
|
margin: 20px auto !important;
|
}
|
}
|
.consumption-value {
|
font-weight: bold;
|
color: #409eff;
|
}
|
|
.consumption-unit {
|
font-size: 12px;
|
color: #909399;
|
margin-left: 4px;
|
}
|
.search_form {
|
:deep(.el-form-item) {
|
margin-bottom: 0px !important;
|
}
|
}
|
</style>
|