修改传参方式

This commit is contained in:
re-JZzzz
2025-09-20 19:27:56 +08:00
parent 3445e54da0
commit 7eabcd203f
15 changed files with 948 additions and 604 deletions

View File

@ -5,11 +5,26 @@
</div>
</template>
<script setup>
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue';
import * as echarts from 'echarts';
// 定义props类型
interface TrendSeriesItem {
name: string;
data: number[];
color: string;
}
interface TrendData {
dates: string[];
series: TrendSeriesItem[];
}
// 定义props
const props = defineProps<{
trendData: TrendData;
}>();
// 图表DOM引用
const chartRef = ref(null);
@ -24,7 +39,7 @@ const initChart = () => {
const option = {
xAxis: {
type: "category",
data: ["09-04", "09-05", "09-06", "09-07", "09-08", "09-09", "09-10"],
data: props.trendData.dates,
axisTick: {
show: false // 去除刻度线
}
@ -52,48 +67,15 @@ const initChart = () => {
bottom: '3%',
containLabel: true
},
series: [
{
name: "维护提醒",
data: [120, 200, 150, 80, 70, 110, 130],
type: "bar",
itemStyle: {
color: "rgb(0, 179, 255)",
},
series: props.trendData.series.map((item, index) => ({
name: item.name,
data: item.data,
type: "bar",
barWidth: '10%' ,
itemStyle: {
color: item.color,
},
{
name: "数据异常",
data: [80, 170, 100, 50, 90, 140, 170],
type: "bar",
itemStyle: {
color: "rgb(22, 93, 255)",
},
},
{
name: "信号减弱",
data: [60, 140, 100, 120, 110, 100, 130],
type: "bar",
itemStyle: {
color: "rgb(255, 153, 0)",
},
},
{
name: "温度过高",
data: [60, 140, 100, 120, 110, 100, 130],
type: "bar",
itemStyle: {
color: "rgb(250, 220, 25)",
},
},
{
name: "通讯中断",
data: [60, 140, 100, 120, 110, 100, 130],
type: "bar",
itemStyle: {
color: "rgb(251, 62, 122)",
}
}
],
})),
};
chartInstance.setOption(option);
@ -106,6 +88,13 @@ const handleResize = () => {
}
};
// 监听props变化
watch(() => props.trendData, () => {
if (chartInstance) {
initChart();
}
}, { deep: true });
// 生命周期钩子
onMounted(() => {
initChart();
@ -120,8 +109,6 @@ onMounted(() => {
}
};
});
</script>
<style scoped>

View File

@ -5,10 +5,29 @@
</div>
</template>
<script setup>
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue';
import * as echarts from 'echarts';
// 定义props类型
interface PieItem {
value: number;
name: string;
displayName: string;
color: string;
}
interface PieData {
normal: PieItem;
interrupt: PieItem;
abnormal: PieItem;
serious: PieItem;
}
// 定义props
const props = defineProps<{
pieData: PieData;
}>();
// 图表DOM引用
const chartRef = ref(null);
@ -22,7 +41,10 @@ const initChart = () => {
}
const option = {
tooltip: {
trigger: 'item'
trigger: 'item',
formatter: (params: any) => {
return `${params.data.displayName}: ${params.value}`;
}
},
grid: {
left: '0%',
@ -37,6 +59,10 @@ const initChart = () => {
right: '5%', // 调整图例位置,使其更靠近左侧
itemWidth: 15,
itemHeight: 15,
formatter: (name: string) => {
const item = Object.values(props.pieData).find(item => item.name === name);
return item?.displayName || name;
}
},
series: [
{
@ -46,16 +72,32 @@ const initChart = () => {
show: false
},
color: [
'rgb(0, 179, 255)', // 提示信息
'rgb(45, 214, 131)', // 一般告警
'rgb(255, 208, 35)', // 重要告警
'rgb(227, 39, 39)' // 严重告警
props.pieData.normal.color,
props.pieData.interrupt.color,
props.pieData.abnormal.color,
props.pieData.serious.color
],
data: [
{ value: 1048, name: '提示信息' },
{ value: 735, name: '一般告警' },
{ value: 580, name: '重要告警' },
{ value: 484, name: '严重告警' },
{
value: props.pieData.normal.value,
name: props.pieData.normal.name,
displayName: props.pieData.normal.displayName
},
{
value: props.pieData.interrupt.value,
name: props.pieData.interrupt.name,
displayName: props.pieData.interrupt.displayName
},
{
value: props.pieData.abnormal.value,
name: props.pieData.abnormal.name,
displayName: props.pieData.abnormal.displayName
},
{
value: props.pieData.serious.value,
name: props.pieData.serious.name,
displayName: props.pieData.serious.displayName
}
],
emphasis: {
itemStyle: {
@ -78,6 +120,13 @@ const handleResize = () => {
}
};
// 监听props变化
watch(() => props.pieData, () => {
if (chartInstance) {
initChart();
}
}, { deep: true });
// 生命周期钩子
onMounted(() => {
initChart();
@ -92,8 +141,6 @@ onMounted(() => {
}
};
});
</script>
<style scoped>

View File

@ -1,5 +1,5 @@
<template>
<el-table :data="alarmLevels" :border="false" style="width: 100%">
<el-table :data="localAlarmLevels" :border="false" style="width: 100%">
<el-table-column prop="levelName" label="级别名称" align="center">
<template #default="scope">
<span :class="['level-name', `level-${scope.row.level}`]">{{ scope.row.levelName }}</span>
@ -78,7 +78,7 @@
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { ref, watch } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
// 定义告警等级类型
@ -102,49 +102,19 @@ interface ConfigData extends AlarmLevel {
processDescription: string;
}
// 模拟数据
const alarmLevels = ref<AlarmLevel[]>([
{
id: 1,
levelName: '严重告警',
description: '系统或应用出现严重故障',
priority: '一级',
responseTime: '15分钟以内',
processingMethod: ['系统锁定', '声光报警', '短信通知'],
enabled: true,
level: 1
},
{
id: 2,
levelName: '重要告警',
description: '系统或应用出现严重故障',
priority: '二级',
responseTime: '30分钟以内',
processingMethod: ['声光报警', '短信通知', '系统记录'],
enabled: true,
level: 2
},
{
id: 3,
levelName: '一般告警',
description: '非关键性故障或潜在风险',
priority: '三级',
responseTime: '120分钟以内',
processingMethod: ['短信通知', '系统记录'],
enabled: true,
level: 3
},
{
id: 4,
levelName: '提示信息',
description: '系统或应用非关键性变化或即将达到阈值的状态',
priority: '四级',
responseTime: '24小时以内',
processingMethod: ['短信通知'],
enabled: false,
level: 4
}
]);
// 定义props
const props = defineProps<{
alarmLevels: AlarmLevel[];
}>();
// 本地数据副本
const localAlarmLevels = ref<AlarmLevel[]>([]);
// 初始化本地数据
watch(() => props.alarmLevels, (newVal) => {
// 深拷贝以避免直接修改props
localAlarmLevels.value = JSON.parse(JSON.stringify(newVal));
}, { immediate: true, deep: true });
// 对话框相关状态
const configDialogVisible = ref(false);
@ -198,10 +168,10 @@ const handleConfig = (row: AlarmLevel) => {
const handleConfigSave = () => {
if (currentConfigData.value) {
// 找到对应的告警等级并更新
const index = alarmLevels.value.findIndex(item => item.id === currentConfigData.value!.id);
const index = localAlarmLevels.value.findIndex(item => item.id === currentConfigData.value!.id);
if (index !== -1) {
alarmLevels.value[index] = {
...alarmLevels.value[index],
localAlarmLevels.value[index] = {
...localAlarmLevels.value[index],
enabled: currentConfigData.value!.enabled
};
}
@ -217,9 +187,9 @@ const handleDelete = (id: number) => {
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const index = alarmLevels.value.findIndex(item => item.id === id);
const index = localAlarmLevels.value.findIndex(item => item.id === id);
if (index !== -1) {
alarmLevels.value.splice(index, 1);
localAlarmLevels.value.splice(index, 1);
ElMessage.success('删除成功');
}
}).catch(() => {

View File

@ -8,7 +8,7 @@
<div class="total-header">
<span class="total-title">今日报警总数</span>
</div>
<div class="total-number">28</div>
<div class="total-number">{{ totalData.totalAlarm }}</div>
</div>
<div class="icon-section">
<el-icon class="total-icon blue">
@ -20,7 +20,7 @@
<el-icon class="trend-icon green">
<img src="/src/assets/demo/up.png" alt="上升">
</el-icon>
<span class="comparison-text green">8</span>
<span class="comparison-text green">+{{ totalData.totalIncrease }}</span>
<span class="period-text">较上月同期</span>
</div>
</div>
@ -34,7 +34,7 @@
<div class="total-header">
<span class="total-title">未处理报警</span>
</div>
<div class="total-number">8</div>
<div class="total-number">{{ totalData.unprocessedAlarm }}</div>
</div>
<div class="icon-section">
<el-icon class="total-icon purple">
@ -46,7 +46,7 @@
<el-icon class="trend-icon green">
<img src="/src/assets/demo/up.png" alt="上升">
</el-icon>
<span class="comparison-text green">8</span>
<span class="comparison-text green">+{{ totalData.unprocessedIncrease }}</span>
<span class="period-text">较上月同期</span>
</div>
</div>
@ -60,7 +60,7 @@
<div class="total-header">
<span class="total-title">已处理报警</span>
</div>
<div class="total-number">20</div>
<div class="total-number">{{ totalData.processedAlarm }}</div>
</div>
<div class="icon-section">
<el-icon class="total-icon green">
@ -72,7 +72,7 @@
<el-icon class="trend-icon green">
<img src="/src/assets/demo/up.png" alt="上升">
</el-icon>
<span class="comparison-text green">8</span>
<span class="comparison-text green">+{{ totalData.processedIncrease }}</span>
<span class="period-text">较上月同期</span>
</div>
</div>
@ -86,7 +86,7 @@
<div class="total-header">
<span class="total-title">严重报警</span>
</div>
<div class="total-number">3</div>
<div class="total-number">{{ totalData.seriousAlarm }}</div>
</div>
<div class="icon-section">
<el-icon class="total-icon orange">
@ -98,7 +98,7 @@
<el-icon class="trend-icon green">
<img src="/src/assets/demo/up.png" alt="上升">
</el-icon>
<span class="comparison-text green">8</span>
<span class="comparison-text green">+{{ totalData.seriousIncrease }}</span>
<span class="period-text">较上月同期</span>
</div>
</div>
@ -107,6 +107,24 @@
</template>
<script setup lang="ts">
import { defineProps } from 'vue';
// 定义props类型
interface TotalData {
totalAlarm: number;
unprocessedAlarm: number;
processedAlarm: number;
seriousAlarm: number;
totalIncrease: number;
unprocessedIncrease: number;
processedIncrease: number;
seriousIncrease: number;
}
// 定义props
const props = defineProps<{
totalData: TotalData;
}>();
</script>
<style scoped lang="scss">

View File

@ -12,14 +12,14 @@
<el-col :span="16">
<el-card shadow="hover" class="custom-card">
<TitleComponent title="报警管理" :font-level="2" />
<totalView />
<totalView :totalData="totalData" />
</el-card>
</el-col>
<el-col :span="8">
<!-- 报警级别分布 -->
<el-card shadow="hover" class="custom-card">
<TitleComponent title="报警级别分布" :font-level="2" />
<levelPie />
<levelPie :pieData="pieData" />
</el-card>
</el-col>
</el-row>
@ -29,7 +29,7 @@
<el-col :span="24">
<el-card shadow="hover" class="custom-card">
<TitleComponent title="报警趋势分析" :font-level="2" />
<fenxiBar />
<fenxiBar :trendData="trendData" />
</el-card>
</el-col>
</el-row>
@ -39,7 +39,7 @@
<el-col :span="24">
<el-card shadow="hover" class="custom-card">
<TitleComponent title="报警级别设置" :font-level="2" />
<levelSet />
<levelSet :alarmLevels="alarmLevelsData" />
</el-card>
</el-col>
</el-row>
@ -47,11 +47,128 @@
</template>
<script setup>
import { ref } from 'vue';
import TitleComponent from '@/components/TitleComponent/index.vue';
import levelPie from '@/views/integratedManage/alarmManage/components/levelPie.vue'
import fenxiBar from '@/views/integratedManage/alarmManage/components/fenxiBar.vue'
import totalView from '@/views/integratedManage/alarmManage/components/totalView.vue';
import levelSet from '@/views/integratedManage/alarmManage/components/levelSet.vue';
// 模拟报警总数数据
const totalData = ref({
totalAlarm: 28,
unprocessedAlarm: 8,
processedAlarm: 20,
seriousAlarm: 3,
totalIncrease: 8,
unprocessedIncrease: 3,
processedIncrease: 5,
seriousIncrease: 1
});
// 模拟报警级别分布数据
const pieData = ref({
normal: {
value: 1048,
name: '提示信息',
displayName: '提示信息',
color: 'rgb(0, 179, 255)'
},
interrupt: {
value: 735,
name: '一般告警',
displayName: '一般告警',
color: 'rgb(45, 214, 131)'
},
abnormal: {
value: 580,
name: '重要告警',
displayName: '重要告警',
color: 'rgb(255, 208, 35)'
},
serious: {
value: 484,
name: '严重告警',
displayName: '严重告警',
color: 'rgb(227, 39, 39)'
}
});
// 模拟报警趋势数据
const trendData = ref({
dates: ['09-04', '09-05', '09-06', '09-07', '09-08', '09-09', '09-10'],
series: [
{
name: '维护提醒',
data: [120, 200, 150, 80, 70, 110, 130],
color: 'rgb(0, 179, 255)'
},
{
name: '数据异常',
data: [80, 170, 100, 50, 90, 140, 170],
color: 'rgb(22, 93, 255)'
},
{
name: '信号减弱',
data: [60, 140, 100, 120, 110, 100, 130],
color: 'rgb(255, 153, 0)'
},
{
name: '温度过高',
data: [60, 140, 100, 120, 110, 100, 130],
color: 'rgb(250, 220, 25)'
},
{
name: '通讯中断',
data: [60, 140, 100, 120, 110, 100, 130],
color: 'rgb(251, 62, 122)'
}
]
});
// 模拟告警级别设置数据
const alarmLevelsData = ref([
{
id: 1,
levelName: '严重告警',
description: '系统或应用出现严重故障',
priority: '一级',
responseTime: '15分钟以内',
processingMethod: ['系统锁定', '声光报警', '短信通知'],
enabled: true,
level: 1
},
{
id: 2,
levelName: '重要告警',
description: '系统或应用出现严重故障',
priority: '二级',
responseTime: '30分钟以内',
processingMethod: ['声光报警', '短信通知', '系统记录'],
enabled: true,
level: 2
},
{
id: 3,
levelName: '一般告警',
description: '非关键性故障或潜在风险',
priority: '三级',
responseTime: '120分钟以内',
processingMethod: ['短信通知', '系统记录'],
enabled: true,
level: 3
},
{
id: 4,
levelName: '提示信息',
description: '系统或应用非关键性变化或即将达到阈值的状态',
priority: '四级',
responseTime: '24小时以内',
processingMethod: ['短信通知'],
enabled: false,
level: 4
}
]);
</script>
<style scoped>

View File

@ -41,53 +41,13 @@
<script setup>
import TitleComponent from '@/components/TitleComponent/index.vue';
const approvalData = [
{
type: '事假',
days: 1,
timeRange: '09.14-09.15',
people: '水泥班组-王五',
status: '待审批',
statusType: 'primary',
iconPath: '/src/assets/demo/approval.png'
},
{
type: '病假',
days: 2,
timeRange: '09.14-09.15',
people: '水泥班组-王五',
status: '待审批',
statusType: 'primary',
iconPath: '/src/assets/demo/approval.png'
},
{
type: '调休',
days: 1,
timeRange: '09.14-09.15',
people: '水泥班组-王五',
status: '待审批',
statusType: 'primary',
iconPath: '/src/assets/demo/approval.png'
},
{
type: '事假',
days: 1,
timeRange: '09.14-09.15',
people: '水泥班组-王五',
status: '待审批',
statusType: 'primary',
iconPath: '/src/assets/demo/approval.png'
},
{
type: '事假',
days: 1,
timeRange: '09.14-09.15',
people: '水泥班组-王五',
status: '已通过',
statusType: 'success',
iconPath: '/src/assets/demo/approval.png'
}
];
// 接收从父组件传入的数据
const props = defineProps({
approvalData: {
type: Array,
default: () => []
}
});
</script>
<style scoped lang="scss">
.chart-header {

View File

@ -57,27 +57,43 @@ import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue';
import { ref, computed } from 'vue';
import { ElMessage } from 'element-plus';
// 初始化当前日期
const today = new Date();
const currentDate = ref(new Date(2025, 8, 27)); // 2025年9月27日截图中显示的日期
const selectedDate = ref(new Date(2025, 8, 27));
// 模拟考勤数据
const attendanceData = ref({
2025: {
9: {
1: 'normal',
4: 'late',
8: 'absent',
10: 'leave',
15: 'normal',
20: 'normal',
25: 'late',
27: 'normal'
}
// 接收从父组件传入的数据
const props = defineProps({
calendarData: {
type: Object,
default: () => ({
// 初始化当前日期
today: new Date(),
currentDate: new Date(2025, 8, 27), // 2025年9月27日截图中显示的日期
selectedDate: new Date(2025, 8, 27),
// 模拟考勤数据
attendanceData: {
2025: {
9: {
1: 'normal',
4: 'late',
8: 'absent',
10: 'leave',
15: 'normal',
20: 'normal',
25: 'late',
27: 'normal'
}
}
}
})
}
});
// 初始化当前日期
const today = ref(props.calendarData.today);
const currentDate = ref(props.calendarData.currentDate);
const selectedDate = ref(props.calendarData.selectedDate);
// 模拟考勤数据
const attendanceData = ref(props.calendarData.attendanceData);
// 星期几的显示
const weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
@ -160,15 +176,15 @@ const getAttendanceStatus = (day) => {
};
const isToday = (day) => {
return day === today.getDate() &&
currentMonth.value === today.getMonth() &&
currentYear.value === today.getFullYear();
return day === today.value.getDate() &&
currentMonth.value === today.value.getMonth() &&
currentYear.value === today.value.getFullYear();
};
const isCurrentDay = (day) => {
return day === today.getDate() &&
currentMonth.value === today.getMonth() &&
currentYear.value === today.getFullYear();
return day === today.value.getDate() &&
currentMonth.value === today.value.getMonth() &&
currentYear.value === today.value.getFullYear();
};
const isSelectedDay = (day) => {

View File

@ -3,31 +3,31 @@
<TitleComponent title="今日出勤" :font-level="2" />
<div class="todayAttend">
<div class="todayAttendItem">
<img src="@/assets/demo/qin.png" alt="" width="30px" height="30px">
<img :src="props.todayAttendData.attendance.icon" alt="" width="30px" height="30px">
<div class="todayAttendItemInfo">
<span class="todayAttendItemTitle">出勤</span>
<span class="todayAttendItemNum">150</span>
<span class="todayAttendItemNum">{{ props.todayAttendData.attendance.count }}</span>
</div>
</div>
<div class="todayAttendItem">
<img src="@/assets/demo/qin.png" alt="" width="30px" height="30px">
<img :src="props.todayAttendData.late.icon" alt="" width="30px" height="30px">
<div class="todayAttendItemInfo">
<span class="todayAttendItemTitle">迟到</span>
<span class="todayAttendItemNum">150</span>
<span class="todayAttendItemNum">{{ props.todayAttendData.late.count }}</span>
</div>
</div>
<div class="todayAttendItem">
<img src="@/assets/demo/qin.png" alt="" width="30px" height="30px">
<img :src="props.todayAttendData.earlyLeave.icon" alt="" width="30px" height="30px">
<div class="todayAttendItemInfo">
<span class="todayAttendItemTitle">早退</span>
<span class="todayAttendItemNum">150</span>
<span class="todayAttendItemNum">{{ props.todayAttendData.earlyLeave.count }}</span>
</div>
</div>
<div class="todayAttendItem">
<img src="@/assets/demo/qin.png" alt="" width="30px" height="30px">
<img :src="props.todayAttendData.absent.icon" alt="" width="30px" height="30px">
<div class="todayAttendItemInfo">
<span class="todayAttendItemTitle">缺勤</span>
<span class="todayAttendItemNum">150</span>
<span class="todayAttendItemNum">{{ props.todayAttendData.absent.count }}</span>
</div>
</div>
</div>
@ -35,6 +35,14 @@
</template>
<script setup>
import TitleComponent from '@/components/TitleComponent/index.vue';
// 接收从父组件传入的数据
const props = defineProps({
todayAttendData: {
type: Object,
default: () => ({})
}
});
</script>
<style scoped lang="scss">
.todayAttend {

View File

@ -1,58 +1,18 @@
<template>
<div class="total-view-container">
<div class="total-view-content">
<!-- 总出勤人数 -->
<div class="stats-card">
<!-- 使用循环生成统计卡片 -->
<div v-for="(item, index) in statsItems" :key="index" class="stats-card">
<div class="stats-card-header">
<span class="stats-title">总出勤人数</span>
<span class="stats-change positive"> 8.2% 较昨日同期</span>
<span class="stats-title">{{ item.title }}</span>
<span class="stats-change" :class="{ positive: item.data.isPositive, negative: !item.data.isPositive }">
{{ item.data.isPositive ? '↑' : '↓' }} {{ item.data.change }} {{ item.compareText }}
</span>
</div>
<div class="stats-card-body">
<div class="stats-value">248</div>
<div class="stats-value">{{ item.data.value }}</div>
<div class="stats-chart">
<div ref="attendanceChart" class="chart-container"></div>
</div>
</div>
</div>
<!-- 调休 -->
<div class="stats-card">
<div class="stats-card-header">
<span class="stats-title">调休</span>
<span class="stats-change positive"> 8.2% 较上月同期</span>
</div>
<div class="stats-card-body">
<div class="stats-value">8</div>
<div class="stats-chart">
<div ref="restChart" class="chart-container"></div>
</div>
</div>
</div>
<!-- 本月请假 -->
<div class="stats-card">
<div class="stats-card-header">
<span class="stats-title">本月请假</span>
<span class="stats-change negative"> 10% 较昨日同期</span>
</div>
<div class="stats-card-body">
<div class="stats-value">24</div>
<div class="stats-chart">
<div ref="leaveChart" class="chart-container"></div>
</div>
</div>
</div>
<!-- 平均出勤率 -->
<div class="stats-card">
<div class="stats-card-header">
<span class="stats-title">平均出勤率</span>
<span class="stats-change positive"> 10% 较昨日同期</span>
</div>
<div class="stats-card-body">
<div class="stats-value">96.8%</div>
<div class="stats-chart">
<div ref="rateChart" class="chart-container"></div>
<div :ref="el => chartRefs[index] = el" class="chart-container"></div>
</div>
</div>
</div>
@ -61,167 +21,177 @@
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { ref, computed, onMounted, watch, nextTick } from 'vue';
import * as echarts from 'echarts';
// 图表引用
const attendanceChart = ref(null);
const restChart = ref(null);
const leaveChart = ref(null);
const rateChart = ref(null);
// 接收从父组件传入的数据
const props = defineProps({
totalData: {
type: Object,
default: () => ({
attendance: {
value: 248,
change: '+8.2%',
isPositive: true,
chartData: [150, 230, 224, 218, 135, 300, 220],
color: '#FF7D00',
title: '总出勤人数',
compareText: '较昨日同期',
chartType: 'bar'
},
rest: {
value: 8,
change: '+8.2%',
isPositive: true,
chartData: [10, 12, 15, 8, 7, 9, 10],
color: '#00C48C',
title: '调休',
compareText: '较上月同期',
chartType: 'line'
},
leave: {
value: 24,
change: '-10%',
isPositive: false,
chartData: [30, 25, 28, 22, 20, 26, 24],
color: '#FF5252',
title: '本月请假',
compareText: '较昨日同期',
chartType: 'line'
},
rate: {
value: '96.8%',
change: '+10%',
isPositive: true,
chartData: [90, 92, 94, 95, 97, 98, 96.8],
color: '#029CD4',
title: '平均出勤率',
compareText: '较昨日同期',
chartType: 'line'
}
})
}
});
// 图表引用数组
const chartRefs = ref([]);
// 转换totalData为数组格式方便循环渲染
const statsItems = computed(() => {
return Object.keys(props.totalData).map(key => ({
title: props.totalData[key].title,
data: {
value: props.totalData[key].value,
change: props.totalData[key].change,
isPositive: props.totalData[key].isPositive,
chartData: props.totalData[key].chartData,
color: props.totalData[key].color
},
compareText: props.totalData[key].compareText,
chartType: props.totalData[key].chartType
}));
});
// 初始化图表
const initCharts = () => {
// 总出勤人数图表 - 条形图
const attendanceChartInstance = echarts.init(attendanceChart.value);
attendanceChartInstance.setOption({
tooltip: { show: false },
grid: { top: 0, bottom: 0, left: -70, right: 0, containLabel: true },
xAxis: {
type: 'category',
data: ['', '', '', '', '', '', ''],
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { show: false }
},
yAxis: {
type: 'value',
show: false
},
series: [{
data: [150, 230, 224, 218, 135, 300, 220],
type: 'bar',
barWidth: 10,
itemStyle: {
color: '#FF7D00',
borderRadius: [10, 10, 0, 0] // 柱状图圆角
const chartInstances = [];
// 循环初始化所有图表
statsItems.value.forEach((item, index) => {
if (!chartRefs.value[index]) return;
const chartInstance = echarts.init(chartRefs.value[index]);
// 根据图表类型设置不同的配置
if (item.chartType === 'bar') {
// 柱状图配置
chartInstance.setOption({
tooltip: { show: false },
grid: { top: 0, bottom: 0, left: -70, right: 0, containLabel: true },
xAxis: {
type: 'category',
data: Array(item.data.chartData.length).fill(''),
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { show: false }
},
emphasis: {
focus: 'series'
}
}]
});
// 调休图表 - 折线图
const restChartInstance = echarts.init(restChart.value);
restChartInstance.setOption({
tooltip: { show: false },
grid: { top:10, bottom: 0, left: -30, right: 0, containLabel: true },
xAxis: {
type: 'category',
data: ['', '', '', '', '', '', '', '', '', ''],
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { show: false }
},
yAxis: {
type: 'value',
show: false
},
series: [{
data: [120, 200, 150, 80, 70, 110, 130, 150, 160, 180],
type: 'line',
smooth: true,
showSymbol: false,
lineStyle: {
width: 3, // 折线图线条加粗
color: '#52C41A'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(82, 196, 26, 0.2)'
}, {
offset: 1,
color: 'rgba(82, 196, 26, 0.01)'
}])
}
}]
});
// 本月请假图表 - 折线图
const leaveChartInstance = echarts.init(leaveChart.value);
leaveChartInstance.setOption({
tooltip: { show: false },
grid: { top: 10, bottom: 0, left: -30, right: 0, containLabel: true },
xAxis: {
type: 'category',
data: ['', '', '', '', '', '', '', '', '', ''],
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { show: false }
},
yAxis: {
type: 'value',
show: false
},
series: [{
data: [80, 150, 120, 200, 180, 130, 160, 190, 140, 100],
type: 'line',
smooth: true,
showSymbol: false,
lineStyle: {
width: 3, // 折线图线条加粗
color: '#F5222D'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(245, 34, 45, 0.2)'
}, {
offset: 1,
color: 'rgba(245, 34, 45, 0.01)'
}])
}
}]
});
// 平均出勤率图表 - 折线图
const rateChartInstance = echarts.init(rateChart.value);
rateChartInstance.setOption({
tooltip: { show: false },
grid: { top: 0, bottom: 0, left: -30, right: 0, containLabel: true },
xAxis: {
type: 'category',
data: ['', '', '', '', '', '', '', '', '', ''],
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { show: false }
},
yAxis: {
type: 'value',
show: false
},
series: [{
data: [90, 92, 91, 93, 95, 94, 96, 95, 97, 98],
type: 'line',
smooth: true,
showSymbol: false,
lineStyle: {
width: 3, // 折线图线条加粗
color: '#186DF5'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(24, 109, 245, 0.2)'
}, {
offset: 1,
color: 'rgba(24, 109, 245, 0.01)'
}])
}
}]
yAxis: {
type: 'value',
show: false
},
series: [{
data: item.data.chartData,
type: 'bar',
barWidth: 10,
itemStyle: {
color: item.data.color,
borderRadius: [10, 10, 0, 0] // 柱状图圆角
},
emphasis: {
focus: 'series'
}
}]
});
} else if (item.chartType === 'line') {
// 折线图配置
chartInstance.setOption({
tooltip: { show: false },
grid: { top: 10, bottom: 0, left: -30, right: 0, containLabel: true },
xAxis: {
type: 'category',
data: Array(item.data.chartData.length).fill(''),
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { show: false }
},
yAxis: {
type: 'value',
show: false
},
series: [{
data: item.data.chartData,
type: 'line',
smooth: true,
showSymbol: false,
lineStyle: {
width: 4, // 折线图线条加粗
color: item.data.color
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: `${item.data.color}33`
}, {
offset: 1,
color: `${item.data.color}02`
}])
}
}]
});
}
chartInstances.push(chartInstance);
});
// 响应窗口大小变化
window.addEventListener('resize', () => {
attendanceChartInstance.resize();
restChartInstance.resize();
leaveChartInstance.resize();
rateChartInstance.resize();
chartInstances.forEach(instance => {
instance.resize();
});
});
};
// 监听props变化重新初始化图表
watch(() => props.totalData, () => {
// 清空之前的图表引用
chartRefs.value = [];
// 等待DOM更新后重新初始化图表
nextTick(() => {
initCharts();
});
}, { deep: true });
// 组件挂载后初始化图表
onMounted(() => {
initCharts();

View File

@ -32,7 +32,7 @@
<!-- 第一行totalView infoBox -->
<el-row :gutter="20">
<el-col :span="17">
<totalView></totalView>
<totalView :totalData="totalData"></totalView>
</el-col>
<el-col :span="7">
<infoBox></infoBox>
@ -55,9 +55,9 @@
<el-col :span="7">
<div class="calendar-content">
<el-card>
<calendar></calendar>
<todayAttend></todayAttend>
<approval></approval>
<calendar :calendarData="calendarData"></calendar>
<todayAttend :todayAttendData="todayAttendData"></todayAttend>
<approval :approvalData="approvalData"></approval>
</el-card>
</div>
</el-col>
@ -72,6 +72,9 @@ import approval from '@/views/integratedManage/attendManage/components/leftBox/a
import calendar from '@/views/integratedManage/attendManage/components/leftBox/calendar.vue'
import totalView from '@/views/integratedManage/attendManage/components/totalView.vue'
import renyuanpaiban from '@/views/integratedManage/attendManage/components/renyuanpaiban.vue'
import { ref } from 'vue';
// 出勤数据 - 用于attendTrend组件
const attendData = ref(
{
week: {
@ -86,6 +89,143 @@ const attendData = ref(
},
}
)
// Mock数据 - 更新为循环生成所需的数据结构
const totalData = ref({
attendance: {
value: 248,
change: '+8.2%',
isPositive: true,
chartData: [150, 230, 224, 218, 135, 300, 220],
color: '#FF7D00',
title: '总出勤人数',
compareText: '较昨日同期',
chartType: 'bar'
},
rest: {
value: 8,
change: '+8.2%',
isPositive: true,
chartData: [10, 12, 15, 8, 7, 9, 10],
color: '#00C48C',
title: '调休',
compareText: '较上月同期',
chartType: 'line'
},
leave: {
value: 24,
change: '-10%',
isPositive: false,
chartData: [30, 25, 28, 22, 20, 26, 24],
color: '#FF5252',
title: '本月请假',
compareText: '较昨日同期',
chartType: 'line'
},
rate: {
value: '96.8%',
change: '+10%',
isPositive: true,
chartData: [90, 92, 94, 95, 97, 98, 96.8],
color: '#029CD4',
title: '平均出勤率',
compareText: '较昨日同期',
chartType: 'line'
}
});
// 审批数据 - 用于approval组件
const approvalData = ref([
{
type: '事假',
days: 1,
timeRange: '09.14-09.15',
people: '水泥班组-王五',
status: '待审批',
statusType: 'primary',
iconPath: '/src/assets/demo/approval.png'
},
{
type: '病假',
days: 2,
timeRange: '09.14-09.15',
people: '水泥班组-王五',
status: '待审批',
statusType: 'primary',
iconPath: '/src/assets/demo/approval.png'
},
{
type: '调休',
days: 1,
timeRange: '09.14-09.15',
people: '水泥班组-王五',
status: '待审批',
statusType: 'primary',
iconPath: '/src/assets/demo/approval.png'
},
{
type: '事假',
days: 1,
timeRange: '09.14-09.15',
people: '水泥班组-王五',
status: '待审批',
statusType: 'primary',
iconPath: '/src/assets/demo/approval.png'
},
{
type: '事假',
days: 1,
timeRange: '09.14-09.15',
people: '水泥班组-王五',
status: '已通过',
statusType: 'success',
iconPath: '/src/assets/demo/approval.png'
}
]);
// 今日出勤数据 - 用于todayAttend组件
const todayAttendData = ref({
attendance: {
count: 150,
icon: '/src/assets/demo/qin.png'
},
late: {
count: 5,
icon: '/src/assets/demo/chi.png'
},
earlyLeave: {
count: 2,
icon: '/src/assets/demo/tui.png'
},
absent: {
count: 8,
icon: '/src/assets/demo/que.png'
}
});
// 日历数据 - 用于calendar组件
const calendarData = ref({
// 初始化当前日期
today: new Date(),
currentDate: new Date(2025, 8, 27), // 2025年9月27日截图中显示的日期
selectedDate: new Date(2025, 8, 27),
// 模拟考勤数据
attendanceData: {
2025: {
9: {
1: 'normal',
4: 'late',
8: 'absent',
10: 'leave',
15: 'normal',
20: 'normal',
25: 'late',
27: 'normal'
}
}
}
});
</script>
<style scoped lang="scss">

View File

@ -82,15 +82,15 @@
</el-table-column>
<el-table-column label="操作" min-width="150" fixed="right">
<template #default="scope">
<el-button type="primary" link @click="handleDetails(scope.row)" size="small">
<span style="color: #1890ff; cursor: pointer; margin-right: 15px;" @click="handleDetails(scope.row)">
查看
</el-button>
<el-button type="primary" link @click="handleConfig(scope.row)" size="small">
</span>
<span style="color: #666666; cursor: pointer; margin-right: 15px;" @click="handleConfig(scope.row)">
配置
</el-button>
<el-button type="primary" link @click="handleDelete(scope.row)" size="small">
</span>
<span style="color: #666666; cursor: pointer;" @click="handleDelete(scope.row)">
删除
</el-button>
</span>
</template>
</el-table-column>
</el-table>
@ -106,8 +106,18 @@
<script setup>
import { Search, CirclePlus, Setting } from '@element-plus/icons-vue';
import { ref, reactive } from 'vue';
import { ref, reactive, watch } from 'vue';
// 定义props接收数据
const props = defineProps({
tableData: {
type: Object,
default: () => ({
list: [],
total: 0
})
}
});
// 搜索表单数据
const searchForm = reactive({
@ -125,112 +135,17 @@ const loading = ref(false);
const pagination = reactive({
currentPage: 1,
pageSize: 10,
total: 545
total: 0
});
// 设备列表数据
const deviceList = ref([
{
deviceId: 'WO-2023-0620-056',
deviceName: '逆变器-01',
deviceType: '逆变器',
station: '兴电基站1',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-057',
deviceName: '温度传感器-45',
deviceType: '传感器',
station: '兴电基站2',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'interrupt'
},
{
deviceId: 'WO-2023-0620-058',
deviceName: '智能电表-03',
deviceType: '电表',
station: '兴电基站3',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'abnormal'
},
{
deviceId: 'WO-2023-0620-059',
deviceName: '监控摄像头-02',
deviceType: '摄像头',
station: '兴电基站4',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-060',
deviceName: '控制器-07',
deviceType: '控制器',
station: '兴电基站5',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-061',
deviceName: '逆变器-02',
deviceType: '逆变器',
station: '兴电基站1',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-062',
deviceName: '电流传感器-08',
deviceType: '传感器',
station: '兴电基站1',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-063',
deviceName: '多功能电表-12',
deviceType: '电表',
station: '兴电基站1',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-064',
deviceName: '门禁摄像头-05',
deviceType: '摄像头',
station: '兴电基站1',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-065',
deviceName: '开关控制器-15',
deviceType: '控制器',
station: '兴电基站1',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
}
]);
const deviceList = ref([]);
// 监听props变化并更新设备列表
watch(() => props.tableData, (newData) => {
deviceList.value = newData.list || [];
pagination.total = newData.total || 0;
}, { immediate: true, deep: true });
// 获取状态文本
const getStatusText = (status) => {
@ -269,6 +184,7 @@ const getDeviceTypeTagType = (deviceType) => {
// 处理搜索
const handleSearch = () => {
loading.value = true;
pagination.currentPage = 1;
// 模拟搜索请求
setTimeout(() => {
loading.value = false;
@ -292,19 +208,19 @@ const handleBatchConfig = () => {
// 处理查看详情
const handleDetails = (row) => {
// 实际项目中这里应该打开设备详情的弹窗或跳转到详情页面
ElMessage.success(`查看设备${row.deviceCode}详情`);
ElMessage.success(`查看设备${row.deviceId}详情`);
};
// 处理配置
const handleConfig = (row) => {
// 实际项目中这里应该打开设备配置的弹窗
ElMessage.success(`配置设备${row.deviceCode}`);
ElMessage.success(`配置设备${row.deviceId}`);
};
// 处理删除
const handleDelete = (row) => {
ElMessageBox.confirm(
`确定要删除设备${row.deviceCode}吗?`,
`确定要删除设备${row.deviceId}吗?`,
'提示',
{
confirmButtonText: '确定',

View File

@ -10,6 +10,16 @@
import { ref, onMounted, watch } from 'vue';
import * as echarts from 'echarts';
// 定义props接收数据
const props = defineProps({
trendData: {
type: Object,
default: () => ({
dates: [],
series: []
})
}
});
// 图表DOM引用
const chartRef = ref(null);
@ -54,7 +64,7 @@ const initChart = () => {
color: '#EAEBF0'
}
},
data: ['9-12', '9-13', '9-14', '9-15', '9-16', '9-17', '9-18']
data: props.trendData.dates || []
},
yAxis: {
type: 'value',
@ -73,48 +83,20 @@ const initChart = () => {
}
}
},
series: [
{
name: '正常',
data: [20, 10, 50, 80, 70, 10, 30],
type: 'bar',
stack: 'one',
color: '#7339F5',
itemStyle: {
// borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 1)', //同背景色一样
barBorderRadius: 8
},
barWidth: '20',
series: props.trendData.series.map((item, index) => ({
name: item.name,
data: item.data,
type: 'bar',
stack: 'one',
color: item.color,
itemStyle: {
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 1)',
barBorderRadius: 8
},
{
name: '中断',
data: [80, 30, 50, 80, 70, 10, 30],
type: 'bar',
stack: 'one', //堆叠
color: '#FF8A00',
itemStyle: {
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 1)', //同背景色一样
barBorderRadius: 8
},
},
{
name: '异常',
data: [50, 30, 50, 80, 70, 10, 30],
type: 'bar',
stack: 'one', //堆叠
color: '#DE4848',
itemStyle: {
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 1)', //同背景色一样
barBorderRadius: 8
},
barWidth: '12',
}
]
};
barWidth: index === 0 ? '20' : index === 2 ? '12' : '20',
}))
}
chartInstance.setOption(option);
};

View File

@ -9,6 +9,36 @@
import { ref, onMounted, watch } from 'vue';
import * as echarts from 'echarts';
// 定义props接收数据
const props = defineProps({
pieData: {
type: Object,
default: () => ({
normal: {
value: 28,
name: '提示信息',
displayName: '设备正常'
},
interrupt: {
value: 45,
name: '一般告警',
displayName: '设备中断'
},
abnormal: {
value: 55,
name: '重要告警',
displayName: '设备异常'
}
})
}
});
// 默认的三种颜色
const defaultColors = {
normal: '#43CF7C',
interrupt: '#00B3FF',
abnormal: '#FB3E7A'
};
// 图表DOM引用
const chartRef = ref(null);
@ -24,16 +54,10 @@ const initChart = () => {
tooltip: {
trigger: 'item',
formatter: function(params) {
// 定义名称映射关系
const nameMap = {
'提示信息': '设备正常',
'一般告警': '设备中断',
'重要告警': '设备异常'
};
// 使用ECharts提供的百分比值
const percentage = params.percent.toFixed(1);
// 返回格式化后的文本
return `${nameMap[params.name]}: ${params.value}台 (${percentage}%)`;
return `${params.data.displayName}: ${params.value}台 (${percentage}%)`;
}
},
grid: {
@ -50,20 +74,11 @@ const initChart = () => {
itemWidth: 15,
itemHeight: 15,
formatter: function(name) {
// 定义名称映射关系
const nameMap = {
'提示信息': '设备正常',
'一般告警': '设备中断',
'重要告警': '设备异常'
};
// 定义数值映射关系
const valueMap = {
'提示信息': 28,
'一般告警': 45,
'重要告警': 55
};
const data = props.pieData.normal.name === name ? props.pieData.normal :
props.pieData.interrupt.name === name ? props.pieData.interrupt :
props.pieData.abnormal;
// 返回格式化后的文本
return `${nameMap[name] || name}(${valueMap[name]})`;
return `${data.displayName}(${data.value})`;
}
},
series: [
@ -78,14 +93,26 @@ const initChart = () => {
show: true
},
color: [
'#43CF7C', // 设备正常
'#00B3FF', // 设备中断
'#FB3E7A', // 设备异常
defaultColors.normal,
defaultColors.interrupt,
defaultColors.abnormal
],
data: [
{ value: 28, name: '提示信息' },
{ value: 45, name: '一般告警' },
{ value: 55, name: '重要告警' },
{
value: props.pieData.normal.value,
name: props.pieData.normal.name,
displayName: props.pieData.normal.displayName
},
{
value: props.pieData.interrupt.value,
name: props.pieData.interrupt.name,
displayName: props.pieData.interrupt.displayName
},
{
value: props.pieData.abnormal.value,
name: props.pieData.abnormal.name,
displayName: props.pieData.abnormal.displayName
}
],
emphasis: {
itemStyle: {

View File

@ -7,11 +7,11 @@
<img src="@/assets/demo/rebot.png" alt="">
</div>
<div class="item-title">设备总数</div>
<div class="item-value">128</div>
<div class="item-value">{{ totalData.deviceCount }}</div>
<div class="item-unit"></div>
<div class="item-trend">
<img src="@/assets/demo/up.png" alt="">
<span class="trend-num">8</span>
<span class="trend-num">+{{ totalData.increase || 8 }}</span>
<span class="trend-des">较上月同期</span>
</div>
</div>
@ -21,12 +21,12 @@
<div class="item-icon">
<img src="@/assets/demo/wifi.png" alt="">
</div>
<div class="item-title">设备总数</div>
<div class="item-value">128</div>
<div class="item-title">正常设备</div>
<div class="item-value">{{ totalData.normalCount }}</div>
<div class="item-unit"></div>
<div class="item-trend">
<img src="@/assets/demo/up.png" alt="">
<span class="trend-num">8</span>
<span class="trend-num">+{{ totalData.normalIncrease || 5 }}</span>
<span class="trend-des">较上月同期</span>
</div>
</div>
@ -36,12 +36,12 @@
<div class="item-icon">
<img src="@/assets/demo/wifiwarn.png" alt="">
</div>
<div class="item-title">设备总数</div>
<div class="item-value">128</div>
<div class="item-title">异常设备</div>
<div class="item-value">{{ totalData.abnormalCount }}</div>
<div class="item-unit"></div>
<div class="item-trend">
<img src="@/assets/demo/up.png" alt="">
<span class="trend-num">8</span>
<img src="@/assets/demo/down.png" alt="">
<span class="trend-num">-{{ totalData.abnormalDecrease || 3 }}</span>
<span class="trend-des">较上月同期</span>
</div>
</div>
@ -51,12 +51,12 @@
<div class="item-icon">
<img src="@/assets/demo/nowifi.png" alt="">
</div>
<div class="item-title">设备总数</div>
<div class="item-value">128</div>
<div class="item-title">中断设备</div>
<div class="item-value">{{ totalData.interruptCount }}</div>
<div class="item-unit"></div>
<div class="item-trend">
<img src="@/assets/demo/up.png" alt="" class="trend-icon">
<span class="trend-num">8</span>
<img src="@/assets/demo/down.png" alt="" class="trend-icon">
<span class="trend-num">-{{ totalData.interruptDecrease || 2 }}</span>
<span class="trend-des">较上月同期</span>
</div>
</div>
@ -64,6 +64,28 @@
</el-row>
</div>
</template>
<script setup>
import { ref } from 'vue';
// 定义props接收数据
const props = defineProps({
totalData: {
type: Object,
default: () => ({
deviceCount: 0,
normalCount: 0,
abnormalCount: 0,
interruptCount: 0,
increase: 0,
normalIncrease: 0,
abnormalDecrease: 0,
interruptDecrease: 0
})
}
});
</script>
<style scoped lang="scss">
.item-box {
padding: 20px;

View File

@ -3,7 +3,7 @@
<!-- 标题栏 -->
<el-row :gutter="24">
<el-col :span="12">
<TitleComponent title="报警管理" subtitle="配置新能源厂站的报警级别、类型及相关规则" />
<TitleComponent title="设备状态管理" subtitle="监控和管理所有设备的运行状态" />
</el-col>
<!-- 外层col控制整体宽度并右对齐同时作为flex容器 -->
<el-col :span="12" style="display: flex; justify-content: flex-end; align-items: center;">
@ -17,38 +17,38 @@
</el-col>
</el-col>
</el-row>
<!-- 第一行报警管理和报警级别分布 -->
<!-- 第一行设备统计和状态分布 -->
<el-row :gutter="20" class="content-row equal-height-row">
<el-col :span="16">
<el-card shadow="hover" class="custom-card">
<totalView />
<totalView :totalData="totalData" />
</el-card>
</el-col>
<el-col :span="8">
<!-- 报警级别分布 -->
<!-- 设备状态分布 -->
<el-card shadow="hover" class="custom-card">
<TitleComponent title="报警级别分布" :font-level="2" />
<statusPie />
<TitleComponent title="设备状态分布" :font-level="2" />
<statusPie :pieData="pieData" />
</el-card>
</el-col>
</el-row>
<!-- 第二行报警趋势分析 -->
<!-- 第二行设备状态趋势 -->
<el-row :gutter="20" class="content-row">
<el-col :span="24">
<el-card shadow="hover" class="custom-card">
<TitleComponent title="报警趋势分析" :font-level="2" />
<stateTrend />
<TitleComponent title="设备状态趋势" :font-level="2" />
<stateTrend :trendData="trendData" />
</el-card>
</el-col>
</el-row>
<!-- 第三行报警管理表单 -->
<!-- 第三行设备管理表单 -->
<el-row :gutter="20" class="content-row">
<el-col :span="24">
<el-card shadow="hover" class="custom-card">
<TitleComponent title="报警管理表单" :font-level="2" />
<manageForm />
<TitleComponent title="设备管理表单" :font-level="2" />
<manageForm :tableData="tableData" />
</el-card>
</el-col>
</el-row>
@ -56,11 +56,175 @@
</template>
<script setup>
import { ref } from 'vue';
import TitleComponent from '@/components/TitleComponent/index.vue';
import totalView from '@/views/integratedManage/stateManage/components/totalView.vue';
import stateTrend from '@/views/integratedManage/stateManage/components/stateTrend.vue'
import statusPie from '@/views/integratedManage/stateManage/components/statusPie.vue'
import manageForm from '@/views/integratedManage/stateManage/components/manageForm.vue';
// Mock数据 - 设备统计数据
const totalData = ref({
deviceCount: 545,
normalCount: 436,
abnormalCount: 65,
interruptCount: 44,
increase: 8,
normalIncrease: 5,
abnormalDecrease: 3,
interruptDecrease: 2
});
// Mock数据 - 饼图数据
const pieData = ref({
normal: {
value: 436,
name: 'normal',
displayName: '设备正常',
percent: '80%'
},
abnormal: {
value: 65,
name: 'abnormal',
displayName: '设备异常',
percent: '12%'
},
interrupt: {
value: 44,
name: 'interrupt',
displayName: '设备中断',
percent: '8%'
}
});
// Mock数据 - 趋势图数据
const trendData = ref({
dates: ['9-12', '9-13', '9-14', '9-15', '9-16', '9-17', '9-18'],
series: [
{
name: '正常',
data: [20, 10, 50, 80, 70, 10, 30],
color: '#7339F5'
},
{
name: '中断',
data: [80, 30, 50, 80, 70, 10, 30],
color: '#FF8A00'
},
{
name: '异常',
data: [50, 30, 50, 80, 70, 10, 30],
color: '#DE4848'
}
]
});
// Mock数据 - 表格数据
const tableData = ref({
list: [
{
deviceId: 'WO-2023-0620-056',
deviceName: '逆变器-01',
deviceType: '逆变器',
station: '兴电基站1',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-057',
deviceName: '温度传感器-45',
deviceType: '传感器',
station: '兴电基站2',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'interrupt'
},
{
deviceId: 'WO-2023-0620-058',
deviceName: '智能电表-03',
deviceType: '电表',
station: '兴电基站3',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'abnormal'
},
{
deviceId: 'WO-2023-0620-059',
deviceName: '监控摄像头-02',
deviceType: '摄像头',
station: '兴电基站4',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-060',
deviceName: '控制器-07',
deviceType: '控制器',
station: '兴电基站5',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-061',
deviceName: '逆变器-02',
deviceType: '逆变器',
station: '兴电基站1',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-062',
deviceName: '电流传感器-08',
deviceType: '传感器',
station: '兴电基站1',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-063',
deviceName: '多功能电表-12',
deviceType: '电表',
station: '兴电基站1',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-064',
deviceName: '门禁摄像头-05',
deviceType: '摄像头',
station: '兴电基站1',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
},
{
deviceId: 'WO-2023-0620-065',
deviceName: '开关控制器-15',
deviceType: '控制器',
station: '兴电基站1',
protocol: 'Modbus TCP',
ipAddress: '192.168.1.101',
lastOnlineTime: '2023-06-30 17:00',
status: 'normal'
}
],
total: 545
});
</script>
<style scoped>