根据甲方意见修改:删除光伏等无数据的展示模块、储能充放电/收益按月+季度+周+年展示、修改首页展示内容

This commit is contained in:
lixiaoyuan
2026-05-27 16:35:12 +08:00
parent 9c51037aa1
commit 0f484a4a68
22 changed files with 788 additions and 193 deletions

View File

@@ -492,10 +492,11 @@ Errcode DAO::deletePolicyById(std::string policyId)
} }
// 系统日志管理 // 系统日志管理
Errcode DAO::querySystemLogList(PageInfo& pageInfo, vector<Fields>& result) Errcode DAO::querySystemLogList(const std::string& stationId, PageInfo& pageInfo, vector<Fields>& result)
{ {
std::string sqlFrom = "FROM " + DMLogSystem::TABLENAME; std::string sqlFrom = "FROM " + DMLogSystem::TABLENAME;
return QueryPagination("*", sqlFrom, pageInfo, result, " order by create_time desc "); if (!stationId.empty()) sqlFrom += (" WHERE station_id='" + stationId + "'");
return QueryPagination("*", sqlFrom, pageInfo, result, " ORDER BY create_time desc ");
} }
Errcode DAO::insertSystemLog(Fields& params) Errcode DAO::insertSystemLog(Fields& params)
{ {
@@ -537,10 +538,11 @@ Errcode DAO::insertSystemLogDevice(int stationId, int deviceId, std::string cont
return DAO::insertSystemLog(fields); return DAO::insertSystemLog(fields);
} }
Errcode DAO::queryAlertLogList(PageInfo& pageInfo, vector<Fields>& result) Errcode DAO::queryAlertLogList(const std::string& stationId, PageInfo& pageInfo, vector<Fields>& result)
{ {
std::string sqlFrom = "from log_alert la left join device d on d.device_id =la.device_id left join station s on s.station_id = d.station_id"; std::string sqlFrom = "FROM log_alert la left join device d on d.device_id =la.device_id left join station s on s.station_id = d.station_id";
return QueryPagination("d.station_id, s.name station_name, d.name device_name, la.*", sqlFrom, pageInfo, result, " order by create_time desc "); if (!stationId.empty()) sqlFrom += (" WHERE s.station_id='" + stationId + "'");
return QueryPagination("d.station_id, s.name station_name, d.name device_name, la.*", sqlFrom, pageInfo, result, " ORDER BY create_time desc ");
} }
Errcode DAO::insertAlertLog(Fields& params) Errcode DAO::insertAlertLog(Fields& params)
{ {

View File

@@ -99,7 +99,7 @@ public:
/////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////
// === 系统日志管理 === // === 系统日志管理 ===
// 分页查询系统日志列表 // 分页查询系统日志列表
static Errcode querySystemLogList(PageInfo& pageInfo, vector<Fields>& result); static Errcode querySystemLogList(const std::string& stationId, PageInfo& pageInfo, vector<Fields>& result);
static Errcode insertSystemLog(Fields& params); static Errcode insertSystemLog(Fields& params);
static Errcode updateSystemLogById(Fields& params); static Errcode updateSystemLogById(Fields& params);
@@ -107,7 +107,7 @@ public:
static Errcode insertSystemLogUser(std::string token, std::string content, int status); static Errcode insertSystemLogUser(std::string token, std::string content, int status);
static Errcode insertSystemLogDevice(int stationId, int deviceId, std::string content, int status); static Errcode insertSystemLogDevice(int stationId, int deviceId, std::string content, int status);
static Errcode queryAlertLogList(PageInfo& pageInfo, vector<Fields>& result); static Errcode queryAlertLogList(const std::string& stationId, PageInfo& pageInfo, vector<Fields>& result);
static Errcode insertAlertLog(Fields& params); static Errcode insertAlertLog(Fields& params);
static Errcode updateAlertLogById(Fields& params); static Errcode updateAlertLogById(Fields& params);

View File

@@ -188,6 +188,8 @@ static std::map<std::string, HandlerOptions> g_mapHttpHandlerGet =
{"/queryStatDetailList", HandlerOptions(&HttpEntity::queryStatDetailList, {})}, {"/queryStatDetailList", HandlerOptions(&HttpEntity::queryStatDetailList, {})},
{"/queryStatCharts", HandlerOptions(&HttpEntity::queryStatCharts, {})}, {"/queryStatCharts", HandlerOptions(&HttpEntity::queryStatCharts, {})},
{"/exportStatReport", HandlerOptions(&HttpEntity::exportStatReport, {})}, {"/exportStatReport", HandlerOptions(&HttpEntity::exportStatReport, {})},
{"/queryStatStationMode", HandlerOptions(&HttpEntity::queryStatStationMode, {})},
{"/queryEnvironment", HandlerOptions(&HttpEntity::queryEnvironment, { "station_id"})}, {"/queryEnvironment", HandlerOptions(&HttpEntity::queryEnvironment, { "station_id"})},
@@ -1225,12 +1227,16 @@ Errcode HttpEntity::queryPolicyByType(const httplib::Request& req, njson& json,
Errcode HttpEntity::querySystemLogList(const httplib::Request& req, njson& json, std::string& errmsg) Errcode HttpEntity::querySystemLogList(const httplib::Request& req, njson& json, std::string& errmsg)
{ {
Fields params;
GetRequestParams(req, {"station_id"}, params);
PageInfo pageinfo; PageInfo pageinfo;
pageinfo.index = Utils::toInt(req.get_param_value("page")); pageinfo.index = Utils::toInt(req.get_param_value("page"));
pageinfo.size = Utils::toInt(req.get_param_value("page_size")); pageinfo.size = Utils::toInt(req.get_param_value("page_size"));
std::string stationId = params.value("station_id");
std::vector<Fields> result; std::vector<Fields> result;
auto err = DAO::querySystemLogList(pageinfo, result); auto err = DAO::querySystemLogList(stationId, pageinfo, result);
HttpHelper::setPagination(pageinfo, result, json); HttpHelper::setPagination(pageinfo, result, json);
return err; return err;
} }
@@ -1245,12 +1251,16 @@ Errcode HttpEntity::updateSystemLog(const httplib::Request& req, njson& json, st
Errcode HttpEntity::queryAlertLogList(const httplib::Request& req, njson& json, std::string& errmsg) Errcode HttpEntity::queryAlertLogList(const httplib::Request& req, njson& json, std::string& errmsg)
{ {
Fields params;
GetRequestParams(req, {"station_id"}, params);
PageInfo pageinfo; PageInfo pageinfo;
pageinfo.index = Utils::toInt(req.get_param_value("page")); pageinfo.index = Utils::toInt(req.get_param_value("page"));
pageinfo.size = Utils::toInt(req.get_param_value("page_size")); pageinfo.size = Utils::toInt(req.get_param_value("page_size"));
std::string stationId = params.value("station_id");
std::vector<Fields> result; std::vector<Fields> result;
auto err = DAO::queryAlertLogList(pageinfo, result); auto err = DAO::queryAlertLogList(stationId, pageinfo, result);
HttpHelper::setPagination(pageinfo, result, json); HttpHelper::setPagination(pageinfo, result, json);
return err; return err;
} }
@@ -1571,12 +1581,10 @@ Errcode HttpEntity::queryStatDayList(const httplib::Request& req, njson& json, s
int64_t t0 = Utils::time(startDate + " 00:00:00"); int64_t t0 = Utils::time(startDate + " 00:00:00");
int64_t t1 = Utils::time(endDate + " 00:00:00"); int64_t t1 = Utils::time(endDate + " 00:00:00");
int i = 0;
njson jsondata = njson::array(); njson jsondata = njson::array();
for (int64_t t = t0; t<=t1; t += 86400) for (int64_t t = t0; t<=t1; t += 86400)
{ {
i++;
njson jsonrow; njson jsonrow;
std::string dt = Utils::dateStr(t); std::string dt = Utils::dateStr(t);
Fields* fields = NULL; Fields* fields = NULL;
@@ -1709,6 +1717,115 @@ Errcode HttpEntity::queryStatCharts(const httplib::Request& req, njson& json, st
return Errcode::OK; return Errcode::OK;
} }
Errcode HttpEntity::queryStatStationMode(const httplib::Request& req, njson& json, std::string& errmsg)
{
Fields params;
GetRequestParams(req, {"station_id", "start_date", "end_date", "mode"}, params);
std::string stationId = params.value("station_id");
std::string startDate = params.value("start_date");
std::string endDate = params.value("end_date");
std::string mode = params.value("mode");
std::string sqlC = std::format(" WHERE dt>='{}' AND dt<='{}'", startDate, endDate);
if (!stationId.empty()) sqlC += std::format(" AND station_id='{}'", stationId);
std::string sql = " SUM(E_in) E_in, SUM(E_out) E_out, SUM(fee_in) fee_in, SUM(fee_out) fee_out, SUM(income) income FROM stat_total_day";
std::string sqlGroupBy;
if (mode == "year") {
sql = "SELECT YEAR(dt) AS year, " + sql + sqlC + " GROUP BY YEAR(dt);";
} else if (mode == "quarter") {
sql = "SELECT YEAR(dt) AS year, QUARTER(dt) quarter, " + sql + sqlC+ " GROUP BY YEAR(dt), QUARTER(dt);";
} else if (mode == "month") {
sql = "SELECT YEAR(dt) AS year, MONTH(dt) month, " + sql + sqlC + "GROUP BY YEAR(dt), MONTH(dt);";
} else if (mode == "week") {
sql = "SELECT YEAR(dt) AS year, WEEK(dt) week, " + sql + sqlC + " GROUP BY YEAR(dt), WEEK(dt);";
} else {
mode = "date";
sql = "SELECT dt, E_in, E_out, fee_in, fee_out, income FROM stat_total_day " + sqlC + " LIMIT 1000;";
}
std::vector<Fields> result;
Errcode err = DAO::exec(NULL, sql, result);
njson jsondata = njson::array();
if (mode == "date")
{
std::map<std::string, Fields*> mapTemp;
for (auto& item: result)
{
auto& dt = item.value("dt");
mapTemp[dt] = &item;
}
int64_t t0 = Utils::time(startDate + " 00:00:00");
int64_t t1 = Utils::time(endDate + " 00:00:00");
for (int64_t t = t0; t<=t1; t += 86400)
{
njson jsonrow;
std::string dt = Utils::dateStr(t);
Fields* item = NULL;
auto iter = mapTemp.find(dt);
if (iter != mapTemp.end()) { item = iter->second; }
jsonrow["dt"] = dt;
jsonrow["E_in"] = item ? item->value("E_in") : "0";
jsonrow["E_out"] = item ? item->value("E_out") : "0";
jsonrow["fee_in"] = item ? item->value("fee_in") : "0";
jsonrow["fee_out"] = item ? item->value("fee_out") : "0";
jsonrow["income"] = item ? item->value("income") : "0";
int rate = 0;
if (item) {
int E_in = item->get<int>("E_in");
int E_out = item->get<int>("E_out");
if (E_in != 0) {
rate = (float(E_out)/float(E_in)) * 100;
}
}
jsonrow["E_rate"] = rate;
jsondata.push_back(jsonrow);
}
}
else
{
for (auto& item: result)
{
njson jsonrow;
if (mode == "year") {
jsonrow["dt"] = item.value("year") + "";
}
else if (mode == "quarter") {
jsonrow["dt"] = item.value("year") + "" + item.value("quarter") + "季度";
}
else if (mode == "month") {
jsonrow["dt"] = item.value("year") + "" + item.value("month") + "";
}
else if (mode == "week") {
jsonrow["dt"] = item.value("year") + "" + item.value("week") + "";
}
else {
jsonrow["dt"] = item.value("dt");
}
jsonrow["E_in"] = item.value("E_in");
jsonrow["E_out"] = item.value("E_out");
int rate = 0;
int E_in = item.get<int>("E_in");
int E_out = item.get<int>("E_out");
if (E_in != 0) {
rate = (float(E_out)/float(E_in)) * 100;
}
jsonrow["E_rate"] = rate;
jsonrow["fee_in"] = item.value("fee_in");
jsonrow["fee_out"] = item.value("fee_out");
jsonrow["income"] = item.value("income");
jsondata.push_back(jsonrow);
}
}
json["data"] = jsondata;
return Errcode::OK;
}
Errcode HttpEntity::exportStatReport(const httplib::Request& req, njson& json, std::string& errmsg) Errcode HttpEntity::exportStatReport(const httplib::Request& req, njson& json, std::string& errmsg)
{ {

View File

@@ -118,6 +118,9 @@ public:
// 场站按类某一天的历史曲线数据 // 场站按类某一天的历史曲线数据
Errcode queryStatCharts(const httplib::Request& req, njson& json, std::string& errmsg); Errcode queryStatCharts(const httplib::Request& req, njson& json, std::string& errmsg);
// 场站按周、月、季度、年统计: 充电量、放电量、 使用率=放电量/充电量、充电费、放电费、收益=放电费-充电费
Errcode queryStatStationMode(const httplib::Request& req, njson& json, std::string& errmsg);
Errcode exportStatReport(const httplib::Request& req, njson& json, std::string& errmsg); Errcode exportStatReport(const httplib::Request& req, njson& json, std::string& errmsg);
Errcode queryEnvironment(const httplib::Request& req, njson& json, std::string& errmsg); Errcode queryEnvironment(const httplib::Request& req, njson& json, std::string& errmsg);

View File

@@ -143,7 +143,7 @@ export default {
// areaStyle: { // areaStyle: {
// global: false, // global: false,
// color: { // color: {
// type: 'linear', x: 0, y: 0, x2: 0, y2: 1, // type: 'linear', x: 0, y: 0, x2: 0, y2: 1,
// colorStops: [ // colorStops: [
// { offset: 0, color: JSON.parse(JSON.stringify(item)).colorStart }, // 顶部颜色 // { offset: 0, color: JSON.parse(JSON.stringify(item)).colorStart }, // 顶部颜色
// { offset: 1, color: JSON.parse(JSON.stringify(item)).colorEnd } // 底部颜色 // { offset: 1, color: JSON.parse(JSON.stringify(item)).colorEnd } // 底部颜色

View File

@@ -69,7 +69,7 @@ export default {
{ title: '场站信息', class: '', componentId: markRaw( PrefabCabin), infoKey: 'prefab' }, { title: '场站信息', class: '', componentId: markRaw( PrefabCabin), infoKey: 'prefab' },
{ title: '储能运行信息', class: 'operation-status', componentId: markRaw(OperationalInfo), infoKey: 'storage' }, { title: '储能运行信息', class: 'operation-status', componentId: markRaw(OperationalInfo), infoKey: 'storage' },
{ title: '充电运行信息', class: 'operation-status', componentId: markRaw(OperationalInfo), infoKey: 'charge' }, { title: '充电运行信息', class: 'operation-status', componentId: markRaw(OperationalInfo), infoKey: 'charge' },
{ title: '光伏运行信息', class: 'operation-status', componentId: markRaw(OperationalInfo), infoKey: 'pv' }, // { title: '光伏运行信息', class: 'operation-status', componentId: markRaw(OperationalInfo), infoKey: 'pv' },
{ title: '电网侧运行信息', class: 'operation-status', componentId: markRaw(OperationalInfo), infoKey: 'grid' }, { title: '电网侧运行信息', class: 'operation-status', componentId: markRaw(OperationalInfo), infoKey: 'grid' },
{ title: '环境信息', class: 'envInfo', componentId:markRaw( EnvInfo), infoKey: 'envTotal' } { title: '环境信息', class: 'envInfo', componentId:markRaw( EnvInfo), infoKey: 'envTotal' }
], ],

View File

@@ -64,14 +64,15 @@ export default {
], ],
myItemsStats: [ myItemsStats: [
{ key: 'storage_device_num', value: '', label: '储能设备数量', d: '个' }, { key: 'storage_device_num', value: '', label: '储能设备数量', d: '个' },
{ key: 'solar_device_num', value: '', label: '光伏设备数量', d: '个' }, // { key: 'solar_device_num', value: '', label: '光伏设备数量', d: '个' },
{ key: 'charge_device_num', value: '', label: '充电设备数量', d: '个' },
{ key: 'solar_elect_grid', value: '', label: '上网总电量', d: 'kWh' },
{ key: 'storage_elect_in', value: '', label: '储能充电总电量', d: 'kWh' }, { key: 'storage_elect_in', value: '', label: '储能充电总电量', d: 'kWh' },
{ key: 'solar_elect_gen', value: '', label: '光伏发电总电量', d: 'kWh' },
{ key: 'charge_elect', value: '', label: '充电桩充电总电量', d: 'kWh' },
{ key: 'income_elect', value: '', label: '收益总金额', d: '元' },
{ key: 'storage_elect_out', value: '', label: '储能放电总电量', d: 'kWh' }, { key: 'storage_elect_out', value: '', label: '储能放电总电量', d: 'kWh' },
// { key: 'solar_elect_gen', value: '', label: '光伏发电总电量', d: 'kWh' },
{ key: 'charge_device_num', value: '', label: '充电设备数量', d: '个' },
{ key: 'charge_elect', value: '', label: '充电桩充电总电量', d: 'kWh' },
// { key: 'solar_elect_grid', value: '', label: '上网总电量', d: 'kWh' },
{ key: 'income_elect', value: '', label: '收益总金额', d: '元' },
], ],
list: [ list: [
{ {

View File

@@ -136,8 +136,8 @@ export default {
smooth: true, smooth: true,
type: 'line', type: 'line',
barWidth: 10, barWidth: 10,
itemStyle: { borderRadius: 10, color: item.lineColor }, itemStyle: {borderRadius: 10, color: item.lineColor},
emphasis: { focus: 'series' }, emphasis: {focus: 'series'},
global: false, global: false,
showSymbol: false, showSymbol: false,
data: [] data: []

View File

@@ -123,8 +123,8 @@ export default {
smooth: true, smooth: true,
type: 'line', type: 'line',
barWidth: 10, barWidth: 10,
itemStyle: { borderRadius: 10, color: item.lineColor }, itemStyle: {borderRadius: 10, color: item.lineColor},
emphasis: { focus: 'series' }, emphasis: {focus: 'series'},
global: false, global: false,
showSymbol: false, showSymbol: false,
data: [] data: []

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="mychart"> <div class="mychartbox">
<!-- <div class="text_Cur"> <!-- <div class="text_Cur">
<div v-for="item in curList" :key="item.key"> <div v-for="item in curList" :key="item.key">
<div>{{ item.name }}</div> <div>{{ item.name }}</div>
@@ -19,7 +19,7 @@ export default {
props: { props: {
propKey: { type: String, default: '' }, propKey: { type: String, default: '' },
propData: { type: Array, default: () => [] }, propData: { type: Array, default: () => [] },
propOption: { type: Object, default: { series: [] } } propOption: { type: Object, default: ()=> ({ series: [] }) }
}, },
data() { data() {
return { return {
@@ -162,11 +162,13 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.mychart { .mychartbox {
height: calc(100% - 35px); height: calc(100% - 35px);
background-color: #80808010; // background-color: #80808010;
background-color: rgba(33, 105, 195, 0.12);
.mychart { .mychart {
margin-left: 5px;
height: calc(100% - 5px); height: calc(100% - 5px);
} }
} }

View File

@@ -0,0 +1,178 @@
<template>
<div class="mychartbox">
<!-- <div class="text_Cur">
<div v-for="item in curList" :key="item.key">
<div>{{ item.name }}</div>
<span class="mark">{{ item.value ? item.value : 0 }}</span>
<span class="d">{{ item.d }}</span>
</div>
</div> -->
<div :id="myChartId" class="mychart"></div>
</div>
</template>
<script>
import { processData } from '@/utils/dealWithData'
export default {
name: '',
props: {
propKey: { type: String, default: '' },
propData: { type: Array, default: () => [] },
propOption: { type: Object, default: ()=> ({ series: [] }) }
},
data() {
return {
myChartId: 'mychart' + Math.floor(Math.random() * 9999),
myEchart: null,
xData: [], // EChart的 x 轴 option
yData: [], // EChart的 y 轴 option
}
},
watch: {
propData: {
handler(newVal, oldVal) {
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
this.$nextTick(() => {
this.drawLineChart()
})
}
},
immediate: true, // 初始化时更新
deep: true // 确保深度比较
},
propOption: {
handler(newVal, oldVal) {
},
immediate: true,
}
},
mounted() { },
beforeUnmount() {
window.removeEventListener('resize', this.handleResize)
if (this.myEchart) {
this.myEchart.dispose()
this.myEchart = null
}
},
methods: {
handleResize() {
if (this.myEchart) {
this.myEchart.resize()
}
},
getChartData() {
const keyList = this.propOption.series.map((item) => item.key)
const result = processData(this.propData, keyList)
this.xData = result.dates
this.yData = result.values
if (this.xData.length == 0) {
const today = new Date();
for (let i = 6; i >= 0; i--) {
const date = new Date(today); // 每次创建新日期实例(避免修改原日期)
date.setDate(today.getDate() - i); // 往前推 i 天
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份 0-11需 +1
const day = String(date.getDate()).padStart(2, '0');
this.xData.push(`${month}-${day}`);
for (let j = 0; j < keyList.length; j++) {
if (j == 0) this.yData.push([])
else this.yData[j].push(0)
}
}
}
},
drawLineChart(activeKey) {
this.getChartData(activeKey)
if (this.myEchart) {
this.myEchart.dispose()
}
const chartDom = document.getElementById(this.myChartId)
if (!chartDom) return;
let myEchart = this.$echarts.init(chartDom)
this.myEchart = myEchart
let option = {
animation: false,
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
legend: { top: 10, textStyle: { color: '#fff' } },
grid: { left: '3%', right: '4%', bottom: '1%', top: '32%' },
xAxis: {
type: 'category',
data: this.xData,
axisLine: { lineStyle: { type: 'dashed', color: '#435463' } },
axisLabel: { color: '#fff' }
},
yAxis: [],
series: []
}
const yAxisItem = {
name: '',
type: 'value',
// min: 0,
// max: 2,
//interval: 1, // 强制步长
splitNumber: 2, // 分段数
nameTextStyle: { color: '#fff' },
splitLine: { lineStyle: { type: 'dashed', color: '#435463' } },
axisLabel: { color: '#fff', fontSize: 12 },
}
if (this.propOption.yAxis) {
this.propOption.yAxis.forEach((item, index) => {
const maxVal = Math.max(...this.yData[index]);
if (maxVal && maxVal > 0) {
// yAxisItem.min = undefined
// yAxisItem.max = maxVal
}
yAxisItem.name = item
option.yAxis.push(yAxisItem)
})
}
if (this.propOption.series) {
this.propOption.series.forEach((item, index) => {
option.series.push({
name: item.name,
type: item.type ? item.type : 'bar',
color: item.color,
data: this.yData[index],
barWidth: '20%',
// 关键:强制显示超出坐标轴范围的点
symbolKeep: true
})
})
}
if (option.yAxis.length == 0) { option.yAxis.push(yAxisItem) }
option && myEchart.setOption(option)
this.setupResizeListener()
},
setupResizeListener() {
window.removeEventListener('resize', this.handleResize);
window.addEventListener('resize', this.handleResize)
}
}
}
</script>
<style lang="scss" scoped>
.mychartbox {
height: calc(100% - 35px);
// background-color: #80808010;
// background-color: rgba(33, 105, 195, 0.12);
background-color: rgba(33, 105, 195, 0.12);
.mychart {
margin-left: 5px;
height: calc(100% - 5px);
}
}
</style>

View File

@@ -2,8 +2,8 @@
<div class="total-station"> <div class="total-station">
<div class="content-my"> <div class="content-my">
<div v-for="item in myItems" :key="item.key" :class="`item ${item.class}`" > <div v-for="item in myItems" :key="item.key" :class="`item ${item.class}`" >
<span style="color:#d0d0d0; margin: 0 0 0 0">{{ item.label }}</span> <span style="height: 50%; color:#d0d0d0; margin: 0 0 0 0; font-size:14px; font-weight: 600; display: flex; align-items: center;">{{ item.label }}</span>
<div style="margin-left: 20%;"> <div style="height: 50%; margin-left: 20%;">
<span :style="{ 'color': item.color, 'font-size':'16px', 'font-weight':600}">{{ item.value ? item.value : (item.d ? 0 : '--') }}</span> <span :style="{ 'color': item.color, 'font-size':'16px', 'font-weight':600}">{{ item.value ? item.value : (item.d ? 0 : '--') }}</span>
<span style="font-size:16px; margin-left: 8px;">{{ item.d }}</span> <span style="font-size:16px; margin-left: 8px;">{{ item.d }}</span>
</div> </div>
@@ -53,18 +53,10 @@ export default {
return { return {
myItems: [ myItems: [
{ color:'#a0f0a0', key: 'runDays', value: 0, label:'场站运行天数', d:'天'}, { color:'#a0f0a0', key: 'runDays', value: 0, label:'场站运行天数', d:'天'},
// { color:'#a0f0a0', key: 'storage_device_num', value: 0, label:'储能设备数量', d:'个'},
// { color:'#a0f0a0', key: 'charge_device_num', value: 0, label:'充电设备数量', d:'个'},
// { color:'#a0f0a0', key: 'solar_device_num', value: 0, label:'光伏设备数量', d:'个'},
// { color:'#a0f0a0', key: 'solar_elect_grid', value: 0, label:'上网总电量', d:'kWh'},
{ color:'#a0f0a0', key: 'storage_elect_in', value: 0, label:'累计储能总电量', d:'kWh'}, { color:'#a0f0a0', key: 'storage_elect_in', value: 0, label:'累计储能总电量', d:'kWh'},
// { color:'#a0f0a0', key: 'charge_elect_out', value: 0, label:'充电桩充电总电量', d:'kWh'},
// { color:'#a0f0a0', key: 'solar_elect_gen', value: 0, label:'光伏发电总电量', d:'kWh'},
{ color:'#a0f0a0', key: 'income_elect', value: 0, label:'累计收益总金额', d:'元'}, { color:'#a0f0a0', key: 'income_elect', value: 0, label:'累计收益总金额', d:'元'},
// { color:'#a0f0a0', key: 'storage_elect_out', value: 0, label:'储能放电总电量', d:'kWh'},
{ color:'#a0f0a0', key: 'storage_status', value: '空闲', label:'储能状态'}, { color:'#a0f0a0', key: 'storage_status', value: '空闲', label:'储能状态'},
{ color:'#a0f0a0', key: 'charge_status', value: '空闲', label:'充电状态'}, { color:'#a0f0a0', key: 'charge_status', value: '空闲', label:'充电状态'},
{ color:'#a0f0a0', key: 'pv_status', value: '离线', label:'光伏状态'},
], ],
} }
}, },

View File

@@ -2,7 +2,7 @@
<div class="onLine"> <div class="onLine">
<div class="content-my"> <div class="content-my">
<div v-for="item in myItems" :key="item.key" :class="`item ${item.class}`" > <div v-for="item in myItems" :key="item.key" :class="`item ${item.class}`" >
<span style="height: 50%; color:#d0d0d0; margin:0 0 0 0">{{ item.label }}</span> <span style="height: 50%; color:#d0d0d0; margin:0 0 0 0; font-size:14px; font-weight: 600; display: flex; align-items: center;">{{ item.label }}</span>
<div style="height: 50%; margin-left: 20%;"> <div style="height: 50%; margin-left: 20%;">
<span style="color:#a0f0a0; font-size:16px; font-weight:600;">{{ item.value ? item.value : 0 }}</span> <span style="color:#a0f0a0; font-size:16px; font-weight:600;">{{ item.value ? item.value : 0 }}</span>
<span style="font-size:16px; margin-left: 8px;">{{ item.d }}</span> <span style="font-size:16px; margin-left: 8px;">{{ item.d }}</span>
@@ -55,11 +55,11 @@ export default {
{ key: 'runDays', value: 0, label:'系统运行天数', d:'天'}, { key: 'runDays', value: 0, label:'系统运行天数', d:'天'},
{ key: 'storage_device_num', value: 0, label:'储能设备数量', d:'个'}, { key: 'storage_device_num', value: 0, label:'储能设备数量', d:'个'},
{ key: 'charge_device_num', value: 0, label:'充电设备数量', d:'个'}, { key: 'charge_device_num', value: 0, label:'充电设备数量', d:'个'},
{ key: 'solar_device_num', value: 0, label:'光伏设备数量', d:'个'}, // { key: 'solar_device_num', value: 0, label:'光伏设备数量', d:'个'},
{ key: 'solar_elect_grid', value: 0, label:'上网总电量', d:'kWh'}, { key: 'solar_elect_grid', value: 0, label:'上网总电量', d:'kWh'},
{ key: 'storage_elect_in', value: 0, label:'储能充电总电量', d:'kWh'}, { key: 'storage_elect_in', value: 0, label:'储能充电总电量', d:'kWh'},
{ key: 'charge_elect_out', value: 0, label:'充电桩充电总电量', d:'kWh'}, { key: 'charge_elect_out', value: 0, label:'充电桩充电总电量', d:'kWh'},
{ key: 'solar_elect_gen', value: 0, label:'光伏发电总电量', d:'kWh'}, // { key: 'solar_elect_gen', value: 0, label:'光伏发电总电量', d:'kWh'},
{ key: 'income_elect', value: 0, label:'累计收益总金额', d:'元'}, { key: 'income_elect', value: 0, label:'累计收益总金额', d:'元'},
{ key: 'storage_elect_out', value: 0, label:'储能放电总电量', d:'kWh'}, { key: 'storage_elect_out', value: 0, label:'储能放电总电量', d:'kWh'},
], ],
@@ -182,7 +182,7 @@ export default {
justify-content: flex-start; justify-content: flex-start;
height: 100%; height: 100%;
.item { .item {
width: calc(25% - 6px); width: calc(33% - 6px);
margin-left: 3px; margin-left: 3px;
margin-right: 3px; margin-right: 3px;
margin-top: 8px; margin-top: 8px;

View File

@@ -35,8 +35,12 @@
</div> </div>
<!-- 日期选择框 date--> <!-- 日期选择框 date-->
<div class="date-picker" v-if="item.type == 'datePick1'"> <div class="date-picker" v-if="item.type == 'datePick1'">
<a-range-picker :locale="locale"
<a-range-picker v-model:value="formData[item.key]" value-format="YYYY-MM-DD" @change="$emit('onSearch', formData)" /> v-model:value="formData[item.key]"
value-format="YYYY-MM-DD"
:picker="datePicker"
@openChange="handleOpenChange"
@change="handleChange(item.key)" />
</div> </div>
<!-- 输入框 --> <!-- 输入框 -->
<div class="input" v-if="item.type == 'input'"> <div class="input" v-if="item.type == 'input'">
@@ -91,10 +95,21 @@
</template> </template>
<script> <script>
import {ref} from 'vue'
import zhCN from 'ant-design-vue/es/locale/zh_CN'
import locale from 'ant-design-vue/es/date-picker/locale/zh_CN'
import 'dayjs/locale/zh-cn'
import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'
dayjs.locale('zh-cn')
export default { export default {
name: 'SearchBox', name: 'SearchBox',
components: {}, components: {},
props: { props: {
datePicker: { type: String, default: ()=> { return "date" }},
titleOption: { titleOption: {
type: Object, type: Object,
default: () => { default: () => {
@@ -143,6 +158,24 @@ export default {
}, },
immediate: true, immediate: true,
deep: true deep: true
},
datePicker: {
handler(newVal) {
// 临时:处理 statisticalAnalysis.vue 中设置日期选择模式时,时间区间的默认值修正
// key = 'time' 只在 statisticalAnalysis.vue 中设置生效
const key = 'time';
if (!this.formData[key]) {
// 今天的日期
const date = new Date();
const dtNow = date.toISOString().split('T')[0];
// 7天前
date.setDate(date.getDate() - 7);
const dtStart = date.toISOString().split('T')[0];
this.formData[key] = [dtStart, dtNow]
}
this.handleChange(key)
},
immediate: true,
} }
}, },
mounted() { mounted() {
@@ -169,14 +202,62 @@ export default {
}, },
handelClick(type) { handelClick(type) {
this.$emit('operateForm', type) this.$emit('operateForm', type)
} },
// handleChange() { handleChange(key) {
// this.$emit("onSearch", this.formData); if (this.formData[key] && this.formData[key][0]) {
// }, if (this.datePicker == "week") {
this.formData[key][0] = dayjs(this.formData[key][0]).startOf('week').format('YYYY-MM-DD')
} else if (this.datePicker == "month") {
this.formData[key][0] = dayjs(this.formData[key][0]).startOf('month').format('YYYY-MM-DD')
} else if (this.datePicker == "quarter") {
this.formData[key][0] = dayjs(this.formData[key][0]).startOf('quarter').format('YYYY-MM-DD')
} else if (this.datePicker == "year") {
this.formData[key][0] = dayjs(this.formData[key][0]).startOf('year').format('YYYY-MM-DD')
}
}
if (this.formData[key] && this.formData[key][1]) {
if (this.datePicker == "week") {
this.formData[key][1] = dayjs(this.formData[key][1]).endOf('week').format('YYYY-MM-DD')
} else if (this.datePicker == "month") {
this.formData[key][1] = dayjs(this.formData[key][1]).endOf('month').format('YYYY-MM-DD')
} else if (this.datePicker == "quarter") {
this.formData[key][1] = dayjs(this.formData[key][1]).endOf('quarter').format('YYYY-MM-DD')
} else if (this.datePicker == "year") {
this.formData[key][1] = dayjs(this.formData[key][1]).endOf('year').format('YYYY-MM-DD')
}
}
this.$emit("onSearch", this.formData);
},
// pressEnter() { // pressEnter() {
// this.$emit("onSearch", this.formData); // this.$emit("onSearch", this.formData);
// }, // },
handleOpenChange() {
if (open) {
// 延迟执行以确保 DOM 已渲染
setTimeout(() => {
const cells = document.querySelectorAll('.ant-picker-cell');
cells.forEach((cell) => {
const title = cell.getAttribute('title');
const innerDiv = cell.querySelector('.ant-picker-cell-inner');
if (title && innerDiv) {
// if (title.includes('Q1')) {
// innerDiv.textContent = '第一季度';
// } else if (title.includes('Q2')) {
// innerDiv.textContent = '第二季度';
// } else if (title.includes('Q3')) {
// innerDiv.textContent = '第三季度';
// } else if (title.includes('Q4')) {
// innerDiv.textContent = '第四季度';
// }
}
});
}, 100);
}
}
} }
} }
</script> </script>
@@ -191,6 +272,7 @@ input:-internal-autofill-selected {
:deep(.anticon) { :deep(.anticon) {
color: var(--theme-text-default) !important; color: var(--theme-text-default) !important;
} }
.search { .search {
// height:70px; // height:70px;
color: #fff; color: #fff;
@@ -259,7 +341,11 @@ input:-internal-autofill-selected {
} }
.label { .label {
width: 80px; // width: 65px;
flex: 1; /* 占满剩余空间 */
text-align: right; /* 文字右对齐 */
white-space: nowrap; /* 防止换行 */
margin-right: 10px; /* 右侧间隔10px */
color: var(--theme-text-default); color: var(--theme-text-default);
} }
.top-right, .top-right,
@@ -338,4 +424,44 @@ input:-internal-autofill-selected {
} }
} }
} }
// :deep(.ant-picker-cell-inner) {
// width: 75px !important;
// }
// /* 深度穿透修改季度/月份/日期面板里面的宽度 */
// :deep(.ant-picker-dropdown .ant-picker-cell-inner) {
// width: 100px !important; /* 你想要的宽度 */
// }
/* 方法1匹配任意hash类名 */
// :deep(.ant-picker-dropdown .ant-picker-quarter-panel .ant-picker-cell-inner) {
// width: 100px !important;
// min-width: 100px !important;
// }
// /* 方法2如果上面不生效,提高特异性 */
// :deep(.ant-picker-dropdown div.ant-picker-quarter-panel .ant-picker-cell-inner) {
// width: 100px !important;
// min-width: 100px !important;
// }
// /* 方法3双重类名提高权重 */
// :deep(.ant-picker-dropdown .ant-picker-quarter-panel .ant-picker-cell.ant-picker-cell-inner) {
// width: 100px !important;
// min-width: 100px !important;
// }
// /* 放到全局样式文件(如 global.css 或 App.vue 中不加 scoped) */
// .ant-picker-dropdown .ant-picker-quarter-panel .ant-picker-cell-inner {
// width: 100px !important;
// min-width: 100px !important;
// }
/* 或者使用 :global 逃逸 scoped */
:global(.ant-picker-dropdown .ant-picker-quarter-panel .ant-picker-cell-inner) {
width: 50px !important;
min-width: 50px !important;
}
</style> </style>

View File

@@ -152,10 +152,10 @@ export default {
key: 'fire40', key: 'fire40',
name: '消防信息' name: '消防信息'
}, },
{ // {
key: 'airc', // key: 'airc',
name: '空调信息' // name: '空调信息'
}, // },
], ],
tableDatas: {}, tableDatas: {},
@@ -270,7 +270,7 @@ export default {
height: 100%; height: 100%;
display: flex; display: flex;
.env-item { .env-item {
width: 24%; width: 30%;
.tab { .tab {
&>span { &>span {

View File

@@ -6,7 +6,7 @@ export const policyTypes = [
{ {
value: '5', value: '5',
label: '自定时段' label: '运营支撑'
} }
// { // {
// value: '2', // value: '2',

View File

@@ -154,16 +154,16 @@ export default {
// { v: '数量', key: 'num' } // { v: '数量', key: 'num' }
] ]
}, },
{ // {
name: '光伏设备', // name: '光伏设备',
power: 60, // power: 60,
num: 62, // num: 62,
systemType: 3, // systemType: 3,
titles: [ // titles: [
//{ v: '总功率', key: 'power', sufix: 'kW' }, // //{ v: '总功率', key: 'power', sufix: 'kW' },
// { v: '数量', key: 'num' } // // { v: '数量', key: 'num' }
] // ]
}, // },
{ {
name: '辅助设备', name: '辅助设备',
power: 60, power: 60,

View File

@@ -12,9 +12,21 @@
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
</div> </div>
</div> </div>
<div v-if="activeKey == 4">
<a-radio-group v-model:value="datePickerMode" class="my-radio-group" @change="onStatTypeChanged">
<a-radio-button style="width: 60px;" value="date"></a-radio-button>
<a-radio-button style="width: 60px;" value="week"></a-radio-button>
<a-radio-button style="width: 60px;" value="month"></a-radio-button>
<a-radio-button style="width: 60px;" value="quarter">季度</a-radio-button>
<a-radio-button style="width: 60px;" value="year"></a-radio-button>
</a-radio-group>
</div>
<searchBox <searchBox
class="searchBox" class="searchBox"
ref="searchBox" ref="searchBox"
:date-picker="datePickerMode"
:btn-option-list="btnOptionList" :btn-option-list="btnOptionList"
:search-options="searchOptions" :search-options="searchOptions"
:title-option="{ title: '', info: '' }" :title-option="{ title: '', info: '' }"
@@ -59,9 +71,22 @@
</div> </div>
<div v-if="activeKey == 4" class="content-table-4" > <div v-if="activeKey == 4" class="content-table-4" >
<div style="display: flex; height: 30%; margin-bottom: 10px; ">
<MyChartLine style="width: calc(33% - 5px); height: 100%; margin-bottom: 10px;"
propKey="chart1" :prop-option="chartPropOption1" :prop-data="chartData">
</MyChartLine>
<MyChartLine style="width:calc(33% - 5px); height: 100%; margin-left: 10px;"
propKey="chart2" :prop-option="chartPropOption2" :prop-data="chartData">
</MyChartLine>
<MyChartLine style="width:calc(33% - 5px); height: 100%; margin-left: 10px;"
propKey="chart3" :prop-option="chartPropOption3" :prop-data="chartData">
</MyChartLine>
</div>
<ComTable <ComTable
:tableH="tableH" :tableH="tableH"
:columns="columns" :columns="tableColumns"
:table-data="tableData" :table-data="tableData"
:table-option="{ page: false, select: false}"> :table-option="{ page: false, select: false}">
<template #action="record"> <template #action="record">
@@ -77,12 +102,47 @@ import energyEchart from '@/components/statisticalAnalysis/energyEchart.vue'
import searchBox from '@/components/SearchBox.vue' import searchBox from '@/components/SearchBox.vue'
import { postReq, getReq } from '@/request/api' import { postReq, getReq } from '@/request/api'
import {downloadByUrl} from '@/utils/download' import {downloadByUrl} from '@/utils/download'
import MyChartLine from '@/components/Home/MyChartLine.vue'
import { ref, computed } from 'vue'
import dayjs from 'dayjs'
export default { export default {
name: 'StatisicalAnView', name: 'StatisicalAnView',
components: { energyEchart, searchBox }, components: { energyEchart, searchBox },
data() { data() {
return { return {
chartInfo: { title: '系统运行统计', infoKey: 'total' },
chartPropOption1: {
yAxis: ['电量(kWh)'],
series: [
{ name: '充电电量', key: 'E_in', color: '#2a82e4' },
{ name: '放电电量', key: 'E_out', color: '#5aabf2' },
]
},
chartData: [
],
chartPropOption2: {
yAxis: ['充放使用率(%)'],
series: [
{ name: '使用率', key: 'E_rate', color: '#2a82e4', type: "line" },
]
},
chartPropOption3: {
yAxis: ['费用(元)'],
series: [
{ name: '充电费', key: 'fee_in', color: '#2a82e4', type: "bar" },
{ name: '放电费', key: 'fee_out', color: '#5aabf2', type: "bar" },
{ name: '收益', key: 'income', color: '#0cdaf5', type: "bar" },
]
},
datePickerMode: "date",
formDatetime: {
start: '',
end: ''
},
btnOptionList: [], btnOptionList: [],
loading: { loading: {
chart: false, chart: false,
@@ -99,7 +159,7 @@ export default {
key: 'time' key: 'time'
}, },
{ {
label: '场站切换', label: '场站选择',
type: 'slot', type: 'slot',
value: [], value: [],
key: 'station', key: 'station',
@@ -455,23 +515,10 @@ export default {
activeKey: 1, activeKey: 1,
interval: null, interval: null,
tabList: [ tabList: [
{ { key: 1, name: '储能设备' },
key: 1, { key: 2, name: '充电设备' },
name: '储能设备' // { key: 3, name: '光伏设备' },
}, { key: 4, name: '运行效益' }
{
key: 2,
name: '充电设备'
},
{
key: 3,
name: '光伏设备'
},
{
key: 4,
name: '策略运行效益'
}
], ],
tableList: { tableList: {
1: { 1: {
@@ -657,15 +704,22 @@ export default {
} }
} }
}, },
columns: [ //每个站显示使用率=放电量/充电量、收益=放电费-充电费,按周、月、季度、年;
tableColumns: [
{ title: '日期', dataIndex: 'dt', key: 'dt' }, { title: '日期', dataIndex: 'dt', key: 'dt' },
{ title: '时段', dataIndex: 'period', key: 'period', ellipsis: true}, // fixed: 'left', // filterable: true { title: '储能充电电量(kWh)', dataIndex: 'E_in', key: 'E_in'},
{ title: '储能电电量(kWh)', dataIndex: 'E_in', key: 'E_in' }, { title: '储能电电量(kWh)', dataIndex: 'E_out', key: 'E_out'},
{ title: '储能放电电量(kWh)', dataIndex: 'E_out', key: 'E_out' }, { title: '充放使用率(%)', dataIndex: 'E_rate', key: 'E_rate'},
{ title: '电网价格(元/kWh)', dataIndex: 'grid_price', key: 'gridPrice' }, { title: '储能充电费(元)', dataIndex: 'fee_in', key: 'fee_in'},
{ title: '充电价格(元/kWh)', dataIndex: 'charge_price', key: 'chargePrice' }, { title: '储能放电费(元)', dataIndex: 'fee_out', key: 'fee_out'},
{ title: '收益(元)', dataIndex: 'income', key: 'income' }, { title: '收益(元)', dataIndex: 'income', key: 'income'},
{ title: '操作', dataIndex: 'operate', key: 'operate', scopedSlots: { customRender: 'action' } } // { title: '时段', dataIndex: 'period', key: 'period', ellipsis: true}, // fixed: 'left', // filterable: true
// { title: '储能充电电量(kWh)', dataIndex: 'E_in', key: 'E_in' },
// { title: '储能放电电量(kWh)', dataIndex: 'E_out', key: 'E_out' },
// { title: '电网价格(元/kWh)', dataIndex: 'grid_price', key: 'gridPrice' },
// { title: '充电价格(元/kWh)', dataIndex: 'charge_price', key: 'chargePrice' },
// { title: '收益(元)', dataIndex: 'income', key: 'income' },
// { title: '操作', dataIndex: 'operate', key: 'operate', scopedSlots: { customRender: 'action' } }
], ],
tableData: [ tableData: [
@@ -676,17 +730,21 @@ export default {
// {period: "总计", gridPrice: "0.8", chargePrice: "0.6", income: "0.2", elect: "35", incomeTotal: "100"} // {period: "总计", gridPrice: "0.8", chargePrice: "0.6", income: "0.2", elect: "35", incomeTotal: "100"}
], ],
tableH: 500 tableH: 500,
} }
}, },
watch: { watch: {
activeKey: { activeKey: {
handler(newVal) { handler(newVal) {
if (!newVal) return if (!newVal) return
console.log("activeKey=", this.activeKey)
// 清除之前的数据 // 清除之前的数据
this.resetDataForInactiveKey() this.resetDataForInactiveKey()
if (newVal !== 4) { if (newVal !== 4) {
this.datePickerMode = "date"
// 并行加载新数据 // 并行加载新数据
Promise.all([ Promise.all([
this.getStationList(), this.getStationList(),
@@ -699,6 +757,9 @@ export default {
}) })
} }
else { else {
console.log("4")
this.datePickerMode = "date"
this.$nextTick(() => { this.$nextTick(() => {
const elementTable = document.getElementsByClassName('content-table-4')[0] const elementTable = document.getElementsByClassName('content-table-4')[0]
if ( elementTable) { if ( elementTable) {
@@ -709,6 +770,16 @@ export default {
} }
}, },
// immediate: true // 添加立即执行 // immediate: true // 添加立即执行
},
datePickerMode: {
handler(newVal) {
if (!newVal) return
if (this.activeKey == 4) {
this.$nextTick(() => {
this.getEGridPeriod()
})
}
}
} }
}, },
mounted() { mounted() {
@@ -717,13 +788,14 @@ export default {
console.log('mounted') console.log('mounted')
// 优先加载第一个页面(activeKey=1)所需的数据 // 优先加载第一个页面(activeKey=1)所需的数据
// this.btnOptionList = this.$getBtns(['导出']) // this.btnOptionList = this.$getBtns(['导出'])
// searchBox 的 onSearch 在初始化的时候也会触发查询
Promise.all([ Promise.all([
this.getStationList() this.getStationList()
]).then(()=>{ ]).then(()=>{
this.getEchartsListForActiveKey(), // this.getEchartsListForActiveKey(),
this.getTableListForActiveKey() // this.getTableListForActiveKey()
this.getStatCharts() // this.getStatCharts()
this.startRealtimeRefresh() this.startRealtimeRefresh()
}) })
@@ -740,6 +812,11 @@ export default {
} }
}, },
onStatTypeChanged(e){
const newValue = e.target.value;
this.datePickerMode = newValue
},
operateForm(type, record = {}) { operateForm(type, record = {}) {
if (type == 'output') { if (type == 'output') {
this.loading.chart=true this.loading.chart=true
@@ -867,7 +944,6 @@ export default {
}, },
async getStationList() { async getStationList() {
console.log('getsStationList')
const params = { const params = {
page_size: 1000, page_size: 1000,
page: 1 page: 1
@@ -901,17 +977,20 @@ export default {
this.getTableListForActiveKey() this.getTableListForActiveKey()
}, },
onSearch(data) { onSearch(data) {
// search组件日期变化
this.paramsDate.start_date = data.time ? data.time[0] : '' this.paramsDate.start_date = data.time ? data.time[0] : ''
this.paramsDate.end_date = data.time ? data.time[1] : '' this.paramsDate.end_date = data.time ? data.time[1] : ''
if (this.activeKey !== 4) { if (this.activeKey !== 4) {
this.tableList[this.activeKey].pageOption.page = 1 this.tableList[this.activeKey].pageOption.page = 1
this.getStationList(), this.getStatCharts(),this.getEchartsListForActiveKey(), this.getTableListForActiveKey() //this.getStationList(),
this.getStatCharts(),this.getEchartsListForActiveKey(), this.getTableListForActiveKey()
} else { } else {
this.getEGridPeriod() this.getEGridPeriod()
} }
}, },
changeStation() { changeStation() {
// search组件场站变化
if (this.activeKey != 4) { if (this.activeKey != 4) {
this.getStatCharts() this.getStatCharts()
this.getEchartsListForActiveKey() this.getEchartsListForActiveKey()
@@ -946,32 +1025,47 @@ export default {
}, },
async getEGridPeriod() { async getEGridPeriod() {
console.log("getEGridPeriod")
const query = { const query = {
dt_start:this.paramsDate.start_date, start_date:this.paramsDate.start_date,
dt_end: this.paramsDate.end_date, end_date: this.paramsDate.end_date,
station_id: this.stationId, station_id: this.stationId,
mode: this.datePickerMode
} }
if (!query.dt_end) { if (!query.end_date) {
const today = new Date(); const today = new Date();
const year = today.getFullYear(); const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0'); // 处理月份:先+1因为getMonth返回0-11再补零到2位 const month = String(today.getMonth() + 1).padStart(2, '0'); // 处理月份:先+1因为getMonth返回0-11再补零到2位
const day = String(today.getDate()).padStart(2, '0'); // 处理日期直接补零到2位 const day = String(today.getDate()).padStart(2, '0'); // 处理日期直接补零到2位
query.dt_end = `${year}-${month}-${day}`; // 拼接成指定格式 query.end_date = `${year}-${month}-${day}`; // 拼接成指定格式
} }
if (!query.dt_start) { if (!query.start_date) {
query.dt_start = query.dt_end; query.start_date = query.end_date;
} }
// try {
// const res = await getReq('/queryEGridPeriod', query)
// if (res.errcode === 0) {
// this.tableData = res.data
// } else {
// throw res
// }
// } catch (error) {
// this.tableData = []
// }
try { try {
const res = await getReq('/queryEGridPeriod', query) const res = await getReq('/queryStatStationMode', query)
if (res.errcode === 0) { if (res.errcode === 0) {
this.tableData = res.data this.tableData = res.data
this.chartData = res.data
} else { } else {
throw res throw res
} }
} catch (error) { }catch (error) {
this.tableData = [] this.tableData = []
this.chartData = []
} }
} }
} }
@@ -1015,7 +1109,7 @@ export default {
.content-table-4 { .content-table-4 {
// overflow: scroll; // overflow: scroll;
width: 100%; width: 100%;
height: calc(100% - 52px); height: calc(70% - 52px);
min-height: 0; min-height: 0;
//overflow: hidden; //overflow: hidden;
@@ -1024,6 +1118,43 @@ export default {
// } // }
} }
} }
/* 选中后的背景色 + 文字色 */
.my-radio-group {
/* 修改默认状态的字体和背景色 */
:deep(.ant-radio-button-wrapper) {
/* 字体设置 */
// font-size: 14px; /* 字体大小 */
// font-weight: 500; /* 字体粗细 */
// font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif; /* 字体类型 */
color: white; /* 字体颜色 */
/* 背景色 */
background-color: #08365c; /* 背景色 - 浅灰/白色调 */
border-color: #12fbff; /* 边框颜色 */
/* 去掉右侧分割线颜色 */
&::before {
background-color: transparent !important;
}
}
/* 选中状态的背景色 */
:deep(.ant-radio-button-wrapper-checked) {
background-color: #1890ff; /* 自定义颜色 */
border-color: #12fbff;
}
// /* 鼠标 hover 效果(可选) */
// :deep(.ant-radio-button-wrapper:not(.ant-radio-button-checked):hover) {
// border-color: #1890ff;
// color:red;
// // color: #1890ff;
// }
}
.main_content { .main_content {
overflow: scroll; overflow: scroll;
height: calc(100% - 40px); height: calc(100% - 40px);

View File

@@ -32,7 +32,8 @@
<span class="linear-text">{{ item.title }}</span> <span class="linear-text">{{ item.title }}</span>
</div> </div>
</div> </div>
<component :is="item.componentId" :prop-key="item.infoKey" :prop-option="compInfo[item.infoKey]" <component
:is="item.componentId" :prop-key="item.infoKey" :prop-option="compInfo[item.infoKey]"
:prop-data="compDataStation[item.infoKey]"> :prop-data="compDataStation[item.infoKey]">
</component> </component>
</div> </div>
@@ -50,6 +51,7 @@ import Pv from '@/components/Home/Pv.vue'
import Alarm from '@/components/Home/Alarm.vue' import Alarm from '@/components/Home/Alarm.vue'
import Map from '@/components/Home/Map.vue' import Map from '@/components/Home/Map.vue'
import MyChartBar from '@/components/Home/MyChartBar.vue' import MyChartBar from '@/components/Home/MyChartBar.vue'
import MyChartLine from '@/components/Home/MyChartLine.vue'
import { getReq, postReq } from '@/request/api' import { getReq, postReq } from '@/request/api'
import { getRunDays, getDateDaysAgo } from '@/utils/dealWithData' import { getRunDays, getDateDaysAgo } from '@/utils/dealWithData'
import { markRaw } from 'vue' import { markRaw } from 'vue'
@@ -80,82 +82,46 @@ export default {
energy: { energy: {
yAxis: ['电量(kWh)'], yAxis: ['电量(kWh)'],
series: [ series: [
{ name: '日充电电量', key: 'storage_elect_in', color: '#22E4FF' }, { name: '日充电电量', key: 'E_in', color: '#0E68E4' },
{ name: '日放电电量', key: 'storage_elect_out', color: '#0E68E4' }, { name: '日放电电量', key: 'E_out', color: '#69b0e7' },
] ]
}, },
pv: { rate: {
yAxis: ['电量(kWh)'], yAxis: ['百分比(%)'],
series: [ series: [
{ name: '日发电电量', key: 'solar_elect_gen', color: '#22E4FF' }, { name: '充放电使用率', key: 'E_rate', color: '#0E68E4', type: "line"},
] ]
}, },
charge: { income: {
yAxis: ['电量(kWh)'], yAxis: ['金额(元)'],
series: [ series: [
{ name: '充电电量', key: 'charge_elect', color: '#22E4FF' }, { name: '充电', key: 'fee_in', color: '#0E68E4' },
] { name: '放电费', key: 'fee_out', color: '#69b0e7' },
}, { name: '收益', key: 'income', color: '#22E4FF' },
stateGrid: {
yAxis: ['电量(kWh)'],
series: [
{ name: '日上网电量', key: 'solar_elect_grid', color: '#22E4FF' },
] ]
} }
}, },
listLeft: [ listLeft: [
{ title: '系统运行统计', class: 'online-status', componentId: markRaw(onLine), infoKey: 'total' }, { title: '系统运行统计', class: 'online-status', componentId: markRaw(onLine), infoKey: 'total' },
{ title: '储能设备', class: 'energy-status', componentId: markRaw(MyChartBar), infoKey: 'energy' }, { title: '储能充放电量', class: 'energy-status', componentId: markRaw(MyChartBar), infoKey: 'energy' },
{ title: '充电设备', class: 'charge-analysis', componentId: markRaw(MyChartBar), infoKey: 'charge' }, { title: '储能充放使用率', class: 'charge-analysis', componentId: markRaw(MyChartLine), infoKey: 'rate' },
{ title: '光伏设备', class: 'work-order', componentId: markRaw(MyChartBar), infoKey: 'pv' }, { title: '储能收益', class: 'work-order', componentId: markRaw(MyChartBar), infoKey: 'income' }
{ title: '电网侧', class: 'work-order', componentId: markRaw(MyChartBar), infoKey: 'stateGrid' },
], ],
listRight: [ listRight: [
{ title: '场站运行统计', class: 'online-status', componentId: markRaw(TotalStation), infoKey: 'totalStation' }, { title: '场站运行统计', class: 'online-status', componentId: markRaw(TotalStation), infoKey: 'totalStation' },
{ title: '储能设备', class: 'energy-status', componentId: markRaw(MyChartBar), infoKey: 'energy' }, { title: '储能充放电量', class: 'energy-status', componentId: markRaw(MyChartBar), infoKey: 'energy' },
{ title: '充电设备', class: 'charge-analysis', componentId: markRaw(MyChartBar), infoKey: 'charge' }, { title: '储能充放使用率', class: 'charge-analysis', componentId: markRaw(MyChartLine), infoKey: 'rate' },
{ title: '光伏设备', class: 'work-order', componentId: markRaw(MyChartBar), infoKey: 'pv' }, { title: '储能收益', class: 'work-order', componentId: markRaw(MyChartBar), infoKey: 'income' }
{ title: '电网侧', class: 'work-order', componentId: markRaw(MyChartBar), infoKey: 'stateGrid' },
], ],
stationList: [], stationList: [],
selectStationId: '', selectStationId: '',
list: [ list: [
{ { title: '系统运行统计', class: 'online-status', componentId: markRaw(onLine), infoKey: 'onLineTotal' },
title: '系统运行统计', { title: '运行分析', class: 'stats-cards', componentId: markRaw(Operational), infoKey: 'operationTotal' },
class: 'online-status', { title: '储能设备', class: 'energy-status', componentId: markRaw(Energy), infoKey: 'energy' },
componentId: markRaw(onLine), { title: '充电设备', class: 'charge-analysis', componentId: markRaw(Charge), infoKey: 'charge' },
infoKey: 'onLineTotal' { title: '光伏设备', class: 'work-order', componentId: markRaw(Pv), infoKey: 'pv' },
}, { title: '告警信息', class: 'alarm-stats', componentId: markRaw(Alarm), infoKey: 'alarm' }
{
title: '运行分析',
class: 'stats-cards',
componentId: markRaw(Operational),
infoKey: 'operationTotal'
},
{
title: '储能设备',
class: 'energy-status',
componentId: markRaw(Energy),
infoKey: 'energy'
},
{
title: '充电设备',
class: 'charge-analysis',
componentId: markRaw(Charge),
infoKey: 'charge'
},
{
title: '光伏设备',
class: 'work-order',
componentId: markRaw(Pv),
infoKey: 'pv'
},
{
title: '告警信息',
class: 'alarm-stats',
componentId: markRaw(Alarm),
infoKey: 'alarm'
}
], ],
sysName: '', sysName: '',
@@ -291,19 +257,17 @@ export default {
query.station_id = curStationId query.station_id = curStationId
} }
//const arr = { 1: 'energy', 2: 'charge', 3: 'pv' } //const arr = { 1: 'energy', 2: 'charge', 3: 'pv' }
const res = await getReq('/queryStatDayList', query) const res = await getReq('/queryStatStationMode', query) // queryStatDayList
if (res.errcode === 0) { if (res.errcode === 0) {
if (curStationId) { if (curStationId) {
this.compDataStation.energy this.compDataStation.energy
= this.compDataStation.charge = this.compDataStation.rate
= this.compDataStation.pv = this.compDataStation.income
= this.compDataStation.stateGrid
= res.data = res.data
} else { } else {
this.compData.energy this.compData.energy
= this.compData.pv = this.compData.rate
= this.compData.stateGrid = this.compData.income
= this.compData.charge
= res.data = res.data
} }
// this.list.forEach((item) => { // this.list.forEach((item) => {
@@ -391,7 +355,7 @@ export default {
-webkit-background-clip: text; -webkit-background-clip: text;
background-clip: text; background-clip: text;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 800;
margin-left: 6px; margin-left: 6px;
} }

View File

@@ -1,6 +1,15 @@
<template> <template>
<div class="alarmLog"> <div class="alarmLog">
<!-- <searchBox :btn-option-list="btnOptionList" @operateForm="operateForm"></searchBox> --> <!-- <searchBox :btn-option-list="btnOptionList" @operateForm="operateForm"></searchBox> -->
<searchBox class="searchBox" ref="searchBox" :search-options="searchOptions" :title-option="{ title: '', info: '' }">
<template #stationSelect="">
<a-select style="width: 200px" :dropdown-match-select-width="false" v-model:value="stationId" allow-clear @change="changeStation">
<a-select-option :value="option.value" v-for="option in stationList" :key="option.value">
{{ option.label }}
</a-select-option>
</a-select>
</template>
</searchBox>
<div class="content-table"> <div class="content-table">
<ComTable <ComTable
@@ -44,12 +53,11 @@ import { getReq, postReq } from '@/request/api.js'
import EditCom from '@/components/EditCom.vue' import EditCom from '@/components/EditCom.vue'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue' import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
import { createVNode } from 'vue' import { createVNode } from 'vue'
import searchBox from '@/components/SearchBox.vue'
export default { export default {
name: '', name: '',
components: { components: { EditCom, searchBox },
EditCom
},
props: {}, props: {},
data() { data() {
return { return {
@@ -61,6 +69,11 @@ export default {
page: 1 page: 1
}, },
btnOptionList: [], btnOptionList: [],
searchOptions: [
{label: '场站选择', type: 'slot', value: [], key: 'station', slotName: 'stationSelect'}
],
stationId: undefined,
stationList: [],
paramsDate: {}, paramsDate: {},
tableData: [] tableData: []
} }
@@ -80,16 +93,42 @@ export default {
mounted() { mounted() {
this.operateList = this.$getBtns(['查看']) this.operateList = this.$getBtns(['查看'])
// this.btnOptionList = this.$getBtns(['新增']) // this.btnOptionList = this.$getBtns(['新增'])
Promise.all([
this.getStationList()
]).then(()=>{
this.getList() this.getList()
})
}, },
methods: { methods: {
// 下拉场站选择
changeStation() {
this.getList()
},
// 查询获取场站列表查询日志列表时stationId可以默认为空查询全部
async getStationList() {
const params = { page_size: 1000, page: 1 }
try {
const res = await getReq('/queryStationList', params)
if (res.errcode === 0) {
this.stationList = res.data.map((item) => {
return { value: item.station_id, label: item.name }
})
} else {
const err = { tip: res.errmsg }
throw err
}
} catch (error) {
//统一处理报错提示
}
},
async getList() { async getList() {
this.$refs.comTable.loading = true this.$refs.comTable.loading = true
const { page, pageSize } = this.pageOption const { page, pageSize } = this.pageOption
const params = { const params = {
station_id: this.stationId,
...this.paramsDate, ...this.paramsDate,
page_size: pageSize, page_size: pageSize,
page page
@@ -196,7 +235,7 @@ export default {
padding: 20px; padding: 20px;
.content-table { .content-table {
height: 100%; height: calc(100% - 75px);
} }
} }
</style> </style>

View File

@@ -1,7 +1,15 @@
<template> <template>
<div class="syslog"> <div class="syslog">
<!-- <searchBox :btn-option-list="btnOptionList" @operateForm="operateForm"></searchBox> --> <!-- <searchBox :btn-option-list="btnOptionList" @operateForm="operateForm"></searchBox> -->
<searchBox class="searchBox" ref="searchBox" :search-options="searchOptions" :title-option="{ title: '', info: '' }">
<template #stationSelect="">
<a-select style="width: 200px" :dropdown-match-select-width="false" v-model:value="stationId" allow-clear @change="changeStation">
<a-select-option :value="option.value" v-for="option in stationList" :key="option.value">
{{ option.label }}
</a-select-option>
</a-select>
</template>
</searchBox>
<div class="content-table"> <div class="content-table">
<ComTable <ComTable
:columns="columns" :columns="columns"
@@ -59,6 +67,11 @@ export default {
page: 1 page: 1
}, },
btnOptionList: [], btnOptionList: [],
searchOptions: [
{label: '场站选择', type: 'slot', value: [], key: 'station', slotName: 'stationSelect'}
],
stationId: undefined,
stationList: [],
paramsDate: {}, paramsDate: {},
tableData: [] tableData: []
} }
@@ -78,16 +91,43 @@ export default {
mounted() { mounted() {
this.operateList = this.$getBtns(['查看']) this.operateList = this.$getBtns(['查看'])
// this.btnOptionList = this.$getBtns(['新增']) // this.btnOptionList = this.$getBtns(['新增'])
// 先获查询取场站列表,然后查询日志列表
Promise.all([
this.getStationList()
]).then(()=>{
this.getList() this.getList()
})
}, },
methods: { methods: {
// 下拉场站选择
changeStation() {
this.getList()
},
// 查询获取场站列表查询日志列表时stationId可以默认为空查询全部
async getStationList() {
const params = { page_size: 1000, page: 1 }
try {
const res = await getReq('/queryStationList', params)
if (res.errcode === 0) {
this.stationList = res.data.map((item) => {
return { value: item.station_id, label: item.name }
})
} else {
const err = { tip: res.errmsg }
throw err
}
} catch (error) {
//统一处理报错提示
}
},
async getList() { async getList() {
this.$refs.comTable.loading = true this.$refs.comTable.loading = true
const { page, pageSize } = this.pageOption const { page, pageSize } = this.pageOption
const params = { const params = {
station_id: this.stationId ? this.stationId : "",
...this.paramsDate, ...this.paramsDate,
page_size: pageSize, page_size: pageSize,
page page
@@ -179,7 +219,7 @@ export default {
padding: 20px; padding: 20px;
.content-table { .content-table {
height: 100%; height: calc(100% - 75px);
} }
} }
</style> </style>