|
|
|
|
@ -4,47 +4,31 @@ import type {
|
|
|
|
|
HourlyStatusItem,
|
|
|
|
|
OverviewOption,
|
|
|
|
|
RunOverviewData,
|
|
|
|
|
RunOverviewQueryParams,
|
|
|
|
|
RunOverviewMetric,
|
|
|
|
|
RunOverviewQueryParams,
|
|
|
|
|
RunStatus
|
|
|
|
|
} from './components/types'
|
|
|
|
|
|
|
|
|
|
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'
|
|
|
|
|
|
|
|
|
|
export const GROUP_OPTIONS: OverviewOption[] = [
|
|
|
|
|
{ label: 'SMT一组', value: 'group-1' },
|
|
|
|
|
{ label: '成型二组', value: 'group-2' },
|
|
|
|
|
{ label: '总装三组', value: 'group-3' }
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
export const DEVICE_OPTIONS: OverviewOption[] = [
|
|
|
|
|
{ label: '模拟干燥设备04', value: 'device-01' },
|
|
|
|
|
{ label: '模拟干燥设备03', value: 'device-02' },
|
|
|
|
|
{ label: '模拟干燥设备02', value: 'device-03' },
|
|
|
|
|
{ label: '成型模拟设备05', value: 'device-04' },
|
|
|
|
|
{ label: '成型模拟设备04', value: 'device-05' },
|
|
|
|
|
{ label: '模拟干燥设备', value: 'device-06' },
|
|
|
|
|
{ label: '成型模拟设备02', value: 'device-07' },
|
|
|
|
|
{ label: '成型模拟设备01', value: 'device-08' },
|
|
|
|
|
{ label: '物流输送设备01', value: 'device-09' },
|
|
|
|
|
{ label: '包装工作站02', value: 'device-10' },
|
|
|
|
|
{ label: '包装工作站03', value: 'device-11' },
|
|
|
|
|
{ label: '拧紧设备01', value: 'device-12' },
|
|
|
|
|
{ label: '视觉检测设备01', value: 'device-13' }
|
|
|
|
|
const FALLBACK_DEVICE_OPTIONS: OverviewOption[] = [
|
|
|
|
|
{ label: '模拟设备01', value: 'device-01' },
|
|
|
|
|
{ label: '模拟设备02', value: 'device-02' },
|
|
|
|
|
{ label: '模拟设备03', value: 'device-03' },
|
|
|
|
|
{ label: '模拟设备04', value: 'device-04' },
|
|
|
|
|
{ label: '模拟设备05', value: 'device-05' },
|
|
|
|
|
{ label: '模拟设备06', value: 'device-06' },
|
|
|
|
|
{ label: '模拟设备07', value: 'device-07' },
|
|
|
|
|
{ label: '模拟设备08', value: 'device-08' },
|
|
|
|
|
{ label: '模拟设备09', value: 'device-09' },
|
|
|
|
|
{ label: '模拟设备10', value: 'device-10' },
|
|
|
|
|
{ label: '模拟设备11', value: 'device-11' },
|
|
|
|
|
{ label: '模拟设备12', value: 'device-12' },
|
|
|
|
|
{ label: '模拟设备13', value: 'device-13' }
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const shiftTimeline = (segments: Array<{ status: RunStatus; startHour: number; endHour: number }>, offset: number) =>
|
|
|
|
|
segments.map((segment, index) => {
|
|
|
|
|
let nextStart = segment.startHour + offset
|
|
|
|
|
let nextEnd = segment.endHour + offset
|
|
|
|
|
if (index === 0 && nextStart < 0) nextStart = 0
|
|
|
|
|
if (index === segments.length - 1 && nextEnd > 24) nextEnd = 24
|
|
|
|
|
return {
|
|
|
|
|
...segment,
|
|
|
|
|
startHour: Math.max(0, Math.min(24, Number(nextStart.toFixed(2)))),
|
|
|
|
|
endHour: Math.max(0, Math.min(24, Number(nextEnd.toFixed(2))))
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
const UTILIZATION_RATES = [82.35, 76.12, 68.54, 75.63, 72.18, 91.24, 65.32, 78.44, 71.05, 83.67, 69.18, 87.42, 74.56]
|
|
|
|
|
const TIMELINE_OFFSETS = [0, -0.3, 0.8, -0.5, 0.45, 1.05, -1.1, 0.25, -0.75, 0.6, -0.2, 1.2, -0.45]
|
|
|
|
|
|
|
|
|
|
const BASE_SEGMENTS = [
|
|
|
|
|
{ status: 'running' as const, startHour: 0, endHour: 2.7 },
|
|
|
|
|
@ -65,33 +49,43 @@ const BASE_SEGMENTS = [
|
|
|
|
|
{ status: 'offline' as const, startHour: 23.7, endHour: 24 }
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const TIMELINE_OFFSETS = [0, -0.3, 0.8, -0.5, 0.45, 1.05, -1.1, 0.25, -0.75, 0.6, -0.2, 1.2, -0.45]
|
|
|
|
|
const shiftTimeline = (segments: Array<{ status: RunStatus; startHour: number; endHour: number }>, offset: number) =>
|
|
|
|
|
segments.map((segment, index) => {
|
|
|
|
|
let nextStart = segment.startHour + offset
|
|
|
|
|
let nextEnd = segment.endHour + offset
|
|
|
|
|
if (index === 0 && nextStart < 0) nextStart = 0
|
|
|
|
|
if (index === segments.length - 1 && nextEnd > 24) nextEnd = 24
|
|
|
|
|
return {
|
|
|
|
|
...segment,
|
|
|
|
|
startHour: Math.max(0, Math.min(24, Number(nextStart.toFixed(2)))),
|
|
|
|
|
endHour: Math.max(0, Math.min(24, Number(nextEnd.toFixed(2))))
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
export const buildDefaultQueryParams = (): RunOverviewQueryParams => {
|
|
|
|
|
const start = dayjs().startOf('day')
|
|
|
|
|
const end = dayjs().endOf('day')
|
|
|
|
|
return {
|
|
|
|
|
groupId: GROUP_OPTIONS[0].value,
|
|
|
|
|
deviceId: '',
|
|
|
|
|
groupId: '',
|
|
|
|
|
deviceId: [],
|
|
|
|
|
quickRange: 'today',
|
|
|
|
|
timeRange: [start.format(DATE_TIME_FORMAT), end.format(DATE_TIME_FORMAT)]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const toTimelineRows = (): DeviceTimelineRow[] =>
|
|
|
|
|
DEVICE_OPTIONS.map((device, index) => ({
|
|
|
|
|
const toTimelineRows = (deviceOptions: OverviewOption[]): DeviceTimelineRow[] =>
|
|
|
|
|
deviceOptions.map((device, index) => ({
|
|
|
|
|
id: device.value,
|
|
|
|
|
name: device.label,
|
|
|
|
|
utilizationRate: [82.35, 76.12, 68.54, 75.63, 72.18, 91.24, 65.32, 78.44, 71.05, 83.67, 69.18, 87.42, 74.56][index],
|
|
|
|
|
segments: shiftTimeline(BASE_SEGMENTS, TIMELINE_OFFSETS[index] || 0)
|
|
|
|
|
utilizationRate: UTILIZATION_RATES[index % UTILIZATION_RATES.length],
|
|
|
|
|
segments: shiftTimeline(BASE_SEGMENTS, TIMELINE_OFFSETS[index % TIMELINE_OFFSETS.length])
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
const toHourlyStatus = (summaryFactor: number): HourlyStatusItem[] => {
|
|
|
|
|
return Array.from({ length: 24 }, (_, hour) => {
|
|
|
|
|
const toHourlyStatus = (summaryFactor: number): HourlyStatusItem[] =>
|
|
|
|
|
Array.from({ length: 24 }, (_, hour) => {
|
|
|
|
|
const runningBase = 74 + Math.sin((hour / 24) * Math.PI * 3) * 14 + summaryFactor * 2
|
|
|
|
|
const standbyBase = 10 + Math.cos((hour / 24) * Math.PI * 4) * 7
|
|
|
|
|
const faultBase = 2 + Math.max(0, Math.sin((hour - 5) / 2.2)) * 5
|
|
|
|
|
const offlineBase = 100 - runningBase - standbyBase - faultBase
|
|
|
|
|
|
|
|
|
|
const running = Math.max(48, Math.min(88, Number(runningBase.toFixed(2))))
|
|
|
|
|
const standby = Math.max(4, Math.min(26, Number(standbyBase.toFixed(2))))
|
|
|
|
|
@ -106,7 +100,6 @@ const toHourlyStatus = (summaryFactor: number): HourlyStatusItem[] => {
|
|
|
|
|
offline
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const createMetrics = (summaryFactor: number): RunOverviewMetric[] => [
|
|
|
|
|
{
|
|
|
|
|
@ -153,7 +146,10 @@ const createSummary = (summaryFactor: number) => {
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const buildRunOverviewData = (query: RunOverviewQueryParams): RunOverviewData => {
|
|
|
|
|
export const buildRunOverviewData = (
|
|
|
|
|
query: RunOverviewQueryParams,
|
|
|
|
|
deviceOptions: OverviewOption[] = FALLBACK_DEVICE_OPTIONS
|
|
|
|
|
): RunOverviewData => {
|
|
|
|
|
const summaryFactor =
|
|
|
|
|
query.quickRange === 'today'
|
|
|
|
|
? 0
|
|
|
|
|
@ -165,8 +161,8 @@ export const buildRunOverviewData = (query: RunOverviewQueryParams): RunOverview
|
|
|
|
|
? 0.45
|
|
|
|
|
: 0.15
|
|
|
|
|
|
|
|
|
|
const rows = toTimelineRows()
|
|
|
|
|
const filteredRows = query.deviceId ? rows.filter((row) => row.id === query.deviceId) : rows
|
|
|
|
|
const rows = toTimelineRows(deviceOptions.length > 0 ? deviceOptions : FALLBACK_DEVICE_OPTIONS)
|
|
|
|
|
const filteredRows = query.deviceId.length > 0 ? rows.filter((row) => query.deviceId.includes(row.id)) : rows
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
metrics: createMetrics(summaryFactor),
|
|
|
|
|
|