Compare commits

...

2 Commits

Author SHA1 Message Date
kkk-ops 6689e7b986 merge 1 week ago
kkk-ops 3f8bfb32ac 综合大屏 1 week ago

@ -57,33 +57,39 @@ export interface DashboardTaskListResponse {
// 编码生成记录 API
export const DashboardApi = {
// 查询编码生成记录分页
getProduction: async (params: any) => {
return await request.get({ url: `/mes/dashboard/getProduction`, params })
},
getPlan: async () => {
return await request.get({ url: `/mes/dashboard/getPlan` })
},
getDevice: async () => {
return await request.get({ url: `/mes/dashboard/getDevice` })
},
getMold: async () => {
return await request.get({ url: `/mes/dashboard/getMold` })
},
getTodoList: async () => {
return await request.get({ url: `/mes/dashboard/getTodoList` })
},
getDeviceOperationalStatus: async () => {
return await request.get({ url: `/iot/device/getDeviceOperationalStatus` })
},
getDeviceRepairLineOptions: async () => {
return await request.get({ url: `/mes/dashboard/getDeviceRepairLineOptions` })
},
getTaskStatistics: async () => {
return await request.get<TaskStatisticsResponse>({ url: `/mes/dashboard/getTaskStatistics` })
},
getAllTaskList: async () => {
return await request.get<DashboardTaskListResponse>({ url: `/mes/dashboard/getAllTaskList` })
}
// 查询编码生成记录分页
getProduction: async (params: any) => {
return await request.get({ url: `/mes/dashboard/getProduction`, params })
},
getPlan: async () => {
return await request.get({ url: `/mes/dashboard/getPlan` })
},
getDevice: async () => {
return await request.get({ url: `/mes/dashboard/getDevice` })
},
getMold: async () => {
return await request.get({ url: `/mes/dashboard/getMold` })
},
getTodoList: async () => {
return await request.get({ url: `/mes/dashboard/getTodoList` })
},
getDeviceOperationalStatus: async () => {
return await request.get({ url: `/iot/device/getDeviceOperationalStatus` })
},
getDeviceRepairLineOptions: async () => {
return await request.get({ url: `/mes/dashboard/getDeviceRepairLineOptions` })
},
getDeviceTypePieOptions: async () => {
return await request.get({ url: `/mes/dashboard/getDeviceTypePieOptions` })
},
getMoldTypeBarOptions: async () => {
return await request.get({ url: `/mes/dashboard/getMoldTypeBarOptions` })
},
getTaskStatistics: async () => {
return await request.get<TaskStatisticsResponse>({ url: `/mes/dashboard/getTaskStatistics` })
},
getAllTaskList: async () => {
return await request.get<DashboardTaskListResponse>({ url: `/mes/dashboard/getAllTaskList` })
}
}

@ -22,7 +22,10 @@ export interface PlanVO {
productionManager: number // 生产主管
remark: string // 备注
isEnable: boolean // 是否启用
feedingPipeline: string //制浆线
feedingPipeline: number //制浆线
feedingPipelineName: string
wangongNumber: number
passRate: number
}
// 生产计划 API
@ -93,4 +96,12 @@ export const PlanApi = {
getPlanByTicketType: async (status: number) => {
return await request.get({ url: `/mes/plan/getByTicketType?status=` + status })
},
// 产线任务看板
getProductPlans: async () => {
return await request.get({ url: `/mes/plan/getProductPlans` })
},
// 周生产趋势
getWeekTrend: async () => {
return await request.get({ url: `/mes/plan/getWeekTrend` })
}
}

@ -220,7 +220,7 @@ v-model="deviceOverviewRange" type="daterange" unlink-panels value-format="YYYY-
</el-row>
</el-card>
<el-row :gutter="16" class="home-section">
<el-col :xl="12" :lg="8" :md="24" :sm="24" :xs="24" class="mb-16px">
<el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-16px">
<el-card shadow="never">
<template #header>
<div class="h-3 flex justify-between">
@ -244,10 +244,10 @@ v-model="deviceOverviewRange" type="daterange" unlink-panels value-format="YYYY-
<el-card shadow="never">
<template #header>
<div class="h-3 flex justify-between">
<span>设备分布统计</span>
<span>模具分类统计</span>
</div>
</template>
<Echart :options="deviceDistributionBarOptionsData" :height="260" />
<Echart :options="moldTypeBarOptionsData" :height="260" />
</el-card>
</el-col>
</el-row>
@ -318,7 +318,6 @@ v-model="deviceOverviewRange" type="daterange" unlink-panels value-format="YYYY-
<script lang="ts" setup>
import { set } from 'lodash-es'
import { EChartsOption } from 'echarts'
import { formatTime } from '@/utils'
import { useUserStore } from '@/store/modules/user'
import { useWatermark } from '@/hooks/web/useWatermark'
import type {
@ -326,20 +325,15 @@ import type {
Project,
Notice,
Shortcut,
ProductionOverview,
ProductionProgressItem,
DeviceOverview,
TodoTask,
DeviceOperationStatus
} from './types'
import {
pieOptions,
barOptions,
deviceCategoryPieOptions,
deviceDistributionBarOptions,
deviceOverviewMock,
} from './echarts-data'
import { HomeApi } from '@/api/home/info'
import { WeatherVO } from '@/api/home/info'
import bannerImg from '@/assets/imgs/banner.png'
import { DashboardApi,DashboardProductVO,DeviceStatusVO } from '@/api/dashboard'
@ -352,21 +346,10 @@ const { setWatermark } = useWatermark()
const loading = ref(true)
const avatar = userStore.getUser.avatar
const username = userStore.getUser.nickname
const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
const deviceCategoryPieOptionsData = reactive<EChartsOption>(
deviceCategoryPieOptions
) as EChartsOption
const deviceDistributionBarOptionsData = reactive<EChartsOption>(
deviceDistributionBarOptions
) as EChartsOption
const productionOverviewRange = ref<string[]>([])
const deviceOverview = ref<DeviceOverview>(deviceOverviewMock)
const formatPercent = (value: number | undefined | null) => {
if (value === null || value === undefined) return '0%'
@ -374,87 +357,14 @@ const formatPercent = (value: number | undefined | null) => {
return `${value}%`
}
const productionOverviewLeft = ref([])
const productionOverviewLeft = ref<{ key: string; label: string; value: number; }[]>([])
const productionOverviewCenter = ref([])
const productionOverviewCenter = ref<{ key: string; label: string; value: number; }[]>([])
const plan = ref<ProductionProgressItem[]>([])
const todo = ref<TodoTask[]>([])
// const productionOverviewRight = computed(() => [
// {
// key: 'attendanceCount',
// label: '',
// value: productionOverview.value.onTimeRate ?? 0
// },
// {
// key: 'attendanceRate',
// label: '',
// value: formatPercent(productionOverview.value.onTimeRate)
// }
// ])
const deviceOverviewTop = computed(() => [
{
key: 'deviceTotal',
label: '总设备数',
value: deviceOverview.value.deviceTotal?.toLocaleString()
},
{
key: 'realtimeAlarm',
label: '实时告警',
value: deviceOverview.value.needRepair ?? 0
},
{
key: 'running',
label: '运行',
value: deviceOverview.value.running ?? 0
},
{
key: 'stop',
label: '停机',
value: deviceOverview.value.stop ?? 0
},
{
key: 'standby',
label: '待机',
value: 0
},
{
key: 'utilization',
label: '利用率',
value: formatPercent(deviceOverview.value.utilization)
},
{
key: 'faultRate',
label: '故障率',
value: formatPercent(deviceOverview.value.alarmRate)
}
])
const deviceOverviewBottom = computed(() => [
{
key: 'faultCount',
label: '设备故障台数',
value: deviceOverview.value.needRepair ?? 0
},
{
key: 'faultTime',
label: '设备故障时间',
value: 0
},
{
key: 'mtbf',
label: '平均故障间隔时间',
value: 0
},
{
key: 'mttr',
label: '平均故障时间',
value: 0
}
])
const groupBySize = <T,>(list: T[], size: number) => {
const result: T[][] = []
@ -492,15 +402,15 @@ const deviceRepairLineOptions = ref<EChartsOption>({
},
grid: {
left: 40,
right: 20,
bottom: 30,
right: 30,
bottom: 50,
top: 60,
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['一月', '二月', '三月', '四月', '五月', '六月']
data: []
},
yAxis: {
type: 'value'
@ -510,29 +420,96 @@ const deviceRepairLineOptions = ref<EChartsOption>({
name: '维修数量',
type: 'line',
smooth: true,
data: [3, 5, 4, 6, 8, 7]
// data: [3, 5, 4, 6, 8, 7]
}
]
})
const deviceCategoryPieOptionsData = ref<EChartsOption>(
{title: {
text: '设备分类统计',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '设备类别',
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
}
]
}
)
const moldTypeBarOptionsData = ref<EChartsOption>({
title: {
text: '模具分类统计',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: 40,
right: 20,
bottom: 30,
top: 60,
containLabel: true
},
xAxis: {
type: 'category',
// data: ['', '', '', '', ''],
axisTick: {
alignWithLabel: true
}
},
yAxis: {
type: 'value'
},
series: [
{
name: '模具数量',
type: 'bar',
// data: [10, 8, 6, 5, 4]
}
]
}
)
const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
/** 初始化 **/
onMounted(async () => {
//
const data = await HomeApi.getWeatherInfo()
weatherEnable.value = data.isEnable
if (data.isEnable && weatherList) {
weatherList.value = data.casts
todayWeather.value = weatherList.value[0]
weatherCity = data.city
}
production.value = await DashboardApi.getProduction(productionOverviewRange.value)
onMounted(async () => {
//
// const data = await HomeApi.getWeatherInfo()
// weatherEnable.value = data.isEnable
// if (data.isEnable && weatherList) {
// weatherList.value = data.casts
// todayWeather.value = weatherList.value[0]
// weatherCity = data.city
// }
production.value = await DashboardApi.getProduction(productionOverviewRange)
plan.value = await DashboardApi.getPlan()
deviceStatusCards.value = await DashboardApi.getDevice()
moldStatusCards.value = await DashboardApi.getMold()
todo.value = await DashboardApi.getTodoList()
formData.value = await DashboardApi.getDeviceOperationalStatus()
const Options = await DashboardApi.getDeviceRepairLineOptions()
deviceRepairLineOptions.value.xAxis.data = Options.xaxis
deviceRepairLineOptions.value.series[0].data = Options.series
deviceRepairLineOptions.value.xAxis!.data = Options.xaxis
deviceRepairLineOptions.value.series![0].data = Options.series
const deviceTypeOptions = await DashboardApi.getDeviceTypePieOptions()
deviceCategoryPieOptionsData.value.series![0].data = deviceTypeOptions
const moldTypeOptions = await DashboardApi.getMoldTypeBarOptions()
console.log(moldTypeOptions)
moldTypeBarOptionsData.value.xAxis!.data = moldTypeOptions.xaxis
moldTypeBarOptionsData.value.series![0].data = moldTypeOptions.series
productionOverviewLeft.value = production.value.taskItems
productionOverviewCenter.value = production.value.planItems

@ -19,10 +19,10 @@
<Icon icon="fa-regular:clock" class="chip-icon" />
<span>{{ timeStr }}</span>
</span>
<span class="chip chip-strong">
<!-- <span class="chip chip-strong">
<Icon icon="fa-solid:circle-nodes" class="chip-icon" />
<span>当前在线产线 <strong>10</strong> </span>
</span>
</span> -->
</div>
</div>
</header>

@ -19,22 +19,22 @@
<div class="metric-card">
<div class="metric-label">排产单数量</div>
<div class="metric-value" ref="dayOrderEl"></div>
<div class="metric-extra"><span></span><span>含加急 4 </span></div>
<!-- <div class="metric-extra"><span></span><span>含加急 4 </span></div> -->
</div>
<div class="metric-card">
<div class="metric-label">排产数量</div>
<div class="metric-value" ref="dayPlanEl"></div>
<div class="metric-extra"><span></span><span>含三班倒</span></div>
<!-- <div class="metric-extra"><span></span><span>含三班倒</span></div> -->
</div>
<div class="metric-card">
<div class="metric-label">待生产数量</div>
<div class="metric-value warn" ref="dayPendingEl"></div>
<div class="metric-extra"><span></span><span>预计 4 小时内完成</span></div>
<!-- <div class="metric-extra"><span></span><span>预计 4 小时内完成</span></div> -->
</div>
<div class="metric-card">
<div class="metric-label">产能达成率</div>
<div class="metric-value accent" ref="dayRateEl"></div>
<div class="metric-extra"><span>目标 80%</span><span>状态良好</span></div>
<!-- <div class="metric-extra"><span>目标 80%</span><span>状态良好</span></div> -->
</div>
</div>
</div>
@ -74,7 +74,7 @@ const initChart = () => {
emphasis: { scale: false },
data: [
{ value: day.plan - day.pending, name: '已排产', itemStyle: { color: colors.cyan } },
{ value: day.pending, name: '待生产', itemStyle: { color: 'rgba(15,23,42,0.8)' } }
{ value: day.pending, name: '已生产', itemStyle: { color: colors.green } }
]
}
]

@ -19,26 +19,26 @@
<thead>
<tr>
<th>产线名称</th>
<th>排产</th>
<th>计划</th>
<th>产品名称</th>
<th>计划数量</th>
<th>完工数量</th>
<th>完工</th>
<th>合格</th>
</tr>
</thead>
<tbody ref="tbodyRef">
<tr v-for="(r, index) in tasks" :key="index">
<td>{{ r.line }}</td>
<td :style="{ color: colors.cyan }">{{ r.order }}</td>
<td :title="r.product">{{ r.product }}</td>
<td>{{ r.plan }}</td>
<td>{{ r.done }}</td>
<td>{{ r.feedingPipelineName }}</td>
<td :style="{ color: colors.cyan }">{{ r.code }}</td>
<td :title="r.productName">{{ r.productName }}</td>
<td>{{ r.planNumber }}</td>
<td>{{ r.wangongNumber }}</td>
<td>
<div style="display:flex; flex-direction:column; gap:4px; align-items:center;">
<div class="progress-bar">
<div class="progress-fill" :style="{ width: getRate(r) + '%', background: getRateColor(r) }"></div>
</div>
<span :style="{ color: getRateColor(r), fontWeight: 700 }">{{ getRate(r) }}%</span>
<span :style="{ color: getRateColor(r), fontWeight: 700 }">{{ r.passRate }}%</span>
</div>
</td>
</tr>
@ -51,6 +51,7 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { PlanApi, PlanVO } from '@/api/mes/plan'
const colors = {
blue: '#1e90ff',
@ -61,18 +62,7 @@ const colors = {
danger: '#ef4444'
}
const tasks = [
{ line: '产线A', order: 'ORD-2025121701', product: '智能模组X1', plan: 1200, done: 1080 },
{ line: '产线B', order: 'ORD-2025121702', product: '高密电芯M2', plan: 1500, done: 1120 },
{ line: '产线C', order: 'ORD-2025121703', product: '组装组件A5', plan: 800, done: 760 },
{ line: '产线D', order: 'ORD-2025121704', product: '精密外壳S7', plan: 600, done: 480 },
{ line: '产线E', order: 'ORD-2025121705', product: '控制板K9', plan: 900, done: 855 },
{ line: '产线F', order: 'ORD-2025121706', product: '电源模组P3', plan: 1100, done: 990 },
{ line: '产线G', order: 'ORD-2025121707', product: '线束套件W4', plan: 700, done: 560 },
{ line: '产线H', order: 'ORD-2025121708', product: '散热组件H2', plan: 650, done: 559 },
{ line: '产线I', order: 'ORD-2025121709', product: '传感器C8', plan: 500, done: 450 },
{ line: '产线J', order: 'ORD-2025121710', product: '整机Z3', plan: 1000, done: 800 }
]
const tasks = ref<PlanVO[]>([])
const getRate = (r: any) => Math.round((r.done / r.plan) * 100)
@ -115,10 +105,12 @@ const startScroll = () => {
}, 5000)
}
onMounted(() => {
onMounted(async () => {
setBodyHeight()
startScroll()
window.addEventListener('resize', setBodyHeight)
tasks.value = await PlanApi.getProductPlans()
// console.log(tasks.value)
})
onUnmounted(() => {

@ -22,10 +22,11 @@
import { ref, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
import { colors, style } from '../utils'
import { PlanApi } from '@/api/mes/plan'
const weekDays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
const weekPlan = [2600, 2800, 3000, 3100, 3200, 2900, 2700]
const weekReal = [2550, 2750, 2950, 3050, 3180, 2850, 2680]
const weekDays = ref()
const weekPlan = ref()
const weekReal = ref()
const chartRef = ref<HTMLElement | null>(null)
let chart: echarts.ECharts | null = null
@ -38,7 +39,7 @@ const initChart = () => {
tooltip: { trigger: 'axis' },
legend: { top: 0, right: 0, textStyle: style.legendText },
grid: { top: '20%', left: '6%', right: '6%', bottom: '10%', containLabel: true },
xAxis: { type: 'category', data: weekDays, axisLine: style.axisLine, axisLabel: style.axisLabel },
xAxis: { type: 'category', data: weekDays.value, axisLine: style.axisLine, axisLabel: style.axisLabel },
yAxis: { type: 'value', axisLine: style.axisLine, axisLabel: style.axisLabel, splitLine: style.splitLine },
series: [
{
@ -47,7 +48,7 @@ const initChart = () => {
smooth: true,
showSymbol: false,
lineStyle: { width: 2, color: colors.purple },
data: weekPlan
data: weekPlan.value
},
{
name: '实际产量',
@ -63,7 +64,7 @@ const initChart = () => {
{ offset: 1, color: 'rgba(15,23,42,0.8)' }
])
},
data: weekReal
data: weekReal.value
}
]
})
@ -73,9 +74,14 @@ const resizeHandler = () => {
chart?.resize()
}
onMounted(() => {
initChart()
onMounted( async() => {
window.addEventListener('resize', resizeHandler)
const data = await PlanApi.getWeekTrend()
weekDays.value = data.weekDays
weekPlan.value = data.weekPlan
weekReal.value = data.weekReal
initChart()
// console.log(data)
})
onUnmounted(() => {

Loading…
Cancel
Save