Compare commits
49 Commits
b12fa64f1e
...
777b92535d
| Author | SHA1 | Date |
|---|---|---|
|
|
777b92535d | 2 months ago |
|
|
072c699d54 | 2 months ago |
|
|
9fca3ac2f0 | 2 months ago |
|
|
21d13a35ad | 2 months ago |
|
|
74592a7ec0 | 2 months ago |
|
|
78b9b741b5 | 2 months ago |
|
|
1095dcb068 | 2 months ago |
|
|
63a1fe18f2 | 2 months ago |
|
|
5361462e35 | 2 months ago |
|
|
cda9974a3e | 2 months ago |
|
|
9c1790ac5a | 2 months ago |
|
|
fa9d21e551 | 2 months ago |
|
|
9ddf6f65d0 | 2 months ago |
|
|
c184e89de0 | 2 months ago |
|
|
200b108f68 | 2 months ago |
|
|
5dbfc3b835 | 2 months ago |
|
|
c31fe17c03 | 2 months ago |
|
|
8681b6401e | 2 months ago |
|
|
477d3fa69b | 2 months ago |
|
|
c18552afb4 | 2 months ago |
|
|
da7b9e3902 | 2 months ago |
|
|
26a43c058c | 2 months ago |
|
|
3ea477968b | 2 months ago |
|
|
96e2be221a | 2 months ago |
|
|
0d09bd2451 | 2 months ago |
|
|
6767579d02 | 2 months ago |
|
|
f65202518c | 2 months ago |
|
|
28265bebdd | 2 months ago |
|
|
90f9ad64ae | 2 months ago |
|
|
38f744b699 | 2 months ago |
|
|
b2d2e298a7 | 2 months ago |
|
|
9f7f685c59 | 2 months ago |
|
|
434e1da621 | 2 months ago |
|
|
ae8bdeb120 | 2 months ago |
|
|
69216ea7bb | 2 months ago |
|
|
eb51a69a6d | 2 months ago |
|
|
74053a529d | 2 months ago |
|
|
71492d157b | 2 months ago |
|
|
133a48dbce | 3 months ago |
|
|
9e1170bbc8 | 3 months ago |
|
|
4349a02db8 | 3 months ago |
|
|
9a41177294 | 4 months ago |
|
|
f6c4ee9011 | 4 months ago |
|
|
93393410dd | 4 months ago |
|
|
c73d294c6e | 4 months ago |
|
|
6126dc5f60 | 4 months ago |
|
|
7fe3d8fa38 | 4 months ago |
|
|
a2a5fc9efa | 5 months ago |
|
|
7b6f54edf3 | 5 months ago |
40 changed files with 1942 additions and 45 deletions
|
After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
@ -0,0 +1,8 @@ |
|||
import { defHttp } from '@/utils/http/axios' |
|||
|
|||
// 获得地区树
|
|||
export function getDeviceInfo(id: string) { |
|||
return defHttp.get({ url: `/device/info?id=${id}` }) |
|||
} |
|||
|
|||
// 获得 IP 对应的地区名
|
|||
@ -0,0 +1,42 @@ |
|||
import { defHttp } from '@/utils/http/axios' |
|||
|
|||
/** |
|||
* @description: 系统配置VO |
|||
*/ |
|||
export interface SystemConfigVO { |
|||
id?: number |
|||
name: string |
|||
abbreviation?: string |
|||
} |
|||
|
|||
/** |
|||
* @description: 系统配置分页查询参数 |
|||
*/ |
|||
export interface SystemConfigPageReqVO { |
|||
name?: string |
|||
} |
|||
|
|||
// 查询系统配置分页列表
|
|||
export function getSystemConfigPage(params: SystemConfigPageReqV) { |
|||
return defHttp.get({ url: '/system/system-config/page', params }) |
|||
} |
|||
|
|||
// 获取系统配置详情
|
|||
export function getSystemConfig(id: number) { |
|||
return defHttp.get({ url: `/system/system-config/get?id=${id}` }) |
|||
} |
|||
|
|||
// 新增系统配置
|
|||
export function createSystemConfig(data: SystemConfigVO) { |
|||
return defHttp.post({ url: '/system/system-config/create', data }) |
|||
} |
|||
|
|||
// 修改系统配置
|
|||
export function updateSystemConfig(data: SystemConfigVO) { |
|||
return defHttp.put({ url: '/system/system-config/update', data }) |
|||
} |
|||
|
|||
// 删除系统配置
|
|||
export function deleteSystemConfig(id: number) { |
|||
return defHttp.delete({ url: `/system/system-config/delete?id=${id}` }) |
|||
} |
|||
|
After Width: | Height: | Size: 9.7 KiB |
@ -0,0 +1,59 @@ |
|||
<script lang="ts" setup> |
|||
import { toRefs, watch } from 'vue' |
|||
|
|||
import { Card, List } from 'ant-design-vue' |
|||
|
|||
const props = defineProps({ |
|||
data: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
}) |
|||
watch( |
|||
() => props.data, |
|||
(newValue, oldValue) => { |
|||
// 下方信息不会打印在控制台中 |
|||
console.log('a has changed', newValue, oldValue) |
|||
}, |
|||
) |
|||
const ListItem = List.Item |
|||
const ListItemMeta = List.Item.Meta |
|||
</script> |
|||
|
|||
<template> |
|||
<Card id="www" :title="props.data.Header" v-bind="$attrs" class-name="spcard"> |
|||
<template #extra> |
|||
<a-button type="link"> |
|||
更多 |
|||
</a-button> |
|||
</template> |
|||
<List item-layout="horizontal" :data-source="props.data.Content"> |
|||
<template #renderItem="{ item }"> |
|||
<ListItem> |
|||
<ListItemMeta> |
|||
<template #description> |
|||
{{ item.StartTime }} {{ item.Duration }} |
|||
</template> |
|||
<!-- eslint-disable-next-line --> |
|||
<!-- <template #title> {{ item.Text }} <span v-html="item.desc"> </span> </template> --> |
|||
<template #title> |
|||
{{ item.Text }} |
|||
</template> |
|||
|
|||
<!-- <template #avatar> |
|||
<Icon :icon="item.avatar" :size="30" /> |
|||
</template> --> |
|||
</ListItemMeta> |
|||
</ListItem> |
|||
</template> |
|||
</List> |
|||
</Card> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
::v-deep(.ant-card-body) { |
|||
height:50%; |
|||
padding:10px; |
|||
overflow-y: auto; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,76 @@ |
|||
<script lang="ts" setup> |
|||
import { Card, Comment, List, ListItem } from 'ant-design-vue' |
|||
import dayjs from 'dayjs' |
|||
import { watch } from 'vue' |
|||
import relativeTime from 'dayjs/plugin/relativeTime' |
|||
|
|||
const props = defineProps({ |
|||
data: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
}) |
|||
watch( |
|||
() => props.data, |
|||
(newValue, oldValue) => { |
|||
// 下方信息不会打印在控制台中 |
|||
console.log('a has changed', newValue, oldValue) |
|||
}, |
|||
) |
|||
dayjs.extend(relativeTime) |
|||
</script> |
|||
|
|||
<template> |
|||
<Card :title="props.data.Header" v-bind="$attrs"> |
|||
<template #extra> |
|||
<a-button type="link"> |
|||
{{ props.data.Content.length || 0 }} 条指导建议 |
|||
</a-button> |
|||
</template> |
|||
<List |
|||
class="comment-list" |
|||
item-layout="horizontal" |
|||
:data-source="props.data.Content" |
|||
> |
|||
<template #renderItem="{ item }"> |
|||
<ListItem> |
|||
<Comment> |
|||
<template #author> |
|||
<a>{{ item.FaultDesc }}</a> |
|||
</template> |
|||
<template #content> |
|||
<p> |
|||
{{ item.Guide }} |
|||
</p> |
|||
</template> |
|||
<template #datetime> |
|||
<a-tooltip :title="dayjs().format('YYYY-MM-DD HH:mm:ss')"> |
|||
<span>{{ dayjs().fromNow() }}</span> |
|||
</a-tooltip> |
|||
</template> |
|||
</Comment> |
|||
</ListItem> |
|||
</template> |
|||
</List> |
|||
</Card> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
::v-deep(.ant-card-body) { |
|||
height:70%; |
|||
padding:5px; |
|||
overflow-y: auto; |
|||
} |
|||
|
|||
::v-deep(.ant-list-item) { |
|||
padding:5px; |
|||
} |
|||
|
|||
::v-deep(.ant-list-header) { |
|||
padding:5px |
|||
} |
|||
|
|||
::v-deep(.ant-comment-inner) { |
|||
padding: 5px 0 |
|||
} |
|||
</style> |
|||
@ -0,0 +1,103 @@ |
|||
<script lang="ts" setup> |
|||
import { Card } from 'ant-design-vue' |
|||
import { onBeforeUpdate, onMounted, onUpdated, ref, toRefs, watch } from 'vue' |
|||
import { BasicTable, useTable } from '@/components/Table' |
|||
import { getExaNow } from '@/api/alert/exa' |
|||
|
|||
const props = defineProps({ |
|||
data: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
}) |
|||
|
|||
const loading = ref(false) |
|||
|
|||
watch( |
|||
() => props.data, |
|||
(newValue, oldValue) => { |
|||
// 下方信息不会打印在控制台中 |
|||
console.log('a has changed', newValue, oldValue) |
|||
}, |
|||
) |
|||
function getInterval(record: any) { |
|||
console.log(record) |
|||
if (record.predictValue === '-') |
|||
return '-' |
|||
record.predictValue = Number(record.predictValue).toFixed(2) |
|||
|
|||
const threshold = record.ResidualThreshold |
|||
console.log(threshold) |
|||
const predictValue = record.predictValue || 0 |
|||
return `[${Number(predictValue) - threshold},${Number(predictValue) + threshold}]` |
|||
} |
|||
const [registerTable, { setTableData }] = useTable({ |
|||
dataSource: [], |
|||
rowKey: 'ID', |
|||
size: 'small', |
|||
immediate: false, |
|||
columns: props.data.Columns, |
|||
useSearchForm: false, |
|||
showTableSetting: false, |
|||
showIndexColumn: false, |
|||
}) |
|||
// 页面挂载时批量请求并更新数据(避免在模板中调用异步) |
|||
onBeforeUpdate(async () => { |
|||
loading.value = true |
|||
try { |
|||
const rr = [] as any[] |
|||
const rows = props.data.Content || [] |
|||
for (const item of rows) { |
|||
try { |
|||
// 如果后端需要同时传 ObservedPoint 和 PredictedPoint,用逗号拼接(请根据后端接口调整) |
|||
const param = item.PredictedPoint ? `${item.ObservedPoint},${item.PredictedPoint}` : `${item.ObservedPoint}` |
|||
const res = await getExaNow(param) |
|||
|
|||
let origin: any = '-' |
|||
let predict: any = '-' |
|||
if (res != null) { |
|||
if (Array.isArray(res)) { |
|||
origin = res[0] ?? '-' |
|||
predict = res[1] ?? '-' |
|||
} |
|||
else if (typeof res === 'object') { |
|||
origin = res.originValue ?? res[0] ?? '-' |
|||
predict = res.predictValue ?? res[1] ?? '-' |
|||
} |
|||
else { |
|||
origin = String(res) |
|||
} |
|||
} |
|||
rr.push(Object.assign({}, item, { originValue: origin, predictValue: predict })) |
|||
} |
|||
catch (e) { |
|||
} |
|||
} |
|||
setTableData(rr) |
|||
} |
|||
finally { |
|||
loading.value = false |
|||
} |
|||
}) |
|||
</script> |
|||
|
|||
<template> |
|||
<Card :title="props.data.Header" v-bind="$attrs"> |
|||
<!-- <template #extra> |
|||
<a-button type="link"> |
|||
更多 |
|||
</a-button> |
|||
</template> --> |
|||
<BasicTable style="min-height:30vh" :loading="loading" @register="registerTable"> |
|||
<template #threshold="{ record }"> |
|||
<span>{{ getInterval(record) }}</span> |
|||
</template> |
|||
</BasicTable> |
|||
</Card> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
::v-deep(.ant-card-body) { |
|||
padding:5px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,103 @@ |
|||
<script lang="ts" setup> |
|||
import { Card, CardGrid } from 'ant-design-vue' |
|||
import { onMounted, ref, watch } from 'vue' |
|||
|
|||
import { getExaNow } from '@/api/alert/exa' |
|||
|
|||
const props = defineProps({ |
|||
data: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
}) |
|||
const gridData = ref<any>([]) |
|||
|
|||
watch( |
|||
() => props.data, |
|||
(newValue, oldValue) => { |
|||
// 下方信息不会打印在控制台中 |
|||
console.log('a has changed', newValue, oldValue) |
|||
getNewData() |
|||
}, |
|||
) |
|||
async function getNewData() { |
|||
const rows = props.data.Content || [] |
|||
for (const item of rows) { |
|||
try { |
|||
const param = item.Point |
|||
const res = await getExaNow(param) |
|||
|
|||
let ifColor: boolean = false |
|||
if (res != null) |
|||
ifColor = res === '1' |
|||
|
|||
gridData.value.push(Object.assign({}, item, { ifColor })) |
|||
|
|||
console.log(gridData.value) |
|||
} |
|||
catch (e) { |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
// 页面挂载时批量请求并更新数据(避免在模板中调用异步) |
|||
// onMounted(async () => { |
|||
// const rows = props.data.Content || [] |
|||
// for (const item of rows) { |
|||
// try { |
|||
// const param = item.Point |
|||
// const res = await getExaNow(param) |
|||
|
|||
// let ifColor: boolean = false |
|||
// if (res != null) |
|||
// ifColor = res === '1' |
|||
|
|||
// gridData.value.push(Object.assign({}, item, { ifColor })) |
|||
|
|||
// console.log(gridData.value) |
|||
// } |
|||
// catch (e) { |
|||
// } |
|||
// } |
|||
// }) |
|||
</script> |
|||
|
|||
<template> |
|||
<Card :title="props.data.Header" v-bind="$attrs"> |
|||
<template #extra> |
|||
<a-button type="link"> |
|||
更多 |
|||
</a-button> |
|||
</template> |
|||
|
|||
<CardGrid v-for="item in gridData" :key="item.Point" :class="{ 'bg-[#990000] bg-opacity-50': item.ifColor }" class="flex flex-col items-center justify-center !h-1/3 !w-full !md:w-1/4"> |
|||
<!-- <Icon :icon="item.icon" :color="item.color" size="30" /> --> |
|||
<div class="flex flex-col items-center justify-center"> |
|||
<div class="text-center text-base"> |
|||
{{ item.FaultDesc }} |
|||
</div> |
|||
|
|||
<!-- <div class="text-secondary mt-1 h-10 flex"> |
|||
{{ item.Point }} |
|||
</div> --> |
|||
</div> |
|||
<!-- <div class="text-secondary flex justify-between"> |
|||
<span>{{ item.group }}</span> |
|||
<span>{{ item.date }}</span> |
|||
</div> --> |
|||
</CardGrid> |
|||
</Card> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
::v-deep(.ant-card-grid) { |
|||
padding:15px; |
|||
} |
|||
|
|||
::v-deep(.ant-card-body) { |
|||
height:80%; |
|||
overflow-y: auto; |
|||
|
|||
} |
|||
</style> |
|||
@ -0,0 +1,16 @@ |
|||
<script lang="ts" setup> |
|||
import { Card, CardGrid } from 'ant-design-vue' |
|||
import { navItems } from './data' |
|||
import { Icon } from '@/components/Icon' |
|||
</script> |
|||
|
|||
<template> |
|||
<Card title="快捷导航"> |
|||
<CardGrid v-for="item in navItems" :key="item.title"> |
|||
<span class="flex flex-col items-center"> |
|||
<Icon :icon="item.icon" :color="item.color" size="20" /> |
|||
<span class="text-md mt-2 truncate">{{ item.title }}</span> |
|||
</span> |
|||
</CardGrid> |
|||
</Card> |
|||
</template> |
|||
@ -0,0 +1,91 @@ |
|||
<script lang="ts" setup> |
|||
import type { Ref } from 'vue' |
|||
import { ref, watch } from 'vue' |
|||
import { Card } from 'ant-design-vue' |
|||
import { useECharts } from '@/hooks/web/useECharts' |
|||
import { propTypes } from '@/utils/propTypes' |
|||
|
|||
const props = defineProps({ |
|||
loading: Boolean, |
|||
width: propTypes.string.def('100%'), |
|||
height: propTypes.string.def('400px'), |
|||
}) |
|||
|
|||
const chartRef = ref<HTMLDivElement | null>(null) |
|||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>) |
|||
watch( |
|||
() => props.loading, |
|||
() => { |
|||
if (props.loading) |
|||
return |
|||
|
|||
setOptions({ |
|||
legend: { |
|||
bottom: 0, |
|||
data: ['Visits', 'Sales'], |
|||
}, |
|||
tooltip: {}, |
|||
radar: { |
|||
radius: '60%', |
|||
splitNumber: 8, |
|||
indicator: [ |
|||
{ |
|||
name: '2017', |
|||
}, |
|||
{ |
|||
name: '2017', |
|||
}, |
|||
{ |
|||
name: '2018', |
|||
}, |
|||
{ |
|||
name: '2019', |
|||
}, |
|||
{ |
|||
name: '2020', |
|||
}, |
|||
{ |
|||
name: '2021', |
|||
}, |
|||
], |
|||
}, |
|||
series: [ |
|||
{ |
|||
type: 'radar', |
|||
symbolSize: 0, |
|||
areaStyle: { |
|||
shadowBlur: 0, |
|||
shadowColor: 'rgba(0,0,0,.2)', |
|||
shadowOffsetX: 0, |
|||
shadowOffsetY: 10, |
|||
opacity: 1, |
|||
}, |
|||
data: [ |
|||
{ |
|||
value: [90, 50, 86, 40, 50, 20], |
|||
name: 'Visits', |
|||
itemStyle: { |
|||
color: '#b6a2de', |
|||
}, |
|||
}, |
|||
{ |
|||
value: [70, 75, 70, 76, 20, 85], |
|||
name: 'Sales', |
|||
itemStyle: { |
|||
color: '#67e0e3', |
|||
}, |
|||
}, |
|||
], |
|||
}, |
|||
], |
|||
}) |
|||
}, |
|||
{ immediate: true }, |
|||
) |
|||
</script> |
|||
|
|||
<template> |
|||
<Card title="销售统计" :loading="loading"> |
|||
<div ref="chartRef" :style="{ width, height }" /> |
|||
</Card> |
|||
</template> |
|||
@ -0,0 +1,43 @@ |
|||
<script lang="ts" setup> |
|||
import { Card } from 'ant-design-vue' |
|||
|
|||
const props = defineProps({ |
|||
data: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
}) |
|||
</script> |
|||
|
|||
<template> |
|||
<!-- <Avatar :src="userinfo.user.avatar || headerImg" :size="72" class="!mx-auto !block" /> --> |
|||
<div class="mt-2 md:mt-0"> |
|||
<h1 class="text-center text-lg md:text-2xl"> |
|||
<!-- 早安, {{ userinfo.user.nickname }}, 开始您一天的工作吧! --> |
|||
{{ props.data.title }} |
|||
</h1> |
|||
<!-- <span class="text-secondary"> 今日晴,20℃ - 32℃! </span> --> |
|||
<!-- </div> --> |
|||
<!-- <div class="mt-4 flex flex-1 justify-end md:mt-0"> |
|||
<div class="flex flex-col justify-center text-right"> |
|||
<span class="text-secondary"> 待办 </span> |
|||
<span class="text-2xl">2/10</span> |
|||
</div> |
|||
|
|||
<div class="mx-12 flex flex-col justify-center text-right md:mx-16"> |
|||
<span class="text-secondary"> 项目 </span> |
|||
<span class="text-2xl">8</span> |
|||
</div> |
|||
<div class="mr-4 flex flex-col justify-center text-right md:mr-10"> |
|||
<span class="text-secondary"> 团队 </span> |
|||
<span class="text-2xl">300</span> |
|||
</div> |
|||
</div> --> |
|||
</div> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
::v-deep(.ant-card-grid) { |
|||
padding:15px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,156 @@ |
|||
interface GroupItem { |
|||
title: string |
|||
icon: string |
|||
color: string |
|||
desc: string |
|||
date: string |
|||
group: string |
|||
} |
|||
|
|||
interface NavItem { |
|||
title: string |
|||
icon: string |
|||
color: string |
|||
} |
|||
|
|||
interface DynamicInfoItem { |
|||
avatar: string |
|||
name: string |
|||
date: string |
|||
desc: string |
|||
} |
|||
|
|||
export const navItems: NavItem[] = [ |
|||
{ |
|||
title: '首页', |
|||
icon: 'ion:home-outline', |
|||
color: '#1fdaca', |
|||
}, |
|||
{ |
|||
title: '仪表盘', |
|||
icon: 'ion:grid-outline', |
|||
color: '#bf0c2c', |
|||
}, |
|||
{ |
|||
title: '组件', |
|||
icon: 'ion:layers-outline', |
|||
color: '#e18525', |
|||
}, |
|||
{ |
|||
title: '系统管理', |
|||
icon: 'ion:settings-outline', |
|||
color: '#3fb27f', |
|||
}, |
|||
{ |
|||
title: '权限管理', |
|||
icon: 'ion:key-outline', |
|||
color: '#4daf1bc9', |
|||
}, |
|||
{ |
|||
title: '图表', |
|||
icon: 'ion:bar-chart-outline', |
|||
color: '#00d8ff', |
|||
}, |
|||
] |
|||
|
|||
export const dynamicInfoItems: DynamicInfoItem[] = [ |
|||
{ |
|||
avatar: 'dynamic-avatar-1|svg', |
|||
name: '威廉', |
|||
date: '刚刚', |
|||
desc: '在 <a>开源组</a> 创建了项目 <a>Vue</a>', |
|||
}, |
|||
{ |
|||
avatar: 'dynamic-avatar-2|svg', |
|||
name: '艾文', |
|||
date: '1个小时前', |
|||
desc: '关注了 <a>威廉</a> ', |
|||
}, |
|||
{ |
|||
avatar: 'dynamic-avatar-3|svg', |
|||
name: '克里斯', |
|||
date: '1天前', |
|||
desc: '发布了 <a>个人动态</a> ', |
|||
}, |
|||
{ |
|||
avatar: 'dynamic-avatar-4|svg', |
|||
name: 'XingyuV', |
|||
date: '2天前', |
|||
desc: '发表文章 <a>如何编写一个Vite插件</a> ', |
|||
}, |
|||
{ |
|||
avatar: 'dynamic-avatar-5|svg', |
|||
name: '皮特', |
|||
date: '3天前', |
|||
desc: '回复了 <a>杰克</a> 的问题 <a>如何进行项目优化?</a>', |
|||
}, |
|||
{ |
|||
avatar: 'dynamic-avatar-6|svg', |
|||
name: '杰克', |
|||
date: '1周前', |
|||
desc: '关闭了问题 <a>如何运行项目</a> ', |
|||
}, |
|||
{ |
|||
avatar: 'dynamic-avatar-1|svg', |
|||
name: '威廉', |
|||
date: '1周前', |
|||
desc: '发布了 <a>个人动态</a> ', |
|||
}, |
|||
{ |
|||
avatar: 'dynamic-avatar-1|svg', |
|||
name: '威廉', |
|||
date: '2021-04-01 20:00', |
|||
desc: '推送了代码到 <a>Github</a>', |
|||
}, |
|||
] |
|||
|
|||
export const groupItems: GroupItem[] = [ |
|||
{ |
|||
title: 'Github', |
|||
icon: 'carbon:logo-github', |
|||
color: '', |
|||
desc: '不要等待机会,而要创造机会。', |
|||
group: '开源组', |
|||
date: '2021-04-01', |
|||
}, |
|||
{ |
|||
title: 'Vue', |
|||
icon: 'ion:logo-vue', |
|||
color: '#3fb27f', |
|||
desc: '现在的你决定将来的你。', |
|||
group: '算法组', |
|||
date: '2021-04-01', |
|||
}, |
|||
{ |
|||
title: 'Html5', |
|||
icon: 'ion:logo-html5', |
|||
color: '#e18525', |
|||
desc: '没有什么才能比努力更重要。', |
|||
group: '上班摸鱼', |
|||
date: '2021-04-01', |
|||
}, |
|||
{ |
|||
title: 'Angular', |
|||
icon: 'ion:logo-angular', |
|||
color: '#bf0c2c', |
|||
desc: '热情和欲望可以突破一切难关。', |
|||
group: 'UI', |
|||
date: '2021-04-01', |
|||
}, |
|||
{ |
|||
title: 'React', |
|||
icon: 'bx:bxl-react', |
|||
color: '#00d8ff', |
|||
desc: '健康的身体是实现目标的基石。', |
|||
group: '技术牛', |
|||
date: '2021-04-01', |
|||
}, |
|||
{ |
|||
title: 'Js', |
|||
icon: 'ion:logo-javascript', |
|||
color: '#EBD94E', |
|||
desc: '路是走出来的,而不是空想出来的。', |
|||
group: '架构组', |
|||
date: '2021-04-01', |
|||
}, |
|||
] |
|||
@ -0,0 +1,89 @@ |
|||
{ |
|||
"title": "示例设备展示", |
|||
"LeftUp": { |
|||
"Header": "1设备静态图", |
|||
"path": "", |
|||
"Content": "" |
|||
}, |
|||
"LeftMidUp": { |
|||
"Header": "2故障诊断", |
|||
"Content": [{ "FaultDesc": "失速", "Point": "YFJ_A_GZ001" }, { "FaultDesc": "喘振", "Point": "YFJ_A_GZ002" }, { "FaultDesc": "动调故障", "Point": "YFJ_A_GZ003" }, { "FaultDesc": "风机动调机构漏油", "Point": "YFJ_A_GZ004" }, { "FaultDesc": "风机动调伺服连杆轴脱开", "Point": "YFJ_A_GZ005" }, { "FaultDesc": "电机前轴(驱动端)承润滑异常", "Point": "YFJ_A_GZ006" }, { "FaultDesc": "电机后轴(非驱动端)承润滑异常", "Point": "YFJ_A_GZ007" }, { "FaultDesc": "风机润滑油冷却系统异常", "Point": "YFJ_A_GZ008" }, { "FaultDesc": "电机前轴(驱动端)承瓦面磨损", "Point": "YFJ_A_GZ009" }, { "FaultDesc": "电机后轴(非驱动端)承瓦面磨损", "Point": "YFJ_A_GZ010" }, { "FaultDesc": "轴承箱轴承(润滑)冷却异常", "Point": "YFJ_A_GZ011" }, { "FaultDesc": "轴承箱前轴(驱动端)承损坏", "Point": "YFJ_A_GZ012" }, { "FaultDesc": "轴承箱中轴(推力轴承)承损坏", "Point": "YFJ_A_GZ013" }, { "FaultDesc": "轴承箱后轴(非驱动端)承损坏", "Point": "YFJ_A_GZ014" }, { "FaultDesc": "油站油箱内油温异常", "Point": "YFJ_A_GZ015" }, { "FaultDesc": "油站油泵1泵体损坏", "Point": "YFJ_A_GZ016" }, { "FaultDesc": "油站油泵2泵体损坏", "Point": "YFJ_A_GZ017" }, { "FaultDesc": "油站控制油外漏", "Point": "YFJ_A_GZ018" }, { "FaultDesc": "油站润滑油外漏", "Point": "YFJ_A_GZ019" }, { "FaultDesc": "电动机电源一相断线", "Point": "YFJ_A_GZ020" }, { "FaultDesc": "电动机定子绕组匝间短路", "Point": "YFJ_A_GZ021" }, { "FaultDesc": "油站油泵1电动机电源一相断线", "Point": "YFJ_A_GZ022" }, { "FaultDesc": "油站油泵1电动机定子绕组匝间短路", "Point": "YFJ_A_GZ023" }, { "FaultDesc": "油站油泵2电动机电源一相断线", "Point": "YFJ_A_GZ024" }, { "FaultDesc": "油站油泵2电动机定子绕组匝间短路", "Point": "YFJ_A_GZ025" }, { "FaultDesc": "风机电动机冷却装置故障", "Point": "YFJ_A_GZ026" }, { "FaultDesc": "风机电动机电流异常变大", "Point": "YFJ_A_GZ027" }, { "FaultDesc": "油站油泵1电动机风扇坏", "Point": "YFJ_A_GZ028" }, { "FaultDesc": "油站油泵2电动机风扇坏", "Point": "YFJ_A_GZ029" }, { "FaultDesc": "油站油泵1电动机机械卡死", "Point": "YFJ_A_GZ030" }, { "FaultDesc": "油站油泵2电动机机械卡死", "Point": "YFJ_A_GZ031" }, { "FaultDesc": "油站油泵1电动机过载", "Point": "YFJ_A_GZ032" }, { "FaultDesc": "油站油泵2电动机过载", "Point": "YFJ_A_GZ033" }, { "FaultDesc": "油泵1和其电机靠背轮脱落", "Point": "YFJ_A_GZ034" }, { "FaultDesc": "油泵2和其电机靠背轮脱落", "Point": "YFJ_A_GZ035" }, { "FaultDesc": "冷却/密封风机1叶轮磨损", "Point": "YFJ_A_GZ036" }, { "FaultDesc": "冷却/密封风机2叶轮磨损", "Point": "YFJ_A_GZ037" }, { "FaultDesc": "油站控制油过滤器堵", "Point": "YFJ_A_GZ038" }, { "FaultDesc": "油站润滑油过滤器堵", "Point": "YFJ_A_GZ039" } |
|||
] |
|||
}, |
|||
"RightMidUp": { |
|||
"Header": "报警记录", |
|||
"Content": [{ |
|||
"Text": "故障1", |
|||
"StartTime": "Diagnosis1", |
|||
"Duration": 12.3 |
|||
}, { |
|||
"Text": "故障1", |
|||
"StartTime": "Diagnosis1", |
|||
"Duration": 12.3 |
|||
}] |
|||
}, |
|||
"RightUp": { |
|||
"Header": "大模型-操作指导", |
|||
"Content": [{ |
|||
"FaultDesc": "引风机抢风", |
|||
"Guide": "A、B引风机动调在自动位,将电流小的风机动调切手动,开大动调,引风机电流增加?A,另一台引风机电流自动减少至?A,直至A、B引风机电流稳定。同时检查并确认引出口至烟囱烟道上档板处“全开”位,引风机出口余热换热器无堵塞后,逐步增加负荷,将A、B引风机电流、动调调至正常范围,投入引风机自动。若预警仍存在或工况改变易发生抢风,将A、B引风机动调设置一定偏置运行,维持A、B引风机电流稳定运行,根据实际能力带负荷。利用机组停机机会,对引风机出口烟道进行全面检查,尽可能降低烟道阻力,改善流动特性。" |
|||
}, { |
|||
"FaultDesc": "故障2", |
|||
"Guide": "如何处理故障2" |
|||
}] |
|||
}, |
|||
"LeftDown": { |
|||
"Header": "生产流程", |
|||
"path": "svg/illustration.svg" |
|||
}, |
|||
"RightDown": { |
|||
"Header": "参数信息", |
|||
"Columns": [{ |
|||
"title": "序号", |
|||
"dataIndex": "ID", |
|||
"width": 40 |
|||
}, { |
|||
"title": "描述", |
|||
"dataIndex": "Desc", |
|||
"width": 200 |
|||
}, { |
|||
"title": "点号", |
|||
"dataIndex": "ObservedPoint", |
|||
"width": 150 |
|||
}, |
|||
{ |
|||
"title": "单位", |
|||
"dataIndex": "Unit", |
|||
"width": 40 |
|||
}, { |
|||
"title": "测量值", |
|||
"dataIndex": "originValue", |
|||
"width": 65 |
|||
}, { |
|||
"title": "预测值", |
|||
"dataIndex": "predictValue", |
|||
"width": 65 |
|||
}, { |
|||
"title": "安全区域", |
|||
"dataIndex": "threshold", |
|||
"width": 100, |
|||
"slots": { "customRender": "threshold" } |
|||
|
|||
}], |
|||
"Content": [{ |
|||
"ID": 1, |
|||
"Desc": "A引风机电机前轴承温度1", |
|||
"ObservedPoint": "SYG1_10HNC10CT110", |
|||
"PredictedPoint": "SYG1_10HNC10CT110_CG", |
|||
"ResidualThreshold": 1.0, |
|||
"Unit": "℃" |
|||
}, { |
|||
"ID": 2, |
|||
"Desc": "A引风机电机前轴承温度2", |
|||
"ObservedPoint": "SYG1_10HNC10CT111", |
|||
"PredictedPoint": "SYG1_10HNC10CT111_CG", |
|||
"ResidualThreshold": 2.0, |
|||
"Unit": "℃" |
|||
}] |
|||
} |
|||
} |
|||
@ -0,0 +1,138 @@ |
|||
{ |
|||
"title": "示例设备展示", |
|||
"LeftUp": { |
|||
"Header": "设备静态图", |
|||
"path": "svg/illustration.svg", |
|||
"Content": "" |
|||
}, |
|||
"LeftMidUp": { |
|||
"Header": "故障诊断", |
|||
"Content": [{ |
|||
"FaultDesc": "故障1故障1故障1故障1故障1", |
|||
"Point": "Diagnosis1" |
|||
}, { |
|||
"FaultDesc": "故障2", |
|||
"Point": "Diagnosis2" |
|||
}, |
|||
{ |
|||
"FaultDesc": "故障2", |
|||
"Point": "Diagnosis2" |
|||
}, { |
|||
"FaultDesc": "故障2", |
|||
"Point": "Diagnosis2" |
|||
}, { |
|||
"FaultDesc": "故障2", |
|||
"Point": "Diagnosis2" |
|||
}, { |
|||
"FaultDesc": "故障2", |
|||
"Point": "Diagnosis2" |
|||
}, { |
|||
"FaultDesc": "故障2", |
|||
"Point": "Diagnosis2" |
|||
}, { |
|||
"FaultDesc": "故障2", |
|||
"Point": "Diagnosis2" |
|||
}, { |
|||
"FaultDesc": "故障2", |
|||
"Point": "Diagnosis2" |
|||
}] |
|||
}, |
|||
"RightMidUp": { |
|||
"Header": "报警记录", |
|||
"Content": [{ |
|||
"Text": "故障1", |
|||
"StartTime": "Diagnosis1", |
|||
"Duration": 12.3 |
|||
}, { |
|||
"Text": "故障1", |
|||
"StartTime": "Diagnosis1", |
|||
"Duration": 12.3 |
|||
}] |
|||
}, |
|||
"RightUp": { |
|||
"Header": "大模型-操作指导", |
|||
"Content": [{ |
|||
"FaultDesc": "故障1", |
|||
"Guide": "如何处理故障1" |
|||
}, { |
|||
"FaultDesc": "故障2", |
|||
"Guide": "如何处理故障2" |
|||
}] |
|||
}, |
|||
"LeftDown": { |
|||
"Header": "生产流程", |
|||
"path": "svg/illustration.svg", |
|||
"Content": "/api/v1/assets/production_flow.svg" |
|||
}, |
|||
"RightDown": { |
|||
"Header": "参数信息", |
|||
"Columns": [{ |
|||
"title": "序号", |
|||
"dataIndex": "序号", |
|||
"width": 40 |
|||
}, { |
|||
"title": "描述", |
|||
"dataIndex": "描述", |
|||
"width": 200 |
|||
}, { |
|||
"title": "点号", |
|||
"dataIndex": "点号", |
|||
"width": 100 |
|||
}, { |
|||
"title": "测量值", |
|||
"dataIndex": "测量值", |
|||
"width": 80 |
|||
}, { |
|||
"title": "预测值", |
|||
"dataIndex": "预测值", |
|||
"width": 100 |
|||
}, { |
|||
"title": "安全区域", |
|||
"dataIndex": "安全区域", |
|||
"width": 140 |
|||
}], |
|||
"Content": [{ |
|||
"序号": 1, |
|||
"描述": "", |
|||
"点号": "", |
|||
"测量值": 0.0, |
|||
"预测值": 0.0, |
|||
"安全区域": "" |
|||
}, { |
|||
"序号": 2, |
|||
"描述": "", |
|||
"点号": "", |
|||
"测量值": 0.0, |
|||
"预测值": 0.0, |
|||
"安全区域": "" |
|||
}, { |
|||
"序号": 3, |
|||
"描述": "", |
|||
"点号": "", |
|||
"测量值": 0.0, |
|||
"预测值": 0.0, |
|||
"安全区域": "" |
|||
}, { |
|||
"序号": 4, |
|||
"描述": "", |
|||
"点号": "", |
|||
"测量值": 0.0, |
|||
"预测值": 0.0, |
|||
"安全区域": "" |
|||
}, { |
|||
"序号": 5, |
|||
"描述": "", |
|||
"点号": "", |
|||
"测量值": 0.0, |
|||
"预测值": 0.0, |
|||
"安全区域": "" |
|||
}, { |
|||
"序号": 6, |
|||
"描述": "", |
|||
"点号": "", |
|||
"测量值": 0.0, |
|||
"预测值": 0.0, |
|||
"安全区域": "" |
|||
}] |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
<script lang="ts" setup> |
|||
import { Card, CardGrid } from 'ant-design-vue' |
|||
import { ref, toRefs, watch } from 'vue' |
|||
|
|||
const props = defineProps({ |
|||
data: { |
|||
type: Object, |
|||
default: () => {}, |
|||
}, |
|||
}) |
|||
|
|||
// const { data } = toRefs(props) |
|||
const imgUrl = ref('') |
|||
|
|||
watch( |
|||
() => props.data, |
|||
(newValue, oldValue) => { |
|||
// 下方信息不会打印在控制台中 |
|||
console.log('a has changed', newValue, oldValue) |
|||
// ../assets/imgs为图片公共路径 |
|||
// imgUrl.value = getAssetsFile() |
|||
// imgUrl.value = '/111.gif' |
|||
}, |
|||
) |
|||
function getAssetsFile() { |
|||
const url = props.data.path |
|||
console.log(url) |
|||
return new URL(`../../../../assets/${url}`, import.meta.url).href |
|||
} |
|||
</script> |
|||
|
|||
<template> |
|||
<Card class="enter-y !my-1" :title="props.data.Header"> |
|||
<img class="mx-auto h-70 w-full" :src="props.data.path"> |
|||
</Card> |
|||
</template> |
|||
@ -0,0 +1,68 @@ |
|||
<script lang="ts" setup> |
|||
import { onMounted, ref } from 'vue' |
|||
import WorkbenchHeader from './components/WorkbenchHeader.vue' |
|||
import ProjectCard from './components/ProjectCard.vue' |
|||
import DynamicInfo from './components/DynamicInfo.vue' |
|||
import StaticImg from './components/staticImg.vue' |
|||
import ParameterInfo from './components/ParameterInfo.vue' |
|||
import Operation from './components/Operation.vue' |
|||
import data from './components/demo.json' |
|||
import { PageWrapper } from '@/components/Page' |
|||
|
|||
const loading = ref(true) |
|||
|
|||
onMounted(() => { |
|||
const htmlRoot = document.getElementsByClassName('workbench') |
|||
// let theme = window.localStorage.getItem('__APP__DARK__MODE__') |
|||
const theme = 'dark' |
|||
|
|||
if (htmlRoot && theme) { |
|||
for (let i = 0; i < htmlRoot.length; i++) |
|||
htmlRoot[i].setAttribute('data-theme', theme) |
|||
} |
|||
// theme = htmlRoot = null |
|||
}) |
|||
|
|||
setTimeout(() => { |
|||
loading.value = false |
|||
}, 500) |
|||
</script> |
|||
|
|||
<template> |
|||
<div class="workbench m-1" data-theme="light"> |
|||
<WorkbenchHeader class="workbench m-1" data-theme="light" :data="data" /> |
|||
<div class="enter-y workbench h-92 md:flex" data-theme="light"> |
|||
<StaticImg data-theme="light" class="workbench m-1 w-full md:w-1/4" :loading="loading" :data="data.LeftUp" /> |
|||
<ProjectCard data-theme="light" class="enter-y workbench m-1 w-full md:w-1/2" :loading="loading" :data="data.LeftMidUp" /> |
|||
<div class="enter-y w-full !mr-4 md:w-1/4"> |
|||
<DynamicInfo :loading="loading" data-theme="light" class="workbench enter-y m-1 h-35 w-full" :data="data.RightMidUp" /> |
|||
<Operation data-theme="light" class="workbench enter-y m-1 h-54 w-full" :loading="loading" :data="data.RightUp" /> |
|||
</div> |
|||
</div> |
|||
<div class="enter-y workbench h-95 md:flex" data-theme="light"> |
|||
<StaticImg data-theme="light" class="workbench m-1 w-full md:w-1/2" :loading="loading" :data="data.LeftDown" /> |
|||
<ParameterInfo data-theme="light" class="workbench m-1 w-full md:w-1/2" :loading="loading" :data="data.RightDown" /> |
|||
</div> |
|||
<!-- <div class="enter-y w-full !mr-4 lg:w-7/10"> |
|||
<StaticImg :loading="loading" :data="data.LeftUp" class="enter-y" /> |
|||
</div> --> |
|||
|
|||
<!-- <div class="enter-y w-full !mr-4 lg:w-7/10"> |
|||
<ProjectCard :loading="loading" class="enter-y" /> |
|||
<DynamicInfo :loading="loading" class="enter-y !my-4" /> |
|||
</div> |
|||
<div class="enter-y w-full lg:w-3/10"> |
|||
<QuickNav :loading="loading" class="enter-y" /> |
|||
|
|||
<Card class="enter-y !my-4" :loading="loading"> |
|||
<img class="mx-auto h-30 xl:h-50" src="@/assets/svg/illustration.svg"> |
|||
</Card> |
|||
|
|||
<SaleRadar :loading="loading" class="enter-y" /> |
|||
</div> --> |
|||
</div> |
|||
</template> |
|||
|
|||
<style lang="less"> |
|||
|
|||
</style> |
|||
@ -0,0 +1,95 @@ |
|||
<script lang="ts" setup> |
|||
import { onBeforeMount, onMounted, ref } from 'vue' |
|||
import { useRoute } from 'vue-router' |
|||
import { message } from 'ant-design-vue' |
|||
import WorkbenchHeader from './components/WorkbenchHeader.vue' |
|||
import ProjectCard from './components/ProjectCard.vue' |
|||
import DynamicInfo from './components/DynamicInfo.vue' |
|||
import StaticImg from './components/staticImg.vue' |
|||
import ParameterInfo from './components/ParameterInfo.vue' |
|||
import Operation from './components/Operation.vue' |
|||
import data1 from './components/demo.json' |
|||
import { PageWrapper } from '@/components/Page' |
|||
import { getDeviceInfo } from '@/api/device' |
|||
import { getExaNow } from '@/api/alert/exa' |
|||
|
|||
const loading = ref(true) |
|||
const route = useRoute() |
|||
|
|||
setTimeout(() => { |
|||
loading.value = false |
|||
}, 500) |
|||
// 为了解决系统不支持传参的问题,改为从路由参数中获取id,不是最终解决办法,带系统commitbug |
|||
const id = route.path.split('/').pop() || '' |
|||
const data = ref<any>(data1) |
|||
|
|||
onMounted(async () => { |
|||
console.log(route.path) |
|||
const res = await getDeviceInfo(id) |
|||
console.log(res) |
|||
if (res) |
|||
data.value = JSON.parse(res.Page_Content) |
|||
// getColor(data.value) |
|||
}) |
|||
|
|||
// async function getColor(data: any) { |
|||
// const rows = data.LeftMidUp.Content || [] |
|||
// const gridData = [] as any[] |
|||
// for (const item of rows) { |
|||
// try { |
|||
// const param = item.Point |
|||
// const res = await getExaNow(param) |
|||
|
|||
// let ifColor: boolean = false |
|||
// if (res != null) |
|||
// ifColor = res === '1' |
|||
|
|||
// gridData.push(Object.assign({}, item, { ifColor })) |
|||
|
|||
// console.log(gridData) |
|||
// } |
|||
// catch (e) { |
|||
// } |
|||
// } |
|||
// data.LeftMidUp.Content = gridData |
|||
// } |
|||
</script> |
|||
|
|||
<template> |
|||
<PageWrapper v-if="id != null && id !== undefined" class="m-1"> |
|||
<!-- <template #headerContent> |
|||
<WorkbenchHeader class="m-1" :data="data" /> |
|||
</template> --> |
|||
<div class="h-[calc(91vh)] bg-[#f5f5f5]"> |
|||
<div class="enter-y h-[calc(91vh/2)] md:flex"> |
|||
<StaticImg class="m-1 w-full md:w-1/4" :loading="loading" :data="data.LeftUp || {}" /> |
|||
<ProjectCard class="enter-y m-1 w-full md:w-1/2" :loading="loading" :data="data.LeftMidUp || {}" /> |
|||
<div class="enter-y h-[calc(91vh/2)] w-full md:w-1/4"> |
|||
<DynamicInfo :loading="loading" class="enter-y m-1 h-[calc(17vh)] w-full" :data="data.RightMidUp || {}" /> |
|||
<Operation class="enter-y m-1 h-[calc(27vh)] w-full" :loading="loading" :data="data.RightUp || {}" /> |
|||
</div> |
|||
</div> |
|||
<div class="enter-y h-[calc(91vh/2)] md:flex"> |
|||
<StaticImg class="m-1 w-full md:w-1/2" :loading="loading" :data="data.LeftDown || {}" /> |
|||
<ParameterInfo class="m-1 w-full md:w-1/2" :loading="loading" :data="data.RightDown || {}" /> |
|||
</div> |
|||
<!-- <div class="enter-y w-full !mr-4 lg:w-7/10"> |
|||
<StaticImg :loading="loading" :data="data.LeftUp" class="enter-y" /> |
|||
</div> --> |
|||
|
|||
<!-- <div class="enter-y w-full !mr-4 lg:w-7/10"> |
|||
<ProjectCard :loading="loading" class="enter-y" /> |
|||
<DynamicInfo :loading="loading" class="enter-y !my-4" /> |
|||
</div> |
|||
<div class="enter-y w-full lg:w-3/10"> |
|||
<QuickNav :loading="loading" class="enter-y" /> |
|||
|
|||
<Card class="enter-y !my-4" :loading="loading"> |
|||
<img class="mx-auto h-30 xl:h-50" src="@/assets/svg/illustration.svg"> |
|||
</Card> |
|||
|
|||
<SaleRadar :loading="loading" class="enter-y" /> |
|||
</div> --> |
|||
</div> |
|||
</pagewrapper> |
|||
</template> |
|||
@ -0,0 +1,188 @@ |
|||
import moment from 'moment' |
|||
|
|||
import { ref } from 'vue' |
|||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|||
import { optionListApi, subSystemListApi } from '@/api/alert/model/select' |
|||
import type { systemSelectParams } from '@/api/alert/model/model/optionsModel' |
|||
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: '编号', |
|||
dataIndex: 'id', |
|||
width: 80, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '模型名称', |
|||
dataIndex: 'modelName', |
|||
width: 250, |
|||
className: 'instant', |
|||
slots: { customRender: 'detail' }, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '算法', |
|||
dataIndex: 'Algorithm', |
|||
width: 200, |
|||
|
|||
}, |
|||
{ |
|||
title: '模式覆盖率', |
|||
dataIndex: 'CoveredPercent', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '报警次数', |
|||
dataIndex: 'AlarmNumber', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '总报警时间(m)', |
|||
dataIndex: 'AlarmToatlMinutes', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '系统维度', |
|||
dataIndex: 'Dimension', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '计算耗时(s)', |
|||
dataIndex: 'CalcSeconds', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
title: '状态', |
|||
dataIndex: 'status', |
|||
width: 100, |
|||
slots: { customRender: 'status' }, |
|||
fixed: 'right', |
|||
}, |
|||
] |
|||
|
|||
const optionList = await optionListApi() |
|||
|
|||
const systemOptions = ref<any>([]) |
|||
systemOptions.value = optionList.systems |
|||
export const searchFormSchema: FormSchema[] = [ |
|||
{ |
|||
label: '机组', |
|||
field: 'unit', |
|||
component: 'Select', |
|||
defaultValue: optionList.units[0].id || null, |
|||
colProps: { span: 4 }, |
|||
|
|||
componentProps: ({ formModel }) => { |
|||
return { |
|||
// xxxx props
|
|||
allowClear: false, |
|||
placeholder: '请选择机组', |
|||
options: optionList.units.map(unit => ({ value: unit.id, label: unit.name })), |
|||
onChange: async (e: any) => { |
|||
// const { reload } = tableAction
|
|||
// reload()
|
|||
// or
|
|||
console.log(e) |
|||
const param: systemSelectParams = { |
|||
unitId: e, |
|||
typeId: formModel.type, |
|||
} |
|||
systemOptions.value = await subSystemListApi(param) |
|||
formModel.system = systemOptions.value[0].id |
|||
}, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
label: '系统', |
|||
field: 'type', |
|||
component: 'Select', |
|||
defaultValue: optionList.types[0].id || null, |
|||
colProps: { span: 4 }, |
|||
componentProps: ({ formModel }) => { |
|||
return { |
|||
allowClear: false, |
|||
placeholder: '请选择系统', |
|||
options: optionList.types.map(type => ({ value: type.id, label: type.name })), |
|||
onChange: async (e: any) => { |
|||
// const { reload } = tableAction
|
|||
// reload()
|
|||
// or
|
|||
console.log(e) |
|||
const param: systemSelectParams = { |
|||
unitId: formModel.unit, |
|||
typeId: e, |
|||
} |
|||
systemOptions.value = await subSystemListApi(param) |
|||
}, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
label: '子系统', |
|||
field: 'system', |
|||
component: 'Select', |
|||
defaultValue: systemOptions.value[0].id || null, |
|||
colProps: { span: 4 }, |
|||
componentProps: () => { |
|||
return { |
|||
allowClear: false, |
|||
placeholder: '请选择子系统', |
|||
options: systemOptions.value.map(system => ({ value: system.id, label: system.name })), |
|||
} |
|||
}, |
|||
}, |
|||
|
|||
{ |
|||
label: '模型名称', |
|||
field: 'modelName', |
|||
component: 'Input', |
|||
|
|||
defaultValue: '', |
|||
componentProps: { |
|||
placeholder: '请输入模型名称', |
|||
}, |
|||
colProps: { span: 4 }, |
|||
}, |
|||
] |
|||
|
|||
export const calcFormSchemas: FormSchema[] = [ |
|||
{ |
|||
label: '回算时间', |
|||
field: 'time', |
|||
component: 'RangePicker', |
|||
componentProps: { |
|||
placeholder: ['开始时间', '结束时间'], |
|||
defaultValue: [moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')], |
|||
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) |
|||
}, |
|||
}, |
|||
required: true, |
|||
|
|||
colProps: { |
|||
span: 8, |
|||
}, |
|||
}, |
|||
{ |
|||
label: '回算采样周期', |
|||
field: 'interval', |
|||
component: 'Select', |
|||
defaultValue: 60, |
|||
|
|||
componentProps: { |
|||
options: [{ value: 10, label: '10秒' }, { value: 60, label: '60秒' }, { value: 300, label: '300秒' }], |
|||
}, |
|||
required: true, |
|||
colProps: { |
|||
span: 4, |
|||
}, |
|||
}, |
|||
|
|||
] |
|||
@ -0,0 +1,185 @@ |
|||
<script lang="ts" setup> |
|||
import { Badge, Button, Divider, Switch } from 'ant-design-vue' |
|||
import { onMounted, ref } from 'vue' |
|||
import moment from 'moment' |
|||
import HistoryModal from '../../exa/config/HistoryModal.vue' |
|||
import { calcFormSchemas, columns, searchFormSchema } from './calc.data' |
|||
|
|||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|||
import { BasicForm, useForm } from '@/components/Form' |
|||
|
|||
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: 'InstantCalc' }) |
|||
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: 70, |
|||
schemas: searchFormSchema, |
|||
showResetButton: false, |
|||
actionColOptions: { |
|||
span: 2, |
|||
}, |
|||
|
|||
}, |
|||
useSearchForm: true, |
|||
showTableSetting: true, |
|||
showIndexColumn: false, |
|||
actionColumn: { |
|||
width: 100, |
|||
title: t('common.action'), |
|||
dataIndex: 'action', |
|||
fixed: 'right', |
|||
}, |
|||
}) |
|||
|
|||
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 }) |
|||
} |
|||
|
|||
function handleWarnConfig(record: Recordable) { |
|||
router.push(`/run/warnConfig?id=${record.id}`) |
|||
} |
|||
|
|||
/** |
|||
* BasicForm绑定注册; |
|||
*/ |
|||
const [registerForm] = useForm({ |
|||
// 注册表单列 |
|||
schemas: calcFormSchemas, |
|||
// 是否显示展开收起按钮,默认false |
|||
// showAdvancedButton: true, |
|||
// // // 超过指定行数折叠,默认3行 |
|||
// autoAdvancedLine: 1, |
|||
// // // 折叠时默认显示行数,默认1行 |
|||
// alwaysShowLines: 1, |
|||
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 }, |
|||
showSubmitButton: false, |
|||
showResetButton: false, |
|||
}) |
|||
|
|||
/** |
|||
* 点击提交按钮的value值----改为导出按钮 |
|||
* @param values |
|||
*/ |
|||
function handleSubmit(values: any) { |
|||
console.log('提交按钮数据::::', values) |
|||
} |
|||
// 回算 |
|||
function handleCalc(values: any) { |
|||
console.log('提交按钮数据::::', values) |
|||
} |
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<BasicTable @register="registerTable"> |
|||
<template #form-formFooter> |
|||
<!-- <a-button v-auth="['run:instant:create']" type="primary" :pre-icon="IconEnum.ADD" @click="handleCreate"> |
|||
{{ t('action.create') }} |
|||
</a-button> --> |
|||
<Divider orientation="left"> |
|||
回算 |
|||
</Divider> |
|||
<!-- 自定义表单 --> |
|||
<BasicForm @register="registerForm"> |
|||
<template #advanceBefore> |
|||
<a-button v-auth="['run:instant:create']" type="primary" :pre-icon="IconEnum.ADD" @click="handleCreate"> |
|||
{{ t('action.create') }} |
|||
</a-button> |
|||
</template> |
|||
</BasicForm> |
|||
</template> |
|||
|
|||
<!-- 统计量点击跳转历史曲线 --> |
|||
<template #history="{ record }"> |
|||
<a @click="handleHistory(record)"> |
|||
{{ record.pointSte }} |
|||
</a> |
|||
<!-- <SlidersOutlined class="click-status" /> --> |
|||
</template> |
|||
|
|||
<template #bodyCell="{ column, record }"> |
|||
<template v-if="column.key === 'action'"> |
|||
<TableAction |
|||
:actions="[ |
|||
{ icon: IconEnum.BACK_CALC, label: t('action.backCalc'), onClick: handleWarnConfig.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,47 @@ |
|||
import { h } from 'vue' |
|||
import { Tag } from 'ant-design-vue' |
|||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|||
|
|||
// 表格列定义
|
|||
export const columns: BasicColumn[] = [ |
|||
{ |
|||
title: '系统名称', |
|||
dataIndex: 'name', |
|||
width: 180, |
|||
}, |
|||
{ |
|||
title: '系统简称', |
|||
dataIndex: 'abbreviation', |
|||
width: 180, |
|||
}, |
|||
{ |
|||
title: '创建时间', |
|||
dataIndex: 'createTime', |
|||
width: 180, |
|||
// 使用 Vben 框架的方式格式化时间
|
|||
customRender: ({ text }) => { |
|||
return h(Tag, { color: 'blue' }, () => text) |
|||
}, |
|||
}, |
|||
] |
|||
|
|||
// 弹窗表单定义
|
|||
export const formSchema: FormSchema[] = [ |
|||
{ |
|||
label: '编号', |
|||
field: 'id', |
|||
show: false, // 隐藏,仅用于表单绑定
|
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '系统名称', |
|||
field: 'name', |
|||
required: true, |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: '系统简称', |
|||
field: 'abbreviation', |
|||
component: 'Input', |
|||
}, |
|||
] |
|||
@ -0,0 +1,66 @@ |
|||
<script lang="ts" setup> |
|||
import { ref, unref } from 'vue' |
|||
import { formSchema } from './SystemConfig' |
|||
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 { createSystemConfig, getSystemConfig, updateSystemConfig } from '@/api/system/config/SystemConfig' |
|||
import type { SystemConfigVO } from '@/api/system/config/SystemConfig' |
|||
|
|||
defineOptions({ name: 'SystemConfigModal' }) |
|||
|
|||
const emit = defineEmits(['success', 'register']) |
|||
const { t } = useI18n() |
|||
const { createMessage } = useMessage() |
|||
const isUpdate = ref(true) |
|||
|
|||
const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({ |
|||
labelWidth: 120, |
|||
baseColProps: { span: 24 }, |
|||
schemas: formSchema, |
|||
showActionButtonGroup: false, |
|||
actionColOptions: { span: 23 }, |
|||
}) |
|||
|
|||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { |
|||
resetFields() |
|||
setModalProps({ confirmLoading: false }) |
|||
isUpdate.value = !!data?.isUpdate |
|||
|
|||
if (unref(isUpdate)) { |
|||
// 获取详情,保证数据最新 |
|||
const res = await getSystemConfig(data.record.id) |
|||
setFieldsValue({ ...res }) |
|||
} |
|||
}) |
|||
|
|||
async function handleSubmit() { |
|||
try { |
|||
const values = await validate() |
|||
setModalProps({ confirmLoading: true }) |
|||
if (unref(isUpdate)) |
|||
await updateSystemConfig(values as SystemConfigVO) |
|||
else |
|||
await createSystemConfig(values as SystemConfigVO) |
|||
|
|||
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,85 @@ |
|||
<script lang="ts" setup> |
|||
import SystemConfigModal from './SystemConfigModal.vue' |
|||
import { columns } from './SystemConfig' |
|||
import { useI18n } from '@/hooks/web/useI18n' |
|||
import { useMessage } from '@/hooks/web/useMessage' |
|||
import { useModal } from '@/components/Modal' |
|||
import { IconEnum } from '@/enums/appEnum' |
|||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|||
import { deleteSystemConfig, getSystemConfigPage } from '@/api/system/config/SystemConfig' |
|||
|
|||
defineOptions({ name: 'SystemConfig' }) |
|||
|
|||
const { t } = useI18n() |
|||
const { createMessage } = useMessage() |
|||
const [registerModal, { openModal }] = useModal() |
|||
|
|||
const [registerTable, { reload }] = useTable({ |
|||
title: '系统列表', |
|||
api: getSystemConfigPage, // 绑定获取分页数据的API |
|||
columns, |
|||
rowKey: 'id', |
|||
pagination: true, |
|||
useSearchForm: false, // 此页面不使用搜索表单,如需开启请设置为 true |
|||
bordered: true, |
|||
showIndexColumn: true, |
|||
actionColumn: { |
|||
width: 140, |
|||
title: t('common.action'), |
|||
dataIndex: 'action', |
|||
fixed: 'right', |
|||
}, |
|||
}) |
|||
|
|||
function handleCreate() { |
|||
openModal(true, { isUpdate: false }) |
|||
} |
|||
|
|||
function handleEdit(record: Recordable) { |
|||
openModal(true, { record, isUpdate: true }) |
|||
} |
|||
|
|||
async function handleDelete(record: Recordable) { |
|||
await deleteSystemConfig(record.id) |
|||
createMessage.success(t('common.delSuccessText')) |
|||
reload() // 刷新表格 |
|||
} |
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<BasicTable @register="registerTable"> |
|||
<template #toolbar> |
|||
<a-button v-auth="'system:system-config:create'" type="primary" :pre-icon="IconEnum.ADD" @click="handleCreate"> |
|||
{{ t('action.create') }} |
|||
</a-button> |
|||
</template> |
|||
<template #bodyCell="{ column, record }"> |
|||
<template v-if="column.key === 'action'"> |
|||
<TableAction |
|||
:actions="[ |
|||
{ |
|||
icon: IconEnum.EDIT, |
|||
label: t('action.edit'), |
|||
auth: 'system:system-config:update', // 【安全】权限控制 |
|||
onClick: handleEdit.bind(null, record), |
|||
}, |
|||
{ |
|||
icon: IconEnum.DELETE, |
|||
danger: true, |
|||
label: t('action.delete'), |
|||
auth: 'system:system-config:delete', // 【安全】权限控制 |
|||
popConfirm: { |
|||
title: t('common.delMessage'), |
|||
placement: 'left', |
|||
confirm: handleDelete.bind(null, record), |
|||
}, |
|||
}, |
|||
]" |
|||
/> |
|||
</template> |
|||
</template> |
|||
</BasicTable> |
|||
<SystemConfigModal @register="registerModal" @success="reload()" /> |
|||
</div> |
|||
</template> |
|||
Loading…
Reference in new issue