<template>
|
<div class="app-container">
|
<PageHeader content="生产计划追踪进度">
|
</PageHeader>
|
<el-card style="height:82vh;overflow:auto;">
|
<template #header>
|
<div class="card-header">
|
<span>申请单编号 - {{ rowData.applyNo || '' }}</span>
|
</div>
|
</template>
|
<!-- 基础信息 -->
|
<div class="detail-section">
|
<h3 class="section-title">基础信息</h3>
|
<el-descriptions :column="3"
|
border>
|
<el-descriptions-item label="申请单编号">{{ rowData.applyNo || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="产品名称">{{ rowData.productName || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="产品规格">{{ rowData.model || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="物料编码">{{ rowData.materialCode || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="下发数量">{{ rowData.assignedQuantity || 0 }} <span class="unit">方</span></el-descriptions-item>
|
<el-descriptions-item label="当前状态">
|
<el-tag :type="getStatusType(rowData.status)">
|
{{ getStatusText(rowData.status) }}
|
</el-tag>
|
</el-descriptions-item>
|
</el-descriptions>
|
</div>
|
<div class="progress-container">
|
<div class="progress-section">
|
<h3 class="section-title">进度信息</h3>
|
<div class="progress-item">
|
<div class="progress-label">完成进度:</div>
|
<div class="progress-content">
|
<el-progress :percentage="trackProgressForm.completionRate"
|
:color="customColors"
|
:status="trackProgressForm.completionRate === 100 ? 'success' : ''" />
|
</div>
|
</div>
|
<div class="progress-item">
|
<div class="progress-label">进度详情:</div>
|
<div class="progress-content">
|
<el-table :data="trackProgressForm.progressDetails"
|
border
|
style="width: auto; height: 300px">
|
<el-table-column prop="step"
|
label="步骤(点击查看详情)"
|
align="center">
|
<template #default="{ row, $index }">
|
<el-link v-if="$index!=0"
|
@click="handleClickStep(row)"
|
type="primary">{{ row.step }}</el-link>
|
<span v-else
|
@click="handleClickStep(row)">{{ row.step }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column prop="status"
|
label="状态"
|
align="center">
|
<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="quantity"
|
label="数量"
|
align="center" />
|
<el-table-column prop="startTime"
|
label="时间"
|
align="center" />
|
</el-table>
|
</div>
|
</div>
|
</div>
|
<div class="progress-section">
|
<h3 class="section-title">订单信息</h3>
|
<div v-for="item in rowData.orderList"
|
:key="item.orderNo"
|
class="order-item">
|
<el-descriptions :column="3"
|
border>
|
<el-descriptions-item label="订单编号">{{ item.orderNo || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="订单状态">
|
<el-tag :type="getStatusType(item.status)">{{ getStatusText(item.status) }}</el-tag>
|
</el-descriptions-item>
|
<el-descriptions-item label="开始日期">{{ item.startTime || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="需求数量">{{ item.quantity || 0 }} <span class="unit">方</span></el-descriptions-item>
|
<el-descriptions-item label="完成数量">{{ item.completeQuantity || 0 }} <span class="unit">方</span></el-descriptions-item>
|
<el-descriptions-item label="完成进度">
|
<el-progress :percentage="item.completionRate"
|
:color="customColors(item.completionRate)"
|
:status="item.completionRate === 100 ? 'success' : ''"
|
style="width: 120px;" />
|
</el-descriptions-item>
|
</el-descriptions>
|
</div>
|
</div>
|
</div>
|
</el-card>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive, onMounted } from "vue";
|
import { ElMessage } from "element-plus";
|
import { useRouter, useRoute } from "vue-router";
|
|
const router = useRouter();
|
const route = useRoute();
|
|
// 路由参数数据
|
const rowData = reactive({});
|
|
// 追踪进度表单数据
|
const trackProgressForm = reactive({
|
materialCode: "",
|
currentStatus: "",
|
completionRate: 0,
|
progressDetails: [],
|
remark: "",
|
});
|
|
// 获取状态类型
|
const getStatusType = status => {
|
const typeMap = {
|
0: "warning",
|
1: "primary",
|
2: "info",
|
};
|
return typeMap[status] || "info";
|
};
|
|
// 获取状态文本
|
const getStatusText = status => {
|
const statusMap = {
|
0: "待下发",
|
1: "部分下发",
|
2: "已下发",
|
};
|
return statusMap[status] || "";
|
};
|
const customColors = percentage => {
|
if (Number(percentage) < 10) {
|
return "#909399";
|
}
|
if (Number(percentage) < 70) {
|
return "#e6a23c";
|
}
|
return "#67c23a";
|
};
|
|
// 生成模拟进度详情数据
|
const generateProgressDetails = status => {
|
const details = [
|
{
|
step: "计划确认",
|
status: "completed",
|
quantity: 233,
|
startTime: "2026-03-01 09:00:00",
|
endTime: "2026-03-01 10:00:00",
|
},
|
{
|
step: "第一次报工",
|
status: "completed",
|
quantity: 233,
|
startTime: "2026-03-01 09:00:00",
|
endTime: "2026-03-01 10:00:00",
|
},
|
{
|
step: "第二次报工",
|
status: "completed",
|
quantity: 233,
|
startTime: "2026-03-01 09:00:00",
|
endTime: "2026-03-01 10:00:00",
|
},
|
{
|
step: "第三次报工",
|
status: "completed",
|
quantity: 233,
|
startTime: "2026-03-01 09:00:00",
|
endTime: "2026-03-01 10:00:00",
|
},
|
{
|
step: "第四次报工",
|
status: "completed",
|
quantity: 233,
|
startTime: "2026-03-01 09:00:00",
|
endTime: "2026-03-01 10:00:00",
|
},
|
{
|
step: "第五次报工",
|
status: "completed",
|
quantity: 233,
|
startTime: "2026-03-01 09:00:00",
|
endTime: "2026-03-01 10:00:00",
|
},
|
{
|
step: "第六次报工",
|
status: "completed",
|
quantity: 233,
|
startTime: "2026-03-01 09:00:00",
|
endTime: "2026-03-01 10:00:00",
|
},
|
{
|
step: "第七次报工",
|
status: "completed",
|
quantity: 233,
|
startTime: "2026-03-01 09:00:00",
|
endTime: "2026-03-01 10: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("进度更新成功");
|
};
|
|
// 处理返回
|
const handleBack = () => {
|
router.push("/productionPlan/productionPlan");
|
};
|
|
// 生成模拟订单数据
|
const generateOrderList = () => {
|
return [
|
{
|
orderNo: "ORD-2026-001",
|
status: 1,
|
quantity: 233.28,
|
completeQuantity: 14,
|
completionRate: 6,
|
startTime: "2026-03-25",
|
},
|
{
|
orderNo: "ORD-2026-002",
|
status: 2,
|
quantity: 150.5,
|
completeQuantity: 100,
|
completionRate: 67,
|
startTime: "2026-03-20",
|
},
|
{
|
orderNo: "ORD-2026-003",
|
status: 0,
|
quantity: 80.0,
|
completeQuantity: 0,
|
completionRate: 0,
|
startTime: "2026-03-30",
|
},
|
];
|
};
|
|
// 页面加载时获取数据
|
onMounted(() => {
|
// 从路由参数中获取数据
|
const data = route.query.row
|
? JSON.parse(decodeURIComponent(route.query.row))
|
: null;
|
if (data) {
|
// 赋值给rowData
|
Object.assign(rowData, data);
|
// 赋值给表单数据
|
trackProgressForm.materialCode = data.materialCode;
|
trackProgressForm.currentStatus = data.status;
|
trackProgressForm.progressDetails = generateProgressDetails(data.status);
|
trackProgressForm.completionRate = calculateCompletionRate(
|
trackProgressForm.progressDetails
|
);
|
trackProgressForm.remark = "";
|
}
|
// 生成模拟订单数据
|
rowData.orderList = generateOrderList();
|
});
|
</script>
|
|
<style scoped>
|
.app-container {
|
padding: 20px;
|
background-color: #f5f7fa;
|
min-height: 100vh;
|
}
|
|
.card-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 0 10px;
|
}
|
|
.action-buttons {
|
display: flex;
|
justify-content: flex-end;
|
margin-top: 20px;
|
gap: 10px;
|
}
|
|
.detail-section {
|
margin-bottom: 24px;
|
background-color: #ffffff;
|
border-radius: 10px;
|
padding: 24px;
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
|
transition: all 0.3s ease;
|
}
|
|
.detail-section:hover {
|
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.12);
|
}
|
|
.section-title {
|
font-size: 16px;
|
font-weight: 600;
|
margin-bottom: 20px;
|
color: #1a1a1a;
|
border-bottom: 2px solid #409eff;
|
padding-bottom: 10px;
|
display: flex;
|
align-items: center;
|
}
|
|
.section-title::before {
|
content: "";
|
display: inline-block;
|
width: 4px;
|
height: 16px;
|
background-color: #409eff;
|
margin-right: 8px;
|
border-radius: 2px;
|
}
|
|
.unit {
|
font-size: 12px;
|
color: #909399;
|
margin-left: 4px;
|
}
|
|
:deep(.el-descriptions) {
|
border-radius: 8px;
|
overflow: hidden;
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
}
|
|
:deep(.el-descriptions__row:nth-child(odd)) {
|
background-color: #f9f9f9;
|
}
|
|
:deep(.el-descriptions__label) {
|
font-weight: 500;
|
color: #606266;
|
background-color: #f5f7fa;
|
}
|
|
:deep(.el-descriptions__content) {
|
color: #303133;
|
font-weight: 500;
|
}
|
|
.progress-container {
|
display: flex;
|
gap: 24px;
|
}
|
|
.progress-section {
|
margin-bottom: 24px;
|
background-color: #ffffff;
|
border-radius: 10px;
|
padding: 24px;
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
|
flex: 1;
|
transition: all 0.3s ease;
|
}
|
|
.progress-section:hover {
|
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.12);
|
}
|
|
.progress-item {
|
margin-bottom: 24px;
|
}
|
|
.progress-label {
|
font-size: 14px;
|
font-weight: 500;
|
color: #606266;
|
margin-bottom: 12px;
|
display: flex;
|
align-items: center;
|
}
|
|
.progress-content {
|
margin-left: 0;
|
}
|
|
.progress-content .el-table {
|
max-height: 400px;
|
overflow-y: auto;
|
border-radius: 8px;
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
}
|
|
:deep(.el-table th) {
|
background-color: #f5f7fa !important;
|
font-weight: 600;
|
color: #606266;
|
}
|
|
:deep(.el-table tr:hover) {
|
background-color: #f5f7fa !important;
|
}
|
|
.order-item {
|
margin-bottom: 20px;
|
border-radius: 8px;
|
overflow: hidden;
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
}
|
|
.order-item:last-child {
|
margin-bottom: 0;
|
}
|
|
:deep(.el-progress-bar__inner) {
|
border-radius: 10px;
|
}
|
|
:deep(.el-tag) {
|
border-radius: 12px;
|
padding: 2px 10px;
|
}
|
</style>
|