- 删除应用配置页面及相关组件,重构路由为 /developer/config/[id].vue - 移除开发者文档页面及其导航与样式实现 - 清理开发者侧功能完善工作日志文件 - 删除全局.gitignore配置文件,清理无用忽略规则 - 优化应用配置页面的参数读取和路由结构,解决刷新404问题 - 解决数据库配置唯一键冲突,调整保存逻辑避免重复插入 - 移除对后端配置加密字段的 secret 标记,修正加密异常问题
156 lines
6.3 KiB
Vue
156 lines
6.3 KiB
Vue
<script setup lang="ts">
|
|
definePageMeta({ layout: 'admin' })
|
|
const { activeTab } = useNav()
|
|
activeTab.value = 'production-schedule'
|
|
|
|
const selectedDate = ref('2026-04-09')
|
|
|
|
const scheduleData = ref([
|
|
{ time: '08:00', tasks: [
|
|
{ wo: 'WO2026040901', product: '精密轴承组件 A型', qty: 500, line: '产线1', status: 'running' },
|
|
]},
|
|
{ time: '10:00', tasks: [
|
|
{ wo: 'WO2026040802', product: '液压缸体 B型', qty: 200, line: '产线2', status: 'pending' },
|
|
]},
|
|
{ time: '14:00', tasks: [
|
|
{ wo: 'WO2026040703', product: '密封圈组件 D型', qty: 3000, line: '产线3', status: 'pending' },
|
|
]},
|
|
])
|
|
|
|
const productionLines = ref([
|
|
{ id: 'L1', name: '产线1', status: 'running', utilization: 92, output: 245, target: 260 },
|
|
{ id: 'L2', name: '产线2', status: 'idle', utilization: 0, output: 0, target: 200 },
|
|
{ id: 'L3', name: '产线3', status: 'running', utilization: 78, output: 180, target: 220 },
|
|
{ id: 'L4', name: '产线4', status: 'maintenance', utilization: 0, output: 0, target: 180 },
|
|
])
|
|
|
|
const statusColor: Record<string, string> = {
|
|
running: '#10b981',
|
|
pending: '#f59e0b',
|
|
idle: '#9ca3af',
|
|
maintenance: '#ef4444',
|
|
}
|
|
|
|
const lineStatusMap: Record<string, string> = {
|
|
running: { status: 'running', text: '运行中' },
|
|
idle: { status: 'default', text: '空闲' },
|
|
maintenance: { status: 'exception', text: '维护中' },
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="page-container">
|
|
<div class="page-header">
|
|
<h2 class="page-title">计划排程</h2>
|
|
<a-space>
|
|
<a-date-picker v-model:value="selectedDate" />
|
|
<a-button type="primary">
|
|
<template #icon><PlusOutlined /></template>
|
|
新建排程
|
|
</a-button>
|
|
</a-space>
|
|
</div>
|
|
|
|
<a-row :gutter="[20, 20]">
|
|
<!-- 排程甘特图 -->
|
|
<a-col :xs="24" :xl="16">
|
|
<div class="card">
|
|
<div class="card-title">生产排程</div>
|
|
<div class="gantt">
|
|
<div class="gantt-header">
|
|
<div class="gantt-time">时间段</div>
|
|
<div class="gantt-tasks">排程任务</div>
|
|
</div>
|
|
<div v-for="slot in scheduleData" :key="slot.time" class="gantt-row">
|
|
<div class="gantt-time">{{ slot.time }}</div>
|
|
<div class="gantt-tasks">
|
|
<div v-for="task in slot.tasks" :key="task.wo" class="task-card" :class="task.status">
|
|
<div class="task-wo">{{ task.wo }}</div>
|
|
<div class="task-info">{{ task.product }} · {{ task.qty }}件</div>
|
|
<div class="task-line">{{ task.line }}</div>
|
|
</div>
|
|
<div v-if="slot.tasks.length === 0" class="task-empty">暂无排程</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</a-col>
|
|
|
|
<!-- 产线状态 -->
|
|
<a-col :xs="24" :xl="8">
|
|
<div class="card">
|
|
<div class="card-title">产线状态</div>
|
|
<div class="line-list">
|
|
<div v-for="line in productionLines" :key="line.id" class="line-item">
|
|
<div class="line-header">
|
|
<span class="line-name">{{ line.name }}</span>
|
|
<a-badge :status="lineStatusMap[line.status].status as any" :text="lineStatusMap[line.status].text" />
|
|
</div>
|
|
<div class="line-stats">
|
|
<div class="line-stat">
|
|
<span class="line-num">{{ line.utilization }}%</span>
|
|
<span class="line-lbl">利用率</span>
|
|
</div>
|
|
<div class="line-stat">
|
|
<span class="line-num">{{ line.output }}</span>
|
|
<span class="line-lbl">实际产量</span>
|
|
</div>
|
|
<div class="line-stat">
|
|
<span class="line-num">{{ line.target }}</span>
|
|
<span class="line-lbl">目标产量</span>
|
|
</div>
|
|
</div>
|
|
<a-progress
|
|
:percent="line.utilization"
|
|
:showInfo="false"
|
|
size="small"
|
|
:status="line.status === 'running' ? 'active' : 'exception'"
|
|
:strokeColor="statusColor[line.status]"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</a-col>
|
|
</a-row>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.page-container { padding: 24px; }
|
|
.page-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
|
|
.page-title { font-size: 20px; font-weight: 600; color: #1f2937; margin: 0; }
|
|
|
|
.card { background: white; border-radius: 12px; padding: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); border: 1px solid #f0f0f0; margin-bottom: 20px; }
|
|
.card-title { font-size: 16px; font-weight: 600; color: #1f2937; margin-bottom: 16px; }
|
|
|
|
.gantt { border: 1px solid #f0f0f0; border-radius: 8px; overflow: hidden; }
|
|
.gantt-header { display: flex; background: #fafafa; border-bottom: 1px solid #f0f0f0; font-weight: 600; font-size: 13px; }
|
|
.gantt-time { width: 80px; padding: 10px 12px; border-right: 1px solid #f0f0f0; }
|
|
.gantt-tasks { flex: 1; padding: 10px 12px; }
|
|
.gantt-row { display: flex; border-bottom: 1px solid #f0f0f0; }
|
|
.gantt-row:last-child { border-bottom: none; }
|
|
.gantt-row .gantt-time { padding: 16px 12px; font-size: 13px; color: #6b7280; }
|
|
.gantt-row .gantt-tasks { display: flex; flex-wrap: wrap; gap: 8px; padding: 12px; min-height: 60px; align-items: center; }
|
|
|
|
.task-card {
|
|
padding: 8px 12px;
|
|
border-radius: 6px;
|
|
font-size: 12px;
|
|
}
|
|
.task-card.running { background: #ecfdf5; border-left: 3px solid #10b981; }
|
|
.task-card.pending { background: #fffbeb; border-left: 3px solid #f59e0b; }
|
|
.task-wo { font-weight: 600; color: #374151; }
|
|
.task-info { color: #6b7280; margin: 2px 0; }
|
|
.task-line { color: #9ca3af; font-size: 11px; }
|
|
.task-empty { color: #d1d5db; font-size: 13px; }
|
|
|
|
.line-list { display: flex; flex-direction: column; gap: 16px; }
|
|
.line-item { padding: 14px; background: #fafafa; border-radius: 8px; }
|
|
.line-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
|
|
.line-name { font-weight: 600; color: #374151; font-size: 14px; }
|
|
.line-stats { display: flex; justify-content: space-between; margin-bottom: 10px; }
|
|
.line-stat { text-align: center; }
|
|
.line-num { display: block; font-size: 16px; font-weight: 700; color: #1f2937; }
|
|
.line-lbl { font-size: 11px; color: #9ca3af; }
|
|
</style>
|