feat: 告警列表通用封装初始化完成

dev-deviceSetting
donghao 1 year ago
parent cec6c417ee
commit 7b6d552db4

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-01-12 14:35:28
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-01-17 10:21:07
* @LastEditTime: 2024-01-18 15:41:26
* @FilePath: \General-AI-Platform-Web-Client\index.html
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
@ -18,10 +18,10 @@
/>
<title>pure-admin-thin</title>
<link rel="icon" href="/favicon.ico" />
<!-- update 2024-01-17 13:23 -->
<!-- update 2024-01-17 15:41 -->
<link
rel="stylesheet"
href="//at.alicdn.com/t/c/font_4412653_abhopwxjly.css"
href="//at.alicdn.com/t/c/font_4412653_c3k3yiaknkn.css"
/>
<script>
window.process = {};

@ -1,5 +1,30 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-01-17 13:54:43
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-01-18 15:37:29
* @FilePath: \General-AI-Platform-Web-Client\mock\alarm.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { MockMethod } from "vite-plugin-mock";
function fetchList(): Record<string, any>[] {
const currList: Record<string, any>[] = [];
// const nameArr = ["玩手机监测", "控制器", "视频监控"];
// const deviceGroupArr = [""]
for (let i = 0; i < 10; i++) {
currList.push({
id: 1,
createTime: "2023-10-21 11:17:11",
updateTime: "2023-10-17T02:35:41.14308Z",
name: "玩手机监测",
code: "DC0000" + (i + 1),
level: "1",
deviceGroup: "设备组" + (i + 1),
remark: ""
});
}
return currList;
}
export default [
{
url: "/getAlarmList",
@ -8,494 +33,7 @@ export default [
return {
success: true,
data: {
list: [
{
index: 1,
isEnabled: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 2,
isEnabled: false,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
deviceSort: "监控1",
state: "在线",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 3,
isEnabled: false,
type: 5,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "监控1",
state: "故障",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 4,
isEnabled: false,
type: 2,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "控制设备",
state: "离线",
description:
"云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
},
{
index: 5,
isEnabled: true,
type: 3,
banner:
"https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
},
{
index: 6,
isEnabled: true,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 7,
isEnabled: false,
type: 1,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
deviceSort: "监控1",
state: "离线",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 8,
isEnabled: true,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
deviceSort: "控制设备",
state: "故障",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 9,
isEnabled: false,
type: 1,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
deviceSort: "监控1",
state: "离线",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 10,
isEnabled: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
},
{
index: 11,
isEnabled: true,
type: 5,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 12,
isEnabled: true,
type: 2,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
deviceSort: "监控1",
state: "在线",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 13,
isEnabled: true,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-db.jpg",
deviceSort: "控制设备",
state: "故障",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 14,
isEnabled: false,
type: 5,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
deviceSort: "控制设备",
state: "故障",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 15,
isEnabled: true,
type: 2,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
deviceSort: "监控1",
state: "在线",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 16,
isEnabled: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
deviceSort: "控制设备",
state: "离线",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 17,
isEnabled: false,
type: 5,
banner:
"https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 18,
isEnabled: false,
type: 4,
banner:
"https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
deviceSort: "监控1",
state: "离线",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 19,
isEnabled: true,
type: 2,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 20,
isEnabled: true,
type: 4,
banner:
"https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
deviceSort: "控制设备",
state: "故障",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 21,
isEnabled: false,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
deviceSort: "监控1",
state: "在线",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 22,
isEnabled: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-db.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 23,
isEnabled: true,
type: 1,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 24,
isEnabled: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "监控1",
state: "在线",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 25,
isEnabled: false,
type: 5,
banner:
"https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 26,
isEnabled: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
deviceSort: "监控1",
state: "在线",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 27,
isEnabled: true,
type: 5,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 28,
isEnabled: false,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 29,
isEnabled: false,
type: 5,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-db.jpg",
deviceSort: "监控1",
state: "故障",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 30,
isEnabled: true,
type: 1,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "控制设备",
state: "离线",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 31,
isEnabled: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
deviceSort: "控制设备",
state: "故障",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 32,
isEnabled: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
deviceSort: "监控1",
state: "在线",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 33,
isEnabled: true,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
},
{
index: 34,
isEnabled: false,
type: 2,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 35,
isEnabled: false,
type: 1,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
deviceSort: "监控1",
state: "在线",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 36,
isEnabled: false,
type: 4,
banner:
"https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
deviceSort: "监控1",
state: "在线",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 37,
isEnabled: true,
type: 5,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
deviceSort: "控制设备",
state: "离线",
description:
"云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
},
{
index: 38,
isEnabled: false,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "监控1",
state: "故障",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 39,
isEnabled: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
deviceSort: "控制设备",
state: "故障",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 40,
isEnabled: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "监控1",
state: "在线",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 41,
isEnabled: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 42,
isEnabled: true,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
deviceSort: "监控1",
state: "在线",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 43,
isEnabled: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-db.jpg",
deviceSort: "控制设备",
state: "故障",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 44,
isEnabled: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
deviceSort: "监控1",
state: "在线",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 45,
isEnabled: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "监控1",
state: "离线",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 46,
isEnabled: true,
type: 2,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
deviceSort: "监控1",
state: "在线",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 47,
isEnabled: false,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
deviceSort: "控制设备",
state: "在线",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 48,
isEnabled: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
deviceSort: "监控1",
state: "在线",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
}
]
list: fetchList()
}
};
}

@ -1,3 +1,11 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-01-15 14:45:56
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-01-18 14:43:01
* @FilePath: \General-AI-Platform-Web-Client\src\api\list.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { http } from "@/utils/http";
type Result = {
@ -12,3 +20,8 @@ type Result = {
export const getCardList = (data?: object) => {
return http.request<Result>("post", "/getCardList", { data });
};
/** 告警列表 */
export const getAlarmList = (data?: object) => {
return http.request<Result>("post", "/getAlarmList", { data });
};

@ -0,0 +1,3 @@
import baseTable from "./src/baseTable";
export const BaseTable = baseTable;

@ -0,0 +1,102 @@
<!--
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-01-18 14:27:25
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-01-18 15:29:02
* @FilePath: \General-AI-Platform-Web-Client\src\components\CustomTable\src\column.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<el-dialog v-model="dialogVisible" :width="600" title="自定义列">
<!-- footer -->
<template #footer>
<el-row type="flex" justify="center">
<el-button @click="handleCancel"> </el-button>
<el-button type="primary" @click="handleConfirm"> </el-button>
</el-row>
</template>
<!-- body -->
<div class="x-custom-column">
<template v-for="item in items" :key="item.prop || item.type">
<el-checkbox
v-if="!item.type"
v-model="item.show"
:label="item.label"
size="large"
/>
</template>
</div>
</el-dialog>
</template>
<script lang="ts" setup>
interface ModalProps {
visible: boolean;
columns: XTableColumn[];
}
type XCustomColumn = XTableColumn & {
show: boolean;
};
const props = withDefaults(defineProps<ModalProps>(), {
visible: false
});
const emit = defineEmits<{
(e: "update:visible", value: boolean): void;
(e: "visibleChange", value: boolean): void;
(e: "change", value: XTableColumn[]): void;
}>();
const dialogVisible = computed({
get: () => props.visible,
set: val => {
emit("update:visible", val);
emit("visibleChange", val);
}
});
const items = ref<XCustomColumn[]>([]);
watch(
() => props.visible,
value => {
if (value) {
items.value = props.columns.map(i => ({
...i,
show: !i.hidden
}));
}
}
);
function handleConfirm() {
const data = items.value.map(i => {
const { show, ...rest } = i;
return {
...rest,
hidden: !show
};
});
emit("change", data);
dialogVisible.value = false;
}
function handleCancel() {
dialogVisible.value = false;
}
</script>
<style lang="scss" scoped>
.x-custom-column {
min-height: 100px;
padding: 10px;
.el-checkbox {
width: 18%;
margin-right: 10px;
}
}
</style>

@ -0,0 +1,60 @@
.baseTable_wrap {
.baseTable_box {
position: relative;
.el-table__body {
border-collapse: separate !important;
/* 让边框独立,而不是合并 */
border-spacing: 0 8px;
/* 设置行与行之间的间距,可以根据需要调整值 */
width: 100%;
/* 表格宽度占据父容器的100% */
tr {
& > td:nth-child(1) {
border-left: 1px solid #dcdcdc;
border-radius: 4px;
}
& > td:last-child {
border-right: 1px solid #dcdcdc !important;
border-radius: 4px;
}
}
}
tr {
& > th:nth-child(1) {
border-left: 1px solid #dcdcdc;
border-radius: 4px 0 0 4px;
}
& > th:last-child {
border-right: 1px solid #dcdcdc !important;
border-radius: 0 4px 4px 0;
}
}
.el-table__header > thead {
th {
background-color: rgba(21, 77, 221, 0.1) !important;
}
}
&.el-table td.el-table__cell,
&.el-table th.el-table__cell.is-leaf {
border-top: 1px solid #dcdcdc;
border-bottom: 1px solid #dcdcdc;
}
}
}
.pagination_box {
margin-top: 50px;
width: 100%;
// position: fixed;
// bottom: 100px;
// right: 40px;
background-color: white;
z-index: 9;
}

@ -0,0 +1,397 @@
import { ElLoading, ElPagination, ElTable, ElTableColumn } from "element-plus";
import BaseColumn from "./baseColumn.vue";
import { isUndefined } from "@/utils/is";
import {
computed,
defineComponent,
nextTick,
reactive,
type PropType
} from "vue";
import "./baseTable.scss";
function getDefaultSort(attrs: Record<string, any>): any {
return attrs["default-sort"] || attrs.defaultSort;
}
export default defineComponent({
name: "XTable",
directives: {
loading: ElLoading.directive
},
inheritAttrs: false,
props: {
/**
*
*/
columns: {
type: Array as PropType<XTableColumn[]>,
required: true
},
/**
*
*/
dataSource: {
type: Array as PropType<XTableData[]>,
required: true
},
/**
* loading
*/
loading: {
type: Boolean,
default: false
},
/**
*
*/
maxHeight: {
type: [Number, String] as PropType<number | "auto">,
default: "auto"
},
/**
*
* always
* false
* true
*/
pageable: {
type: [Boolean, String] as PropType<boolean | "always">,
default: true,
validator(value: boolean | "always") {
return ["always", true, false].includes(value);
}
},
/**
*
*/
pagerLayout: {
type: String,
default: "total, sizes, prev, pager, next, jumper",
validator(value: string) {
return value
.split(",")
.map(item => item.trim())
.every(item =>
["total", "sizes", "prev", "pager", "next", "jumper"].includes(item)
);
}
},
/**
*
*/
total: {
type: Number,
default: 0
},
/**
*
*/
pageSize: {
type: Number,
default: 10
},
/**
*
*/
pageNum: {
type: Number,
default: 1
},
/**
*
*/
pageSizes: {
type: Array as PropType<number[]>,
default() {
return [10, 20, 30, 50];
}
},
/**
* Key
*/
rowKey: {
type: [Function, String] as PropType<
(row: XTableData) => string | string
>,
default: "id"
},
/**
*
*/
visibleColumn: {
type: Boolean,
default: undefined
}
},
emits: ["change", "columnChange", "update:visibleColumn"],
setup(props, { slots, attrs, emit }) {
const nonPropsAttrs = attrs;
const { prop: sortBy, order: sortOrder } = getDefaultSort(attrs) || {};
const tableState = reactive<XTableState>({
tid: 0,
sortBy,
sortOrder
});
const showPagination = computed(() => {
if (props.pageable === "always") return true;
return props.pageable && props.dataSource.length > 0;
});
const mHeight = computed(() => {
if (props.maxHeight === "auto") {
return "auto";
}
return showPagination.value ? props.maxHeight - 44 : props.maxHeight;
});
/**
*
*/
function getSlot(column: XTableColumn, suffix?: string) {
const name = column.prop || column.type;
if (name) {
const key = suffix ? `${name}-${suffix}` : name;
return slots[key];
}
}
/**
*
*/
function onChange(data: XTableChangeData) {
emit("change", data);
}
/**
*
*/
function handlePageNumChange(pageNum: number) {
const { sortBy, sortOrder } = tableState;
const { pageSize } = props;
onChange({
pageNum,
pageSize,
prop: sortBy,
order: sortOrder,
type: "number"
});
}
/**
*
*/
function handlePageSizeChange(pageSize: number) {
const { sortBy, sortOrder } = tableState;
nextTick(() => {
// 下拉框溢出可能导致溢出 body 出现滚动条
// 加个延迟,等下拉隐藏
onChange({
pageNum: 1,
pageSize,
prop: sortBy,
order: sortOrder,
type: "size"
});
});
}
/**
*
*/
function handleTableSortChange({ prop, order }: XTableSort) {
const { pageSize } = props;
onChange({ pageNum: 1, pageSize, prop, order, type: "sort" });
}
/**
*
*/
function handleColumnChange(cols: XTableColumn[]) {
emit("columnChange", cols);
}
/**
*
*/
function handleVisibleChange(val: boolean) {
emit("update:visibleColumn", val);
}
/**
*
*/
function getColumnProps(column: XTableColumn) {
const col = { ...column };
Reflect.deleteProperty(col, "children");
Reflect.deleteProperty(col, "hidden");
col.key = column.key || column.prop || column.type;
col.showOverflowTooltip = col.showOverflowTooltip ?? true;
col.showOverflowTooltip =
column.prop === "action" ? false : column.showOverflowTooltip;
return col;
}
/**
*
*/
function renderTypeColumn(column: XTableColumn) {
if (column.type === "expand") {
return (
<ElTableColumn {...getColumnProps(column)}>
{{
default: (scope: Record<string, any>) => {
const slot = getSlot(column);
return slot?.(scope);
}
}}
</ElTableColumn>
);
}
return <ElTableColumn {...getColumnProps(column)} />;
}
/**
*
*/
function renderBaseColumn(column: XTableColumn) {
const columnSlots: {
default?: (scope: Record<string, any>) => any;
header?: (scope: Record<string, any>) => any;
} = {};
const slot = getSlot(column);
const headerSlot = getSlot(column, "header");
if (slot) {
columnSlots.default = scope => slot(scope);
}
if (headerSlot) {
columnSlots.header = scope => headerSlot(scope);
}
return (
<ElTableColumn {...getColumnProps(column)}>{columnSlots}</ElTableColumn>
);
}
/**
*
*/
function renderTableColumn(column: XTableColumn) {
if (column.hidden) return;
if (column.type) {
return renderTypeColumn(column);
}
return renderBaseColumn(column);
}
/**
*
*/
function renderColumnChildren(
column: XTableColumn,
children: Required<XTableColumn>["children"]
) {
if (column.hidden) return;
return (
<ElTableColumn {...getColumnProps(column)}>
{children.map(column => renderTableColumn(column))}
</ElTableColumn>
);
}
/**
*
*/
function renderPagination() {
const paginationProps = {
size: "small",
background: false,
total: props.total,
layout: props.pagerLayout,
pageSize: props.pageSize,
pageSizes: props.pageSizes,
currentPage: props.pageNum,
onSizeChange: handlePageSizeChange,
onCurrentChange: handlePageNumChange
};
return (
<div class="x-table-pagination">
<ElPagination class="float-right mt-[50px]" {...paginationProps} />
</div>
);
}
/**
*
*/
function renderCustomColumn() {
const customColumnProps = {
columns: props.columns,
visible: props.visibleColumn,
onChange: handleColumnChange,
onVisibleChange: handleVisibleChange
};
return <BaseColumn {...customColumnProps} />;
}
return () => {
const tableProps = {
ref: "elTableRef",
...nonPropsAttrs,
maxHeight: mHeight.value,
data: props.dataSource,
rowKey: props.rowKey,
onSortChange: handleTableSortChange
};
const extraSlots: {
append?: () => any;
empty?: () => any;
} = {};
if (slots.append) {
extraSlots.append = () => slots.append?.();
}
if (slots.empty) {
extraSlots.empty = () => slots.empty?.();
}
return (
<div class="x-table baseTable_wrap">
<ElTable
class="baseTable_box"
{...tableProps}
v-loading={props.loading}
v-slots={extraSlots}
>
{props.columns.map(column => {
if (Array.isArray(column.children)) {
return renderColumnChildren(column, column.children);
}
return renderTableColumn(column);
})}
</ElTable>
{showPagination.value && renderPagination()}
{!isUndefined(props.visibleColumn) && renderCustomColumn()}
</div>
);
};
}
});

@ -0,0 +1,37 @@
import type ElTable from "element-plus/lib/components/table";
import type { ElTableColumn } from "element-plus/lib/components/table";
export {};
type ElTableType = InstanceType<typeof ElTable>;
type ElTableProps = ElTableType["$props"];
type ElTableColumnProps = InstanceType<typeof ElTableColumn>["$props"];
type ElTableSort = Pick<
Required<ElTableProps>["defaultSort"],
"prop" | "order"
>;
declare global {
type XTableSort = ElTableSort;
interface XTableColumn extends ElTableColumnProps {
children?: XTableColumn[];
hidden?: boolean;
}
interface XTableData {
[key: string]: any;
}
interface XTableState {
tid: number;
sortBy?: XTableSort["prop"];
sortOrder?: XTableSort["order"];
}
interface XTableChangeData extends Partial<XTableSort> {
type: "size" | "number" | "sort";
pageNum: number;
pageSize: number;
}
}

@ -96,10 +96,13 @@ export default defineComponent({
return () => {
return (
<div class="collapseTree_wrap">
<ul class="root_cat_box" style={{ padding: "16px" }}>
<ul
class="root_cat_box"
style={{ padding: "16px", overflowY: "scroll", minHeight: "100%" }}
>
{treeData.list.map((vFirst, kFirst) => {
return (
<li key={kFirst}>
<li key={kFirst} style={{ marginBottom: "16px" }}>
<div
class={[
"first_level_box",

@ -45,7 +45,7 @@ export default defineComponent({
class={[
"collapseTreeItem_info flex",
currentTreeNodeId.value === nodeLatestInfo.value.id
? "text-web-font0"
? "theme-color"
: "text-web-font2"
]}
onClick={() => {

@ -4,7 +4,7 @@ import Notice from "./notice/index.vue";
import mixNav from "./sidebar/mixNav.vue";
import { useNav } from "@/layout/hooks/useNav";
import Breadcrumb from "./sidebar/breadCrumb.vue";
import topCollapse from "./sidebar/topCollapse.vue";
// import topCollapse from "./sidebar/topCollapse.vue";
import { useTranslationLang } from "../hooks/useTranslationLang";
import globalization from "@/assets/svg/globalization.svg?component";
import LogoutCircleRLine from "@iconify-icons/ri/logout-circle-r-line";
@ -13,14 +13,14 @@ import Check from "@iconify-icons/ep/check";
const {
layout,
device,
// device,
logout,
// onPanel,
pureApp,
// pureApp,
username,
userAvatar,
avatarsStyle,
toggleSideBar,
// toggleSideBar,
getDropdownItemStyle,
getDropdownItemClass
} = useNav();
@ -32,12 +32,12 @@ const { t, locale, translationCh, translationEn } = useTranslationLang();
<div
class="navbar bg-[#fff] shadow-sm shadow-[rgba(0, 21, 41, 0.08)] dark:shadow-[#0d0d0d]"
>
<topCollapse
<!-- <topCollapse
v-if="device === 'mobile'"
class="hamburger-container"
:is-active="pureApp.sidebar.opened"
@toggleClick="toggleSideBar"
/>
/> -->
<Breadcrumb class="breadcrumb-container" />

@ -96,7 +96,7 @@ watch(
v-for="item in levelList"
:key="item.path"
>
<span :class="['text-web-font1 text-[14px] font-bold']">{{
<span :class="['text-web-font1 text-[14px] font-bold mx-[16px]']">{{
transformI18n(item.meta.title)
}}</span>
</el-breadcrumb-item>

@ -0,0 +1,57 @@
const { toString } = Object.prototype;
export function is(val: unknown, type: string): boolean {
return toString.call(val) === `[object ${type}]`;
}
export function isString(val: any): val is string {
return is(val, "String");
}
export function isNumber(val: any): val is number {
return is(val, "Number");
}
export function isBoolean(val: any): val is boolean {
return is(val, "Boolean");
}
export function isObject(val: any): val is Record<string, any> {
return val !== null && is(val, "Object");
}
export function isEmptyObject(val: any): val is boolean {
return isObject(val) && Object.keys(val).length === 0;
}
export function isArray(val: any): val is any[] {
return val && Array.isArray(val);
}
export function isNull(val: any): val is null {
return is(val, "Null");
}
export function isUndefined(val: any): val is undefined {
return is(val, "Undefined");
}
export function isFunction(val: any): val is (...args: any[]) => any {
return typeof val === "function";
}
export function isFile(val: any): val is File {
return is(val, "File");
}
export function isBlob(val: any): val is Blob {
return is(val, "Blob");
}
export function isRegExp(val: any) {
return is(val, "RegExp");
}
export function isExternal(val: any) {
return /^(https?:|mailto:|tel:)/.test(val);
}

@ -1,6 +1,7 @@
<script setup lang="ts">
import { getCardList } from "@/api/list";
import { getAlarmList } from "@/api/list";
import { onMounted, ref, reactive } from "vue";
import { BaseTable } from "@/components/CustomTable";
defineOptions({
name: "AlarmList"
});
@ -52,6 +53,38 @@ const alarmLevelStatusEnum: Record<string, any>[] = [
}
];
const columns = [
{
type: "selection"
},
{
label: "告警名称",
property: "name"
},
{
label: "告警代码",
property: "code"
},
// TODO
{
label: "告警等级",
property: "level"
},
{
label: "设备组",
property: "deviceGroup"
},
{
label: "告警日期",
property: "createTime"
}
// TODO
// {
// label: "",
// property: "name"
// }
];
const svg = `
<path class="path" d="
M 30 15
@ -65,9 +98,9 @@ const svg = `
const pagination = ref({ current: 1, pageSize: 10, total: 0 });
const deviceList = ref([]);
const listData = ref([]);
const searchValue = ref("");
// const searchValue = ref("");
const formData = reactive({
deviceSort: "",
@ -76,20 +109,11 @@ const formData = reactive({
});
const dataLoading = ref(true);
// const onSubmit = () => {
// console.log("submit!");
// };
const onPageSizeChange = (size: number) => {
pagination.value.pageSize = size;
pagination.value.current = 1;
};
const onCurrentChange = (current: number) => {
pagination.value.current = current;
};
const getCardListData = async () => {
const getList = async () => {
try {
const { data } = await getCardList();
deviceList.value = data.list;
const { data } = await getAlarmList();
listData.value = data.list;
console.log(data.list);
pagination.value = {
...pagination.value,
@ -104,7 +128,7 @@ const getCardListData = async () => {
}
};
onMounted(() => {
getCardListData();
getList();
});
</script>
@ -141,52 +165,8 @@ onMounted(() => {
:element-loading-svg="svg"
element-loading-svg-view-box="-10, -10, 50, 50"
>
<el-empty
v-show="
deviceList
.slice(
pagination.pageSize * (pagination.current - 1),
pagination.pageSize * pagination.current
)
.filter(v =>
v.deviceSort.toLowerCase().includes(searchValue.toLowerCase())
).length === 0
"
:description="`${searchValue} 产品不存在`"
/>
<template v-if="pagination.total > 0">
<el-row :gutter="16">
<el-col
class="mb-4 w-[100%]"
v-for="(device, index) in deviceList
.slice(
pagination.pageSize * (pagination.current - 1),
pagination.pageSize * pagination.current
)
.filter(v =>
v.deviceSort.toLowerCase().includes(searchValue.toLowerCase())
)"
:key="index"
:xs="24"
:sm="24"
:md="24"
:lg="24"
:xl="24"
>
<div>123</div>
</el-col>
</el-row>
<el-pagination
v-model:currentPage="pagination.current"
class="float-right"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[10, 20, 30]"
:background="false"
layout="total, sizes, prev, pager, next, jumper"
@size-change="onPageSizeChange"
@current-change="onCurrentChange"
/>
<BaseTable :total="48" :dataSource="listData" :columns="columns" />
</template>
</div>
</div>

@ -18,7 +18,7 @@ const svg = `
" style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
`;
const pagination = ref({ current: 1, pageSize: 12, total: 0 });
const pagination = ref({ current: 1, pageSize: 9, total: 0 });
const deviceList = ref([]);
@ -63,10 +63,10 @@ onMounted(() => {
</script>
<template>
<div class="main flex justify-start p-4">
<div class="flex justify-start p-4 main">
<TreeCard />
<div
class="ml-5 flex-1"
class="flex-1 ml-5"
v-loading="dataLoading"
:element-loading-svg="svg"
element-loading-svg-view-box="-10, -10, 50, 50"
@ -146,10 +146,10 @@ onMounted(() => {
</el-row>
<el-pagination
v-model:currentPage="pagination.current"
class="absolute right-4 bottom-0"
class="float-right"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[12, 18, 36]"
:page-sizes="[9, 18, 36]"
:background="false"
layout="total, sizes, prev, pager, next, jumper"
@size-change="onPageSizeChange"

@ -17,7 +17,7 @@ const svg = `
" style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
`;
const pagination = ref({ current: 1, pageSize: 12, total: 0 });
const pagination = ref({ current: 1, pageSize: 9, total: 0 });
const deviceList = ref([]);
@ -56,7 +56,7 @@ onMounted(() => {
</script>
<template>
<div class="main p-4">
<div class="p-4 main">
<div
v-loading="dataLoading"
:element-loading-svg="svg"
@ -99,10 +99,10 @@ onMounted(() => {
</el-row>
<el-pagination
v-model:currentPage="pagination.current"
class="absolute right-4 bottom-0"
class="float-right"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[12, 24, 36]"
:page-sizes="[9, 24, 36]"
:background="false"
layout="total, sizes, prev, pager, next, jumper"
@size-change="onPageSizeChange"

@ -17,7 +17,7 @@ const svg = `
" style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
`;
const pagination = ref({ current: 1, pageSize: 12, total: 0 });
const pagination = ref({ current: 1, pageSize: 9, total: 0 });
const deviceList = ref([]);
@ -56,7 +56,7 @@ onMounted(() => {
</script>
<template>
<div class="main p-4">
<div class="p-4 main">
<div class="mt-4 mb-5">
<el-button> {{ `全部状态(${90})` }} </el-button>
<el-button> {{ `在线(${80})` }}</el-button>
@ -104,10 +104,10 @@ onMounted(() => {
</el-row>
<el-pagination
v-model:currentPage="pagination.current"
class="absolute right-4 bottom-0"
class="float-right"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[12, 24, 36]"
:page-sizes="[9, 24, 36]"
:background="false"
layout="total, sizes, prev, pager, next, jumper"
@size-change="onPageSizeChange"

@ -1,9 +0,0 @@
<script setup lang="ts">
defineOptions({
name: "Welcome"
});
</script>
<template>
<h1>Pure-Admin-Thin国际化版本</h1>
</template>

@ -30,7 +30,7 @@ const pie3Ddata = {
</script>
<template>
<div class="main">
<div class="main ml-[16px]">
<el-row :gutter="24" justify="space-around">
<re-col
v-motion
@ -76,7 +76,7 @@ const pie3Ddata = {
}
}"
>
<span class="text-base mb-3 inline-block">违规总量</span>
<span class="inline-block mb-3 text-base">违规总量</span>
<el-card class="line-card" shadow="always">
<div class="flex justify-between h-[422px]">
<barChart />
@ -102,7 +102,7 @@ const pie3Ddata = {
}
}"
>
<span class="text-base mb-3 inline-block">消息通知</span>
<span class="inline-block mb-3 text-base">消息通知</span>
<el-card class="line-card" shadow="always">
<div class="flex justify-between h-[422px]">
<Notify />
@ -128,7 +128,7 @@ const pie3Ddata = {
}
}"
>
<span class="text-base mb-3 inline-block">设备状态</span>
<span class="inline-block mb-3 text-base">设备状态</span>
<el-card class="line-card" shadow="always">
<div class="flex justify-between h-[282px]"><DeviceStatus /></div>
</el-card>
@ -152,7 +152,7 @@ const pie3Ddata = {
}
}"
>
<span class="text-base mb-3 inline-block">设备告警情况</span>
<span class="inline-block mb-3 text-base">设备告警情况</span>
<el-card class="line-card" shadow="always">
<div class="flex justify-between h-[282px]">
<pie3DChart :data="pie3Ddata.data" />
@ -178,7 +178,7 @@ const pie3Ddata = {
}
}"
>
<span class="text-base mb-3 inline-block">算力占用</span>
<span class="inline-block mb-3 text-base">算力占用</span>
<el-card class="line-card" shadow="always">
<div class="flex justify-between h-[282px]">
<pieChart />

Loading…
Cancel
Save