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
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> |