| | |
| | | const minutes = Math.floor(seconds / 60); |
| | | return `${Math.floor(minutes / 60)}小时${minutes % 60}分${seconds % 60}秒`; |
| | | } |
| | | onMounted(() => { void load(); void loadCollect(); }); |
| | | /** ===== 停机汇总报表(跨设备,按采集间隔推算) ===== */ |
| | | interface DowntimeItem { |
| | | machineryId: number; |
| | | machineryCode: string; |
| | | machineryName: string; |
| | | deviceCode: string; |
| | | sampleCount: number; |
| | | downtimeCount: number; |
| | | downtimeMinutes: number; |
| | | intervals: { start: string; end: string; seconds: number }[]; |
| | | } |
| | | interface DowntimeDetail { |
| | | startTime: string; |
| | | endTime: string; |
| | | timeoutMinutes: number; |
| | | totalMinutes: number; |
| | | downtimeMinutes: number; |
| | | downtimeRate: number; |
| | | items: DowntimeItem[]; |
| | | } |
| | | const downtimeRange = ref<[Dayjs, Dayjs]>([dayjs().subtract(7, 'day'), dayjs()]); |
| | | const downtimeLoading = ref(false); |
| | | const downtimeResult = ref<DowntimeDetail>(); |
| | | const downtimeError = ref(''); |
| | | const downtimeColumns = [ |
| | | { title: '设备编码', dataIndex: 'machineryCode' }, |
| | | { title: '设备名称', dataIndex: 'machineryName' }, |
| | | { title: '数采设备', dataIndex: 'deviceCode' }, |
| | | { title: '采样数', dataIndex: 'sampleCount' }, |
| | | { title: '停机次数', dataIndex: 'downtimeCount' }, |
| | | { title: '停机合计(分)', dataIndex: 'downtimeMinutes' }, |
| | | ]; |
| | | |
| | | async function loadDowntime() { |
| | | downtimeLoading.value = true; |
| | | downtimeError.value = ''; |
| | | try { |
| | | const range = downtimeRange.value; |
| | | downtimeResult.value = await requestClient.get<DowntimeDetail>( |
| | | '/mes/dv/statistics/downtime', |
| | | { |
| | | params: { |
| | | startTime: range[0].startOf('day').format('YYYY-MM-DD HH:mm:ss'), |
| | | endTime: range[1].endOf('day').format('YYYY-MM-DD HH:mm:ss'), |
| | | }, |
| | | }, |
| | | ); |
| | | } catch (e: unknown) { |
| | | downtimeResult.value = undefined; |
| | | // 保留后端给出的可读原因(如超出保留期、区间过长) |
| | | downtimeError.value = (e as Error).message || '停机报表加载失败'; |
| | | } finally { |
| | | downtimeLoading.value = false; |
| | | } |
| | | } |
| | | |
| | | onMounted(() => { void load(); void loadCollect(); void loadDowntime(); }); |
| | | </script> |
| | | |
| | | <template> |
| | |
| | | <Card title="设备明细"> |
| | | <Table :columns="columns" :data-source="result?.items ?? []" :loading="loading" row-key="machineryId" :scroll="{ x: 1000 }" /> |
| | | </Card> |
| | | <Card title="停机汇总报表(跨设备)"> |
| | | <template #extra> |
| | | <div class="flex items-center gap-2"> |
| | | <DatePicker.RangePicker v-model:value="downtimeRange" /> |
| | | <Button type="primary" :loading="downtimeLoading" @click="loadDowntime">查询</Button> |
| | | </div> |
| | | </template> |
| | | <Alert class="mb-4" type="info" show-icon message="按采集间隔超过离线阈值推算停机;通信中断计入停机但不标记为机械故障。单次最多查询 31 天,且不得超出数采历史保留期。" /> |
| | | <Alert v-if="downtimeError" class="mb-4" type="warning" show-icon :message="downtimeError" /> |
| | | <template v-if="downtimeResult"> |
| | | <Row :gutter="16" class="mb-4"> |
| | | <Col :span="6"><Statistic title="停机合计(分)" :value="downtimeResult.downtimeMinutes" /></Col> |
| | | <Col :span="6"><Statistic title="停机率" :value="downtimeResult.downtimeRate" suffix="%" /></Col> |
| | | <Col :span="6"><Statistic title="统计区间(分)" :value="downtimeResult.totalMinutes" /></Col> |
| | | <Col :span="6"><Statistic title="设备数" :value="downtimeResult.items?.length ?? 0" /></Col> |
| | | </Row> |
| | | <Table :columns="downtimeColumns" :data-source="downtimeResult.items ?? []" :loading="downtimeLoading" row-key="machineryId" :scroll="{ x: 900 }" size="small" bordered> |
| | | <template #bodyCell="{ column, record }"> |
| | | <template v-if="column.dataIndex === 'downtimeMinutes'"> |
| | | {{ record.downtimeMinutes }} |
| | | </template> |
| | | <template v-else-if="column.dataIndex === 'sampleCount'"> |
| | | {{ record.sampleCount }} |
| | | </template> |
| | | </template> |
| | | </Table> |
| | | </template> |
| | | </Card> |
| | | <Card title="设备数采实时状态"> |
| | | <template #extra><Button :loading="collectLoading" @click="loadCollect">刷新</Button></template> |
| | | <Alert v-if="collectError" type="warning" show-icon message="数采状态加载失败,请检查数采服务后重试。" class="mb-4" /> |