30 changed files with 2483 additions and 438 deletions
@ -0,0 +1,10 @@ |
|||
import { defHttp } from '@/utils/http/axios' |
|||
|
|||
export interface CalcGroupPageReqVO extends PageParam { |
|||
unitId?: number |
|||
} |
|||
|
|||
// 查询计算组列表-不分页
|
|||
export function getCalcGroupList(params: CalcGroupPageReqVO) { |
|||
return defHttp.get({ url: '/alert/calcgroup/list', params }) |
|||
} |
|||
@ -0,0 +1,87 @@ |
|||
import qs from 'qs' |
|||
import { defHttp } from '@/utils/http/axios' |
|||
|
|||
export interface InstantPageReqVO extends PageParam { |
|||
mpName?: string |
|||
|
|||
} |
|||
|
|||
export interface InstantVO { |
|||
id: number |
|||
status: number |
|||
modelId: number |
|||
pointInfo: Array<any> |
|||
mpName: string |
|||
intervalTime: number |
|||
visible: number |
|||
hisSto: number |
|||
calcGroup: number |
|||
modelVersionId: number |
|||
} |
|||
|
|||
export interface EXAHistoryReqVO { |
|||
itemName?: string |
|||
startTime?: Date |
|||
endTime?: Date |
|||
interval?: string |
|||
} |
|||
|
|||
export interface InstantChartReqVO extends EXAHistoryReqVO { |
|||
id?: number |
|||
|
|||
} |
|||
|
|||
export interface EXANowReqVO { |
|||
itemName?: string |
|||
|
|||
} |
|||
|
|||
export interface EXAPoint { |
|||
AssetCode?: string |
|||
ItemName?: string |
|||
GroupName?: string |
|||
ItemType?: number |
|||
Descriptor?: string |
|||
EngUnits?: string |
|||
Source?: string |
|||
AutoSave?: number |
|||
UpperBound?: number |
|||
LowerBound?: number |
|||
UpperLimit?: number |
|||
LowerLimit?: number |
|||
UpperUpperLimit?: number |
|||
LowerLowerLimit?: number |
|||
Comment?: string |
|||
Note?: string |
|||
} |
|||
// 查询模型实例列表
|
|||
export function getInstantPage(params: InstantPageReqVO) { |
|||
return defHttp.get({ url: '/alert/instant/page', params }) |
|||
} |
|||
// 查询模型实例详情
|
|||
export function getInstant(id: number) { |
|||
return defHttp.get({ url: `/alert/instant/get?id=${id}` }) |
|||
} |
|||
// 新增模型实例
|
|||
export function createInstant(data: InstantVO) { |
|||
return defHttp.post({ url: '/alert/instant/create', data }) |
|||
} |
|||
|
|||
// 修改模型实例
|
|||
export function updateInstant(data: InstantVO) { |
|||
return defHttp.put({ url: '/alert/instant/update', data }) |
|||
} |
|||
|
|||
// 获取模型实例数量
|
|||
export function getInstantCount() { |
|||
return defHttp.get({ url: '/alert/instant/count' }) |
|||
} |
|||
|
|||
// 查询模型实例测点列表
|
|||
export function getInstantPoint(id: number) { |
|||
return defHttp.get({ url: `/alert/instant/getPoint?id=${id}` }) |
|||
} |
|||
// 查询模型实例测点曲线
|
|||
export function getInstantChart(data: InstantChartReqVO) { |
|||
return defHttp.post({ url: `/alert/instant/getChart`, data }) |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
import { defHttp } from '@/utils/http/axios' |
|||
|
|||
export interface ModelPageReqVO extends PageParam { |
|||
modelName?: string |
|||
} |
|||
|
|||
export interface ModelVersionPageReqVO extends PageParam { |
|||
modelId?: number |
|||
} |
|||
|
|||
// 查询模型实例列表
|
|||
export function getModelPage(params: ModelPageReqVO) { |
|||
return defHttp.get({ url: '/alert/model/page', params }) |
|||
} |
|||
|
|||
// 查询模型版本列表-不分页
|
|||
export function getModelVersionList(params: ModelVersionPageReqVO) { |
|||
return defHttp.get({ url: '/alert/model/version/list', params }) |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
import { defHttp } from '@/utils/http/axios' |
|||
|
|||
export interface WarnPageReqVO extends PageParam { |
|||
mpId?: string |
|||
} |
|||
|
|||
export interface WarnVO { |
|||
id: number |
|||
warnStatus: number |
|||
|
|||
} |
|||
|
|||
export interface EXAHistoryReqVO { |
|||
itemName?: string |
|||
startTime?: string |
|||
endTime?: string |
|||
interval?: string |
|||
} |
|||
|
|||
// 查询预警列表-分页
|
|||
export function getWarnPage(params: WarnPageReqVO) { |
|||
return defHttp.get({ url: '/alert/warn/page', params }) |
|||
} |
|||
|
|||
// 修改预警
|
|||
export function updateWarn(data: WarnVO) { |
|||
return defHttp.put({ url: '/alert/warn/update', data }) |
|||
} |
|||
|
|||
// 查询预警详情
|
|||
export function getWarn(id: number) { |
|||
return defHttp.get({ url: `/alert/warn/get?id=${id}` }) |
|||
} |
|||
@ -1,114 +0,0 @@ |
|||
<script lang="ts" setup> |
|||
import type { Ref } from 'vue' |
|||
import { onMounted, ref, watch } from 'vue' |
|||
import type { YAXisOption } from 'echarts/types/dist/shared' |
|||
import { useECharts } from '@/hooks/web/useECharts' |
|||
import { propTypes } from '@/utils/propTypes' |
|||
|
|||
const props = defineProps({ |
|||
height: { |
|||
type: String, |
|||
default: propTypes.string.def('500px'), |
|||
}, |
|||
name: { |
|||
type: Array<string>, |
|||
default: [], |
|||
}, |
|||
data: { |
|||
type: Array<Array<number>>, |
|||
default: () => [[]], |
|||
}, |
|||
width: propTypes.string.def('100%'), |
|||
// height: propTypes.string.def('70vh'), |
|||
}) |
|||
const chartRef = ref<HTMLDivElement | null>(null) |
|||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>) |
|||
onMounted(() => { |
|||
|
|||
}) |
|||
|
|||
// const yAxis = reactive<yAxisForm>({ |
|||
// type: 'value', |
|||
// scale: true, // 开启自适应刻度 |
|||
|
|||
// }) |
|||
watch( |
|||
() => props.data, |
|||
() => { |
|||
console.log(props.data) |
|||
const yAxis = ref<YAXisOption[]>([]) |
|||
const series = ref<any[]>([]) |
|||
|
|||
for (let i = 0; i < props.data.length; i++) { |
|||
yAxis.value.push({ |
|||
type: 'value', |
|||
show: false, |
|||
scale: true, // 开启自适应刻度 |
|||
}) |
|||
series.value.push({ |
|||
name: props.name[i], |
|||
type: 'line', |
|||
smooth: true, |
|||
itemStyle: { |
|||
normal: { |
|||
lineStyle: { |
|||
width: 3, // 0.1的线条是非常细的了 |
|||
}, |
|||
}, |
|||
}, |
|||
showSymbol: false, |
|||
data: props.data[i], |
|||
yAxisIndex: i, |
|||
}) |
|||
} |
|||
|
|||
setOptions({ |
|||
tooltip: { |
|||
trigger: 'axis', |
|||
position(pt) { |
|||
return [pt[0], '10%'] |
|||
}, |
|||
}, |
|||
title: { |
|||
left: 'center', |
|||
text: 'Large Ara Chart', |
|||
show: false, |
|||
}, |
|||
toolbox: { |
|||
feature: { |
|||
dataZoom: { |
|||
yAxisIndex: 'none', |
|||
}, |
|||
restore: {}, |
|||
saveAsImage: {}, |
|||
}, |
|||
}, |
|||
xAxis: { |
|||
type: 'time', |
|||
// boundaryGap: false, |
|||
}, |
|||
yAxis: yAxis.value, |
|||
legend: { |
|||
|
|||
}, |
|||
dataZoom: [ |
|||
{ |
|||
type: 'inside', |
|||
start: 0, |
|||
end: 100, |
|||
}, |
|||
{ |
|||
start: 0, |
|||
end: 100, |
|||
}, |
|||
], |
|||
series: series.value, |
|||
}) |
|||
}, |
|||
{ immediate: true }, |
|||
) |
|||
</script> |
|||
|
|||
<template> |
|||
<div ref="chartRef" :style="{ width, height }" /> |
|||
</template> |
|||
@ -0,0 +1,189 @@ |
|||
<script lang="ts" setup> |
|||
import type { Ref } from 'vue' |
|||
import { onMounted, ref, watch } from 'vue' |
|||
import type { YAXisOption } from 'echarts/types/dist/shared' |
|||
import moment from 'moment' |
|||
import { useECharts } from '@/hooks/web/useECharts' |
|||
import { propTypes } from '@/utils/propTypes' |
|||
|
|||
const props = defineProps({ |
|||
isAsync: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
height: { |
|||
type: String, |
|||
default: propTypes.string.def('500px'), |
|||
}, |
|||
title: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
name: { |
|||
type: Array<string>, |
|||
default: [], |
|||
}, |
|||
data: { |
|||
type: Array<Array<number>>, |
|||
default: () => [[]], |
|||
}, |
|||
width: propTypes.string.def('100%'), |
|||
// height: propTypes.string.def('70vh'), |
|||
}) |
|||
const chartRef = ref<HTMLDivElement | null>(null) |
|||
|
|||
const { setOptions, setGroup, chartInstance } = useECharts(chartRef as Ref<HTMLDivElement>, 'default', props.isAsync) |
|||
onMounted(() => { |
|||
|
|||
}) |
|||
|
|||
// const yAxis = reactive<yAxisForm>({ |
|||
// type: 'value', |
|||
// scale: true, // 开启自适应刻度 |
|||
|
|||
// }) |
|||
watch( |
|||
() => props.data, |
|||
() => { |
|||
console.log(props.data) |
|||
const yAxis = ref<YAXisOption[]>([]) |
|||
const series = ref<any[]>([]) |
|||
const title = ref<any>({}) |
|||
|
|||
for (let i = 0; i < props.data.length; i++) { |
|||
title.value = { |
|||
left: 'left', |
|||
text: props.title, |
|||
show: true, |
|||
textStyle: { // 设置主标题的文字风格 |
|||
fontFamily: 'sans-serif', // 字体系列 |
|||
fontWeight: 350, |
|||
color: 'black', // 字体颜色 |
|||
fontSize: 16, // 文字大小 |
|||
}, |
|||
|
|||
} |
|||
yAxis.value.push({ |
|||
type: 'value', |
|||
show: false, |
|||
scale: true, // 开启自适应刻度 |
|||
}) |
|||
series.value.push({ |
|||
name: props.name[i], |
|||
type: 'line', |
|||
smooth: true, |
|||
showSymbol: false, |
|||
data: props.data[i], |
|||
yAxisIndex: i, |
|||
}) |
|||
} |
|||
// const aa = getInstance() |
|||
|
|||
setOptions({ |
|||
// 网格 |
|||
grid: { |
|||
x: '2%', |
|||
y: '5%', |
|||
x2: '2%', |
|||
y2: '30%', |
|||
containLabel: false, |
|||
// width: {totalWidth} - x - x2, |
|||
// height: {totalHeight} - y - y2, |
|||
backgroundColor: 'rgba(0,0,0,0)', |
|||
borderWidth: 1, |
|||
borderColor: '#ccc', |
|||
}, |
|||
|
|||
tooltip: { |
|||
trigger: 'axis', |
|||
position(pt) { |
|||
return [pt[0], '10%'] |
|||
}, |
|||
}, |
|||
title: title.value, |
|||
toolbox: { |
|||
feature: { |
|||
dataZoom: { |
|||
yAxisIndex: 'none', |
|||
}, |
|||
restore: { show: false }, |
|||
saveAsImage: {}, |
|||
/* 自定义事件,注意:自定义事件必须以my开头 */ |
|||
myTool2: { |
|||
show: true, |
|||
title: '下载csv文件', /* 鼠标停留时的提示文字 */ |
|||
// icon: 'image://../0IMG/tool.png', /* 显示图标,必须以image://为开头显示后面是图表的路径 */ |
|||
icon: 'path://M18 20.288L21.288 17l-.688-.688l-2.1 2.1v-4.887h-1v4.887l-2.1-2.1l-.688.688zM14.5 23.5v-1h7v1zm-10-4v-17H13L18.5 8v3.14h-1V8.5h-5v-5h-7v15h6.615v1zm1-1v-15z', |
|||
/* 点击时触发的事件 */ |
|||
onclick() { |
|||
setTimeout(() => { |
|||
// 使用这个函数转换数据为CSV格式 |
|||
const csv = convertToCSV(props.data) |
|||
console.log(props.data) |
|||
// 如果你想提供下载链接 |
|||
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }) |
|||
const link = document.createElement('a') |
|||
link.href = URL.createObjectURL(blob) |
|||
link.download = 'data.csv' |
|||
link.click() |
|||
function convertToCSV(data) { |
|||
let csv = '' |
|||
// 添加列头 |
|||
const name = props.name.join(',') |
|||
csv += `时间,${name}\n` |
|||
// 遍历数据并添加到CSV字符串中 |
|||
for (let i = 0; i < props.data[0].length; i++) { |
|||
let data = '' |
|||
for (let j = 0; j < props.data.length; j++) |
|||
data += `,${props.data[j][i][1]}` |
|||
|
|||
csv += `${moment(props.data[0][i][0]).format('YYYY-MM-DD HH:mm:ss')}${data}\n` |
|||
// props.data[i].map((item, index) => { |
|||
// csv += 'x值' + ',' + 'y值' + '\n' |
|||
// }) |
|||
} |
|||
return csv |
|||
} |
|||
}, 10) |
|||
}, |
|||
}, |
|||
}, |
|||
}, |
|||
xAxis: { |
|||
type: 'time', |
|||
axisTick: { |
|||
length: 6, |
|||
lineStyle: { |
|||
type: 'dashed', |
|||
// ... |
|||
}, |
|||
}, |
|||
// boundaryGap: false, |
|||
}, |
|||
yAxis: yAxis.value, |
|||
legend: { |
|||
|
|||
}, |
|||
dataZoom: [ |
|||
{ |
|||
type: 'slider', |
|||
start: 0, |
|||
end: 100, |
|||
}, |
|||
// 没有下面这块的话,只能拖动滚动条, |
|||
// 鼠标滚轮在区域内不能控制外部滚动条 |
|||
// { |
|||
// start: 0, |
|||
// end: 100, |
|||
// }, |
|||
], |
|||
series: series.value, |
|||
}) |
|||
}, |
|||
{ immediate: true }, |
|||
) |
|||
</script> |
|||
|
|||
<template> |
|||
<div ref="chartRef" :style="{ width, height }" /> |
|||
</template> |
|||
@ -1,260 +0,0 @@ |
|||
<script lang="ts" setup> |
|||
import { computed, onMounted, reactive, ref } from 'vue' |
|||
import type { Dayjs } from 'dayjs' |
|||
import moment from 'moment' |
|||
import { Button, Card, Form, FormItem, Modal, RangePicker, Space, message } from 'ant-design-vue' |
|||
import { columns, searchFormSchema } from '../exa.data' |
|||
import EXAHistoryLine from '../EXAHistoryLine.vue' |
|||
import type { TableActionType } from '@/components/Table' |
|||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|||
import { getEXAPage, getExaHistorys } from '@/api/alert/exa' |
|||
import { useI18n } from '@/hooks/web/useI18n' |
|||
import { IconEnum } from '@/enums/appEnum' |
|||
|
|||
const { t } = useI18n() |
|||
interface FormState { |
|||
publishTime: any[] |
|||
} |
|||
const searchForm = reactive<FormState>({ |
|||
publishTime: [], |
|||
}) |
|||
const loading = ref(true) |
|||
|
|||
function onRangeChange(value: [Dayjs, Dayjs], dateString: [string, string]) { |
|||
console.log('Selected Time: ', value) |
|||
console.log('Formatted Selected Time: ', dateString) |
|||
} |
|||
|
|||
function onRangeOk(value: [Dayjs, Dayjs]) { |
|||
console.log('onOk: ', value) |
|||
console.log(searchForm.publishTime) |
|||
searchForm.publishTime = value |
|||
} |
|||
|
|||
const open = ref<boolean>(false) |
|||
const selectedData = ref<Recordable[]>([]) |
|||
|
|||
interface RowKeys { |
|||
selectedRowKeys: number[] |
|||
} |
|||
const state = reactive<RowKeys>({ |
|||
selectedRowKeys: [], |
|||
|
|||
}) |
|||
|
|||
const tableRef = ref<Nullable<TableActionType>>(null) |
|||
const tableRef1 = ref<Nullable<TableActionType>>(null) |
|||
|
|||
const [registerTable] = useTable({ |
|||
title: '测点列表', |
|||
api: getEXAPage, |
|||
immediate: false, |
|||
showTableSetting: false, |
|||
tableSetting: { |
|||
// 是否显示刷新按钮 |
|||
redo: false, |
|||
// 是否显示尺寸调整按钮 |
|||
size: false, |
|||
// 是否显示字段调整按钮 |
|||
setting: false, |
|||
// 是否显示全屏按 |
|||
fullScreen: false, |
|||
}, |
|||
columns, |
|||
formConfig: { |
|||
labelWidth: 150, |
|||
schemas: searchFormSchema, |
|||
showResetButton: false, |
|||
actionColOptions: { |
|||
span: 2, |
|||
}, |
|||
}, |
|||
rowKey: 'serialNumber', |
|||
useSearchForm: true, |
|||
showIndexColumn: false, |
|||
|
|||
}) |
|||
|
|||
// 这个必须写在computed计算属性里,心酸啊,弄一下午! |
|||
const rowSelection = computed(() => { |
|||
return { |
|||
preserveSelectedRowKeys: true, // 2.加这一行 |
|||
type: 'checkbox', |
|||
selectedRowKeys: state.selectedRowKeys, |
|||
onChange: onSelectChange, |
|||
|
|||
} |
|||
}) |
|||
|
|||
// defaultChecked: record.serialNumber === 93, |
|||
|
|||
onMounted(() => { |
|||
state.selectedRowKeys = localStorage.getItem('pointInfo') ? JSON.parse(localStorage.getItem('pointInfo') || '') : [] |
|||
selectedData.value = localStorage.getItem('pointInfoList') ? JSON.parse(localStorage.getItem('pointInfoList') || '') : [] |
|||
searchForm.publishTime = [moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')] |
|||
getHistoryChart() |
|||
}) |
|||
|
|||
const historyData = ref() |
|||
const legendName = ref<any[]>([]) |
|||
|
|||
async function getHistoryChart() { |
|||
const pointCodeList = selectedData.value.map(item => (item.itemName)) |
|||
loading.value = true |
|||
|
|||
if (pointCodeList.length !== 0) { |
|||
const pointCode = selectedData.value.map(item => (item.itemName)).join(',') |
|||
const pointDesc: any[] = selectedData.value.map(item => (item.descriptor)) |
|||
|
|||
const exaHistoryReqVO = { |
|||
startTime: searchForm.publishTime[0], |
|||
endTime: searchForm.publishTime[1], |
|||
itemName: pointCode, |
|||
} |
|||
historyData.value = await getExaHistorys(exaHistoryReqVO) |
|||
legendName.value = pointDesc |
|||
} |
|||
else { |
|||
message.info('暂无测点') |
|||
} |
|||
loading.value = false |
|||
} |
|||
|
|||
const [registerSelectedTable] = useTable({ |
|||
title: '已选中测点列表', |
|||
showTableSetting: false, |
|||
tableSetting: { |
|||
// 是否显示刷新按钮 |
|||
redo: false, |
|||
// 是否显示尺寸调整按钮 |
|||
size: false, |
|||
// 是否显示字段调整按钮 |
|||
setting: false, |
|||
// 是否显示全屏按 |
|||
fullScreen: false, |
|||
}, |
|||
columns, |
|||
formConfig: { |
|||
labelWidth: 150, |
|||
schemas: searchFormSchema, |
|||
showResetButton: false, |
|||
actionColOptions: { |
|||
span: 2, |
|||
}, |
|||
}, |
|||
rowKey: 'serialNumber', |
|||
useSearchForm: false, |
|||
showIndexColumn: false, |
|||
actionColumn: { |
|||
width: 140, |
|||
title: t('common.action'), |
|||
dataIndex: 'action', |
|||
fixed: 'right', |
|||
}, |
|||
}) |
|||
function openModal() { |
|||
open.value = true |
|||
console.log(24) |
|||
console.log(selectedData.value) |
|||
} |
|||
function onSelectChange(selectedRowKeys, selectedRows) { |
|||
console.log(selectedRowKeys, selectedRows) |
|||
state.selectedRowKeys = selectedRowKeys |
|||
let selectionRows: any[] = [] |
|||
console.log('3', selectedData.value) |
|||
|
|||
selectionRows = selectedData.value.concat(selectedRows) |
|||
console.log('2', selectionRows) |
|||
|
|||
selectionRows = selectionRows.filter(item => selectedRowKeys.includes(item.serialNumber)) |
|||
console.log('1', selectionRows) |
|||
// 数组对象去重 |
|||
const map = new Map() |
|||
for (const item of selectionRows) { |
|||
if (!map.has(item.serialNumber)) |
|||
map.set(item.serialNumber, item) |
|||
}; |
|||
selectedData.value = [...map.values()] |
|||
} |
|||
|
|||
function handleOk() { |
|||
console.log('onOk:') |
|||
localStorage.setItem('pointInfo', JSON.stringify(state.selectedRowKeys)) |
|||
localStorage.setItem('pointInfoList', JSON.stringify(selectedData.value)) |
|||
open.value = false |
|||
getHistoryChart() |
|||
} |
|||
async function handleDelete(record: Recordable) { |
|||
const newArr = state.selectedRowKeys.filter((value) => { |
|||
return value !== record.serialNumber |
|||
}) |
|||
state.selectedRowKeys = newArr |
|||
localStorage.setItem('pointInfo', JSON.stringify(state.selectedRowKeys)) |
|||
|
|||
const newArrObj = selectedData.value.filter((value) => { |
|||
return value.serialNumber !== record.serialNumber |
|||
}) |
|||
selectedData.value = newArrObj |
|||
} |
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<Card> |
|||
<Form layout="inline" :model="searchForm"> |
|||
<FormItem label="时间范围"> |
|||
<RangePicker |
|||
:model="searchForm.publishTime" |
|||
:show-time="{ format: 'HH:mm:ss' }" |
|||
:placeholder="['开始时间', '结束时间']" :default-value="[moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')]" |
|||
value-format="YYYY-MM-DD HH:mm:ss" |
|||
@change="onRangeChange" |
|||
@ok="onRangeOk" |
|||
/> |
|||
</FormItem> |
|||
<FormItem> |
|||
<Space wrap> |
|||
<Button type="primary" @click="getHistoryChart"> |
|||
查看趋势 |
|||
</Button> |
|||
<Button @click="openModal()"> |
|||
测点配置 |
|||
</Button> |
|||
</Space> |
|||
</FormItem> |
|||
</Form> |
|||
</Card> |
|||
<Card style="margin:5px" :loading="loading"> |
|||
<EXAHistoryLine :data="historyData" :name="legendName" height="70vh" /> |
|||
</Card> |
|||
<Modal v-model:open="open" :destroy-on-close="false" width="1000px" title="测点配置" @ok="handleOk"> |
|||
<BasicTable |
|||
ref="tableRef" :can-resize="false" title="RefTable示例" title-help-message="使用Ref调用表格内方法" |
|||
:row-selection="rowSelection" size="small" @register="registerTable" |
|||
/> |
|||
<BasicTable |
|||
ref="tableRef1" :pagination="false" size="small" :data-source="selectedData" :can-resize="false" |
|||
title="已选中测点" title-help-message="使用Ref调用表格内方法" @register="registerSelectedTable" |
|||
> |
|||
<template #bodyCell="{ column, record }"> |
|||
<template v-if="column.key === 'action'"> |
|||
<TableAction |
|||
:actions="[{ |
|||
icon: IconEnum.DELETE, |
|||
danger: true, |
|||
label: t('action.delete'), |
|||
auth: 'system:role:delete', |
|||
popConfirm: { |
|||
title: t('common.delMessage'), |
|||
placement: 'left', |
|||
confirm: handleDelete.bind(null, record), |
|||
}, |
|||
}, |
|||
]" |
|||
/> |
|||
</template> |
|||
</template> |
|||
</BasicTable> |
|||
</Modal> |
|||
</div> |
|||
</template> |
|||
@ -0,0 +1,211 @@ |
|||
<script lang="ts" setup> |
|||
import { reactive, ref } from 'vue' |
|||
import { Card, Divider, Steps } from 'ant-design-vue' |
|||
import ModalTable from '../model/ModelTable.vue' |
|||
import PointTable from '../model/PointTable.vue' |
|||
import { createInstantForm } from './instant.data' |
|||
import { useI18n } from '@/hooks/web/useI18n' |
|||
import { BasicModal, useModalInner } from '@/components/Modal' |
|||
import { BasicForm, useForm } from '@/components/Form' |
|||
import { getModelVersionList } from '@/api/alert/run/model/index' |
|||
import { getCalcGroupList } from '@/api/alert/run/calcgroup/index' |
|||
import { createInstant } from '@/api/alert/run/instant/index' |
|||
import { useMessage } from '@/hooks/web/useMessage' |
|||
|
|||
const emit = defineEmits(['success']) |
|||
const { createMessage } = useMessage() |
|||
const { t } = useI18n() |
|||
|
|||
const [registerCreateModal, { setModalProps, closeModal }] = useModalInner(async (data) => { |
|||
setModalProps({ destroyOnClose: true, showCancelBtn: false, showOkBtn: false }) |
|||
}) |
|||
|
|||
const current = ref<number>(0) |
|||
function next() { |
|||
current.value++ |
|||
} |
|||
function prev() { |
|||
current.value-- |
|||
} |
|||
const steps = [ |
|||
{ |
|||
title: '壹', |
|||
content: 'First-content', |
|||
}, |
|||
{ |
|||
title: '贰', |
|||
content: 'Second-content', |
|||
}, |
|||
] |
|||
const items = steps.map(item => ({ key: item.title, title: item.title })) |
|||
|
|||
const [registerForm, { validate, setFieldsValue, updateSchema, setProps }] = useForm({ |
|||
labelWidth: 100, |
|||
schemas: createInstantForm, |
|||
showSubmitButton: false, |
|||
showResetButton: false, |
|||
layout: 'horizontal', |
|||
|
|||
actionColOptions: { span: 2 }, |
|||
disabled: true, |
|||
}) |
|||
|
|||
interface instantForms { |
|||
modelId?: string |
|||
mpName?: string |
|||
} |
|||
const instantForm = reactive<instantForms>({ |
|||
modelId: '', |
|||
mpName: '', |
|||
}) |
|||
const isDisabled = ref<boolean>(true) |
|||
const state = reactive<any>({ |
|||
pointInfo: [], |
|||
type: false, |
|||
}) |
|||
async function updatempName(selectedRowKeys, selectedRows) { |
|||
console.log(selectedRows.length) |
|||
|
|||
if (selectedRows.length !== 0) { |
|||
state.type = selectedRows[0].algorithm === 'ANN' |
|||
console.log(state.type) |
|||
state.pointInfo = JSON.parse(selectedRows[0].modelInfo).pointInfo |
|||
for (const p of state.pointInfo) { |
|||
p.modelName = selectedRows[0].modelName |
|||
p.modelDescription = selectedRows[0].description |
|||
p.algorithm = selectedRows[0].algorithm |
|||
} |
|||
} |
|||
// 下一步按钮的禁用与启用 |
|||
isDisabled.value = selectedRows.length === 0 |
|||
console.log(isDisabled) |
|||
if (selectedRows.length === 0) |
|||
setProps({ disabled: true }) |
|||
|
|||
else |
|||
setProps({ disabled: false }) |
|||
|
|||
instantForm.modelId = selectedRows.length !== 0 ? `${selectedRows[0].id}` : `` |
|||
|
|||
instantForm.mpName = selectedRows.length !== 0 ? `${selectedRows[0].modelName}-实例` : `` |
|||
setFieldsValue(instantForm) |
|||
|
|||
const versionData = selectedRows.length !== 0 ? await getModelVersionList({ modelId: selectedRows[0].id }) : [] |
|||
const versionList = [] as any |
|||
// // 组名下拉框问题 |
|||
versionData.forEach((item) => { |
|||
versionList.push({ label: item.version, value: item.id }) |
|||
}) |
|||
const calcGroupData = selectedRows.length !== 0 ? await getCalcGroupList({ unitId: selectedRows[0].unitId }) : [] |
|||
const calcGroupList = [] as any |
|||
// // 组名下拉框问题 |
|||
calcGroupData.forEach((item) => { |
|||
calcGroupList.push({ label: item.groupName, value: item.id }) |
|||
}) |
|||
|
|||
// 将数据放入下拉框中 |
|||
updateSchema({ |
|||
field: 'modelVersionId', |
|||
componentProps: { |
|||
options: versionList, |
|||
}, |
|||
}) |
|||
updateSchema({ |
|||
field: 'calcGroup', |
|||
componentProps: { |
|||
options: calcGroupList, |
|||
}, |
|||
}) |
|||
} |
|||
|
|||
function onCanel() { |
|||
current.value = 0 |
|||
closeModal() |
|||
} |
|||
const loading = ref<boolean>(false) |
|||
const pointRef = ref() |
|||
async function CompleteCreate() { |
|||
try { |
|||
loading.value = true |
|||
|
|||
// 由于自定义按钮的,所以confirmLoading失效 |
|||
setModalProps({ confirmLoading: true, loading: true }) |
|||
|
|||
const values = await validate() |
|||
// if (unref(isUpdate)) { |
|||
// await updateDemo02Category(values) |
|||
// } else { |
|||
// await createDemo02Category(values) |
|||
// } |
|||
// 插入数据库 |
|||
// 获取子组件的测点列表数据 |
|||
const pointInfoNew = pointRef.value.getPointTableData() |
|||
values.pointInfo = pointInfoNew |
|||
console.log(values) |
|||
await createInstant(values) |
|||
|
|||
emit('success') |
|||
createMessage.success(t('common.saveSuccessText')) |
|||
} |
|||
finally { |
|||
closeModal() |
|||
loading.value = false |
|||
|
|||
// 由于自定义按钮的,所以confirmLoading失效 |
|||
setModalProps({ confirmLoading: false, loading: false }) |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<template> |
|||
<BasicModal v-bind="$attrs" title="新增模型实例" width="80%" @cancel="onCanel" @register="registerCreateModal"> |
|||
<Card title="实例信息"> |
|||
<BasicForm @register="registerForm" /> |
|||
</Card> |
|||
<Divider /> |
|||
|
|||
<Steps :current="current" :items="items" /> |
|||
<div class="steps-content"> |
|||
<ModalTable v-if="current === 0" @success="updatempName" /> |
|||
<PointTable v-if="current === 1" ref="pointRef" :data="state.pointInfo" :type="state.type" /> |
|||
</div> |
|||
<!-- modal 底部区域插槽实现--替换原按钮 --> |
|||
<template #footer> |
|||
<div class="steps-action"> |
|||
<a-button v-if="current < steps.length - 1 " :disabled="isDisabled" type="primary" @click="next"> |
|||
下一步 |
|||
</a-button> |
|||
<a-button |
|||
v-if="current === steps.length - 1" |
|||
type="primary" |
|||
:loading="loading" |
|||
@click="CompleteCreate" |
|||
> |
|||
完成 |
|||
</a-button> |
|||
<!-- <a-button v-if="current > 0" style="margin-left: 8px" @click="prev"> |
|||
上一步+ |
|||
</a-button> --> |
|||
</div> |
|||
</template> |
|||
</BasicModal> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
.steps-content { |
|||
margin-top: 16px; |
|||
text-align: center; |
|||
background-color: #fafafa; |
|||
border: 1px dashed #e9e9e9; |
|||
border-radius: 6px; |
|||
} |
|||
|
|||
.steps-action { |
|||
margin-top: 24px; |
|||
} |
|||
|
|||
[data-theme='dark'] .steps-content { |
|||
background-color: #2f2f2f; |
|||
border: 1px dashed #404040; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,88 @@ |
|||
<script lang="ts" setup> |
|||
import { ref, unref } from 'vue' |
|||
import { updateInstantForm } from './instant.data' |
|||
import { useI18n } from '@/hooks/web/useI18n' |
|||
import { useMessage } from '@/hooks/web/useMessage' |
|||
import { BasicForm, useForm } from '@/components/Form' |
|||
import { BasicModal, useModalInner } from '@/components/Modal' |
|||
import { getInstant, updateInstant } from '@/api/alert/run/instant/index' |
|||
|
|||
import { getModelVersionList } from '@/api/alert/run/model/index' |
|||
import { getCalcGroupList } from '@/api/alert/run/calcgroup/index' |
|||
|
|||
defineOptions({ name: 'InstantUpdateModal' }) |
|||
|
|||
const emit = defineEmits(['success', 'register']) |
|||
const { t } = useI18n() |
|||
const { createMessage } = useMessage() |
|||
const isUpdate = ref(true) |
|||
|
|||
const [registerForm, { updateSchema, setFieldsValue, resetFields, validate }] = useForm({ |
|||
labelWidth: 120, |
|||
baseColProps: { span: 24 }, |
|||
schemas: updateInstantForm, |
|||
showActionButtonGroup: false, |
|||
actionColOptions: { span: 23 }, |
|||
|
|||
}) |
|||
|
|||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { |
|||
resetFields() |
|||
// 如果是修改modal,则赋值给表单 |
|||
isUpdate.value = !!data?.isUpdate |
|||
if (unref(isUpdate)) { |
|||
const res = await getInstant(data.record.id) |
|||
setFieldsValue({ ...res }) |
|||
} |
|||
// 获取下拉框的数据 |
|||
const versionData = await getModelVersionList({ modelId: data?.record.modelId }) |
|||
const versionList = [] as any |
|||
// // 组名下拉框问题 |
|||
versionData.forEach((item) => { |
|||
versionList.push({ label: item.version, value: item.id }) |
|||
}) |
|||
const calcGroupData = await getCalcGroupList({ unitId: data?.record.unitId }) |
|||
const calcGroupList = [] as any |
|||
// // 组名下拉框问题 |
|||
calcGroupData.forEach((item) => { |
|||
calcGroupList.push({ label: item.groupName, value: item.id }) |
|||
}) |
|||
|
|||
// 将数据放入下拉框中 |
|||
updateSchema({ |
|||
field: 'modelVersionId', |
|||
componentProps: { |
|||
options: versionList, |
|||
}, |
|||
}) |
|||
updateSchema({ |
|||
field: 'calcGroup', |
|||
componentProps: { |
|||
options: calcGroupList, |
|||
}, |
|||
}) |
|||
setModalProps({ useWrapper: true, minHeight: 180, confirmLoading: false }) |
|||
}) |
|||
|
|||
async function handleSubmit() { |
|||
try { |
|||
const values = await validate() |
|||
setModalProps({ confirmLoading: true }) |
|||
if (unref(isUpdate)) |
|||
await updateInstant(values) |
|||
|
|||
closeModal() |
|||
emit('success') |
|||
createMessage.success(t('common.saveSuccessText')) |
|||
} |
|||
finally { |
|||
setModalProps({ confirmLoading: false }) |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<template> |
|||
<BasicModal v-bind="$attrs" :title="isUpdate ? t('action.edit') : t('action.create')" @register="registerModal" @ok="handleSubmit"> |
|||
<BasicForm @register="registerForm" /> |
|||
</BasicModal> |
|||
</template> |
|||
@ -0,0 +1,195 @@ |
|||
<script lang="ts" setup> |
|||
import { onMounted, reactive, ref } from 'vue' |
|||
import type { Dayjs } from 'dayjs' |
|||
import moment from 'moment' |
|||
import { Card, Descriptions, DescriptionsItem, Form, FormItem, RangePicker, Space, Switch, message } from 'ant-design-vue' |
|||
import { mount } from 'sortablejs' |
|||
import { number } from 'vue-types' |
|||
import { useRoute } from 'vue-router' |
|||
import HistoryLine from '../../exa/HistoryLine.vue' |
|||
import { detailColumns, instantForm } from './instant.data' |
|||
import { getExaHistorys } from '@/api/alert/exa' |
|||
import { useModal } from '@/components/Modal' |
|||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|||
import { getInstant, getInstantChart, getInstantPage, getInstantPoint } from '@/api/alert/run/instant' |
|||
import { useI18n } from '@/hooks/web/useI18n' |
|||
import { router } from '@/router' |
|||
import { BasicForm, useForm } from '@/components/Form' |
|||
import PropsPanel from '@/components/FormDesign/src/components/VFormDesign/modules/PropsPanel.vue' |
|||
import echarts from '@/utils/lib/echarts' |
|||
|
|||
defineOptions({ name: 'InstantDetail' }) |
|||
|
|||
const route = useRoute() |
|||
|
|||
// const props = defineProps({ |
|||
// id: { |
|||
// type: Number, |
|||
// default: null, |
|||
// }, |
|||
// }) |
|||
const { t } = useI18n() |
|||
const loadingBasic = ref<boolean>(false) |
|||
const loadingChart = ref<boolean>(false) |
|||
|
|||
const basicInfo = ref<any>({}) |
|||
const modelInfo = ref<any>({}) |
|||
const pointInfo = ref<any>({}) |
|||
const pointList = ref<any>([]) |
|||
const historyList = ref<any>([]) |
|||
const [registerForm, { getFieldsValue, setProps }] = useForm({ |
|||
labelWidth: 100, |
|||
// baseColProps: { span: 24 }, |
|||
schemas: instantForm, |
|||
showResetButton: false, |
|||
layout: 'horizontal', |
|||
// model: { time: [moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')] }, |
|||
fieldMapToTime: [ |
|||
// data为时间组件在表单内的字段,startTime,endTime为转化后的开始时间于结束时间 |
|||
['time', ['startTime', 'endTime'], 'YYYY-MM-DD HH:mm:ss'], |
|||
], |
|||
actionColOptions: { span: 2 }, |
|||
}) |
|||
|
|||
const instantId = ref<any>(route.query.id) // 获取URL中的query参数 |
|||
|
|||
onMounted(async () => { |
|||
loadingBasic.value = true |
|||
basicInfo.value = await getInstant(instantId.value) |
|||
loadingBasic.value = false |
|||
|
|||
modelInfo.value = JSON.parse(basicInfo.value.modelInfo) |
|||
pointInfo.value = modelInfo.value.pointInfo |
|||
console.log(modelInfo.value) |
|||
pointList.value = await getInstantPoint(instantId.value) |
|||
getChartsData() |
|||
}) |
|||
|
|||
function handleSubmitR() { |
|||
getChartsData() |
|||
} |
|||
async function getChartsData() { |
|||
setProps({ |
|||
submitButtonOptions: { |
|||
loading: true, |
|||
}, |
|||
}) |
|||
|
|||
loadingChart.value = true |
|||
console.log(getFieldsValue()) |
|||
const instantForm = getFieldsValue() |
|||
|
|||
historyList.value = await getInstantChart({ ...{ id: instantId.value }, ...instantForm }) |
|||
echarts.connect('async') |
|||
|
|||
loadingChart.value = false |
|||
setProps({ |
|||
submitButtonOptions: { |
|||
loading: false, |
|||
}, |
|||
}) |
|||
} |
|||
|
|||
const [registerTable] = useTable({ |
|||
title: '测点列表', |
|||
size: 'small', |
|||
dataSource: pointList, |
|||
columns: detailColumns, |
|||
useSearchForm: false, |
|||
showTableSetting: true, |
|||
showIndexColumn: false, |
|||
actionColumn: { |
|||
width: 140, |
|||
title: t('common.action'), |
|||
dataIndex: 'action', |
|||
fixed: 'right', |
|||
}, |
|||
}) |
|||
|
|||
function handleDetail(record) { |
|||
console.log(record) |
|||
router.push('/run/instant/detail') |
|||
} |
|||
|
|||
function config(value) { |
|||
console.log(value) |
|||
} |
|||
</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="创建时间"> |
|||
{{ moment(basicInfo.createTime).format("YYYY-MM-DD HH:mm:ss") }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem label="最近修改人"> |
|||
{{ basicInfo.updateName }} |
|||
</DescriptionsItem> |
|||
<DescriptionsItem label="最近修改时间"> |
|||
{{ 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> |
|||
<!-- <SlidersOutlined class="click-status" /> --> |
|||
</template> |
|||
</BasicTable> |
|||
</Card> |
|||
<Card> |
|||
<BasicForm @register="registerForm" @submit="handleSubmitR"> |
|||
<!-- 添加button的插槽 --> |
|||
<template #configButton="{ field }"> |
|||
<a-button style="margin-left:20px" @click="config"> |
|||
故障配置 |
|||
</a-button> |
|||
</template> |
|||
</BasicForm> |
|||
</Card> |
|||
<Card :loading="loadingChart"> |
|||
<div> |
|||
<div v-for="(item, index) in historyList" :key="index"> |
|||
<div style="border:1px solid #ccc"> |
|||
<HistoryLine :is-async="index !== 0" :title="item.title" :data="item.seriesData" :name="item.name" height="250px" /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</Card> |
|||
</div> |
|||
</template> |
|||
|
|||
<style lang="less" scoped> |
|||
:deep(.ant-table-body){ |
|||
height:100% !important; |
|||
max-height:100% !important |
|||
} |
|||
</style> |
|||
@ -0,0 +1,260 @@ |
|||
<script lang="ts" setup> |
|||
import { Badge, Switch } from 'ant-design-vue' |
|||
import { onMounted, ref } from 'vue' |
|||
|
|||
import HistoryModal from '../../exa/config/HistoryModal.vue' |
|||
import { columns, searchFormSchema } from './instant.data' |
|||
import CreateModal from './CreateModal.vue' |
|||
import UpdateModal from './UpdateModal.vue' |
|||
|
|||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|||
import { getInstantCount, getInstantPage, updateInstant } from '@/api/alert/run/instant' |
|||
import { getExaNow } from '@/api/alert/exa' |
|||
import { useI18n } from '@/hooks/web/useI18n' |
|||
import { router } from '@/router' |
|||
import { useMessage } from '@/hooks/web/useMessage' |
|||
import { IconEnum } from '@/enums/appEnum' |
|||
import { useModal } from '@/components/Modal' |
|||
|
|||
defineOptions({ name: 'Instant' }) |
|||
const { createMessage } = useMessage() |
|||
const { t } = useI18n() |
|||
|
|||
const [registerHistoryModal, { openModal: openHistoryModal }] = useModal() |
|||
const [registerCreateModal, { openModal: openCreateModal }] = useModal() |
|||
const [registerUpdateModal, { openModal: openUpdateModal }] = useModal() |
|||
|
|||
const [registerTable, { getForm, reload, getDataSource, updateTableDataRecord }] = useTable({ |
|||
title: '实例列表', |
|||
api: getInstantPage, |
|||
rowKey: 'id', |
|||
immediate: true, |
|||
columns, |
|||
formConfig: { |
|||
labelWidth: 120, |
|||
schemas: searchFormSchema, |
|||
showResetButton: false, |
|||
actionColOptions: { |
|||
span: 2, |
|||
}, |
|||
|
|||
}, |
|||
useSearchForm: true, |
|||
showTableSetting: true, |
|||
showIndexColumn: false, |
|||
actionColumn: { |
|||
width: 240, |
|||
title: t('common.action'), |
|||
dataIndex: 'action', |
|||
fixed: 'right', |
|||
}, |
|||
}) |
|||
|
|||
function handleDetail(record) { |
|||
console.log(record) |
|||
router.push(`/run/instant/detail?id=${record.id}`) |
|||
} |
|||
|
|||
async function updateStatus(record) { |
|||
await updateInstant(record) |
|||
createMessage.success(t('common.saveSuccessText')) |
|||
console.log(record) |
|||
reload() |
|||
} |
|||
const isShow = ref<boolean>(false) |
|||
|
|||
function handleCreate() { |
|||
openCreateModal(true, { isUpdate: false }) |
|||
isShow.value = true |
|||
} |
|||
|
|||
function handleEdit(record: Recordable) { |
|||
openUpdateModal(true, { record, isUpdate: true }) |
|||
} |
|||
async function handleDelete(record: Recordable) { |
|||
await deleteRole(record.id) |
|||
createMessage.success(t('common.delSuccessText')) |
|||
reload() |
|||
} |
|||
|
|||
const itemName = ref<string>() |
|||
const legendName = ref<string[]>() |
|||
function handleHistory(record: Recordable) { |
|||
itemName.value = (JSON.parse(record.instantInfo)).model_state |
|||
legendName.value = [] |
|||
legendName.value.push(`${record.mpName}-${itemName.value}`) |
|||
openHistoryModal(true, { record }) |
|||
} |
|||
interface countObj { |
|||
normal: number |
|||
outside: number |
|||
failure: number |
|||
update: number |
|||
stop: number |
|||
} |
|||
const countData = ref<countObj>() |
|||
onMounted(async () => { |
|||
countData.value = await getInstantCount() |
|||
console.log(countData.value) |
|||
getNow() |
|||
}) |
|||
async function getTableData(type) { |
|||
const { getFieldsValue, setFieldsValue } = getForm() |
|||
await setFieldsValue({ runningLog: null, running: null, isUpdate: null }) |
|||
if (type === 'normal') { |
|||
await setFieldsValue({ runningLog: '运行正常' }) |
|||
console.log(getFieldsValue()) |
|||
} |
|||
else if (type === 'outside') { |
|||
await setFieldsValue({ runningLog: '模式外运行' }) |
|||
} |
|||
else if (type === 'stop') { |
|||
await setFieldsValue({ runningLog: '模型已停运' }) |
|||
} |
|||
else if (type === 'failure') { |
|||
await setFieldsValue({ running: 0 }) |
|||
} |
|||
else if (type === 'isUpdate') { |
|||
await setFieldsValue({ isUpdate: 1 }) |
|||
} |
|||
else { |
|||
await setFieldsValue({ runningLog: null, running: null, isUpdate: null }) |
|||
} |
|||
reload() |
|||
} |
|||
async function getNow() { |
|||
const params = getDataSource() |
|||
params.forEach((item: any) => { |
|||
const pointCode = (JSON.parse(item.instantInfo)).model_state |
|||
// 对数组中的每个元素执行异步操作 |
|||
getExaNow(pointCode).then((result) => { |
|||
updateTableDataRecord(item.id, Object.assign(item, { pointSte: result })) |
|||
}) |
|||
}) |
|||
} |
|||
|
|||
function handleWarnConfig(record: Recordable) { |
|||
router.push(`/run/warnConfig?id=${record.id}`) |
|||
} |
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<BasicTable @register="registerTable"> |
|||
<template #detail="{ record }"> |
|||
<a class="click-status" @click="handleDetail(record)"> |
|||
{{ record.mpName }} |
|||
</a> |
|||
|
|||
<!-- <SlidersOutlined class="click-status" /> --> |
|||
</template> |
|||
<!-- 统计量点击跳转历史曲线 --> |
|||
<template #history="{ record }"> |
|||
<a @click="handleHistory(record)"> |
|||
{{ record.pointSte }} |
|||
</a> |
|||
<!-- <SlidersOutlined class="click-status" /> --> |
|||
</template> |
|||
<template #toolbar> |
|||
<span class="runningStatus" @click="getTableData('all')"> |
|||
全部</span> |
|||
<Badge |
|||
:class="countData?.normal === 0 ? 'runningStatus' : 'runningStatus alarm'" color="green" text="正常运行" |
|||
@click="getTableData('normal')" |
|||
/> |
|||
<Badge |
|||
:class="countData?.outside === 0 ? 'runningStatus' : 'runningStatus alarm'" color="#0B55A4" text="模式外运行" |
|||
@click="getTableData('outside')" |
|||
/> |
|||
<Badge |
|||
:class="countData?.failure === 0 ? 'runningStatus' : 'runningStatus alarm'" color="red" text="运行失败" |
|||
@click="getTableData('failure')" |
|||
/> |
|||
<Badge |
|||
:class="countData?.update === 0 ? 'runningStatus' : 'runningStatus alarm'" color="orange" text="版本更新" |
|||
@click="getTableData('isUpdate')" |
|||
/> |
|||
<Badge |
|||
:class="countData?.stop === 0 ? 'runningStatus' : 'runningStatus alarm'" color="black" text="模型停运" |
|||
@click="getTableData('stop')" |
|||
/> |
|||
<a-button v-auth="['run:instant:create']" type="primary" :pre-icon="IconEnum.ADD" @click="handleCreate"> |
|||
{{ t('action.create') }} |
|||
</a-button> |
|||
</template> |
|||
<template #runStatus="{ record }"> |
|||
<div v-if="record.runningLog === '模式已停运'"> |
|||
<span style="color:black">模式已停运</span> |
|||
</div> |
|||
<div v-else-if="record.running === '0'"> |
|||
<span style="color:red">运行失败</span> |
|||
</div> |
|||
<div v-else-if="record.runningLog === '模式外运行'"> |
|||
<span style="color:#0B55A4">模式外运行</span> |
|||
</div> |
|||
<div v-else-if="record.isUpdate === '1'"> |
|||
<span style="color:orange">版本更新</span> |
|||
</div> |
|||
<div v-else> |
|||
<span style="color:green">正常运行</span> |
|||
</div> |
|||
</template> |
|||
<template #status="{ record }"> |
|||
<Switch |
|||
v-model:checked="record.status" :checked-value="1" :un-checked-value="0" checked-children="开" |
|||
un-checked-children="关" @change="updateStatus(record)" |
|||
/> |
|||
</template> |
|||
<template #bodyCell="{ column, record }"> |
|||
<template v-if="column.key === 'action'"> |
|||
<TableAction |
|||
:actions="[ |
|||
{ icon: IconEnum.WARN, label: t('action.warnConfig'), auth: 'run:instant:warnConfig', onClick: handleWarnConfig.bind(null, record) }, |
|||
|
|||
{ icon: IconEnum.EDIT, label: t('action.edit'), auth: 'run:instant:update', onClick: handleEdit.bind(null, record) }, |
|||
{ |
|||
icon: IconEnum.DELETE, |
|||
danger: true, |
|||
label: t('action.delete'), |
|||
auth: 'run:instant:delete', |
|||
popConfirm: { |
|||
title: t('common.delMessage'), |
|||
placement: 'left', |
|||
confirm: handleDelete.bind(null, record), |
|||
}, |
|||
}, |
|||
]" |
|||
/> |
|||
</template> |
|||
</template> |
|||
</BasicTable> |
|||
<HistoryModal :item-name="itemName" :legend-name="legendName" @register="registerHistoryModal" /> |
|||
<CreateModal :item-name="itemName" :legend-name="legendName" @register="registerCreateModal" @success="reload" /> |
|||
<UpdateModal @register="registerUpdateModal" @success="reload" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<style lang="less" scoped> |
|||
:deep(.instant) { |
|||
font-weight: bold; |
|||
color: #0B55A4 |
|||
} |
|||
|
|||
:deep(.alarm .ant-badge-status-dot) { |
|||
animation: flash 1s linear infinite; |
|||
} |
|||
|
|||
@keyframes flash { |
|||
from { |
|||
opacity: 0; |
|||
} |
|||
|
|||
to { |
|||
opacity: 1; |
|||
} |
|||
} |
|||
|
|||
.runningStatus { |
|||
cursor: pointer; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,479 @@ |
|||
import moment from 'moment' |
|||
import { left } from 'inquirer/lib/utils/readline' |
|||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|||
import { getModelVersionList } from '@/api/alert/run/model/index' |
|||
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: '编号', |
|||
dataIndex: 'id', |
|||
width: 80, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '实例状态', |
|||
dataIndex: 'status1', |
|||
width: 100, |
|||
slots: { customRender: 'runStatus' }, |
|||
fixed: 'left', |
|||
}, |
|||
|
|||
{ |
|||
title: '实例名称', |
|||
dataIndex: 'mpName', |
|||
width: 250, |
|||
className: 'instant', |
|||
slots: { customRender: 'detail' }, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '专业', |
|||
dataIndex: 'systemName', |
|||
width: 200, |
|||
|
|||
}, |
|||
{ |
|||
title: '算法', |
|||
dataIndex: 'algorithmName', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '模式', |
|||
dataIndex: 'conditionName', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '原模型名称', |
|||
dataIndex: 'modelName', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '版本', |
|||
dataIndex: 'modelVersion', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '运行日志', |
|||
dataIndex: 'runningLog', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '计算组', |
|||
dataIndex: 'groupName', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '统计量', |
|||
dataIndex: 'pointSte', |
|||
width: 120, |
|||
slots: { customRender: 'history' }, |
|||
fixed: 'left', |
|||
|
|||
}, |
|||
{ |
|||
title: '投切', |
|||
dataIndex: 'status', |
|||
width: 100, |
|||
slots: { customRender: 'status' }, |
|||
fixed: 'right', |
|||
}, |
|||
|
|||
// {
|
|||
// title: '实时值',
|
|||
// dataIndex: 'value',
|
|||
// width: 90,
|
|||
// className: 'value',
|
|||
// slots: { customRender: 'value' },
|
|||
|
|||
// }
|
|||
|
|||
] |
|||
|
|||
export const searchFormSchema: FormSchema[] = [ |
|||
{ |
|||
label: '模型实例名称', |
|||
field: 'mpName', |
|||
component: 'Input', |
|||
defaultValue: '', |
|||
required: true, |
|||
colProps: { span: 8 }, |
|||
}, |
|||
{ |
|||
label: '状态1', |
|||
field: 'running', |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: '状态2', |
|||
field: 'runningLog', |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: '状态3', |
|||
field: 'isUpdate', |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
] |
|||
|
|||
export const formSchema: FormSchema[] = [ |
|||
|
|||
{ |
|||
label: '测点编码', |
|||
field: 'ItemName', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '测点描述', |
|||
field: 'Descriptor', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '单位', |
|||
field: 'EngUnits', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '组名', |
|||
field: 'GroupName', |
|||
component: 'Select', |
|||
componentProps: { |
|||
options: getDictOptions(DICT_TYPE.COMMON_STATUS), |
|||
}, |
|||
required: true, |
|||
|
|||
}, |
|||
{ |
|||
label: '类型', |
|||
field: 'ItemType', |
|||
component: 'Select', |
|||
componentProps: { |
|||
options: [{ value: 1, label: 1 }, { value: 2, label: 2 }, { value: 3, label: 3 }, { value: 4, label: 4 }, { value: 5, label: 5 }], |
|||
}, |
|||
required: true, |
|||
|
|||
}, |
|||
{ |
|||
label: '自动保存', |
|||
field: 'AutoSave', |
|||
component: 'Select', |
|||
componentProps: { |
|||
options: [{ value: 1, label: '是' }, { value: 2, label: '否' }], |
|||
}, |
|||
required: true, |
|||
|
|||
}, |
|||
{ |
|||
label: '数据来源', |
|||
field: 'Source', |
|||
component: 'Input', |
|||
}, |
|||
] |
|||
|
|||
export const instantForm: FormSchema[] = [ |
|||
{ |
|||
label: '时间范围', |
|||
field: 'time', |
|||
show: true, |
|||
component: 'RangePicker', |
|||
defaultValue: [moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')], |
|||
|
|||
componentProps: { |
|||
placeholder: ['开始时间', '结束时间'], |
|||
valueFormat: 'YYYY-MM-DD HH:mm:ss', |
|||
showTime: { |
|||
defaultValue: [moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')], |
|||
}, |
|||
onChange: (e: any) => { |
|||
console.log(e) |
|||
}, |
|||
}, |
|||
}, |
|||
{ |
|||
label: '时间间隔', |
|||
field: 'interval', |
|||
component: 'Select', |
|||
defaultValue: 300, |
|||
|
|||
componentProps: { |
|||
options: [{ value: 1, label: '1秒' }, { value: 10, label: '10秒' }, { value: 100, label: '100秒' }, { value: 300, label: '300秒' }], |
|||
}, |
|||
required: true, |
|||
colProps: { |
|||
span: 3, |
|||
}, |
|||
}, |
|||
{ |
|||
label: '', |
|||
field: '0', |
|||
component: 'Input', |
|||
slot: 'configButton', |
|||
colProps: { |
|||
span: 2, |
|||
}, |
|||
|
|||
}, |
|||
{ |
|||
label: '复盘', |
|||
field: 'fp', |
|||
component: 'RadioGroup', |
|||
defaultValue: 0, |
|||
|
|||
componentProps: { |
|||
|
|||
options: [ |
|||
{ |
|||
label: '是', |
|||
value: 1, |
|||
}, |
|||
{ |
|||
label: '否', |
|||
value: 0, |
|||
}, |
|||
], |
|||
}, |
|||
required: true, |
|||
|
|||
}, |
|||
] |
|||
|
|||
export const searchFormSchemaModel: FormSchema[] = [ |
|||
{ |
|||
label: '模型实例名称', |
|||
field: 'mpName', |
|||
component: 'Input', |
|||
defaultValue: '', |
|||
required: true, |
|||
colProps: { span: 8 }, |
|||
}, |
|||
] |
|||
|
|||
export const createInstantForm: FormSchema[] = [ |
|||
|
|||
{ |
|||
label: '所用模型的id', |
|||
field: 'modelId', |
|||
component: 'Input', |
|||
required: true, |
|||
show: false, |
|||
colProps: { |
|||
span: 12, |
|||
}, |
|||
}, |
|||
{ |
|||
label: '实例名称', |
|||
field: 'mpName', |
|||
component: 'Input', |
|||
required: true, |
|||
colProps: { |
|||
span: 12, |
|||
}, |
|||
componentProps: { |
|||
placeholder: '请选择下方模型以生成实例', |
|||
}, |
|||
rules: [{ required: true, message: '请选择下方模型以生成实例' }], |
|||
}, |
|||
{ |
|||
label: '运行周期', |
|||
field: 'intervalTime', |
|||
component: 'Input', |
|||
required: true, |
|||
defaultValue: 30, |
|||
colProps: { |
|||
span: 6, |
|||
}, |
|||
}, |
|||
{ |
|||
label: '计算组', |
|||
field: 'calcGroup', |
|||
component: 'Select', |
|||
componentProps: { |
|||
options: [], |
|||
}, |
|||
colProps: { |
|||
span: 6, |
|||
}, |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: '版本号', |
|||
field: 'modelVersionId', |
|||
component: 'Select', |
|||
|
|||
componentProps: { |
|||
// api: getModelVersionList,
|
|||
// labelField: 'version',
|
|||
// valueField: 'id',
|
|||
// params: {},
|
|||
options: [], |
|||
}, |
|||
colProps: { |
|||
span: 12, |
|||
}, |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: '是否存储', |
|||
field: 'hisSto', |
|||
component: 'RadioGroup', |
|||
defaultValue: '1', |
|||
componentProps: { |
|||
options: [ |
|||
{ |
|||
label: '是', |
|||
value: '1', |
|||
}, |
|||
{ |
|||
label: '否', |
|||
value: '0', |
|||
}, |
|||
], |
|||
}, |
|||
colProps: { |
|||
span: 6, |
|||
}, |
|||
required: true, |
|||
|
|||
}, |
|||
] |
|||
export const updateInstantForm: FormSchema[] = [ |
|||
|
|||
{ |
|||
label: '编号', |
|||
field: 'id', |
|||
component: 'Input', |
|||
required: true, |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: '实例名称', |
|||
field: 'mpName', |
|||
component: 'Input', |
|||
required: true, |
|||
|
|||
componentProps: { |
|||
placeholder: '请输入实例名称', |
|||
}, |
|||
rules: [{ required: true, message: '请输入实例名称' }], |
|||
}, |
|||
{ |
|||
label: '计算组', |
|||
field: 'calcGroup', |
|||
component: 'Select', |
|||
componentProps: { |
|||
options: [], |
|||
}, |
|||
|
|||
required: true, |
|||
}, |
|||
{ |
|||
label: '版本号', |
|||
field: 'modelVersionId', |
|||
component: 'Select', |
|||
componentProps: { |
|||
options: [], |
|||
}, |
|||
|
|||
required: true, |
|||
}, |
|||
] |
|||
export const InstantBasicInfo: any[] = [ |
|||
|
|||
{ |
|||
label: '实例名称', |
|||
field: 'mpName', |
|||
|
|||
}, |
|||
{ |
|||
label: '创建人', |
|||
field: 'creator', |
|||
}, |
|||
{ |
|||
label: '创建时间', |
|||
field: 'createTime', |
|||
}, |
|||
{ |
|||
label: '最近修改人', |
|||
field: 'updater', |
|||
}, |
|||
{ |
|||
label: '最近修改时间', |
|||
field: 'updateTime', |
|||
}, |
|||
{ |
|||
label: '算法', |
|||
field: 'algorithm_shortname', |
|||
}, |
|||
|
|||
// modelInfo中的字段
|
|||
{ |
|||
label: '训练采样间隔', |
|||
field: 'sampling', |
|||
}, |
|||
|
|||
{ |
|||
label: '参数个数', |
|||
field: 'pointInfo', |
|||
}, |
|||
{ |
|||
label: '最小主元贡献率', |
|||
field: 'rate', |
|||
}, |
|||
{ |
|||
label: '主元个数', |
|||
field: 'principal', |
|||
}, |
|||
{ |
|||
label: '模型精度', |
|||
field: 'rate', |
|||
}, |
|||
] |
|||
|
|||
export const detailColumns: BasicColumn[] = [ |
|||
{ |
|||
title: '编号', |
|||
dataIndex: 'id', |
|||
width: 80, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '测点编码', |
|||
dataIndex: 'inputInfo', |
|||
width: 150, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '测点名称', |
|||
dataIndex: 'inputName', |
|||
width: 200, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '单位', |
|||
dataIndex: 'unit', |
|||
width: 50, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '重构值测点', |
|||
dataIndex: 'outPointInfo', |
|||
width: 200, |
|||
|
|||
}, |
|||
{ |
|||
title: '偏差值测点', |
|||
dataIndex: 'biasPointInfo', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '错误状态测点', |
|||
dataIndex: 'faultVariablePointInfo', |
|||
width: 200, |
|||
}, |
|||
] |
|||
@ -0,0 +1,66 @@ |
|||
<script lang="ts" setup> |
|||
import { onMounted, reactive, ref, watch } from 'vue' |
|||
import { columns, searchFormSchema } from './model.data' |
|||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|||
import { getModelPage } from '@/api/alert/run/model' |
|||
import { IconEnum } from '@/enums/appEnum' |
|||
import { useI18n } from '@/hooks/web/useI18n' |
|||
|
|||
defineOptions({ name: 'ModelTable' }) |
|||
const emit = defineEmits(['success']) |
|||
|
|||
const { t } = useI18n() |
|||
|
|||
const [registerTable, { setSelectedRowKeys }] = useTable({ |
|||
title: '模型列表', |
|||
api: getModelPage, |
|||
rowKey: 'id', |
|||
rowSelection: { type: 'radio', async onChange(selectedRowKeys, selectedRows) { |
|||
emit('success', selectedRowKeys, selectedRows) |
|||
} }, |
|||
size: 'small', |
|||
immediate: true, |
|||
columns, |
|||
formConfig: { |
|||
labelWidth: 80, |
|||
schemas: searchFormSchema, |
|||
showResetButton: false, |
|||
actionColOptions: { |
|||
span: 2, |
|||
}, |
|||
}, |
|||
useSearchForm: true, |
|||
showTableSetting: true, |
|||
showIndexColumn: false, |
|||
|
|||
}) |
|||
onMounted(async () => { |
|||
}) |
|||
|
|||
// watch( |
|||
// () => props.selectedRowKeys, |
|||
// () => { |
|||
// state.selectedRowKeys = props.selectedRowKeys |
|||
// }, |
|||
// ) |
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<BasicTable @register="registerTable"> |
|||
<template #pointNumber="{ record }"> |
|||
{{ (JSON.parse(record.modelInfo)).pointInfo.length }} |
|||
</template> |
|||
<template #precision="{ record }"> |
|||
{{ (JSON.parse(record.modelInfo)).precision }} |
|||
</template> |
|||
</BasicTable> |
|||
</div> |
|||
</template> |
|||
|
|||
<style lang="less" scoped> |
|||
:deep(.ant-table-body){ |
|||
height:100% !important; |
|||
max-height:100% !important |
|||
} |
|||
</style> |
|||
@ -0,0 +1,110 @@ |
|||
<script lang="ts" setup> |
|||
import { defineExpose, onMounted, reactive, ref, watch } from 'vue' |
|||
import { autoCompleteProps } from 'ant-design-vue/es/auto-complete' |
|||
import PointModal from '../../exa/history/PointModal.vue' |
|||
import { columns } from './point.data' |
|||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|||
import { useI18n } from '@/hooks/web/useI18n' |
|||
import { IconEnum } from '@/enums/appEnum' |
|||
import { useModal } from '@/components/Modal' |
|||
|
|||
defineOptions({ name: 'ModelTable' }) |
|||
const props = defineProps({ |
|||
data: { |
|||
type: Array<Recordable>, |
|||
default: () => [], |
|||
}, |
|||
type: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
}) |
|||
|
|||
const { t } = useI18n() |
|||
const updateIndex = ref<number>(0) |
|||
|
|||
const [registerPointModal, { openModal: openPointModal }] = useModal() |
|||
function handlePoint(record) { |
|||
openPointModal(true, record) |
|||
console.log(record) |
|||
updateIndex.value = record.LAY_TABLE_INDEX |
|||
} |
|||
const [registerTable, { setColumns, getDataSource, updateTableDataRecord }] = useTable({ |
|||
title: '测点列表', |
|||
maxHeight: 300, |
|||
dataSource: props.data, |
|||
size: 'small', |
|||
columns, |
|||
useSearchForm: false, |
|||
showTableSetting: false, |
|||
showIndexColumn: true, |
|||
actionColumn: { |
|||
width: 140, |
|||
title: t('common.action'), |
|||
dataIndex: 'action', |
|||
fixed: 'right', |
|||
}, |
|||
}) |
|||
// 自动请求并暴露内部方法 |
|||
onMounted(() => { |
|||
console.log(props.type) |
|||
if (props.type) { |
|||
console.log('改变列') |
|||
setColumns([...columns, { |
|||
title: '测点类型', |
|||
dataIndex: 'type', |
|||
width: 80, |
|||
slots: { customRender: 'type' }, |
|||
}]) |
|||
} |
|||
}) |
|||
const source = ref<string>('run') |
|||
const rowSelectType = ref<string>('radio') |
|||
|
|||
function updateTableData(selectedData) { |
|||
const item = getDataSource()[updateIndex.value] |
|||
item.PointId = selectedData[0].itemName |
|||
item.Description = selectedData[0].descriptor |
|||
item.Unit = selectedData[0].engUnits |
|||
updateTableDataRecord(updateIndex.value, item) |
|||
|
|||
console.log(selectedData) |
|||
|
|||
// 替换测点列表中的测点 |
|||
console.log('更新表格数据') |
|||
} |
|||
function getPointTableData() { |
|||
const tableData = getDataSource() |
|||
|
|||
return tableData |
|||
} |
|||
// <!-- 使用defineExpose将组件中的数据交给外部,这样父组件中的demoRef.value才可以访问到如下数据 --> |
|||
defineExpose({ getPointTableData }) |
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<BasicTable @register="registerTable"> |
|||
<template #type="{ record }"> |
|||
{{ record.type ? '输入' : '输出' }} |
|||
</template> |
|||
<template #bodyCell="{ column, record }"> |
|||
<template v-if="column.key === 'action'"> |
|||
<TableAction |
|||
:actions="[{ icon: IconEnum.CHANGE, label: t('action.pointConfig'), auth: 'run:instant:update', onClick: handlePoint.bind(null, record) }, |
|||
|
|||
]" |
|||
/> |
|||
</template> |
|||
</template> |
|||
</BasicTable> |
|||
<PointModal :source="source" :row-select-type="rowSelectType" @register="registerPointModal" @success="updateTableData" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<style lang="less" scoped> |
|||
:deep(.ant-table-body){ |
|||
height:100% !important; |
|||
max-height:100% !important |
|||
} |
|||
</style> |
|||
@ -0,0 +1,55 @@ |
|||
import moment from 'moment' |
|||
import { left } from 'inquirer/lib/utils/readline' |
|||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|||
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: '编号', |
|||
dataIndex: 'id', |
|||
width: 80, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '机组', |
|||
dataIndex: 'unitName', |
|||
width: 100, |
|||
fixed: 'left', |
|||
}, |
|||
|
|||
{ |
|||
title: '模型名称', |
|||
dataIndex: 'modelName', |
|||
width: 250, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '算法', |
|||
dataIndex: 'algorithmName', |
|||
width: 200, |
|||
|
|||
}, |
|||
{ |
|||
title: '测点个数', |
|||
dataIndex: 'pointNumber', |
|||
width: 200, |
|||
slots: { customRender: 'pointNumber' }, |
|||
|
|||
}, |
|||
{ |
|||
title: '模型精度', |
|||
dataIndex: 'precision', |
|||
width: 200, |
|||
slots: { customRender: 'precision' }, |
|||
}, |
|||
] |
|||
|
|||
export const searchFormSchema: FormSchema[] = [ |
|||
{ |
|||
label: '模型名称', |
|||
field: 'modelName', |
|||
component: 'Input', |
|||
defaultValue: '', |
|||
colProps: { span: 6 }, |
|||
}, |
|||
] |
|||
@ -0,0 +1,34 @@ |
|||
import moment from 'moment' |
|||
import { left } from 'inquirer/lib/utils/readline' |
|||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|||
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: '点号', |
|||
dataIndex: 'PointId', |
|||
width: 150, |
|||
}, |
|||
{ |
|||
title: '描述', |
|||
dataIndex: 'Description', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '单位', |
|||
dataIndex: 'Unit', |
|||
width: 80, |
|||
}, |
|||
|
|||
{ |
|||
title: '所属模型', |
|||
dataIndex: 'modelName', |
|||
width: 150, |
|||
}, |
|||
{ |
|||
title: '模型描述', |
|||
dataIndex: 'modelDescirption', |
|||
width: 150, |
|||
|
|||
}, |
|||
] |
|||
@ -0,0 +1,125 @@ |
|||
<script lang="ts" setup> |
|||
import { Badge, Switch } from 'ant-design-vue' |
|||
import { onMounted, ref } from 'vue' |
|||
|
|||
import { useRoute } from 'vue-router' |
|||
import HistoryModal from '../../exa/config/HistoryModal.vue' |
|||
import { columns, searchFormSchema } from './warn.data' |
|||
import CreateModal from './CreateModal.vue' |
|||
import UpdateModal from './UpdateModal.vue' |
|||
|
|||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|||
import { getWarnPage, updateWarn } from '@/api/alert/warn' |
|||
import { getExaNow } from '@/api/alert/exa' |
|||
import { useI18n } from '@/hooks/web/useI18n' |
|||
import { router } from '@/router' |
|||
import { useMessage } from '@/hooks/web/useMessage' |
|||
import { IconEnum } from '@/enums/appEnum' |
|||
import { useModal } from '@/components/Modal' |
|||
|
|||
defineOptions({ name: 'Warn' }) |
|||
|
|||
const route = useRoute() |
|||
|
|||
const { createMessage } = useMessage() |
|||
const { t } = useI18n() |
|||
const [registerUpdateModal, { openModal: openUpdateModal }] = useModal() |
|||
const [registerTable, { getForm, reload, getDataSource, updateTableDataRecord }] = useTable({ |
|||
title: '预警测点列表', |
|||
api: getWarnPage, |
|||
rowKey: 'id', |
|||
immediate: true, |
|||
columns, |
|||
formConfig: { |
|||
labelWidth: 120, |
|||
schemas: searchFormSchema, |
|||
showResetButton: false, |
|||
showSubmitButton: false, |
|||
actionColOptions: { |
|||
span: 2, |
|||
}, |
|||
|
|||
}, |
|||
beforeFetch: (params) => { |
|||
// 方式二:通过查询前的事件增加默认值,然后设置到表单值中 |
|||
params.mpId = route.query.id |
|||
getForm().setFieldsValue(params) |
|||
return params |
|||
}, |
|||
useSearchForm: !route.query.id, |
|||
showTableSetting: true, |
|||
showIndexColumn: false, |
|||
actionColumn: { |
|||
width: 120, |
|||
title: t('common.action'), |
|||
dataIndex: 'action', |
|||
fixed: 'right', |
|||
}, |
|||
|
|||
}) |
|||
|
|||
async function updateStatus(record) { |
|||
await updateWarn(record) |
|||
createMessage.success(t('common.saveSuccessText')) |
|||
console.log(record) |
|||
reload() |
|||
} |
|||
function handleWarnConfig(record: Recordable) { |
|||
openUpdateModal(true, { record, isUpdate: true }) |
|||
} |
|||
|
|||
onMounted(async () => { |
|||
|
|||
}) |
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<BasicTable @register="registerTable"> |
|||
<template #bodyCell="{ column, record }"> |
|||
<template v-if="column.key === 'action'"> |
|||
<TableAction |
|||
:actions="[ |
|||
|
|||
{ icon: IconEnum.WARN, label: t('action.warnConfig'), auth: 'run:instant:warnConfig', onClick: handleWarnConfig.bind(null, record) }, |
|||
|
|||
]" |
|||
/> |
|||
</template> |
|||
</template> |
|||
<template #warnStatus="{ record }"> |
|||
<Switch |
|||
v-model:checked="record.warnStatus" :checked-value="1" :un-checked-value="0" checked-children="是" |
|||
un-checked-children="否" @change="updateStatus(record)" |
|||
/> |
|||
</template> |
|||
<template #shortMessageOnOff="{ record }"> |
|||
<Switch |
|||
v-model:checked="record.shortMessageOnOff" :checked-value="1" :un-checked-value="0" checked-children="是" |
|||
un-checked-children="否" @change="updateStatus(record)" |
|||
/> |
|||
</template> |
|||
<template #gzpOnOff="{ record }"> |
|||
<Switch |
|||
v-model:checked="record.gzpOnOff" :checked-value="1" :un-checked-value="0" checked-children="是" |
|||
un-checked-children="否" @change="updateStatus(record)" |
|||
/> |
|||
</template> |
|||
<template #copyToDiagOnOff="{ record }"> |
|||
<Switch |
|||
v-model:checked="record.copyToDiagOnOff" :checked-value="1" :un-checked-value="0" checked-children="是" |
|||
un-checked-children="否" @change="updateStatus(record)" |
|||
/> |
|||
</template> |
|||
|
|||
<template #timeDurationThreshold="{ record }"> |
|||
{{ `${record.timeDurationThreshold}秒` }} |
|||
</template> |
|||
</BasicTable> |
|||
<UpdateModal @register="registerUpdateModal" @success="reload" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<style lang="less" scoped> |
|||
|
|||
</style> |
|||
@ -0,0 +1,88 @@ |
|||
<script lang="ts" setup> |
|||
import { ref, unref } from 'vue' |
|||
import { updateWarnForm } from './warn.data' |
|||
import { useI18n } from '@/hooks/web/useI18n' |
|||
import { useMessage } from '@/hooks/web/useMessage' |
|||
import { BasicForm, useForm } from '@/components/Form' |
|||
import { BasicModal, useModalInner } from '@/components/Modal' |
|||
import { getWarn, updateWarn } from '@/api/alert/warn/index' |
|||
|
|||
import { getModelVersionList } from '@/api/alert/run/model/index' |
|||
import { getCalcGroupList } from '@/api/alert/run/calcgroup/index' |
|||
|
|||
defineOptions({ name: 'WarnUpdateModal' }) |
|||
|
|||
const emit = defineEmits(['success', 'register']) |
|||
const { t } = useI18n() |
|||
const { createMessage } = useMessage() |
|||
const isUpdate = ref(true) |
|||
|
|||
const [registerForm, { updateSchema, setFieldsValue, resetFields, validate }] = useForm({ |
|||
labelWidth: 120, |
|||
baseColProps: { span: 24 }, |
|||
schemas: updateWarnForm, |
|||
showActionButtonGroup: false, |
|||
actionColOptions: { span: 23 }, |
|||
|
|||
}) |
|||
|
|||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { |
|||
resetFields() |
|||
setModalProps({ useWrapper: true, minHeight: 180, confirmLoading: false }) |
|||
// 如果是修改modal,则赋值给表单 |
|||
isUpdate.value = !!data?.isUpdate |
|||
if (unref(isUpdate)) { |
|||
const res = await getWarn(data.record.id) |
|||
setFieldsValue({ ...res }) |
|||
} |
|||
// // 获取下拉框的数据 |
|||
// const versionData = await getModelVersionList({ modelId: data?.record.modelId }) |
|||
// const versionList = [] as any |
|||
// // // 组名下拉框问题 |
|||
// versionData.forEach((item) => { |
|||
// versionList.push({ label: item.version, value: item.id }) |
|||
// }) |
|||
// const calcGroupData = await getCalcGroupList({ unitId: data?.record.unitId }) |
|||
// const calcGroupList = [] as any |
|||
// // // 组名下拉框问题 |
|||
// calcGroupData.forEach((item) => { |
|||
// calcGroupList.push({ label: item.groupName, value: item.id }) |
|||
// }) |
|||
|
|||
// // 将数据放入下拉框中 |
|||
// updateSchema({ |
|||
// field: 'modelVersionId', |
|||
// componentProps: { |
|||
// options: versionList, |
|||
// }, |
|||
// }) |
|||
// updateSchema({ |
|||
// field: 'calcGroup', |
|||
// componentProps: { |
|||
// options: calcGroupList, |
|||
// }, |
|||
// }) |
|||
}) |
|||
|
|||
async function handleSubmit() { |
|||
try { |
|||
const values = await validate() |
|||
setModalProps({ confirmLoading: true }) |
|||
if (unref(isUpdate)) |
|||
await updateWarn(values) |
|||
|
|||
closeModal() |
|||
emit('success') |
|||
createMessage.success(t('common.saveSuccessText')) |
|||
} |
|||
finally { |
|||
setModalProps({ confirmLoading: false }) |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<template> |
|||
<BasicModal v-bind="$attrs" :title="isUpdate ? t('action.edit') : t('action.create')" @register="registerModal" @ok="handleSubmit"> |
|||
<BasicForm @register="registerForm" /> |
|||
</BasicModal> |
|||
</template> |
|||
@ -0,0 +1,352 @@ |
|||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|||
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: '编号', |
|||
dataIndex: 'id', |
|||
width: 80, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '点号', |
|||
dataIndex: 'pointId', |
|||
width: 150, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '描述', |
|||
dataIndex: 'pointName', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '单位', |
|||
dataIndex: 'unit', |
|||
width: 80, |
|||
}, |
|||
{ |
|||
title: '上限', |
|||
dataIndex: 'uplimit', |
|||
width: 80, |
|||
}, |
|||
{ |
|||
title: '下限', |
|||
dataIndex: 'lowlimit', |
|||
width: 80, |
|||
}, |
|||
{ |
|||
title: '实例名称', |
|||
dataIndex: 'mpName', |
|||
width: 250, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '专业', |
|||
dataIndex: 'systemName', |
|||
width: 200, |
|||
|
|||
}, |
|||
{ |
|||
title: '报警类型', |
|||
dataIndex: 'alarmModelRuleName', |
|||
width: 120, |
|||
|
|||
}, |
|||
{ |
|||
title: '报警限制', |
|||
dataIndex: 'warnConstraintName', |
|||
width: 120, |
|||
|
|||
}, |
|||
{ |
|||
title: '报警类型', |
|||
dataIndex: 'alarmModelRuleName', |
|||
width: 120, |
|||
|
|||
}, |
|||
{ |
|||
title: '告警延时', |
|||
dataIndex: 'timeDurationThreshold', |
|||
width: 100, |
|||
slots: { customRender: 'timeDurationThreshold' }, |
|||
}, |
|||
{ |
|||
title: '短信告警', |
|||
dataIndex: 'shortMessageOnOff', |
|||
width: 100, |
|||
slots: { customRender: 'shortMessageOnOff' }, |
|||
|
|||
}, |
|||
{ |
|||
title: '光字牌告警', |
|||
dataIndex: 'gzpOnOff', |
|||
width: 100, |
|||
slots: { customRender: 'gzpOnOff' }, |
|||
|
|||
}, |
|||
{ |
|||
title: '推送诊断', |
|||
dataIndex: 'copyToDiagOnOff', |
|||
width: 100, |
|||
slots: { customRender: 'copyToDiagOnOff' }, |
|||
|
|||
}, |
|||
{ |
|||
title: '已有实例数量', |
|||
dataIndex: 'number', |
|||
width: 100, |
|||
}, |
|||
{ |
|||
title: '参与报警', |
|||
dataIndex: 'warnStatus', |
|||
width: 100, |
|||
slots: { customRender: 'warnStatus' }, |
|||
fixed: 'right', |
|||
}, |
|||
// {
|
|||
// title: '实时值',
|
|||
// dataIndex: 'value',
|
|||
// width: 90,
|
|||
// className: 'value',
|
|||
// slots: { customRender: 'value' },
|
|||
|
|||
// }
|
|||
|
|||
] |
|||
|
|||
export const searchFormSchema: FormSchema[] = [ |
|||
{ |
|||
label: '模型实例id', |
|||
field: 'mpId', |
|||
component: 'Input', |
|||
defaultValue: '', |
|||
required: true, |
|||
show: false, |
|||
colProps: { span: 8 }, |
|||
}, |
|||
|
|||
] |
|||
|
|||
export const updateWarnForm: FormSchema[] = [ |
|||
{ |
|||
label: '编号', |
|||
field: 'id', |
|||
component: 'Input', |
|||
required: true, |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: '残差上限', |
|||
field: 'uplimit', |
|||
component: 'Input', |
|||
required: true, |
|||
componentProps: { |
|||
placeholder: '请输入残差上限', |
|||
}, |
|||
rules: [{ required: true, message: '请输入残差上限' }], |
|||
colProps: { |
|||
span: 12, |
|||
}, |
|||
}, |
|||
{ |
|||
label: '残差下限', |
|||
field: 'lowlimit', |
|||
component: 'Input', |
|||
required: true, |
|||
componentProps: { |
|||
placeholder: '请输入残差下限', |
|||
}, |
|||
rules: [{ required: true, message: '请输入残差下限' }], |
|||
colProps: { |
|||
span: 12, |
|||
}, |
|||
}, |
|||
{ |
|||
label: '延时告警', |
|||
field: 'timeDurationThreshold', |
|||
component: 'Input', |
|||
required: true, |
|||
componentProps: { |
|||
placeholder: '请输入延时告警', |
|||
}, |
|||
rules: [{ required: true, message: '请输入延时告警' }], |
|||
colProps: { |
|||
span: 12, |
|||
}, |
|||
}, |
|||
|
|||
{ |
|||
label: '告警等级', |
|||
field: 'alarmLevel', |
|||
component: 'Select', |
|||
componentProps: { |
|||
options: [], |
|||
}, |
|||
required: true, |
|||
colProps: { |
|||
span: 12, |
|||
}, |
|||
}, |
|||
{ |
|||
label: '光字牌名称', |
|||
field: 'gzpName', |
|||
component: 'Input', |
|||
required: true, |
|||
colProps: { |
|||
span: 12, |
|||
}, |
|||
}, |
|||
{ |
|||
label: '光字牌状态', |
|||
field: 'gzpOnOff', |
|||
component: 'RadioGroup', |
|||
componentProps: { |
|||
// 数据源1:固定数据
|
|||
options: [ |
|||
{ label: '是', value: 1 }, |
|||
{ label: '否', value: 0 }, |
|||
], |
|||
}, |
|||
required: true, |
|||
colProps: { |
|||
span: 12, |
|||
}, |
|||
}, |
|||
|
|||
{ |
|||
label: '短信推送', |
|||
field: 'shortMessageOnOff', |
|||
component: 'RadioGroup', |
|||
componentProps: { |
|||
options: [{ label: '是', value: 1 }, { label: '否', value: 0 }], |
|||
}, |
|||
required: true, |
|||
colProps: { |
|||
span: 12, |
|||
}, |
|||
}, |
|||
{ |
|||
label: '推送诊断', |
|||
field: 'copyToDiagOnOff', |
|||
component: 'RadioGroup', |
|||
componentProps: { |
|||
options: [{ label: '是', value: 1 }, { label: '否', value: 0 }], |
|||
}, |
|||
required: true, |
|||
colProps: { |
|||
span: 12, |
|||
}, |
|||
}, |
|||
{ |
|||
label: '告警限制名称', |
|||
field: 'warnConstraintName', |
|||
component: 'Input', |
|||
|
|||
required: true, |
|||
colProps: { |
|||
span: 12, |
|||
}, |
|||
}, |
|||
{ |
|||
label: '告警限制条件', |
|||
field: 'warnConstraint', |
|||
component: 'Input', |
|||
required: true, |
|||
colProps: { |
|||
span: 12, |
|||
}, |
|||
}, |
|||
] |
|||
export const InstantBasicInfo: any[] = [ |
|||
|
|||
{ |
|||
label: '实例名称', |
|||
field: 'mpName', |
|||
|
|||
}, |
|||
{ |
|||
label: '创建人', |
|||
field: 'creator', |
|||
}, |
|||
{ |
|||
label: '创建时间', |
|||
field: 'createTime', |
|||
}, |
|||
{ |
|||
label: '最近修改人', |
|||
field: 'updater', |
|||
}, |
|||
{ |
|||
label: '最近修改时间', |
|||
field: 'updateTime', |
|||
}, |
|||
{ |
|||
label: '算法', |
|||
field: 'algorithm_shortname', |
|||
}, |
|||
|
|||
// modelInfo中的字段
|
|||
{ |
|||
label: '训练采样间隔', |
|||
field: 'sampling', |
|||
}, |
|||
|
|||
{ |
|||
label: '参数个数', |
|||
field: 'pointInfo', |
|||
}, |
|||
{ |
|||
label: '最小主元贡献率', |
|||
field: 'rate', |
|||
}, |
|||
{ |
|||
label: '主元个数', |
|||
field: 'principal', |
|||
}, |
|||
{ |
|||
label: '模型精度', |
|||
field: 'rate', |
|||
}, |
|||
] |
|||
|
|||
export const detailColumns: BasicColumn[] = [ |
|||
{ |
|||
title: '编号', |
|||
dataIndex: 'id', |
|||
width: 80, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '测点编码', |
|||
dataIndex: 'inputInfo', |
|||
width: 150, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '测点名称', |
|||
dataIndex: 'inputName', |
|||
width: 200, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '单位', |
|||
dataIndex: 'unit', |
|||
width: 50, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '重构值测点', |
|||
dataIndex: 'outPointInfo', |
|||
width: 200, |
|||
|
|||
}, |
|||
{ |
|||
title: '偏差值测点', |
|||
dataIndex: 'biasPointInfo', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '错误状态测点', |
|||
dataIndex: 'faultVariablePointInfo', |
|||
width: 200, |
|||
}, |
|||
] |
|||
Loading…
Reference in new issue