You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
6.0 KiB

<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import moment from 'moment'
import { Card, Descriptions, DescriptionsItem, message } from 'ant-design-vue'
import { useRoute, useRouter } from 'vue-router'
import { useI18n } from '@/hooks/web/useI18n'
import { BasicForm, useForm } from '@/components/Form'
import { BasicTable, useTable } from '@/components/Table'
import HistoryLine from '../../exa/HistoryLine.vue'
import { detailColumns, instantForm } from './instant.data'
import { getInstant, getInstantChart, getInstantPoint } from '@/api/alert/run/instant'
import echarts from '@/utils/lib/echarts'
/* =======================
* 类型定义严格 TS 核心
* ======================= */
interface BasicInfo {
mpName?: string
createName?: string
createTime?: string
updateName?: string
updateTime?: string
algorithmShortname?: string
modelInfo?: string
}
interface ModelInfo {
sampling?: string | number
rate?: number
principal?: number
precision?: number
pointInfo?: any[]
}
interface HistoryItem {
title: string
name: string
seriesData: any[]
}
/* ======================= */
defineOptions({ name: 'InstantDetail' })
const route = useRoute()
const router = useRouter()
const { t } = useI18n()
const instantId = ref<number | null>(Number(route.query.mpId) || null)
const loadingBasic = ref(false)
const loadingChart = ref(false)
const basicInfo = ref<BasicInfo>({})
const modelInfo = ref<ModelInfo>({})
const pointInfo = ref<any[]>([])
const pointList = ref<any[]>([])
const historyList = ref<HistoryItem[]>([])
/* =======================
* 表单
* ======================= */
const [registerForm, { getFieldsValue, setProps }] = useForm({
labelWidth: 100,
schemas: instantForm,
showResetButton: false,
layout: 'horizontal',
fieldMapToTime: [['time', ['startTime', 'endTime'], 'YYYY-MM-DD HH:mm:ss']],
})
/* =======================
* 表格
* ======================= */
const [registerTable] = useTable({
title: '测点列表',
size: 'small',
dataSource: pointList,
columns: detailColumns,
useSearchForm: false,
showIndexColumn: false,
actionColumn: {
width: 140,
title: t('common.action'),
dataIndex: 'action',
},
})
/* =======================
* 生命周期
* ======================= */
onMounted(async () => {
if (!instantId.value) return
try {
loadingBasic.value = true
const res = await getInstant(instantId.value)
if (!res) return
basicInfo.value = res
if (res.modelInfo) {
try {
const parsed: ModelInfo = JSON.parse(res.modelInfo)
modelInfo.value = parsed
pointInfo.value = Array.isArray(parsed.pointInfo) ? parsed.pointInfo : []
} catch (e) {
console.error('modelInfo JSON 解析失败', e)
}
}
pointList.value = (await getInstantPoint(instantId.value)) || []
await getChartsData()
} catch (e) {
message.error('加载实例详情失败')
} finally {
loadingBasic.value = false
}
})
/* =======================
* 事件
* ======================= */
async function getChartsData() {
if (!instantId.value) return
loadingChart.value = true
setProps({ submitButtonOptions: { loading: true } })
try {
const formValue = getFieldsValue() || {}
const res = await getInstantChart({ id: instantId.value, ...formValue })
historyList.value = Array.isArray(res) ? res : []
if (historyList.value.length) {
echarts.connect('async')
}
} catch (e) {
historyList.value = []
message.error('获取图表数据失败')
} finally {
loadingChart.value = false
setProps({ submitButtonOptions: { loading: false } })
}
}
function handleDetail(record: any) {
router.push('/run/instant/detail')
}
</script>
<template>
<div>
<Card :loading="loadingBasic">
<Descriptions
size="small"
title="模型基本信息"
bordered
:column="{ xxl: 4, xl: 3, lg: 3, md: 3, sm: 2, xs: 1 }"
>
<DescriptionsItem label="实例名称" :span="4">{{ basicInfo.mpName || '-' }}</DescriptionsItem>
<DescriptionsItem label="创建人">{{ basicInfo.createName || '-' }}</DescriptionsItem>
<DescriptionsItem label="创建时间">{{ basicInfo.createTime ? moment(basicInfo.createTime).format('YYYY-MM-DD HH:mm:ss') : '-' }}</DescriptionsItem>
<DescriptionsItem label="最近修改人">{{ basicInfo.updateName || '-' }}</DescriptionsItem>
<DescriptionsItem label="最近修改时间">{{ basicInfo.updateTime ? moment(basicInfo.updateTime).format('YYYY-MM-DD HH:mm:ss') : '-' }}</DescriptionsItem>
<DescriptionsItem label="算法">{{ basicInfo.algorithmShortname || '-' }}</DescriptionsItem>
<DescriptionsItem label="训练采样间隔">{{ modelInfo.sampling ?? '-' }}</DescriptionsItem>
<DescriptionsItem label="参数个数">{{ pointInfo.length }}</DescriptionsItem>
<DescriptionsItem label="最小主元贡献率">{{ modelInfo.rate ?? '-' }}</DescriptionsItem>
<DescriptionsItem label="主元个数">{{ modelInfo.principal ?? '-' }}</DescriptionsItem>
<DescriptionsItem label="模型精度">{{ modelInfo.precision ?? '-' }}</DescriptionsItem>
</Descriptions>
</Card>
<Card>
<BasicTable @register="registerTable">
<template #detail="{ record }">
<a class="click-status" @click="handleDetail(record)">{{ record.mpName }}</a>
</template>
</BasicTable>
</Card>
<Card>
<BasicForm @register="registerForm" @submit="getChartsData" />
</Card>
<Card :loading="loadingChart">
<div v-if="historyList.length">
<div v-for="(item, index) in historyList" :key="index" style="border:1px solid #ccc">
<HistoryLine
:is-async="index !== 0"
:title="item.title"
:data="item.seriesData"
:name="item.name"
height="250px"
/>
</div>
</div>
<div v-else class="empty">暂无数据</div>
</Card>
</div>
</template>
<style lang="less" scoped>
:deep(.ant-table-body) {
height: 100% !important;
max-height: 100% !important;
}
</style>