楼宇能效监测控制系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

625 lines
19 KiB

<template>
<div class="lighting-ai-saving report-wrapper">
<!-- 报表标题 -->
<div class="report-title-section">
<h1>{{ reportData.title }}</h1>
<p class="report-time">生成时间{{ reportData.generateTime }}</p>
</div>
<!-- 报表摘要 -->
<div class="report-summary">
<h3>AI照明节能策略报告</h3>
<p>{{ reportData.summary }}</p>
</div>
<!-- 策略配置区域 -->
<div class="strategy-config">
<h2>节能策略配置</h2>
<!-- 目标选择 -->
<div class="target-selection">
<h3>优化目标</h3>
<el-radio-group v-model="selectedTarget" size="small">
<el-radio label="energy">节能优先</el-radio>
<el-radio label="comfort">舒适优先</el-radio>
<el-radio label="balanced">平衡模式</el-radio>
</el-radio-group>
</div>
<!-- 区域选择 -->
<div class="area-selection">
<h3>适用区域</h3>
<el-checkbox-group v-model="selectedAreas">
<el-checkbox label="office">办公区</el-checkbox>
<el-checkbox label="corridor">走廊</el-checkbox>
<el-checkbox label="meeting">会议室</el-checkbox>
<el-checkbox label="garage">车库</el-checkbox>
</el-checkbox-group>
</div>
<!-- 执行模式 -->
<div class="execution-mode">
<h3>执行方式</h3>
<el-radio-group v-model="executionMode" size="small">
<el-radio label="auto">自动执行(动态调整)</el-radio>
<el-radio label="suggestion">仅建议</el-radio>
</el-radio-group>
</div>
</div>
<!-- 场景策略详情 -->
<div class="scene-strategy">
<h2>二、场景化调光策略</h2>
<el-tabs v-model="activeAreaTab" type="card">
<el-tab-pane
v-for="area in areaConfig"
:key="area.value"
:label="area.label"
:name="area.value"
>
<div class="area-strategy">
<h3>{{ area.label }}照明策略</h3>
<!-- 亮度占比配置 -->
<div class="brightness-config">
<h4>亮度模式占比</h4>
<div class="brightness-sliders">
<div class="slider-item">
<label>低亮模式 ({{ area.brightness.low }}%)</label>
<el-slider
v-model="area.brightness.low"
:min="0"
:max="100"
@change="updateBrightness(area)"
/>
</div>
<div class="slider-item">
<label>中亮模式 ({{ area.brightness.medium }}%)</label>
<el-slider
v-model="area.brightness.medium"
:min="0"
:max="100"
@change="updateBrightness(area)"
/>
</div>
<div class="slider-item">
<label>高亮模式 ({{ area.brightness.high }}%)</label>
<el-slider
v-model="area.brightness.high"
:min="0"
:max="100"
@change="updateBrightness(area)"
/>
</div>
</div>
</div>
<!-- 感应触发时长 -->
<div class="trigger-config">
<h4>感应触发设置</h4>
<el-form :inline="true" size="small">
<el-form-item label="无人检测延时">
<el-input-number
v-model="area.trigger.delay"
:min="1"
:max="60"
controls-position="right"
/> 分钟
</el-form-item>
<el-form-item label="恢复亮度延时">
<el-input-number
v-model="area.trigger.recovery"
:min="1"
:max="30"
controls-position="right"
/> 秒
</el-form-item>
</el-form>
</div>
<!-- 时间段策略 -->
<div class="time-strategy">
<h4>时段策略</h4>
<el-table :data="area.timeSlots" size="small" border>
<el-table-column prop="timeRange" label="时间段" width="120"/>
<el-table-column prop="brightnessLevel" label="亮度等级" width="100">
<template slot-scope="{row}">
<el-select v-model="row.brightnessLevel" size="small">
<el-option label="低亮" value="low"/>
<el-option label="中亮" value="medium"/>
<el-option label="高亮" value="high"/>
</el-select>
</template>
</el-table-column>
<el-table-column prop="occupancySensitivity" label="人员感应灵敏度" width="140">
<template slot-scope="{row}">
<el-select v-model="row.occupancySensitivity" size="small">
<el-option label="高" value="high"/>
<el-option label="中" value="medium"/>
<el-option label="低" value="low"/>
</el-select>
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template slot-scope="{row, $index}">
<el-button
type="text"
size="small"
@click="removeTimeSlot(area, $index)"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<el-button
type="primary"
size="small"
icon="el-icon-plus"
style="margin-top: 10px;"
@click="addTimeSlot(area)"
>添加时段</el-button>
</div>
</div>
</el-tab-pane>
</el-tabs>
</div>
<!-- 效果预览与评估 -->
<div class="effect-preview">
<h2>三、策略效果预览</h2>
<div class="preview-metrics">
<div class="metric-card">
<div class="metric-value">{{ estimatedSaving }}%</div>
<div class="metric-label">预计节能率</div>
</div>
<div class="metric-card">
<div class="metric-value">{{ comfortScore }}</div>
<div class="metric-label">舒适度评分</div>
</div>
<div class="metric-card">
<div class="metric-value">{{ implementationCost }}</div>
<div class="metric-label">实施成本</div>
</div>
<div class="metric-card">
<div class="metric-value">{{ paybackPeriod }}</div>
<div class="metric-label">投资回收期(月)</div>
</div>
</div>
<!-- 节能效果图表 -->
<div class="charts-container">
<div ref="savingTrendChart" class="chart-box"></div>
<div ref="areaComparisonChart" class="chart-box"></div>
</div>
</div>
<!-- 操作按钮 -->
<div class="action-buttons">
<el-button type="primary" @click="saveStrategy">保存策略</el-button>
<el-button type="success" @click="executeStrategy">立即执行</el-button>
<el-button @click="resetStrategy">重置</el-button>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'LightingAISaving',
props: {
reportData: {
type: Object,
required: true
},
userName: {
type: String,
default: ''
}
},
data() {
return {
selectedTarget: 'balanced',
selectedAreas: ['office', 'corridor', 'meeting', 'garage'],
executionMode: 'auto',
activeAreaTab: 'office',
// 区域配置数据
areaConfig: [
{
value: 'office',
label: '办公区',
brightness: { low: 20, medium: 50, high: 80 },
trigger: { delay: 15, recovery: 10 },
timeSlots: [
{ timeRange: '08:00-12:00', brightnessLevel: 'high', occupancySensitivity: 'high' },
{ timeRange: '12:00-13:00', brightnessLevel: 'medium', occupancySensitivity: 'medium' },
{ timeRange: '13:00-18:00', brightnessLevel: 'high', occupancySensitivity: 'high' },
{ timeRange: '18:00-22:00', brightnessLevel: 'low', occupancySensitivity: 'low' }
]
},
{
value: 'corridor',
label: '走廊',
brightness: { low: 10, medium: 30, high: 60 },
trigger: { delay: 5, recovery: 5 },
timeSlots: [
{ timeRange: '06:00-22:00', brightnessLevel: 'medium', occupancySensitivity: 'high' },
{ timeRange: '22:00-06:00', brightnessLevel: 'low', occupancySensitivity: 'low' }
]
},
{
value: 'meeting',
label: '会议室',
brightness: { low: 15, medium: 40, high: 75 },
trigger: { delay: 30, recovery: 15 },
timeSlots: [
{ timeRange: '08:00-18:00', brightnessLevel: 'medium', occupancySensitivity: 'medium' },
{ timeRange: '18:00-22:00', brightnessLevel: 'low', occupancySensitivity: 'low' }
]
},
{
value: 'garage',
label: '车库',
brightness: { low: 5, medium: 25, high: 50 },
trigger: { delay: 10, recovery: 8 },
timeSlots: [
{ timeRange: '06:00-22:00', brightnessLevel: 'medium', occupancySensitivity: 'high' },
{ timeRange: '22:00-06:00', brightnessLevel: 'low', occupancySensitivity: 'low' }
]
}
],
// 效果预览数据
estimatedSaving: 45,
comfortScore: 8.2,
implementationCost: '低',
paybackPeriod: 6
};
},
mounted() {
this.initCharts();
},
beforeDestroy() {
this.disposeCharts();
},
methods: {
initCharts() {
// 节能趋势图
if (this.$refs.savingTrendChart) {
const savingTrendChart = echarts.init(this.$refs.savingTrendChart);
savingTrendChart.setOption({
title: { text: '月度节能效果趋势', left: 'center' },
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: ['1月', '2月', '3月', '4月', '5月', '6月'] },
yAxis: { type: 'value', name: '节能率(%)' },
series: [{
name: '节能率',
type: 'line',
data: [30, 35, 40, 42, 45, 48],
smooth: true,
lineStyle: { width: 3 },
itemStyle: { color: '#0ac1c7' }
}]
});
this.savingTrendChart = savingTrendChart;
}
// 区域对比图
if (this.$refs.areaComparisonChart) {
const areaComparisonChart = echarts.init(this.$refs.areaComparisonChart);
areaComparisonChart.setOption({
title: { text: '各区域节能效果对比', left: 'center' },
tooltip: { trigger: 'item' },
legend: { top: 'bottom' },
series: [{
name: '节能效果',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: { show: false, position: 'center' },
emphasis: {
label: { show: true, fontSize: '16', fontWeight: 'bold' }
},
labelLine: { show: false },
data: [
{ value: 35, name: '办公区' },
{ value: 25, name: '走廊' },
{ value: 20, name: '会议室' },
{ value: 20, name: '车库' }
]
}]
});
this.areaComparisonChart = areaComparisonChart;
}
},
disposeCharts() {
if (this.savingTrendChart) {
this.savingTrendChart.dispose();
this.savingTrendChart = null;
}
if (this.areaComparisonChart) {
this.areaComparisonChart.dispose();
this.areaComparisonChart = null;
}
},
updateBrightness(area) {
// 确保三个亮度值总和不超过100%
const total = area.brightness.low + area.brightness.medium + area.brightness.high;
if (total > 100) {
// 按比例调整
const ratio = 100 / total;
area.brightness.low = Math.round(area.brightness.low * ratio);
area.brightness.medium = Math.round(area.brightness.medium * ratio);
area.brightness.high = Math.round(area.brightness.high * ratio);
}
},
addTimeSlot(area) {
area.timeSlots.push({
timeRange: '00:00-24:00',
brightnessLevel: 'medium',
occupancySensitivity: 'medium'
});
},
removeTimeSlot(area, index) {
if (area.timeSlots.length > 1) {
area.timeSlots.splice(index, 1);
}
},
saveStrategy() {
this.$message.success('策略保存成功!');
// 这里可以调用API保存策略
},
executeStrategy() {
this.$confirm('确定要立即执行此AI节能策略吗?', '确认执行', {
confirmButtonText: '确定执行',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$message.success('策略已开始执行!');
// 这里可以调用API执行策略
}).catch(() => {
// 取消操作
});
},
resetStrategy() {
this.$confirm('确定要重置所有策略配置吗?', '确认重置', {
confirmButtonText: '确定重置',
cancelButtonText: '取消',
type: 'info'
}).then(() => {
// 重置到默认配置
this.areaConfig = JSON.parse(JSON.stringify([
{
value: 'office',
label: '办公区',
brightness: { low: 20, medium: 50, high: 80 },
trigger: { delay: 15, recovery: 10 },
timeSlots: [
{ timeRange: '08:00-12:00', brightnessLevel: 'high', occupancySensitivity: 'high' },
{ timeRange: '12:00-13:00', brightnessLevel: 'medium', occupancySensitivity: 'medium' },
{ timeRange: '13:00-18:00', brightnessLevel: 'high', occupancySensitivity: 'high' },
{ timeRange: '18:00-22:00', brightnessLevel: 'low', occupancySensitivity: 'low' }
]
},
{
value: 'corridor',
label: '走廊',
brightness: { low: 10, medium: 30, high: 60 },
trigger: { delay: 5, recovery: 5 },
timeSlots: [
{ timeRange: '06:00-22:00', brightnessLevel: 'medium', occupancySensitivity: 'high' },
{ timeRange: '22:00-06:00', brightnessLevel: 'low', occupancySensitivity: 'low' }
]
},
{
value: 'meeting',
label: '会议室',
brightness: { low: 15, medium: 40, high: 75 },
trigger: { delay: 30, recovery: 15 },
timeSlots: [
{ timeRange: '08:00-18:00', brightnessLevel: 'medium', occupancySensitivity: 'medium' },
{ timeRange: '18:00-22:00', brightnessLevel: 'low', occupancySensitivity: 'low' }
]
},
{
value: 'garage',
label: '车库',
brightness: { low: 5, medium: 25, high: 50 },
trigger: { delay: 10, recovery: 8 },
timeSlots: [
{ timeRange: '06:00-22:00', brightnessLevel: 'medium', occupancySensitivity: 'high' },
{ timeRange: '22:00-06:00', brightnessLevel: 'low', occupancySensitivity: 'low' }
]
}
]));
this.$message.success('策略已重置!');
}).catch(() => {
// 取消操作
});
}
}
};
</script>
<style lang="scss" scoped>
.lighting-ai-saving {
.strategy-config {
margin-bottom: 20px;
h3 {
margin: 15px 0 10px 0;
color: #0ac1c7;
}
.el-radio-group,
.el-checkbox-group {
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.el-radio,
.el-checkbox {
margin-right: 20px;
}
}
.scene-strategy {
margin-bottom: 20px;
.area-strategy {
padding: 15px;
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
h3 {
margin-bottom: 15px;
color: #0ac1c7;
}
.brightness-config {
margin-bottom: 20px;
h4 {
margin-bottom: 10px;
color: #e0e6ed;
}
.brightness-sliders {
display: flex;
flex-direction: column;
gap: 15px;
.slider-item {
label {
display: block;
margin-bottom: 5px;
font-size: 14px;
color: #a0b3c6;
}
::v-deep .el-slider {
.el-slider__runway {
height: 6px;
background: #2d3f52;
}
.el-slider__bar {
height: 6px;
background: #0ac1c7;
}
.el-slider__button {
width: 16px;
height: 16px;
border: 2px solid #0ac1c7;
background: #1a2a3a;
}
}
}
}
}
.trigger-config {
margin-bottom: 20px;
h4 {
margin-bottom: 10px;
color: #e0e6ed;
}
::v-deep .el-form-item {
margin-right: 20px;
margin-bottom: 10px;
}
}
.time-strategy {
h4 {
margin-bottom: 10px;
color: #e0e6ed;
}
::v-deep .el-table {
.el-table__header th {
background: #2d3f52;
color: #e0e6ed;
}
.el-table__body td {
background: #1a2a3a;
color: #e0e6ed;
}
}
}
}
}
.effect-preview {
margin-bottom: 20px;
.preview-metrics {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 20px;
.metric-card {
background: rgba(10, 193, 199, 0.1);
border: 1px solid rgba(10, 193, 199, 0.3);
border-radius: 8px;
padding: 15px;
text-align: center;
.metric-value {
font-size: 24px;
font-weight: bold;
color: #0ac1c7;
margin-bottom: 5px;
}
.metric-label {
font-size: 14px;
color: #a0b3c6;
}
}
}
.charts-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
.chart-box {
height: 300px;
background: #1a2a3a;
border-radius: 8px;
padding: 15px;
}
}
}
.action-buttons {
text-align: center;
padding: 20px 0;
.el-button {
margin: 0 10px;
}
}
}
</style>