mirror of
https://gitee.com/js-yhsec/energy_storage.git
synced 2026-05-27 18:59:26 +08:00
feat(web): 新增预测管理和策略表单功能
- 添加预测管理页面和相关组件 - 实现策略表单组件,支持创建和编辑策略 - 优化表格组件,增加分页和数据加载功能 - 调整视频监控组件布局 - 修复部分组件样式问题
This commit is contained in:
BIN
doc/.~充站控系统-HTTP管理接口.docx
Normal file
BIN
doc/.~充站控系统-HTTP管理接口.docx
Normal file
Binary file not shown.
@@ -26,5 +26,6 @@ const locale = ref(zhCN)
|
||||
right: 0;
|
||||
min-width: 1440px;
|
||||
min-height: 900px;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -39,13 +39,13 @@
|
||||
:data-source="record.currentLimitList"
|
||||
:pagination="false"
|
||||
>
|
||||
<template #bodyCell="{ column, record_ }">
|
||||
<!-- <template #bodyCell="{ column, record_ }">
|
||||
<template v-if="column.key === 'type'">
|
||||
<span>
|
||||
{{ getType(record_.type) }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</template> -->
|
||||
</a-table>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
|
||||
<div class="top" v-if="searchOptions.length">
|
||||
<div class="top-left">
|
||||
<template v-for="item in searchOptions" :key="item.key">
|
||||
@@ -9,9 +8,10 @@
|
||||
<span class="label"> {{ item.label }}</span>
|
||||
<div class="select" v-if="item.type == 'select'">
|
||||
<a-select
|
||||
:dropdown-match-select-width="false" v-model:value="formData[item.key]"
|
||||
:dropdown-match-select-width="false"
|
||||
v-model:value="formData[item.key]"
|
||||
allow-clear
|
||||
:max-tag-count='2'
|
||||
:max-tag-count="2"
|
||||
:placeholder="item.label"
|
||||
:mode="item.mode ? item.mode : 'combobox'"
|
||||
>
|
||||
@@ -70,12 +70,11 @@
|
||||
<div style="display: flex" v-if="btnOptionList.length">
|
||||
<div v-for="(item, i) in btnOptionList" :key="i" class="button">
|
||||
<a-button
|
||||
:class="'btn-' + item.type"
|
||||
:class="'btn-' + item.type"
|
||||
type="primary"
|
||||
@click="handelClick(item.type)"
|
||||
:disabled="item.disabled ? item.disabled : false"
|
||||
>
|
||||
|
||||
{{ item.label }}
|
||||
</a-button>
|
||||
</div>
|
||||
@@ -188,7 +187,7 @@ input:-internal-autofill-selected {
|
||||
color: var(--theme-text-default) !important;
|
||||
}
|
||||
.search {
|
||||
color:#fff;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
@@ -232,12 +231,12 @@ input:-internal-autofill-selected {
|
||||
.date-picker {
|
||||
width: 360px;
|
||||
|
||||
.ant-picker{
|
||||
background: transparent;
|
||||
border: 1px solid #00B9D0;
|
||||
.ant-picker-input >input{
|
||||
color: #fff!important;
|
||||
}
|
||||
.ant-picker {
|
||||
background: transparent;
|
||||
border: 1px solid #00b9d0;
|
||||
.ant-picker-input > input {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,19 +322,13 @@ input:-internal-autofill-selected {
|
||||
}
|
||||
.bottom {
|
||||
display: flex;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.button{
|
||||
.button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="device">
|
||||
<div class="device-item" v-for="item in 8" :key="item">
|
||||
<div class="device-item" v-for="item in deviceList" :key="item">
|
||||
<div class="item-header">
|
||||
<div style="display: flex;width: 50%;">
|
||||
<div style="display: flex; width: 50%">
|
||||
<div class="icon-bg"></div>
|
||||
<div class="title">
|
||||
<span class="number">521245786665412</span>
|
||||
@@ -29,12 +29,18 @@
|
||||
<div class="item-content">
|
||||
<div v-for="info in chunengInfo" :key="info.key">
|
||||
<span class="text">{{ info.label }}:</span>
|
||||
<a-button v-if="info.key === 'realTimeData'" type="primary" size="small" @click="openModal">查看</a-button>
|
||||
<span v-else class="value" >{{ info.value }}</span>
|
||||
<a-button
|
||||
v-if="info.key === 'realTimeData'"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="openModal"
|
||||
>查看</a-button
|
||||
>
|
||||
<span v-else class="value">{{ info.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-modal v-model:open="modalOpen" @ok="handleOk" width="800px">
|
||||
<a-modal v-model:open="modalOpen" @ok="handleOk" width="800px">
|
||||
<!-- <p>Some contents...</p>
|
||||
<p>Some contents...</p>
|
||||
<p>Some contents...</p> -->
|
||||
@@ -43,16 +49,27 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { postReq, getReq } from '@/request/api'
|
||||
export default {
|
||||
name: '',
|
||||
components: {},
|
||||
props: {},
|
||||
props: {
|
||||
stationId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
systemType: {
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
modalOpen:false,
|
||||
modalOpen: false,
|
||||
deviceList: [],
|
||||
chunengInfo: [
|
||||
{label:'运行模式',key:'operationMode',value:'并网运行'},
|
||||
{label:'电池储能容量',key:'batteryCapacity',value:'100kWh'},
|
||||
{ label: '运行模式', key: 'operationMode', value: '并网运行' },
|
||||
{ label: '电池储能容量', key: 'batteryCapacity', value: '100kWh' },
|
||||
{ label: '实时电压', key: 'voltage', value: '232.5V' },
|
||||
{ label: '功率因数', key: 'powerFactor', value: '0.95' },
|
||||
{ label: '实时电流', key: 'current', value: '0.01A' },
|
||||
@@ -62,26 +79,48 @@ export default {
|
||||
{ label: '实时数据', key: 'realTimeData', value: '0.01kWh' },
|
||||
{ label: '额定功率', key: 'ratedPower', value: '0.01kW' },
|
||||
{ label: '冷却方式', key: 'coolingMethod', value: '风冷' }
|
||||
|
||||
],
|
||||
// guangfuInfo: [
|
||||
// { label: '实时电压', key: 'voltage', value: '232.5V' },
|
||||
// { label: '额定电压', key: 'ratedVoltage', value: '232.5V' },
|
||||
// { label: '实时电流', key: 'current', value: '0.01A' },
|
||||
// { label: '额定电流', key: 'ratedCurrent', value: '0.01A' },
|
||||
// { label: '实时功率', key: 'power', value: '0.01kW' },
|
||||
// { label: '额定功率', key: 'ratedPower', value: '0.01kW' },
|
||||
// { label: '实时数据', key: 'realTimeData', value: '0.01kWh' }
|
||||
// ]
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
openModal(){
|
||||
this.modalOpen=true;
|
||||
watch: {
|
||||
// 监听父组件数据变化
|
||||
stationId(newVal) {
|
||||
if (newVal) {
|
||||
this.getDeviceList()
|
||||
}
|
||||
},
|
||||
handleOk(){
|
||||
this.modalOpen=false;
|
||||
systemType(newVal, oldVal) {
|
||||
if (newVal !== oldVal) {
|
||||
this.getDeviceList()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getDeviceList()
|
||||
},
|
||||
methods: {
|
||||
async getDeviceList() {
|
||||
const data = {
|
||||
category: this.systemType,
|
||||
'station_id': this.stationId,
|
||||
page: 0,
|
||||
'page_size': 1000
|
||||
}
|
||||
try {
|
||||
const res = await getReq('/queryDeviceList', data)
|
||||
|
||||
console.log(res)
|
||||
this.deviceList = res.data
|
||||
// this.selectStation=this.stations[0]['station_id']
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
},
|
||||
openModal() {
|
||||
this.modalOpen = true
|
||||
},
|
||||
handleOk() {
|
||||
this.modalOpen = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,35 +21,26 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="environment">
|
||||
<div class="item">
|
||||
<div class="title">环境温湿度信息</div>
|
||||
<img src="@/assets/images/titleLine.png" alt="" width="100%" />
|
||||
<div class="content">
|
||||
<div class="header">
|
||||
<div>点位</div>
|
||||
<div>温度</div>
|
||||
<div>湿度</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div>#1</div>
|
||||
<div>20 ℃</div>
|
||||
<div>20%</div>
|
||||
</div>
|
||||
<div class="tab-header">
|
||||
<div v-for="item in tabList" :key="item.key" class="tab">
|
||||
<span
|
||||
:class="[activeTab == item.key ? 'actived' : 'uactived']"
|
||||
@click="activeTab = item.key"
|
||||
>{{ item.name }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item" style="margin-top: 40px">
|
||||
<div class="title">消防信息</div>
|
||||
<img src="@/assets/images/titleLine.png" alt="" width="100%" />
|
||||
<div class="content">
|
||||
<div class="header">
|
||||
<div>点位</div>
|
||||
<div>烟感状态</div>
|
||||
</div>
|
||||
<div class="row" v-for="value in 6" :key="value">
|
||||
<div>#{{ value }}</div>
|
||||
<div>xxx</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-content">
|
||||
<ComTable
|
||||
:columns="columns"
|
||||
:table-data="tableData"
|
||||
@handlePagesizeChange="handlePagesizeChange"
|
||||
ref="comTable"
|
||||
:table-option="tableOption"
|
||||
:page-option="pageOption"
|
||||
:table-h="tableH"
|
||||
>
|
||||
</ComTable>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -60,7 +51,51 @@ export default {
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {}
|
||||
return {
|
||||
activeTab: '0',
|
||||
tabList: [
|
||||
{
|
||||
key: '0',
|
||||
name: '环境温湿度信息'
|
||||
},
|
||||
{
|
||||
key: '1',
|
||||
name: '安防信息'
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: '空调信息'
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
name: '冷机信息'
|
||||
}
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
title: '点位',
|
||||
dataIndex: 'policyId',
|
||||
key: 'policyId',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '温度',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '湿度',
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
ellipsis: true
|
||||
}
|
||||
],
|
||||
tableOption: {
|
||||
select: false,
|
||||
page: false
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {}
|
||||
@@ -69,11 +104,11 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.videos {
|
||||
width: calc(100% - 240px);
|
||||
width: 60%;
|
||||
margin-left: 20px;
|
||||
display: grid;
|
||||
grid-gap: 20px;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
overflow-y: auto;
|
||||
.video-item {
|
||||
// width: 410px;
|
||||
@@ -95,9 +130,10 @@ export default {
|
||||
}
|
||||
}
|
||||
.environment {
|
||||
width: 220px;
|
||||
margin-left: 10px;
|
||||
width: calc(40% - 20px);
|
||||
margin-left: 20px;
|
||||
color: #fff;
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
@@ -125,5 +161,39 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
.tab-header {
|
||||
display: flex;
|
||||
|
||||
.tab {
|
||||
& > span {
|
||||
font-size: 14px;
|
||||
margin-right: 15px;
|
||||
display: inline-block;
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
border: 1px solid $tab-border;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
.actived {
|
||||
color: #ffffff;
|
||||
|
||||
background-color: $green;
|
||||
}
|
||||
.uactived {
|
||||
color: #a6b8dd;
|
||||
background-color: $bg2-color;
|
||||
}
|
||||
}
|
||||
.table-content {
|
||||
margin-top: 20px;
|
||||
:deep(.ant-table) {
|
||||
border-radius: 10px 10px 0 0 !important;
|
||||
overflow: hidden; /* 确保圆角生效 */
|
||||
}
|
||||
:deep(.ant-table-body) {
|
||||
border-radius: 0px 0px 10px 10px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
187
web/src/components/predict/predictEcharts.vue
Normal file
187
web/src/components/predict/predictEcharts.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<div class="echarts">
|
||||
<div class="chart-container">
|
||||
<div class="content-header">
|
||||
<div class="verline"></div>
|
||||
<span>{{ chartOptions.title }}</span>
|
||||
</div>
|
||||
<div ref="chartContainer" class="echarts-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { postReq } from '@/request/api'
|
||||
export default {
|
||||
name: 'PredictEcharts',
|
||||
props: {
|
||||
chartOptions: {
|
||||
type: Object,
|
||||
default: () => {}, // 默认空对象
|
||||
required: false // 非必须
|
||||
},
|
||||
chartData: {
|
||||
type: Array,
|
||||
default: () => ([]), // 默认空对象
|
||||
required: false // 非必须
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chartInstances: [] // 存储 ECharts 实例
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
|
||||
this.$nextTick(() => {
|
||||
// 确保 DOM 完全渲染
|
||||
this.initCharts()
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
})
|
||||
},
|
||||
beforeUnmount() {
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
this.chartInstances.forEach((chart) => chart && chart.dispose())
|
||||
},
|
||||
methods: {
|
||||
initCharts() {
|
||||
// this.chartOptions.forEach((option, index) => {
|
||||
const {title,infoKeys,dataKey,type,smooth}=this.chartOptions
|
||||
|
||||
const dom = this.$refs.chartContainer
|
||||
if (!dom) return
|
||||
|
||||
const chart = this.$echarts.init(dom)
|
||||
this.chartInstances.push(chart) // 存储实例
|
||||
|
||||
// 设置图表配置
|
||||
chart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
top: 20,
|
||||
textStyle: {
|
||||
color: '#fff'
|
||||
},
|
||||
data: infoKeys.map((info) => info.label)
|
||||
},
|
||||
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '3%',
|
||||
bottom: '1%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: this.chartData.map((item) => item.date),
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#fff' // x轴线颜色
|
||||
}
|
||||
},
|
||||
|
||||
axisLabel: {
|
||||
color: '#fff'
|
||||
},
|
||||
|
||||
axisTick: {
|
||||
lineStyle: {
|
||||
color: '#fff' // x 轴刻度线颜色
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#fff' // y轴线颜色
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#fff'
|
||||
},
|
||||
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#A6B8DD', // 网格线颜色,
|
||||
type: 'dashed'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: infoKeys.map((info, i) => {
|
||||
return {
|
||||
name: info.label,
|
||||
smooth: smooth || false,
|
||||
type: type,
|
||||
data: this.chartData.map((item) => item[info.key]),
|
||||
...info.seriesOptions,
|
||||
}
|
||||
})
|
||||
})
|
||||
// })
|
||||
},
|
||||
|
||||
handleResize() {
|
||||
this.chartInstances.forEach((chart) => chart && chart.resize())
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.echarts {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
& > div {
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
|
||||
|
||||
.content-header {
|
||||
height: 20px;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 3%;
|
||||
.verline {
|
||||
margin-right: 10px;
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgba(0, 230, 172, 1) 0%,
|
||||
rgba(0, 210, 255, 1) 98.78%,
|
||||
rgba(0, 210, 255, 1) 100%
|
||||
),
|
||||
rgba(1, 223, 239, 1);
|
||||
width: 4px;
|
||||
height: 20px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
.echarts-content{
|
||||
height: calc(100% - 20px);
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
156
web/src/components/system/policyForm copy.vue
Normal file
156
web/src/components/system/policyForm copy.vue
Normal file
@@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<div class="policyForm">
|
||||
<div class="title">
|
||||
<div>基础信息</div>
|
||||
<img src="@/assets/images/titleLine.png" alt="" />
|
||||
</div>
|
||||
<a-form
|
||||
:model="formState"
|
||||
layout="inline"
|
||||
label-align="right"
|
||||
:label-col="{ style: { width: '100px' } }"
|
||||
>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="名称" :label-col="{ span: 3 }" :wrapper-col="{ span: 18}">
|
||||
<a-input v-model:value="formState.name" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="类型" :label-col="{ span: 3 }" :wrapper-col="{ span: 18 }">
|
||||
<a-select v-model:value="formState.region" placeholder="please select your zone">
|
||||
<a-select-option value="shanghai">Zone one</a-select-option>
|
||||
<a-select-option value="beijing">Zone two</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="6">
|
||||
<a-form-item label="低谷电价" :label-col="{ span: 12 }" :wrapper-col="{ span: 12 }">
|
||||
<a-input v-model:value="formState.name" suffix="元/kWh" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item label="平段电价" :label-col="{ span: 12 }" :wrapper-col="{ span: 12 }">
|
||||
<a-input v-model:value="formState.name" suffix="元/kWh" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item label="高峰电价" :label-col="{ span: 12 }" :wrapper-col="{ span: 12 }">
|
||||
<a-input v-model:value="formState.name" suffix="元/kWh" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item label="尖峰电价" :label-col="{ span: 12 }" :wrapper-col="{ span: 12 }">
|
||||
<a-input v-model:value="formState.name" suffix="元/kWh" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<!-- <a-row :gutter="24">
|
||||
<a-col :span="24">
|
||||
<a-form-item label="时段表">
|
||||
<a-radio-group v-model:value="formState.resource">
|
||||
<a-radio value="1">Sponsor</a-radio>
|
||||
<a-radio value="2">Venue</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="24">
|
||||
<a-form-item label="充放策略">
|
||||
<a-radio-group v-model:value="formState.resource">
|
||||
<a-radio value="1">一充一放</a-radio>
|
||||
<a-radio value="2">两充两放</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="24">
|
||||
<a-form-item label="充放策略"> 休息休息休息休息、 </a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="策略描述">
|
||||
<a-textarea v-model:value="formState.desc" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="是否启用">
|
||||
<a-switch v-model:checked="formState.delivery" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row> -->
|
||||
</a-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { styleProviderProps } from 'ant-design-vue/es/_util/cssinjs/StyleContext'
|
||||
|
||||
export default {
|
||||
name: '',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
formState: {
|
||||
name: '',
|
||||
delivery: false,
|
||||
type: [],
|
||||
resource: '',
|
||||
desc: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.policyForm {
|
||||
color: #fff;
|
||||
.title {
|
||||
display: flex;
|
||||
font-weight: 700;
|
||||
flex-direction: column;
|
||||
|
||||
img {
|
||||
width: 232px;
|
||||
height: 6px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
.ant-form {
|
||||
}
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin-inline-end: 0 !important;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.ant-form {
|
||||
.ant-form-item-label > label {
|
||||
color: #fff;
|
||||
}
|
||||
:deep(.ant-row) {
|
||||
width: 100%;
|
||||
}
|
||||
.ant-input,
|
||||
.ant-select,
|
||||
.ant-input-affix-wrapper {
|
||||
// max-width: 240px;
|
||||
// min-width: 120px;
|
||||
}
|
||||
textarea{
|
||||
.ant-input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
227
web/src/components/system/policyForm.vue
Normal file
227
web/src/components/system/policyForm.vue
Normal file
@@ -0,0 +1,227 @@
|
||||
<template>
|
||||
<div class="policyForm">
|
||||
<div class="title">
|
||||
<div>基础信息</div>
|
||||
<img src="@/assets/images/titleLine.png" alt="" />
|
||||
</div>
|
||||
<a-form
|
||||
:model="formState"
|
||||
layout="inline"
|
||||
label-align="left"
|
||||
:label-col="{ style: { width: '85px' } }"
|
||||
>
|
||||
<a-form-item label="名称" class="col2">
|
||||
<a-input v-model:value="formState.name" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="类型" class="col2">
|
||||
<a-select v-model:value="formState.type" placeholder="">
|
||||
<a-select-option v-for="item in policyTypes" :value="item.value">{{
|
||||
item.label
|
||||
}}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="低谷电价" class="col4">
|
||||
<a-input v-model:value="formState.name" suffix="元/kWh" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="平段电价" class="col4">
|
||||
<a-input v-model:value="formState.name" suffix="元/kWh" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="高峰电价" class="col4">
|
||||
<a-input v-model:value="formState.name" suffix="元/kWh" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="尖峰电价" class="col4">
|
||||
<a-input v-model:value="formState.name" suffix="元/kWh" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="时段表" class="col1">
|
||||
<a-table :columns="columns" :data-source="data" size="small">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<span>
|
||||
<a @click="edit(record.key)">操作</a>
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-form-item>
|
||||
<a-form-item label="充放策略" class="col1">
|
||||
<a-radio-group v-model:value="formState.resource">
|
||||
<a-radio value="1">一充一放</a-radio>
|
||||
<a-radio value="2">两充两放</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="" class="col1">
|
||||
<div class="charge">
|
||||
<div class="box">
|
||||
<span>第一次充放过程</span>
|
||||
<a-form
|
||||
:model="formState"
|
||||
layout="inline"
|
||||
label-align="left"
|
||||
:label-col="{ style: { width: '85px' } }"
|
||||
>
|
||||
<a-form-item label="充电时间" class="col2">
|
||||
<a-time-range-picker v-model:value="formState.name" format="HH:mm" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="放电时间" class="col2">
|
||||
<a-select v-model:value="formState.type" placeholder="">
|
||||
<a-select-option v-for="item in policyTypes" :value="item.value">{{
|
||||
item.label
|
||||
}}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="充电功率" class="col2">
|
||||
<a-radio-group v-model:value="formState.resource">
|
||||
<a-radio value="1">自动</a-radio>
|
||||
<a-radio value="2">自定义</a-radio>
|
||||
<a-input style="width: 60px"></a-input>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="放电功率" class="col2">
|
||||
<a-radio-group v-model:value="formState.resource">
|
||||
<a-radio value="1">自动</a-radio>
|
||||
<a-radio value="2">自定义</a-radio>
|
||||
<a-input style="width: 60px"></a-input>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
<div class="box">222</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="策略描述" class="col2">
|
||||
<a-textarea v-model:value="formState.desc" />
|
||||
</a-form-item>
|
||||
<a-form-item label="是否启用" class="col2">
|
||||
<a-switch v-model:checked="formState.delivery" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { policyTypes } from '@/utils/config'
|
||||
export default {
|
||||
name: '',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
policyTypes,
|
||||
formState: {
|
||||
name: '',
|
||||
delivery: false,
|
||||
type: [],
|
||||
resource: '',
|
||||
desc: ''
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
title: '月份',
|
||||
dataIndex: 'month',
|
||||
key: 'month'
|
||||
},
|
||||
{
|
||||
title: '开始时间',
|
||||
dataIndex: 'startTime',
|
||||
key: 'startTime'
|
||||
},
|
||||
{
|
||||
title: '时段类型',
|
||||
dataIndex: 'type',
|
||||
key: 'type'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
key: 'action'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.policyForm {
|
||||
color: #fff;
|
||||
.title {
|
||||
display: flex;
|
||||
font-weight: 700;
|
||||
flex-direction: column;
|
||||
|
||||
img {
|
||||
width: 232px;
|
||||
height: 6px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-form {
|
||||
.charge {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 10px;
|
||||
.box {
|
||||
border: 1px solid $table-border;
|
||||
margin-left: 10px;
|
||||
border-radius: 10px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-form-item {
|
||||
margin-inline-end: 0 !important;
|
||||
margin-top: 15px;
|
||||
:deep(.ant-form-item-label) {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
.ant-form {
|
||||
.ant-form-item-label {
|
||||
> label {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-row) {
|
||||
width: 100%;
|
||||
}
|
||||
input,
|
||||
.ant-picker,
|
||||
.ant-select,
|
||||
.ant-input-affix-wrapper {
|
||||
width: 150px;
|
||||
}
|
||||
textarea {
|
||||
.ant-input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.col2 {
|
||||
width: 50%;
|
||||
}
|
||||
.col4 {
|
||||
width: 25%;
|
||||
}
|
||||
.col1 {
|
||||
width: 100%;
|
||||
:deep(textarea.ant-input) {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.ant-form-item-row){
|
||||
// border: 1px solid red;
|
||||
}
|
||||
</style>
|
||||
@@ -9,8 +9,14 @@ import '@/style/index.scss'
|
||||
// import '@/assets/iconfont/iconfont.css'
|
||||
import * as echarts from 'echarts'
|
||||
import VueTianditu from 'vue-tianditu'
|
||||
import SearchBox from '@/components/SearchBox.vue'
|
||||
import ComTable from '@/components/ComTable.vue'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.component('SearchBox', SearchBox)
|
||||
app.component('ComTable', ComTable)
|
||||
|
||||
app.config.globalProperties.$echarts = echarts // 挂载到全局属性
|
||||
|
||||
app.use(store).use(router).use(Antd).use(VueTianditu).mount('#app')
|
||||
|
||||
@@ -1,16 +1,26 @@
|
||||
import request from "@/request/index.js";
|
||||
export function postReq(data, url) {
|
||||
import request from '@/request/index.js'
|
||||
import qs from 'qs'
|
||||
export function postReq(url, data) {
|
||||
return request({
|
||||
method: "post",
|
||||
method: 'post',
|
||||
url,
|
||||
data,
|
||||
});
|
||||
data: {
|
||||
...data,
|
||||
token: localStorage.getItem('token')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getReq(data, url) {
|
||||
// const query = qs.stringify(data, { indices: false })
|
||||
export function getReq(url, data) {
|
||||
const query = qs.stringify(
|
||||
{
|
||||
...data,
|
||||
token: localStorage.getItem('token')
|
||||
},
|
||||
{ indices: false }
|
||||
)
|
||||
return request({
|
||||
method: "get",
|
||||
url: url + "?" + data,
|
||||
});
|
||||
method: 'get',
|
||||
url: url + '?' + query
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
import axios from "axios";
|
||||
import axios from 'axios'
|
||||
// import openNotification from "../utils/notification";
|
||||
// let { config } = window;
|
||||
// let { baseUrl } = config;
|
||||
|
||||
const service = axios.create({
|
||||
// baseURL: baseUrl,
|
||||
baseURL: "",
|
||||
timeout: 120000,
|
||||
});
|
||||
baseURL: '/api',
|
||||
timeout: 120000
|
||||
})
|
||||
|
||||
service.interceptors.request.use((config) => {
|
||||
const webConfig = config;
|
||||
// if (!["/user/login", "/config/getConfig"].includes(config.url)) {
|
||||
// if (localStorage.getItem("token")) {
|
||||
// webConfig.headers = {
|
||||
// Authorization: localStorage.getItem("token"),
|
||||
// };
|
||||
const webConfig = config
|
||||
// if (!['/login'].includes(config.url)) {
|
||||
// if (localStorage.getItem('token')) {
|
||||
// webConfig.headers = {
|
||||
// token: localStorage.getItem('token')
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
return webConfig;
|
||||
});
|
||||
return webConfig
|
||||
})
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
// 排除以下接口的错误提示
|
||||
const { url } = response.config;
|
||||
const urls = ["/light/", "/serve/delete", "/user/checkRandom"];
|
||||
const { url } = response.config
|
||||
const urls = ['/light/', '/serve/delete', '/user/checkRandom']
|
||||
const urlFlag = urls.map((item) => {
|
||||
return url.includes(item);
|
||||
});
|
||||
return url.includes(item)
|
||||
})
|
||||
|
||||
const res = response.data;
|
||||
const res = response.data
|
||||
|
||||
if (res.code !== 200) {
|
||||
if (res.code == 401 || res.tip == "校验token过期") {
|
||||
if (res.code == 401 || res.tip == '校验token过期') {
|
||||
setTimeout(() => {
|
||||
window.$wujie?.props.jump({ path: "/login" });
|
||||
}, 1000);
|
||||
window.$wujie?.props.jump({ path: '/login' })
|
||||
}, 1000)
|
||||
} else if (urlFlag.every((item) => item === false)) {
|
||||
// openNotification({
|
||||
// status: "error",
|
||||
@@ -44,18 +44,18 @@ service.interceptors.response.use(
|
||||
// });
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return res
|
||||
},
|
||||
(error) => {
|
||||
// console.log(error, 'error 此处添加监控超时处理')
|
||||
if (
|
||||
error.name === "AxiosError" &&
|
||||
error.message === "timeout of 120000ms exceeded" &&
|
||||
error.code === "ECONNABORTED"
|
||||
error.name === 'AxiosError' &&
|
||||
error.message === 'timeout of 120000ms exceeded' &&
|
||||
error.code === 'ECONNABORTED'
|
||||
) {
|
||||
return error;
|
||||
return error
|
||||
}
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
export default service;
|
||||
export default service
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
export const routes = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: '/main/Home'
|
||||
},
|
||||
// {
|
||||
// path: '/',
|
||||
// redirect: '/main/Home'
|
||||
// },
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: () => import(/* webpackChunkName: "login" */ '@/views/LoginView.vue')
|
||||
},
|
||||
{
|
||||
path: '/main',
|
||||
name: 'main',
|
||||
redirect: '/main/Home',
|
||||
path: '/',
|
||||
name: '/',
|
||||
redirect: '/Home',
|
||||
component: () => import(/* webpackChunkName: "main" */ '@/views/MainView.vue'),
|
||||
children: [
|
||||
{
|
||||
@@ -26,6 +26,12 @@ export const routes = [
|
||||
title: '运行监控',
|
||||
component: () => import(/* webpackChunkName: "monitor" */ '@/views/monitor.vue')
|
||||
},
|
||||
{
|
||||
path: 'predict',
|
||||
name: 'predict',
|
||||
title: '预测管理',
|
||||
component: () => import(/* webpackChunkName: "predict" */ '@/views/predict.vue')
|
||||
},
|
||||
{
|
||||
path: 'statisticalAnalysis',
|
||||
name: 'statisticalAnalysis',
|
||||
@@ -35,7 +41,7 @@ export const routes = [
|
||||
{
|
||||
path: 'system',
|
||||
name: 'system',
|
||||
redirect: '/system/policy',
|
||||
redirect: '/system/user',
|
||||
component: () => import(/* webpackChunkName: "system" */ '@/views/system/index.vue'),
|
||||
children: [
|
||||
{
|
||||
|
||||
@@ -1,49 +1,134 @@
|
||||
$border-color: #12fbff;
|
||||
$btn-confirm: #1C918A;
|
||||
$btn-del:#D43030;
|
||||
//级联器样式
|
||||
$btn-confirm: #1c918a;
|
||||
$btn-del: #d43030;
|
||||
$btn-edit: #ff8d1a;
|
||||
$bg1-color: #052f4d;
|
||||
$bg2-color: #2169c31f;
|
||||
$bg3-color: #00d2ff1f;
|
||||
|
||||
$text-color: #a6b8dd;
|
||||
|
||||
$green: #27a188;
|
||||
$tab-border: #1489c0;
|
||||
|
||||
$table-border: #1c797a;
|
||||
$table-bg: #072e4a;
|
||||
$page-border: #cad2dd;
|
||||
//级联器样式,下拉选择器样式输入框等。。。
|
||||
.ant-select,
|
||||
.ant-cascader {
|
||||
.ant-select-selector {
|
||||
background: none !important;
|
||||
border: 1px solid $border-color !important;
|
||||
color: #fff;
|
||||
}
|
||||
.ant-select-arrow {
|
||||
color: $border-color;
|
||||
}
|
||||
.ant-select-selection-placeholder{
|
||||
.ant-select-selection-placeholder {
|
||||
color: #ffffff3b;
|
||||
}
|
||||
}
|
||||
.ant-input,
|
||||
.ant-input-affix-wrapper,
|
||||
.ant-picker
|
||||
{
|
||||
background: none !important;
|
||||
border: 1px solid $border-color !important;
|
||||
color: #fff;
|
||||
}
|
||||
:deep(.ant-picker){
|
||||
.ant-picker-input >input,.ant-picker-separator{
|
||||
color: #fff !important;
|
||||
}
|
||||
.ant-picker-input::placeholder{
|
||||
color: #ffffff3b !important;
|
||||
}
|
||||
}
|
||||
.ant-input-affix-wrapper {
|
||||
.ant-input {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
.ant-radio-wrapper {
|
||||
color: #fff;
|
||||
}
|
||||
//表单
|
||||
.ant-form {
|
||||
.ant-form-item-label > label {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
//按钮样式
|
||||
// .ant-btn{
|
||||
// padding: 4px 8px;
|
||||
// }
|
||||
.ant-btn-primary{
|
||||
.ant-btn-primary {
|
||||
background: $btn-confirm;
|
||||
&:hover {
|
||||
background: $btn-confirm;
|
||||
&:hover{
|
||||
background: $btn-confirm;
|
||||
opacity: 0.8;
|
||||
}
|
||||
&:active{
|
||||
background: #0f6f6a;
|
||||
|
||||
}
|
||||
opacity: 0.8;
|
||||
}
|
||||
&:active {
|
||||
background: #0f6f6a;
|
||||
}
|
||||
}
|
||||
.btn-del{
|
||||
.btn-del {
|
||||
background: $btn-del;
|
||||
&:hover{
|
||||
background: $btn-del;
|
||||
opacity: 0.8;
|
||||
}
|
||||
&:active{
|
||||
background: $btn-del;
|
||||
|
||||
}
|
||||
&:hover {
|
||||
background: $btn-del;
|
||||
opacity: 0.8;
|
||||
}
|
||||
&:active {
|
||||
background: $btn-del;
|
||||
}
|
||||
}
|
||||
.btn-edit {
|
||||
background: $btn-edit;
|
||||
&:hover {
|
||||
background: $btn-edit;
|
||||
opacity: 0.8;
|
||||
}
|
||||
&:active {
|
||||
background: $btn-edit;
|
||||
}
|
||||
}
|
||||
//modal样式
|
||||
.ant-modal .ant-modal-content{
|
||||
background-image: url('@/assets/images/modalBg.png');
|
||||
background-size: 100% 100%;
|
||||
background-color: #ffffff00 !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
.ant-modal .ant-modal-content {
|
||||
background-image: url('@/assets/images/modalBg.png');
|
||||
background-size: 100% 100%;
|
||||
background-color: #ffffff00 !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
.ant-modal .ant-modal-footer {
|
||||
text-align: center;
|
||||
}
|
||||
//表单中的表格样式
|
||||
.ant-form{
|
||||
.ant-table-thead {
|
||||
background: rgba(30, 85, 95, 1) !important;
|
||||
}
|
||||
:deep(.ant-table-thead > tr > th) {
|
||||
border-inline: 1px solid transparent !important;
|
||||
background: transparent;
|
||||
color: #fff !important;
|
||||
border-bottom: none !important; /* 可选:去除底部边框 */
|
||||
}
|
||||
:deep(.ant-table-tbody){
|
||||
color: #fff;
|
||||
background: $table-bg ;
|
||||
border: 1px solid $table-border !important;
|
||||
border-radius: 0px 0px 20px 20px;
|
||||
|
||||
}
|
||||
:deep(.ant-table-wrapper .ant-table-tbody>tr.ant-table-placeholder:hover>td){
|
||||
background: transparent !important;
|
||||
}
|
||||
:deep(.ant-empty-description){
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,39 +1,14 @@
|
||||
const copyRight =
|
||||
'Copyright © 2016-2024 Jiangsu YuHong.All Rights Reserved.江苏禹弘科技有限公司 版权所有'
|
||||
const companyName1 = '江苏禹弘科技有限公司'
|
||||
const copyRight1 = 'Copyright © 2016 - 2024'
|
||||
const themeColor = {
|
||||
'--theme-bg-default': { light: '#fff', dark: '#111111' },
|
||||
'--theme-bg': { light: '#eceff4', dark: '#2c2c2c' },
|
||||
'--theme-bg1': { light: '#065758', dark: '#065758' },
|
||||
'--theme-bg2': { light: '#0657584d', dark: '#CDDDDE' },
|
||||
'--theme-bg3': { light: '#00968826', dark: '#00968826' },
|
||||
'--theme-bg4': { light: 'rgba(6, 87, 88, 0.75)', dark: 'rgba(6, 87, 88, 0.75)' },
|
||||
|
||||
// 字体颜色
|
||||
'--theme-text-default': { light: '#000000', dark: '#ffffff' },
|
||||
'--theme-text': { light: '#065758', dark: '#065758' },
|
||||
'--theme-text1': { light: 'rgba(0,0,0,0.5)', dark: '#040909FF' },
|
||||
'--theme-text2': { light: '#ffffff', dark: '#ffffff' },
|
||||
'--theme-text3': { light: 'rgba(0,0,0,0.5)', dark: 'rgba(255,255,255,0.5)' },
|
||||
'--theme-text4': { light: 'rgba(0,0,0,0.75)', dark: 'rgba(255,255,255,0.75)' },
|
||||
'--theme-text5': { light: 'rgba(0,0,0,0.65)', dark: 'rgba(255,255,255,0.65)' },
|
||||
'--theme-text6': { light: 'rgba(0,0,0,0.3)', dark: 'rgba(255,255,255,0.3)' }, // placeholder颜色
|
||||
|
||||
// 按钮颜色
|
||||
'--theme-btn1': { light: '#FF921B', dark: '#FF921B' },
|
||||
'--theme-btn2': { light: '#ca4d2a', dark: '#ca4d2a' },
|
||||
'--theme-btn3': { light: '#065758', dark: '#065758' },
|
||||
|
||||
// 阴影颜色
|
||||
'--shadow-color1': { light: '#0657584d', dark: '#065758a6' },
|
||||
'--shadow-color': { light: 'rgba(0, 0, 0, 0.25)', dark: 'rgba(255, 255, 255, 0.25)' },
|
||||
|
||||
// 表格颜色
|
||||
'--table-header-bg': { light: '#5d9292', dark: '#065253' }, // 65%
|
||||
'--table-tag': { light: '#D6DEEB', dark: '#D6DEEB' },
|
||||
'--theme-opert-bg': { light: '#FFFFFF', dark: '#2c2c2c' },
|
||||
'--table-select': { light: '#c4d4d9', dark: '#384846' }
|
||||
}
|
||||
|
||||
export { copyRight, copyRight1, themeColor, companyName1 }
|
||||
export const policyTypes = [
|
||||
{
|
||||
value: 1,
|
||||
label: '削峰套利'
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '需求响应'
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '自发自用'
|
||||
}
|
||||
]
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
<div class="main-title">能源站监控与运行管理系统</div>
|
||||
<div class="login-content">
|
||||
<div class="title" style="">账号登录</div>
|
||||
<a-form ref="ruleForm" :model="form" :rules="rules">
|
||||
<a-form-item label="" name="user">
|
||||
<a-input v-model:value="form.user" placeholder="请输入账号" autocomplete>
|
||||
<a-form ref="ruleForm" :model="form" :rules="rules" >
|
||||
<a-form-item label="" name="account">
|
||||
<a-input v-model:value="form.account" placeholder="请输入账号" autocomplete>
|
||||
<template #prefix>
|
||||
<user-outlined />
|
||||
</template>
|
||||
@@ -39,7 +39,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import { UserOutlined, LockOutlined } from '@ant-design/icons-vue'
|
||||
|
||||
import { postReq,getReq } from '@/request/api.js'
|
||||
export default {
|
||||
name: 'LoginView',
|
||||
components: {
|
||||
@@ -49,11 +49,11 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
user: 'admin',
|
||||
account: 'admin',
|
||||
passwd: '123456'
|
||||
},
|
||||
rules: {
|
||||
user: [
|
||||
account: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入账号'
|
||||
@@ -71,27 +71,30 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async login() {
|
||||
this.$refs.ruleForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await this.$http.post('/login', this.form)
|
||||
this.loading = false
|
||||
if (res.code === 200) {
|
||||
this.$message.success('登录成功')
|
||||
localStorage.setItem('token', res.token)
|
||||
this.$router.push('/main')
|
||||
} else {
|
||||
this.$message.error(res.message || '登录失败')
|
||||
}
|
||||
} catch (error) {
|
||||
this.loading = false
|
||||
this.$message.error('请求失败,请稍后重试')
|
||||
}
|
||||
} else {
|
||||
// console.log("表单验证失败");
|
||||
}
|
||||
})
|
||||
try {
|
||||
const values = await this.$refs.ruleForm.validateFields()
|
||||
const res = await getReq('/login',this.form )
|
||||
this.loading = false
|
||||
console.log(res);
|
||||
|
||||
// if (res.code === 200) {
|
||||
this.$message.success('登录成功')
|
||||
localStorage.setItem('token', res.token)
|
||||
this.$router.push('/')
|
||||
// } else {
|
||||
// this.$message.error(res.message || '登录失败')
|
||||
// }
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
this.loading = false
|
||||
this.$message.error('请求失败,请稍后重试')
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,15 +47,20 @@ export default {
|
||||
menuList: [
|
||||
{
|
||||
name: '系统总览',
|
||||
icon: 'icon-xitongguanli'
|
||||
path:'/home'
|
||||
},
|
||||
{
|
||||
name: '运行监控',
|
||||
path: '/main/monitor'
|
||||
path: '/monitor'
|
||||
},
|
||||
{
|
||||
|
||||
name: '预测管理',
|
||||
path: '/predict'
|
||||
},
|
||||
{
|
||||
name: '统计分析',
|
||||
path: '/main/statisticalAnalysis'
|
||||
path: '/statisticalAnalysis'
|
||||
},
|
||||
{
|
||||
name: '系统管理',
|
||||
|
||||
@@ -4,36 +4,43 @@
|
||||
<div class="left">
|
||||
<div class="search-item">
|
||||
<span>场站切换</span>
|
||||
<a-cascader v-model:value="value" :options="options" placeholder="Please select" />
|
||||
<a-select v-model:value="selectStation" style="width: 220px">
|
||||
<a-select-option v-for="station in stations" :value="station['station_id']"
|
||||
>{{ station.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="search-item">
|
||||
<span>运行模式</span>
|
||||
<a-cascader v-model:value="value" :options="options" placeholder="Please select" />
|
||||
<a-select v-model:value="value" style="width: 220px">
|
||||
<a-select-option value="lucy">Lucy</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<span>策略名称</span>
|
||||
<a-cascader v-model:value="value" :options="options" placeholder="Please select" />
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<a-button type="primary">调控</a-button>
|
||||
<a-button type="primary">下发</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="stations">
|
||||
<div class="station-item" v-for="station in stations" :key="station.name" @click="()=>currentKey=station.name" :class="currentKey==station.name?'active':''">
|
||||
<span class="name">{{ station.name }}</span>
|
||||
<span class="des">总功率:{{ station.power }} W</span>
|
||||
<span class="des">数量:{{ station.num }}</span>
|
||||
<div
|
||||
class="station-item"
|
||||
v-for="system in systems"
|
||||
:key="system.name"
|
||||
@click="chooseStation(system)"
|
||||
:class="systemType == system.systemType ? 'active' : ''"
|
||||
>
|
||||
<span class="name">{{ system.name }}</span>
|
||||
<span class="des">边缘网关:{{ system.power }} W</span>
|
||||
<span class="des">总有功功率(台区):{{ system.num }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<device v-if="stationType" />
|
||||
<videos v-else />
|
||||
<videos v-if="systemType == 4" />
|
||||
<device v-else :station-id="selectStation" :system-type="systemType"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -41,6 +48,7 @@
|
||||
<script>
|
||||
import device from '@/components/monitor/device.vue'
|
||||
import videos from '@/components/monitor/videos.vue'
|
||||
import { postReq, getReq } from '@/request/api'
|
||||
|
||||
export default {
|
||||
name: 'MonitorView',
|
||||
@@ -50,63 +58,64 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentKey:'储能系统1',
|
||||
stationType: 1,
|
||||
// currentKey: '储能系统',
|
||||
systemType: 1,
|
||||
value: [],
|
||||
options: [
|
||||
stations: [],
|
||||
selectStation:'',
|
||||
systems: [
|
||||
{
|
||||
value: 'zhejiang',
|
||||
label: 'Zhejiang',
|
||||
children: [
|
||||
{
|
||||
value: 'hangzhou',
|
||||
label: 'Hangzhou',
|
||||
children: [
|
||||
{
|
||||
value: 'xihu',
|
||||
label: 'West Lake'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
name: '储能系统',
|
||||
power: 60,
|
||||
num: 62,
|
||||
systemType: 1
|
||||
},
|
||||
{
|
||||
value: 'jiangsu',
|
||||
label: 'Jiangsu',
|
||||
children: [
|
||||
{
|
||||
value: 'nanjing',
|
||||
label: 'Nanjing',
|
||||
children: [
|
||||
{
|
||||
value: 'zhonghuamen'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
stations: [
|
||||
{
|
||||
name: '储能系统1',
|
||||
name: '充电系统',
|
||||
power: 60,
|
||||
num: 62
|
||||
num: 62,
|
||||
systemType: 2
|
||||
},
|
||||
{
|
||||
name: '储能系统2',
|
||||
name: '光伏系统',
|
||||
power: 60,
|
||||
num: 62
|
||||
num: 62,
|
||||
systemType: 3
|
||||
},
|
||||
{
|
||||
name: '安防系统',
|
||||
power: 60,
|
||||
num: 62,
|
||||
systemType: 4
|
||||
}
|
||||
// {
|
||||
// name: "储能系统3",
|
||||
// power: 60,
|
||||
// num: 62
|
||||
// },
|
||||
// {
|
||||
// name: "储能系统4",
|
||||
// }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getStations()
|
||||
},
|
||||
methods: {
|
||||
//查询场站列表
|
||||
async getStations() {
|
||||
try {
|
||||
const res = await getReq('/queryStationList', { page: 0, 'page_size': 10000 })
|
||||
|
||||
console.log(res)
|
||||
this.stations = res.data
|
||||
this.selectStation=this.stations[0]['station_id']
|
||||
} catch (error) {
|
||||
this.stations = []
|
||||
this.selectStation=''
|
||||
this.$message.error(error.message)
|
||||
}
|
||||
},
|
||||
|
||||
chooseStation(system) {
|
||||
this.systemType = system.systemType
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -157,12 +166,12 @@ export default {
|
||||
width: calc(100% - 30px);
|
||||
margin: 0 15px 15px 15px;
|
||||
border-radius: 12px;
|
||||
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: #fff;
|
||||
padding: 10px 15px;
|
||||
cursor: pointer;
|
||||
cursor: pointer;
|
||||
|
||||
.name {
|
||||
font-size: 20px;
|
||||
@@ -175,13 +184,13 @@ export default {
|
||||
line-height: 40px;
|
||||
}
|
||||
}
|
||||
.active{
|
||||
.active {
|
||||
background: $bg3-color;
|
||||
}
|
||||
}
|
||||
.container {
|
||||
width: 87%;
|
||||
display: flex;
|
||||
width: 87%;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
293
web/src/views/predict.vue
Normal file
293
web/src/views/predict.vue
Normal file
@@ -0,0 +1,293 @@
|
||||
<template>
|
||||
<div class="predict">
|
||||
<div class="top">
|
||||
<predictEcharts :chart-options="chartOptions[0]" :chart-data="chartData"/>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div class="item">
|
||||
<predictEcharts :chart-options="chartOptions[1]" :chart-data="chartData"/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<predictEcharts :chart-options="chartOptions[2]" :chart-data="chartData"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import predictEcharts from '@/components/predict/predictEcharts.vue';
|
||||
export default {
|
||||
name: '',
|
||||
components: {predictEcharts},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
chartOptions:[ {
|
||||
title: '储能充放电预测',
|
||||
type: 'line',
|
||||
smooth:false,
|
||||
dataKey: 'chargeDischarge',
|
||||
infoKeys: [
|
||||
|
||||
{
|
||||
key: 'key1',
|
||||
label: '电压',
|
||||
seriesOptions:{
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
itemStyle: {
|
||||
color: '#00FDF9' // 充电电量线条颜色
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#00FDF9' // 充电电量线条颜色
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
key: 'key2',
|
||||
label: '电流',
|
||||
|
||||
seriesOptions:{
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
itemStyle: {
|
||||
color: '#3E7EEF' // 充电电量线条颜色
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#3E7EEF' // 充电电量线条颜色
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
title: '充电负荷预测',
|
||||
type: 'line',
|
||||
smooth:false,
|
||||
dataKey: 'chargeDischarge',
|
||||
infoKeys: [
|
||||
|
||||
{
|
||||
key: 'key1',
|
||||
label: '电压',
|
||||
seriesOptions:{
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
itemStyle: {
|
||||
color: '#00FDF9' // 充电电量线条颜色
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#00FDF9' // 充电电量线条颜色
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
key: 'key2',
|
||||
label: '电流',
|
||||
|
||||
seriesOptions:{
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
itemStyle: {
|
||||
color: '#3E7EEF' // 充电电量线条颜色
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#3E7EEF' // 充电电量线条颜色
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
title: '光伏发电预测',
|
||||
type: 'line',
|
||||
smooth:false,
|
||||
dataKey: 'chargeDischarge',
|
||||
infoKeys: [
|
||||
|
||||
{
|
||||
key: 'key1',
|
||||
label: '电压',
|
||||
seriesOptions:{
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
itemStyle: {
|
||||
color: '#00FDF9' // 充电电量线条颜色
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#00FDF9' // 充电电量线条颜色
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
key: 'key2',
|
||||
label: '电流',
|
||||
|
||||
seriesOptions:{
|
||||
symbol: 'circle',
|
||||
symbolSize: 8,
|
||||
itemStyle: {
|
||||
color: '#3E7EEF' // 充电电量线条颜色
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#3E7EEF' // 充电电量线条颜色
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
|
||||
chartData: [
|
||||
{
|
||||
date: '2025-08-30',
|
||||
key1: 10,
|
||||
key2: 10,
|
||||
key3: 15,
|
||||
key4: 5
|
||||
},
|
||||
{
|
||||
date: '2025-08-29',
|
||||
key1: 8,
|
||||
key2: 5,
|
||||
key3: 5,
|
||||
key4: 7
|
||||
},
|
||||
{
|
||||
date: '2025-08-28',
|
||||
key1: 10,
|
||||
key2: 10,
|
||||
key3: 20,
|
||||
key4: 4
|
||||
},
|
||||
{
|
||||
date: '2025-08-27',
|
||||
key1: 10,
|
||||
key2: 10,
|
||||
key3: 15,
|
||||
key4: 5
|
||||
},
|
||||
{
|
||||
date: '2025-08-26',
|
||||
key1: 10,
|
||||
key2: 5,
|
||||
key3: 15,
|
||||
key4: 5
|
||||
},
|
||||
{
|
||||
date: '2025-08-25',
|
||||
key1: 10,
|
||||
key2: 5,
|
||||
key3: 15,
|
||||
key4: 5
|
||||
},
|
||||
{
|
||||
date: '2025-08-24',
|
||||
key1: 10,
|
||||
key2: 6,
|
||||
key3: 15,
|
||||
key4: 5
|
||||
},
|
||||
{
|
||||
date: '2025-08-23',
|
||||
key1: 10,
|
||||
key2: 7,
|
||||
key3: 15,
|
||||
key4: 5
|
||||
},
|
||||
{
|
||||
date: '2025-08-22',
|
||||
key1: 10,
|
||||
key2: 0,
|
||||
key3: 15,
|
||||
key4: 5
|
||||
},
|
||||
{
|
||||
date: '2025-08-21',
|
||||
key1: 10,
|
||||
key2: 0,
|
||||
key3: 15,
|
||||
key4: 5
|
||||
},
|
||||
{
|
||||
date: '2025-08-20',
|
||||
key1: 10,
|
||||
key2: 0,
|
||||
key3: 15,
|
||||
key4: 5
|
||||
},
|
||||
{
|
||||
date: '2025-08-19',
|
||||
key1: 10,
|
||||
key2: 0,
|
||||
key3: 15,
|
||||
key4: 5
|
||||
},
|
||||
{
|
||||
date: '2025-08-18',
|
||||
key1: 10,
|
||||
key2: 0,
|
||||
key3: 15,
|
||||
key4: 5
|
||||
},
|
||||
{
|
||||
date: '2025-08-17',
|
||||
key1: 10,
|
||||
key2: 0,
|
||||
key3: 15,
|
||||
key4: 5
|
||||
}
|
||||
],
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.predict {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: $bg1-color;
|
||||
border-radius: 15px;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
.top,
|
||||
.bottom {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: calc(50% - 10px);
|
||||
|
||||
}
|
||||
.bottom {
|
||||
display: flex;
|
||||
}
|
||||
.top{
|
||||
background-color: rgba(33, 105, 195, 0.12);
|
||||
padding: 20px 5px;
|
||||
border-radius: 15px;
|
||||
}
|
||||
.item{
|
||||
background-color: rgba(33, 105, 195, 0.12);
|
||||
padding: 20px 5px;
|
||||
flex: 1;
|
||||
border-radius: 15px;
|
||||
|
||||
&:nth-child(2){
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,46 +1,209 @@
|
||||
<template>
|
||||
<div class="policy">
|
||||
<searchBox :btn-option-list="btnOptionList" @onSearch="onSearch" @operateForm="operateForm"/>
|
||||
<searchBox :btn-option-list="btnOptionList" @onSearch="onSearch" @operateForm="operateForm" />
|
||||
<div class="content-table">
|
||||
|
||||
<ComTable
|
||||
:columns="columns"
|
||||
:table-data="tableData"
|
||||
@handlePagesizeChange="handlePagesizeChange"
|
||||
ref="comTable"
|
||||
:table-option="tableOption"
|
||||
:page-option="pageOption"
|
||||
:table-h="tableH"
|
||||
>
|
||||
<template #type="record">
|
||||
<div>{{record.type}}</div>
|
||||
|
||||
</template>
|
||||
<template #action >
|
||||
<a-button type="primary" size="small" @click="operateForm('edit')" style="margin-left: 10px">查看</a-button>
|
||||
<a-button type="primary" size="small" @click="operateForm('edit')" class="btn-edit" style="margin-left: 10px">修改</a-button>
|
||||
<a-button type="primary" size="small" @click="operateForm('edit')" class="btn-del" style="margin-left: 10px">删除</a-button>
|
||||
|
||||
|
||||
</template>
|
||||
</ComTable>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a-modal v-model:open="formModal" @ok="handleOk" width="70%">
|
||||
<policyForm/>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import searchBox from '@/components/SearchBox.vue'
|
||||
import policyForm from '@/components/system/policyForm.vue'
|
||||
import {getReq} from '@/request/api'
|
||||
export default {
|
||||
name: '',
|
||||
components:{searchBox
|
||||
},
|
||||
props: {
|
||||
|
||||
},
|
||||
data() {
|
||||
components: { policyForm },
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
btnOptionList:[
|
||||
{label:'新增',icon:'icon-tianjia',type:'add'},
|
||||
{label:'删除',icon:'icon-tianjia',type:'del'}
|
||||
|
||||
]
|
||||
formModal:true,
|
||||
btnOptionList: [
|
||||
{ label: '新增', icon: 'icon-tianjia', type: 'add' },
|
||||
{ label: '删除', icon: 'icon-tianjia', type: 'del' }
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
title: '策略ID',
|
||||
dataIndex: 'policyId',
|
||||
key: 'policyId',
|
||||
width: 120,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '策略名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: 120,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '策略类型',
|
||||
dataIndex: 'type',//策略类型:1:削峰套利;2:需求响应;3:自发自用
|
||||
key: 'type',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
scopedSlots: { customRender: 'type' }
|
||||
},
|
||||
{
|
||||
title: '策略描述',
|
||||
dataIndex: 'describe',
|
||||
key: 'describe',
|
||||
width: 120,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '策略参数',
|
||||
dataIndex: 'value',
|
||||
key: 'value',
|
||||
width: 120,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '是否启用',
|
||||
dataIndex: 'isOpen',
|
||||
key: 'isOpen',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
scopedSlots: { customRender: 'isOpen' }
|
||||
},
|
||||
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
key: 'action',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
],
|
||||
tableData:[{
|
||||
policyId: 'P001',
|
||||
name: '峰谷套利策略',
|
||||
type: 1, // 削峰套利
|
||||
describe: '利用峰谷电价差进行储能充放电优化',
|
||||
value: '峰时段: 08:00-22:00, 谷时段: 22:00-08:00',
|
||||
isOpen: true,
|
||||
action: 'edit|delete'
|
||||
},
|
||||
{
|
||||
policyId: 'P002',
|
||||
name: '需求响应策略',
|
||||
type: 2, // 需求响应
|
||||
describe: '参与电网调峰的需求侧响应方案',
|
||||
value: '响应阈值: 80%, 持续时间: 2小时',
|
||||
isOpen: false,
|
||||
action: 'edit|delete'
|
||||
},
|
||||
{
|
||||
policyId: 'P003',
|
||||
name: '光伏自发自用',
|
||||
type: 3, // 自发自用
|
||||
describe: '优先使用光伏发电,余电上网',
|
||||
value: '自用比例: 90%, 上网比例: 10%',
|
||||
isOpen: true,
|
||||
action: 'edit|delete'
|
||||
},
|
||||
{
|
||||
policyId: 'P004',
|
||||
name: '工业削峰策略',
|
||||
type: 1, // 削峰套利
|
||||
describe: '通过储能系统平抑工业用电高峰',
|
||||
value: '削峰容量: 500kWh, 持续时间: 4小时',
|
||||
isOpen: true,
|
||||
action: 'edit|delete'
|
||||
},
|
||||
{
|
||||
policyId: 'P005',
|
||||
name: '商业综合体响应',
|
||||
type: 2, // 需求响应
|
||||
describe: '商业建筑参与电网需求响应',
|
||||
value: '可中断负荷: 200kW, 响应次数: 3次/月',
|
||||
isOpen: false,
|
||||
action: 'edit|delete'
|
||||
}],
|
||||
tableOption:{},
|
||||
pageOption:{
|
||||
page:1,
|
||||
pageSize:10,
|
||||
},
|
||||
tableH:''
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
this.getTableList()
|
||||
},
|
||||
methods:{
|
||||
onSearch(data){
|
||||
methods: {
|
||||
async getTableList(){
|
||||
try {
|
||||
const res = await getReq('/queryPolicyList', {
|
||||
page: this.pageOption.page,
|
||||
'page_size': this.pageOption.pageSize
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
handleOk(){
|
||||
this.formModal=false
|
||||
},
|
||||
onSearch(data) {
|
||||
console.log(data)
|
||||
},
|
||||
operateForm(type){
|
||||
console.log(type )
|
||||
|
||||
operateForm(type) {
|
||||
console.log(type)
|
||||
switch (type){
|
||||
case 'add':
|
||||
this.formModal= true
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
},
|
||||
handlePagesizeChange(data) {
|
||||
console.log(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.policy{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 15px;
|
||||
.policy {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 15px;
|
||||
.content-table {
|
||||
width: 100%;
|
||||
height: calc(100% - 92px );
|
||||
}
|
||||
</style>
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -32,6 +32,15 @@ module.exports = defineConfig({
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://192.168.0.187:19801', // 目标服务器地址
|
||||
changeOrigin: true, // 修改请求头中的host
|
||||
pathRewrite: {
|
||||
'^/api': '' // 重写路径,去掉/api前缀
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
css: {
|
||||
@@ -44,8 +53,7 @@ module.exports = defineConfig({
|
||||
}
|
||||
},
|
||||
extract: {
|
||||
filename: `css/.[contenthash:8].css`,
|
||||
chunkFilename: `css/.[contenthash:8].chunk.css`
|
||||
ignoreOrder: true // 忽略 CSS 顺序警告
|
||||
}
|
||||
},
|
||||
// webpack相关配置
|
||||
|
||||
Reference in New Issue
Block a user