Compare commits

..

No commits in common. 'f4d3a4de8260c2ae8ab1934c9e38be9bdbd6ff75' and '49f600191adf33c64643d4b8a94bdb61ecff4d0c' have entirely different histories.

@ -8,14 +8,8 @@ export interface DeviceOperationRecordVO {
totalStandbyTime: number totalStandbyTime: number
totalFaultTime: number totalFaultTime: number
totalWarningTime: number totalWarningTime: number
totalOfflineTime?: number
utilizationRate: string utilizationRate: string
powerOnRate?: string powerOnRate?: string
startTime?: string
endTime?: string
lineCode?: string
lineName?: string
deviceId?: number
} }
export interface DeviceOperationRecordPageParams { export interface DeviceOperationRecordPageParams {
@ -28,23 +22,10 @@ export interface DeviceOperationRecordPageParams {
ids?: string ids?: string
} }
export interface DeviceOperationListParams {
deviceCode?: string
deviceName?: string
startTime?: string
endTime?: string
lineCode?: string
lineName?: string
deviceId?: number | string
}
export const DeviceOperationRecordApi = { export const DeviceOperationRecordApi = {
getDeviceOperationRecordPage: async (params: DeviceOperationRecordPageParams) => { getDeviceOperationRecordPage: async (params: DeviceOperationRecordPageParams) => {
return await request.get({ url: `/iot/device-operation-record/deviceOperationPage`, params }) return await request.get({ url: `/iot/device-operation-record/deviceOperationPage`, params })
}, },
getDeviceOperationList: async (params?: DeviceOperationListParams) => {
return await request.get({ url: `/iot/device-operation-record/deviceOperationList`, params })
},
exportDeviceOperationReport: async (params: DeviceOperationRecordPageParams) => { exportDeviceOperationReport: async (params: DeviceOperationRecordPageParams) => {
return await request.download({ url: `/iot/device-operation-record/export-device-operation-report`, params }) return await request.download({ url: `/iot/device-operation-record/export-device-operation-report`, params })
} }

@ -45,7 +45,6 @@
:disabled-date="disableFutureDate" :disabled-date="disableFutureDate"
@change="(value) => handleDateRangeChange(group, value)" @change="(value) => handleDateRangeChange(group, value)"
/> />
<div class="mt-4px text-12px text-gray-500">最多选择 8 小时且不能选择未来日期</div>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>

@ -267,18 +267,6 @@ const parseIdsValue = (value: any): number[] => {
.filter((v) => !Number.isNaN(v)) .filter((v) => !Number.isNaN(v))
} }
const normalizeNumberish = (value: any): number | undefined => {
if (value === null || value === undefined || value === '') return undefined
if (typeof value === 'number') return Number.isFinite(value) ? value : undefined
if (typeof value === 'string') {
const trimmed = value.trim()
if (!trimmed) return undefined
const n = Number(trimmed)
return Number.isFinite(n) ? n : undefined
}
return undefined
}
const normalizeYmd = (value: any): string | undefined => { const normalizeYmd = (value: any): string | undefined => {
if (value === null || value === undefined || value === '') return undefined if (value === null || value === undefined || value === '') return undefined
if (typeof value === 'string') { if (typeof value === 'string') {
@ -487,7 +475,6 @@ const open = async (type: string, id?: number, defaultDeviceTypeId?: number) =>
formData.value = { formData.value = {
...initFormData(), ...initFormData(),
...(detail as any), ...(detail as any),
deviceType: normalizeNumberish((detail as any)?.deviceType),
deviceManagerIds: parseIdsValue((detail as any)?.deviceManager), deviceManagerIds: parseIdsValue((detail as any)?.deviceManager),
productionDate: normalizeYmd((detail as any)?.productionDate), productionDate: normalizeYmd((detail as any)?.productionDate),
factoryEntryDate: normalizeYmd((detail as any)?.factoryEntryDate), factoryEntryDate: normalizeYmd((detail as any)?.factoryEntryDate),
@ -516,7 +503,6 @@ const submitForm = async () => {
try { try {
const data = { const data = {
...(formData.value as any), ...(formData.value as any),
deviceType: normalizeNumberish(formData.value.deviceType),
productionDate: normalizeYmd(formData.value.productionDate), productionDate: normalizeYmd(formData.value.productionDate),
factoryEntryDate: normalizeYmd(formData.value.factoryEntryDate), factoryEntryDate: normalizeYmd(formData.value.factoryEntryDate),
deviceManager: formData.value.deviceManagerIds?.length ? formData.value.deviceManagerIds.join(',') : undefined, deviceManager: formData.value.deviceManagerIds?.length ? formData.value.deviceManagerIds.join(',') : undefined,

@ -17,59 +17,23 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue' import { ref, onMounted, onUnmounted } from 'vue'
import dayjs from 'dayjs'
import { useChart, colors } from '../utils' import { useChart, colors } from '../utils'
import { DeviceOperationRecordApi, type DeviceOperationRecordVO } from '@/api/iot/deviceOperationRecord'
const { init, instance } = useChart('chart-today') const { init, instance } = useChart('chart-today')
type LineMetric = { name: string; run: number; avail: number } const lineMetrics = [
const lineMetrics = ref<LineMetric[]>([]) { name: '产线A', run: 88, avail: 82 },
{ name: '产线B', run: 86, avail: 80 },
{ name: '产线C', run: 90, avail: 84 },
{ name: '产线D', run: 85, avail: 79 },
{ name: '产线E', run: 87, avail: 81 },
{ name: '产线F', run: 92, avail: 86 }
]
const currentLineName = ref('') const currentLineName = ref(lineMetrics[0].name)
let timer: ReturnType<typeof setInterval> | null = null let timer: ReturnType<typeof setInterval> | null = null
let currentLineIndex = 0 let currentLineIndex = 0
const toRateNumber = (value: unknown) => {
if (typeof value === 'number') {
if (!Number.isFinite(value)) return 0
if (value >= 0 && value <= 1) return Math.round(value * 10000) / 100
return Math.max(0, Math.min(100, Math.round(value * 100) / 100))
}
const raw = String(value ?? '').trim()
if (!raw) return 0
const numeric = Number(raw.replace(/[^\d.+-]/g, ''))
if (!Number.isFinite(numeric)) return 0
if (raw.includes('%')) return Math.max(0, Math.min(100, Math.round(numeric * 100) / 100))
if (numeric >= 0 && numeric <= 1) return Math.round(numeric * 10000) / 100
return Math.max(0, Math.min(100, Math.round(numeric * 100) / 100))
}
const buildLineMetrics = (rows: DeviceOperationRecordVO[]) => {
const groupMap = new Map<string, { name: string; power: number[]; util: number[] }>()
rows.forEach((row) => {
const name = String((row as any)?.lineName ?? (row as any)?.lineCode ?? row.deviceName ?? row.deviceCode ?? '').trim()
if (!name) return
const power = toRateNumber((row as any)?.powerOnRate)
const util = toRateNumber((row as any)?.utilizationRate)
const key = name
if (!groupMap.has(key)) {
groupMap.set(key, { name, power: [], util: [] })
}
const g = groupMap.get(key)!
if (Number.isFinite(power)) g.power.push(power)
if (Number.isFinite(util)) g.util.push(util)
})
const avg = (arr: number[]) => (arr.length ? arr.reduce((s, v) => s + v, 0) / arr.length : 0)
const list = Array.from(groupMap.values()).map((g) => ({
name: g.name,
run: Math.round(avg(g.power) * 100) / 100,
avail: Math.round(avg(g.util) * 100) / 100
}))
list.sort((a, b) => a.name.localeCompare(b.name))
return list
}
const gaugeOption = (run: number, avail: number) => { const gaugeOption = (run: number, avail: number) => {
return { return {
backgroundColor: 'transparent', backgroundColor: 'transparent',
@ -116,56 +80,25 @@ const gaugeOption = (run: number, avail: number) => {
} }
} }
const renderCurrent = () => { onMounted(() => {
const list = lineMetrics.value
if (!list.length) {
currentLineName.value = '暂无数据'
const c = instance()
if (c) c.setOption(gaugeOption(0, 0))
return
}
const idx = Math.max(0, Math.min(list.length - 1, currentLineIndex))
const item = list[idx]
currentLineName.value = item.name
const c = instance()
if (c) c.setOption(gaugeOption(item.run, item.avail))
}
const loadTodayOps = async () => {
const res = await DeviceOperationRecordApi.getDeviceOperationList({})
const rawList = Array.isArray(res) ? res : (res as any)?.list || (res as any)?.data || []
const list = Array.isArray(rawList) ? (rawList as DeviceOperationRecordVO[]) : []
lineMetrics.value = buildLineMetrics(list)
currentLineIndex = 0
renderCurrent()
}
const startRotate = () => {
if (timer) clearInterval(timer)
timer = null
if (lineMetrics.value.length <= 1) return
timer = setInterval(() => {
const list = lineMetrics.value
if (!list.length) return
currentLineIndex = (currentLineIndex + 1) % list.length
renderCurrent()
}, 8000)
}
onMounted(async () => {
const chart = init() const chart = init()
if (!chart) return if (!chart) return
chart.setOption(gaugeOption(0, 0)) // Initial render
try { chart.setOption(gaugeOption(lineMetrics[0].run, lineMetrics[0].avail))
await loadTodayOps()
} catch (e) { // Start rotation
console.error('Failed to load today ops:', e) timer = setInterval(() => {
lineMetrics.value = [] currentLineIndex = (currentLineIndex + 1) % lineMetrics.length
currentLineIndex = 0 const item = lineMetrics[currentLineIndex]
renderCurrent() currentLineName.value = item.name
}
startRotate() // Update chart
const c = instance()
if (c) {
c.setOption(gaugeOption(item.run, item.avail))
}
}, 3000)
}) })
onUnmounted(() => { onUnmounted(() => {

Loading…
Cancel
Save