修改菜单+权限+图表渲染

This commit is contained in:
ym1026
2025-09-11 19:01:01 +08:00
parent 45ff73c295
commit 506c2e98f2
26 changed files with 1069 additions and 527 deletions

View File

@@ -87,6 +87,8 @@ export const columnList = [
title: '关联权限', title: '关联权限',
dataIndex: 'permission', dataIndex: 'permission',
key: 'permission', key: 'permission',
ellipsis: true,
scopedSlots: { customRender: 'permission' } scopedSlots: { customRender: 'permission' }
}, },
{ {
@@ -581,7 +583,7 @@ export const roleOptions = [
dataIndex: 'is_view', dataIndex: 'is_view',
key: 'is_view', key: 'is_view',
align: 'center', align: 'center',
scopedSlots: { customRender: 'isQuery' } scopedSlots: { customRender: 'is_view' }
} }
] ]
}, },

View File

@@ -190,16 +190,16 @@ watch(
}, },
{ deep: true, immediate: true } { deep: true, immediate: true }
) )
watch( // watch(
() => props.tableH, // () => props.tableH,
(n, o) => { // (n, o) => {
if (n && n !== o) { // if (n && n !== o) {
const pageH = data.newTableOpt.page ? 42 : 0 // const pageH = data.newTableOpt.page ? 42 : 0
scroll.value = { y: n - pageH - 56 } // scroll.value = { y: n - pageH - 56 }
} // }
} // }
// { deep: true, immediate: true } // // { deep: true, immediate: true }
) // )
function rowClassName(record, index) { function rowClassName(record, index) {
return 'table-row' return 'table-row'

View File

@@ -38,17 +38,18 @@
scroll: { y: 500 } scroll: { y: 500 }
}" }"
> >
<template #is_add="recordList"> <template #is_add="{ record, index }">
<a-checkbox v-model:checked="recordList.is_add"></a-checkbox> <a-checkbox v-model:checked="record.is_add"></a-checkbox>
</template> </template>
<template #is_del="recordList">
<a-checkbox v-model:checked="recordList.is_del"></a-checkbox> <template #is_del="{ record, index }">
<a-checkbox v-model:checked="record.is_del"></a-checkbox>
</template> </template>
<template #is_edit="recordList"> <template #is_edit="{ record, index }">
<a-checkbox v-model:checked="recordList.is_edit"></a-checkbox> <a-checkbox v-model:checked="record.is_edit"></a-checkbox>
</template> </template>
<template #isQuery="recordList"> <template #is_view="{ record, index }">
<a-checkbox v-model:checked="recordList.isQuery"></a-checkbox> <a-checkbox v-model:checked="record.is_view"></a-checkbox>
</template> </template>
</TreeTable> </TreeTable>
</template> </template>
@@ -120,7 +121,7 @@ export default {
role: 'roleConfirm', role: 'roleConfirm',
device: 'deviceConfirm', device: 'deviceConfirm',
station: 'stationConfirm', station: 'stationConfirm',
serviceApi: 'serviceApiConfirm', serviceApi: 'serviceApiConfirm'
// permission: 'permissionConfirm', // permission: 'permissionConfirm',
}, },
form: {}, form: {},
@@ -304,30 +305,127 @@ export default {
try { try {
const menuApi = { const menuApi = {
add: '/insertRole', add: '/insertRole',
edit: '/deleteRole' edit: '/updateRole'
} }
const { selectedRowKeys } = this.$refs.treeTable[0] const { selectedRowKeys ,selectedArr} = this.$refs.treeTable[0]
console.log(selectedRowKeys, 'selectedRowKeys') console.log(selectedRowKeys,selectedArr, 'selectedRowKeys')
// const arr = selectedArr.map((item) => ({
// ...item,
// // 转换操作权限为布尔值
// ...this.getPerOperBoolean(item),
// // 递归处理children
// children: item.children
// ? item.children.map((child) => ({
// ...child,
// ...this.getPerOperBoolean(child),
// }))
// : []
// }))
// console.log(arr,"arr")
const data=this.filterTreeData(selectedRowKeys,this.$refs.treeTable[0].tableData)
const arr = data.map((item) => ({
...item,
// 转换操作权限为布尔值
...this.getPerOperBoolean(item),
// 递归处理children
children: item.children
? item.children.map((child) => ({
...child,
...this.getPerOperBoolean(child),
}))
: []
}))
const paramsDate = { const paramsDate = {
...this.form ...this.form,
permission:arr
} }
// if (this.action == 'edit') { if (this.action == 'edit') {
// paramsDate.role_id = this.record.role_id paramsDate.role_id = this.record.role_id
// } }
// const res = await postReq(menuApi[this.action], paramsDate) const res = await postReq(menuApi[this.action], paramsDate)
// if (res.errcode === 0) { if (res.errcode === 0) {
// setTimeout(() => { setTimeout(() => {
// this.handleback() this.handleback()
// }, 1000) }, 1000)
// } else { } else {
// throw res throw res
// } }
} catch (error) { } catch (error) {
console.log(error, 'roleConfirm') console.log(error, 'roleConfirm')
} }
}, },
// 定义筛选树形数据的函数
filterTreeData(list1, list2) {
const keySet = new Set(list1);
// 递归处理节点的函数
const filterNode = (node) => {
// 创建新节点对象(浅拷贝)
const newNode = Object.assign({}, node);
// 临时删除children属性以便处理
const { children, ...rest } = newNode;
// 处理子节点
let newChildren = [];
if (children) {
newChildren = children
.map((child) => filterNode(child))
.filter((child) => child !== null);
}
// 重建新节点
const resultNode = Object.assign(rest, {});
if (newChildren.length > 0) {
resultNode.children = newChildren;
}
// 判断是否保留节点
if (keySet.has(node.key)) {
return resultNode;
}
// 保留有符合条件子节点的父节点移除自身key
if (newChildren.length > 0) {
return resultNode;
}
return null;
};
// 处理根节点
const result = list2
.map((node) => filterNode(node))
.filter((node) => node !== null);
return result;
},
getPerOperBoolean(data) {
return {
is_add: Boolean(data.is_add)? '1' : '0',
is_del: Boolean(data.is_del)? '1' : '0',
is_edit: Boolean(data.is_edit)? '1' : '0',
is_view: Boolean(data.is_view)? '1' : '0'
}
},
getPermissionData(keys,list){
const arr=[]
// list.forEach(item=>{
// if(keys.include(item.key)){
// arr.push(item)
// if()
// }
// })
},
async stationConfirm() { async stationConfirm() {
try { try {
const menuApi = { const menuApi = {
@@ -363,10 +461,9 @@ export default {
const paramsDate = { const paramsDate = {
...this.form, ...this.form,
is_open: Number(is_open), is_open: Number(is_open),
attrs: JSON.stringify({rated_capacity, rated_current, rated_voltage, reted_power}) attrs: JSON.stringify({ rated_capacity, rated_current, rated_voltage, reted_power })
} }
if (this.action == 'edit') { if (this.action == 'edit') {
paramsDate.device_id = this.record.device_id paramsDate.device_id = this.record.device_id
} }
@@ -451,6 +548,6 @@ export default {
} }
:deep(.treeTable) { :deep(.treeTable) {
width: 550px !important; width: 750px !important;
} }
</style> </style>

View File

@@ -169,7 +169,9 @@ export default {
}, },
axisLabel: { axisLabel: {
interval: 4, interval: 4,
color: '#fff' color: '#fff',
fontSize:12
} }
}, },
series: this.lineChartData.ydata series: this.lineChartData.ydata

View File

@@ -198,7 +198,9 @@ export default {
}, },
axisLabel: { axisLabel: {
interval: 4, interval: 4,
color: '#fff' color: '#fff',
fontSize:12
} }
}, },
series: this.chargeChartData.ydata series: this.chargeChartData.ydata

View File

@@ -166,7 +166,9 @@ export default {
}, },
axisLabel: { axisLabel: {
interval: 4, interval: 4,
color: '#fff' color: '#fff',
fontSize:12
} }
}, },
series: this.energyChartData.ydata series: this.energyChartData.ydata

View File

@@ -1,7 +1,6 @@
<template> <template>
<div class="map"> <div class="map">
<div ref="mapContent" class="mapContent">
<div ref="mapContent" class="mapContent" >
<tdt-map <tdt-map
ref="tiandituMap" ref="tiandituMap"
:center="center" :center="center"
@@ -16,7 +15,7 @@
:position="[marker.lon, marker.lat]" :position="[marker.lon, marker.lat]"
:key="marker.id" :key="marker.id"
:icon="marker.iconMap" :icon="marker.iconMap"
style="width: 20px; height: 20px" style="width: 20px;height: auto"
@click="clickArrayMarker(marker)" @click="clickArrayMarker(marker)"
:title="marker.name" :title="marker.name"
> >
@@ -44,11 +43,12 @@
</a-modal> </a-modal>
</div> </div>
</template> </template>
<script> <script>
import { getReq, postReq } from '@/request/api' import { getReq, postReq } from '@/request/api'
import Modal from '@/components/Home/Modal.vue' import Modal from '@/components/Home/Modal.vue'
import { loadTMap } from '@/utils/loadTMap' import { loadTMap } from '@/utils/loadTMap'
import {gcj02ToWgs84} from '@/utils/gcj02ToWgs84' import { gcj02ToWgs84, wgs84ToGcj02 } from '@/utils/gcj02ToWgs84'
import { TdtMap } from 'vue-tianditu' import { TdtMap } from 'vue-tianditu'
export default { export default {
@@ -57,14 +57,12 @@ export default {
data() { data() {
return { return {
center: [], center: [116.404, 39.915], // 默认中心点(北京)
// zoom: 16, zoom: 12,
zoom: 2,
map: null, map: null,
currentMarker: {}, currentMarker: {},
showCtrModal: false, showCtrModal: false,
markers: [], markers: [],
testVal: { testVal: {
name: '场站211', name: '场站211',
id: '2' id: '2'
@@ -75,19 +73,11 @@ export default {
}, },
mounted() { mounted() {
this.initMap() this.initMap()
// this.getMarkList()
}, },
methods: { methods: {
init(map) { init(map) {
this.map = map this.map = map
// console.log(this.map.getCenter(),"this.map.getCenter()") this.center= [110.404, 40.915]
this.map.centerAndZoom(new T.LngLat(116.404, 39.915), 12);
// 监听地图加载完成事件
this.map.addEventListener('load', () => {
const c= this.map.getCenter()
this.center =gcj02ToWgs84(c);
console.log('GCJ02坐标:', this.center);
});
this.getMarkList() this.getMarkList()
}, },
async getMarkList() { async getMarkList() {
@@ -98,50 +88,41 @@ export default {
const res = await getReq('/queryStationList', query) const res = await getReq('/queryStationList', query)
if (res.errcode === 0) { if (res.errcode === 0) {
this.markers = res.data.map((item) => { this.markers = res.data.map((item) => {
console.log(gcj02ToWgs84(+item.lon, +item.lat),"gcj02ToWgs84(+item.lon, +item.lat)")
let wgs = +item.lat && +item.lon ? gcj02ToWgs84(+item.lon, +item.lat) : [null, null]
return { return {
...item, ...item,
lon: wgs[0],
lat: wgs[1],
iconMap: !+item.status iconMap: !+item.status
? require('../../assets/home/homeIcon1.png') ? require('../../assets/home/homeIcon1.png')
: require('../../assets/home/homeIcon.png') : require('../../assets/home/homeIcon.png')
} }
}) })
console.log("this.markers ",this.markers )
} else { } else {
this.markers = [] this.markers = []
throw res throw res
} }
} catch (error) { } catch (error) {
console.log(error,'eeeeeeeeeeeeeeee') console.log(error, 'eeeeeeeeeeeeeeee')
} }
}, },
async initMap() { async initMap() {
try { try {
const [mapKey] = await Promise.all([this.getSysConfig('map-key')]) const [mapKey] = await Promise.all([this.getSysConfig('map-key')])
// const gcj02LngLat=map.getCenter()
// console.log(gcj02LngLat.getLng())
console.log(mapKey,"mapKey")
await loadTMap(mapKey) await loadTMap(mapKey)
// 创建地图实例需要HTML中存在id为mapContainer的元素
// this.map = new T.Map("amap-vue");
// // this.map.centerAndZoom(new T.LngLat(116.404, 39.915), 12); // 初始中心点
// const centerGcj02 = this.map.getCenter();
// console.log("GCJ02坐标:", centerGcj02.getLng(), centerGcj02.getLat());
// const centerWgs84=gcj02ToWgs84(centerGcj02.getLng(),centerGcj02.getLat())
// this.center =[]
} catch (err) { } catch (err) {
console.error('天地图加载失败:', err) console.error('天地图加载失败:', err)
} }
}, },
// 备用定位方案
// setFallbackLocation() {
// const fallbackCoords = [116.404, 39.915] // 北京坐标
// this.center = fallbackCoords
// if (this.map) {
// this.map.setCenter(new T.LngLat(...fallbackCoords))
// }
// },
async getSysConfig() { async getSysConfig() {
let sysConfig let sysConfig
try { try {
@@ -157,28 +138,17 @@ export default {
} }
return sysConfig return sysConfig
}, },
async clickArrayMarker(currentVal) { async clickArrayMarker(currentVal) {
this.changeStationId = currentVal.station_id this.changeStationId = currentVal.station_id
console.log(currentVal, 'cccccccccccccccccccccc')
this.showCtrModal = true this.showCtrModal = true
// try {
// const query = {
// // station_id:this.changeStationId
// }
// const res = await postReq(query, '')
// if (res.errcode === 0) {
// this.modalInfo = res.data.records
// } else {
// throw res
// }
// } catch (err) {
// console.log(err, 'eeeeeeeeeeeeeeeerr')
// }
} }
} }
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
/* 保持原有样式不变 */
.map { .map {
width: 100%; width: 100%;
height: 100%; height: 100%;

View File

@@ -47,6 +47,7 @@ import DisCharge from '@/components/Home/Modal/DisCharge.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 EnvInfo from './Modal/EnvInfo.vue' import EnvInfo from './Modal/EnvInfo.vue'
import { markRaw } from 'vue';
export default { export default {
name: 'Home', name: 'Home',
@@ -64,44 +65,44 @@ export default {
{ {
title: '预制舱信息', title: '预制舱信息',
class: '', class: '',
componentId: PrefabCabin, componentId: markRaw( PrefabCabin),
infoKey: 'prefab' infoKey: 'prefab'
}, },
{ {
title: '储能充放电量', title: '储能充放电量',
class: 'stats-cards', class: 'stats-cards',
componentId: DisCharge, componentId:markRaw( DisCharge),
infoKey: 'energy' infoKey: 'energy'
}, },
{ {
title: '运行信息', title: '运行信息',
class: 'operation-status', class: 'operation-status',
componentId: OperationalInfo, componentId:markRaw( OperationalInfo),
infoKey: 'dataTotal' infoKey: 'dataTotal'
}, },
{ {
title: '场站收益情况', title: '场站收益情况',
class: 'revenue', class: 'revenue',
componentId: Revenue, componentId:markRaw( Revenue),
infoKey: 'energy' infoKey: 'energy'
}, },
{ {
title: '统计信息', title: '统计信息',
class: 'statistical', class: 'statistical',
componentId: StatisticalInfo, componentId:markRaw( StatisticalInfo),
infoKey: '' infoKey: ''
}, },
{ {
title: '设备利用率', title: '设备利用率',
class: '', class: '',
componentId: Utilization, componentId:markRaw( Utilization),
infoKey: 'energy' infoKey: 'energy'
}, },
{ {
title: '环境信息', title: '环境信息',
class: 'envInfo', class: 'envInfo',
componentId: EnvInfo, componentId:markRaw( EnvInfo),
infoKey: 'dataTotal' infoKey: 'dataTotal'
} }
], ],

View File

@@ -166,7 +166,9 @@ export default {
}, },
axisLabel: { axisLabel: {
interval: 4, interval: 4,
color: '#fff' color: '#fff',
fontSize:12
} }
}, },
series: this.pvChartData.ydata series: this.pvChartData.ydata

View File

@@ -258,7 +258,7 @@ input:-internal-autofill-selected {
} }
.label { .label {
width: 40px; width: 80px;
color: var(--theme-text-default); color: var(--theme-text-default);
} }
.top-right, .top-right,

View File

@@ -8,18 +8,19 @@
:data-source="tableData" :data-source="tableData"
:pagination="false" :pagination="false"
:row-class-name="(record, index) => rowClassName(record, index)" :row-class-name="(record, index) => rowClassName(record, index)"
row-key="id" row-key="key"
size="middle" size="middle"
:row-selection="rowSelection" :row-selection="rowSelection"
:indent-size="30" :indent-size="30"
:check-strictly="false" :check-strictly="false"
@resizeColumn="handleResizeColumn" @resizeColumn="handleResizeColumn"
> >
<template #bodyCell="{ column, record }"> <template #bodyCell="{ text, record, index, column }">
<template v-if="column.scopedSlots"> <template v-if="column.scopedSlots">
<slot <slot
v-bind="record" v-bind="{record,index}"
:name="column.scopedSlots ? column.scopedSlots.customRender : ''" :name="column.scopedSlots ? column.scopedSlots.customRender : ''"
></slot> ></slot>
</template> </template>
</template> </template>
@@ -85,6 +86,7 @@ export default {
realColumns: [], realColumns: [],
realTableData: [], realTableData: [],
selectedRows: {}, selectedRows: {},
defaultTabOpt: { defaultTabOpt: {
page: true, page: true,
align: 'center', align: 'center',
@@ -149,6 +151,8 @@ export default {
onSelectChange(selectedRowKeys, selectedRows) { onSelectChange(selectedRowKeys, selectedRows) {
this.selectedRowKeys = selectedRowKeys this.selectedRowKeys = selectedRowKeys
this.selectedRows = selectedRows[selectedRows.length - 1] this.selectedRows = selectedRows[selectedRows.length - 1]
this.selectedArr=selectedRows
console.log(selectedRowKeys, this.selectedArr ,"selectedRowKeys")
this.$emit('getSelectedIds', selectedRowKeys) this.$emit('getSelectedIds', selectedRowKeys)
}, },
onSelect(record, selected) { onSelect(record, selected) {
@@ -232,6 +236,8 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.ant-table-body) { :deep(.ant-table-body) {
border-radius: 0px 0px 20px 20px !important;
.ant-table-cell { .ant-table-cell {
background: var(--theme-bg) !important; background: var(--theme-bg) !important;
} }
@@ -272,8 +278,9 @@ export default {
} }
:deep(.ant-table) { :deep(.ant-table) {
border-radius:20px 20px 0 0 !important; // border-radius:20px 20px 0 0 !important;
overflow: hidden; /* 确保圆角生效 */ overflow: hidden; /* 确保圆角生效 */
} }
:deep(.ant-table-wrapper .ant-table.ant-table-bordered >.ant-table-container){ :deep(.ant-table-wrapper .ant-table.ant-table-bordered >.ant-table-container){
border-inline-start:none!important; border-inline-start:none!important;
@@ -516,6 +523,8 @@ export default {
} }
:deep(.ant-table-wrapper .ant-table) { :deep(.ant-table-wrapper .ant-table) {
border: 1px solid $table-border;
background-color: transparent !important; background-color: transparent !important;
} }
@@ -525,4 +534,9 @@ export default {
:deep(.ant-table-wrapper .ant-table-thead th.ant-table-column-has-sorters:hover) { :deep(.ant-table-wrapper .ant-table-thead th.ant-table-column-has-sorters:hover) {
background: var(--table-select) !important; background: var(--table-select) !important;
} }
:deep(.ant-table-wrapper .ant-table-row-expand-icon){
background:#2c538a!important;
}
</style> </style>

View File

@@ -17,7 +17,6 @@
ref="comTable" ref="comTable"
:table-option="tableOption" :table-option="tableOption"
:page-option="pageOption" :page-option="pageOption"
:table-h="tableH"
></ComTable> ></ComTable>
</div> </div>
</div> </div>
@@ -26,10 +25,16 @@
import { processData } from '@/utils/dealWithData' import { processData } from '@/utils/dealWithData'
import { postReq } from '@/request/api' import { postReq } from '@/request/api'
import ComTable from '@/components/ComTable' import ComTable from '@/components/ComTable'
// import { debounce } from 'lodash';
export default { export default {
name: 'StatisicalAnView', name: 'StatisicalAnView',
components: { ComTable }, components: { ComTable },
props: { props: {
pageOption: {
type: Object,
default: () => ({}), // 默认空对象
required: false // 非必须
},
tableInfo: { tableInfo: {
type: Object, type: Object,
default: () => ({}), // 默认空对象 default: () => ({}), // 默认空对象
@@ -50,6 +55,11 @@ export default {
default: () => ({}), // 默认空对象 default: () => ({}), // 默认空对象
required: false // 非必须 required: false // 非必须
}, },
chartDatav: {
type: Object,
default: () => ({}), // 默认空对象
required: false // 非必须
},
tableData: { tableData: {
type: Array, type: Array,
default: () => [] // 默认空对象 default: () => [] // 默认空对象
@@ -64,94 +74,172 @@ export default {
}, },
select: false select: false
}, },
tableH: 0,
chartInstances: [] // 存储 ECharts 实例 chartInstances: [] // 存储 ECharts 实例
} }
}, },
watch: { watch: {
chartData: { chartData: {
handler(n) { handler(newVal) {
console.log(n, 'nnnnnnnnnnnnnnnnnnnnnnn') if (newVal && Object.keys(newVal).length > 0) {
this.$nextTick(() => { this.$nextTick(() => {
this.initCharts() // this.destroyCharts(); // 先销毁旧图表
window.addEventListener('resize', this.handleResize) this.initBarCharts(); // 重新初始化
}) });
} }
},
deep: true,
// immediate: true,
},
chartDatav: {
handler(newVal) {
if (newVal && Object.keys(newVal).length > 0) {
this.$nextTick(() => {
// this.destroyCharts(); // 先销毁旧图表
this.initLineCharts(); // 重新初始化
});
} }
}, },
deep: true,
// immediate: true,
},
},
mounted() { mounted() {
// this.initCharts() window.addEventListener('resize', this.handleResize);
// window.addEventListener('resize', this.handleResize)
}, },
beforeUnmount() { beforeUnmount() {
window.removeEventListener('resize', this.handleResize) window.removeEventListener('resize', this.handleResize);
this.chartInstances.forEach((chart) => chart && chart.dispose()) this.destroyCharts();
}, },
methods: { methods: {
initCharts() { destroyCharts() {
this.chartOptions.forEach((option, index) => { this.chartInstances.forEach((chart) => {
const dom = this.$refs[`chartContainer${index}`][0] if (chart && !chart.isDisposed()) {
if (!dom) return chart.dispose(); // 销毁旧图表
const chart = this.$echarts.init(dom) }
this.chartInstances.push(chart) // 存储实例 });
const keys= option.infoKeys.map((item) => item.key) this.chartInstances = []; // 清空实例数组
// 设置图表配置 },
chart.setOption({ // 公共 ECharts 配置
getCommonOption(option, dataKeys, isLineChart = false) {
return {
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { axisPointer: { type: 'shadow' },
type: 'shadow'
}
}, },
legend: { legend: {
top: 20, top: 20,
textStyle: { textStyle: { color: '#fff' },
color: '#fff'
}
}, },
grid: { grid: {
left: '3%', left: '3%',
right: '3%', right: '3%',
bottom: '5%', bottom: '5%',
containLabel: true containLabel: true,
}, },
xAxis: { xAxis: {
type: 'category', type: 'category',
data: processData(this.chartData,keys) data: isLineChart ? this.generateTimePoints() : processData(this.chartData, dataKeys).dates,
.dates, axisLine: { lineStyle: { color: '#fff' } },
axisLabel: { color: '#fff' },
axisLine: {
lineStyle: { type: 'dashed', color: '#435463' }
},
axisLabel: {
color: '#fff'
}
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
splitLine: { splitLine: { lineStyle: { type: 'dashed', color: '#435463' } },
lineStyle: { type: 'dashed', color: '#435463' } axisLabel: { color: '#fff' },
}, },
axisLabel: { };
color: '#fff' },
generateTimePoints() {
const timePoints = []
for (let hour = 0; hour <= 24; hour++) {
for (let minute = 0; minute < 60; minute += 10) {
// 处理24:00的特殊情况
if (hour === 24 && minute === 0) {
timePoints.push('24:00')
break
} }
// 格式化小时和分钟,确保两位数
const formattedHour = hour.toString().padStart(2, '0')
const formattedMinute = minute.toString().padStart(2, '0')
timePoints.push(`${formattedHour}:${formattedMinute}`)
}
}
return timePoints
}, },
series: option.infoKeys.map((info, i) => { // 初始化柱状图
return { initBarCharts() {
this.chartOptions.forEach((option, index) => {
if (option.type === 'bar') {
const dom = this.$refs[`chartContainer${index}`]?.[0];
if (!dom) return;
const chart = this.$echarts.init(dom);
this.chartInstances.push(chart);
const dataKeys = option.infoKeys.map((item) => item.key);
const commonOption = this.getCommonOption(option, dataKeys);
chart.setOption({
...commonOption,
series: option.infoKeys.map((info, i) => ({
name: info.label, name: info.label,
smooth: true, type: 'bar',
type: option.type,
barWidth: 10, barWidth: 10,
itemStyle: { itemStyle: {
borderRadius: [10, 10, 0, 0], borderRadius: [10, 10, 0, 0],
color: info.lineColor color: info.lineColor,
}, },
emphasis: { data: processData(this.chartData, dataKeys).values[i],
focus: 'series' })),
});
}
});
}, },
// 初始化折线图
initLineCharts() {
this.chartOptions.forEach((option, index) => {
if (option.type === 'line') {
const dom = this.$refs[`chartContainer${index}`]?.[0];
if (!dom) return;
const chart = this.$echarts.init(dom);
this.chartInstances.push(chart);
const dataKeys = option.infoKeys.map((item) => item.key);
const commonOption = this.getCommonOption(option, dataKeys, true);
chart.setOption({
...commonOption,
dataZoom: [
{
type: 'slider',
show: true,
xAxisIndex: 0,
start: 0,
end: 20,
height: 20,
bottom: 10,
},
{
type: 'inside',
xAxisIndex: 0,
start: 0,
end: 20,
},
],
series: option.infoKeys.map((info, i) => ({
name: info.label,
type: 'line',
smooth: true,
showSymbol: false,
itemStyle: { color: info.lineColor },
areaStyle: { areaStyle: {
global: false,
color: { color: {
type: 'linear', type: 'linear',
x: 0, x: 0,
@@ -159,32 +247,33 @@ export default {
x2: 0, x2: 0,
y2: 1, y2: 1,
colorStops: [ colorStops: [
{ offset: 0, color: info.colorStart }, // 顶部颜色 { offset: 0, color: info.colorStart },
{ offset: 1, color: info.colorEnd } // 底部颜色 { offset: 1, color: info.colorEnd },
] ],
}
}, },
global: false, },
showSymbol: false, data: this.chartDatav[info.key],
data: processData( })),
this.chartData, });
keys
).values[i]
} }
}) });
}) },
}) handleResize () {
this.chartInstances.forEach((chart) => chart && chart.resize());
// this.handleResize = debounce(this.resize, 300);
},
resize() {
this.chartInstances.forEach((chart) => chart && chart.resize());
}, },
handleResize() {
this.chartInstances.forEach((chart) => chart && chart.resize())
},
handlePagesizeChange(pageOption) { handlePagesizeChange(pageOption) {
this.$emit('pagesizeChange_energy', pageOption) this.$emit('pagesizeChange_energy', pageOption)
} }
} },
} }
</script> </script>
@@ -242,5 +331,11 @@ export default {
min-height: 500px; min-height: 500px;
width: 100%; width: 100%;
padding-right: 10px; padding-right: 10px;
padding-bottom: 10px;
.comtable{
height:610px;
// overflow: scroll;
}
} }
</style> </style>

View File

@@ -1,4 +1,3 @@
import route from 'vue-router'
const btnList = [ const btnList = [
{ label: '', type: '', disFlag: '' }, { label: '', type: '', disFlag: '' },
{ label: '新增', type: 'add', disFlag: 'is_add', icon: 'icon-add' }, { label: '新增', type: 'add', disFlag: 'is_add', icon: 'icon-add' },
@@ -8,14 +7,16 @@ const btnList = [
] ]
function getBtns(arr) { function getBtns(arr) {
console.log(this.$route, 'route') const curPermission =
// JSON.parse(localStorage.getItem('permission')).find((item)=>item.route==) JSON.parse(localStorage.getItem('permission')).find(
// const permissions = (item) => item.route == this.$route.fullPath
// JSON.parse(localStorage.getItem('permission')) || {} ) || {}
// console.log(this.$route, curPermission, localStorage.getItem('permission'), 'curPermission')
const btns = [] const btns = []
btnList.forEach((item) => { btnList.forEach((item) => {
if (arr.includes(item.label)) { if (arr.includes(item.label)) {
// item.disabled = !Boolean(permissions[item.disFlag]) // item.disabled = !Boolean(curPermission[item.disFlag])
btns.push(item) btns.push(item)
} }
}) })

View File

@@ -63,7 +63,7 @@ export function gcj02ToWgs84(lng, lat) {
/** /**
* WGS-84 转 GCJ-02用于迭代优化 * WGS-84 转 GCJ-02用于迭代优化
*/ */
function wgs84ToGcj02(lng, lat) { export function wgs84ToGcj02(lng, lat) {
if (outOfChina(lng, lat)) { if (outOfChina(lng, lat)) {
return [lng, lat] return [lng, lat]
} }

View File

@@ -0,0 +1,32 @@
function transformlat(lonx, laty) {
/* 略 */
}
function transformlng(lonx, laty) {
/* 略 */
}
// WGS-84 转 GCJ-02 坐标
export function wgs84ToGcj02(lon, lat) {
const PI = 3.1415926535897932384626
const a = 6378245.0
const ee = 0.00669342162296594323
// if (outOfChina(lon, lat)) {
// return [lon, lat]
// }
let dlat = transformlat(lon - 105.0, lat - 35.0)
let dlon = transformlng(lon - 105.0, lat - 35.0)
const radlat = (lat / 180.0) * PI
let magic = Math.sin(radlat)
magic = 1 - ee * magic * magic
const sqrtmagic = Math.sqrt(magic)
dlat = (dlat * 180.0) / (((a * (1 - ee)) / (magic * sqrtmagic)) * PI)
dlon = (dlon * 180.0) / ((a / sqrtmagic) * Math.cos(radlat) * PI)
const mglat = lat + dlat
const mglon = lon + dlon
return [mglon, mglat]
}
// // 辅助函数保持原样...
// function outOfChina(lon, lat) {
// /* 略 */
// }

View File

@@ -43,136 +43,143 @@ export default {
return { return {
currentKey: '', currentKey: '',
subCurrentKey: '', subCurrentKey: '',
menuList: [ menuList: [],
{ // menuList: [
name: '系统总览', // {
path: '/home' // name: '系统总览',
}, // path: '/home'
{ // },
name: '运行监控', // {
path: '/monitor' // name: '运行监控',
}, // path: '/monitor'
{ // },
name: '预测管理', // {
path: '/predict' // name: '预测管理',
}, // path: '/predict'
{ // },
name: '统计分析', // {
path: '/statisticalAnalysis' // name: '统计分析',
}, // path: '/statisticalAnalysis'
{ // },
name: '系统管理', // {
path: '/system', // name: '系统管理',
children: [ // path: '/system',
{ // children: [
name: '用户管理', // {
path: '/user' // name: '用户管理',
}, // path: '/user'
{ // },
name: '角色管理', // {
path: '/role' // name: '角色管理',
}, // path: '/role'
{ // },
name: '权限管理', // {
icon: 'icon-caidanguanli' // name: '权限管理',
}, // icon: 'icon-caidanguanli'
{ // },
name: '场站管理', // {
path: '/station', // name: '场站管理',
icon: 'icon-caidanguanli' // path: '/station',
}, // icon: 'icon-caidanguanli'
{ // },
name: '服务管理', // {
icon: 'icon-bumenguanli' // name: '服务管理',
}, // icon: 'icon-bumenguanli'
{ // },
name: '策略管理', // {
path: '/policy' // name: '策略管理',
}, // path: '/policy'
{ // },
name: '设备管理', // {
path: '/device ' // name: '设备管理',
}, // path: '/device '
{ // },
name: '告警日志', // {
path: '/log' // name: '告警日志',
}, // path: '/log'
{ // },
name: '系统日志', // {
path: '/syslog' // name: '系统日志',
} // path: '/syslog'
] // }
} // ]
], // }
// ],
subMenu: [] subMenu: []
} }
}, },
computed: {
dynamicMenuList() {
return this.generateMenu(JSON.parse(localStorage.getItem('permission')))
}
},
watch: { watch: {
$route: { $route: {
handler(n) { immediate: true,
console.log(n,"nnnnnnnnnnnnnn") handler(to) {
this.subMenu =n.matched[1].children || [] console.log(this.dynamicMenuList, 'this.dynamicMenuList')
}, // // 更新当前激活的菜单项
immediate: true // // this.currentKey = to.matched[0]?.path || ''
this.menuList = this.dynamicMenuList
// 解析当前路由路径
const pathSegments = to.path.split('/').filter(Boolean)
// 处理主菜单激活状态
this.currentKey = pathSegments.length > 0 ? `/${pathSegments[0]}` : ''
// 处理子菜单逻辑
this.handleSubMenu(pathSegments,to)
}
} }
}, },
mounted() { mounted() {
this.initRoute() // this.initRoute()
}, },
methods: { methods: {
// 过滤函数:根据权限数据过滤路由并附加权限信息 // 新增子菜单处理方法
filterRoutes(routes, permissions) { handleSubMenu(pathSegments,to) {
return routes.filter((route) => { // 查找当前激活的主菜单项
let hasViewPermission = false const activeMainMenu = this.menuList.find((menu) => menu.path === `/${pathSegments[0]}`)
// 查找当前路由对应的权限项
const routePermissions = permissions.filter((perm) => perm.route === route.path)
// 如果有权限项,附加到路由对象 // 更新子菜单列表
if (routePermissions.length > 0) { this.subMenu = activeMainMenu?.children || []
route.permissions = routePermissions;
hasViewPermission = true // 处理子菜单激活状态
if (pathSegments.length > 1) {
this.subCurrentKey = `/${pathSegments[1]}`
} else {
this.subCurrentKey = ''
} }
// 检查是否有查看权限 // 自动跳转至默认子菜单(当主菜单有子菜单时)
// const hasViewPermission = routePermissions.some((perm) => if (this.subMenu.length > 0 && to.path === `/${pathSegments[0]}`) {
// perm.is_view === '1' const defaultPath = this.subMenu[0].path
// ); this.$router.replace(`/${pathSegments[0]}/${defaultPath}`)
// 递归处理子路由
if (route.children && route.children.length) {
route.children = this.filterRoutes(route.children, permissions)
} }
// 保留有权限的路由或包含有效子路由的父路由
return hasViewPermission || (route.children && route.children.length)
})
}, },
initRoute() { generateMenu(routes) {
console.log(localStorage.getItem('permission'), "localStorage.getItem('permission')") console.log(routes, 'routes')
// 执行过滤 return routes.map((route) => ({
// const filteredRoutes = this.filterRoutes( ...route,
// this.menuList, title: route.name,
// JSON.parse(localStorage.getItem('permission')) path: route.route,
// ) children: route.children ? this.generateMenu(route.children) : []
console.log( this.$route.matched, 'filteredRoutes') }))
this.subMenu = this.$route.matched[1].children || []
// this.menuList= JSON.parse(localStorage.getItem('permission'))
// this.subMenu =filteredRoutes[0].children||[]
this.currentKey = '/' + this.$route.fullPath.split('/')[1]
this.subCurrentKey = this.$route.fullPath.split('/')[2]
console.log(this.subCurrentKey)
}, },
menuClick(menu) { menuClick(menu) {
this.currentKey = menu.path this.currentKey = '/' + menu.path
this.subMenu = menu.children || [] this.subMenu = menu.children || []
this.$router.push(menu.path) const targetPath = menu.children?.length > 0 ? menu.path + menu.children[0].path : menu.path
this.$router.push(targetPath)
}, },
subMenuClick(subMenu) { subMenuClick(subMenu) {
console.log(subMenu, subMenu.path)
this.subCurrentKey = subMenu.path this.subCurrentKey = subMenu.path
this.$router.push('/system'+subMenu.path) this.$router.push('/system' + subMenu.path)
} }
} }
} }

View File

@@ -18,19 +18,39 @@
:title-option="{ title: '', info: '' }" :title-option="{ title: '', info: '' }"
@onSearch="onSearch" @onSearch="onSearch"
> >
<template #stationSelect="item">
<a-select
style="width: 120px;"
: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> </searchBox>
</div> </div>
<div class="main_content"> <div class="main_content">
<a-spin :spinning="loading.chart || loading.table">
<energyEchart <energyEchart
:key="activeKey" :key="`${activeKey}_${renderKey}`"
:chart-options="echartsInfo[activeKey].chartOptions" :chart-options="echartsInfo[activeKey].chartOptions"
:chart-data="echartsInfo[activeKey].chartData" :chart-data="echartsInfo[activeKey].chartData"
:chart-datav="echartsInfo[activeKey].chartDatav"
:columns="tableList[activeKey].columns" :columns="tableList[activeKey].columns"
:page-option="tableList[activeKey].pageOption"
:table-info="tableList[activeKey].tableInfo" :table-info="tableList[activeKey].tableInfo"
:table-data="tableList[activeKey].tableData" :table-data="tableList[activeKey].tableData"
@pagesizeChange="pagesizeChange()" @pagesizeChange="pagesizeChange()"
></energyEchart> ></energyEchart>
</a-spin>
</div> </div>
</div> </div>
</template> </template>
@@ -47,6 +67,12 @@ export default {
data() { data() {
return { return {
loading: {
chart: false,
table: false
},
stationId: undefined,
renderKey: 0,
categoryArr: [ categoryArr: [
{ {
type: 1, type: 1,
@@ -71,10 +97,18 @@ export default {
type: 'datePick1', type: 'datePick1',
value: [], value: [],
key: 'time' key: 'time'
},
{
label: '场站切换',
type: 'slot',
value: [],
key: 'station',
slotName: 'stationSelect'
} }
], ],
stationList: [],
echartsInfo: { echartsInfo: {
0: { 1: {
chartOptions: [ chartOptions: [
{ {
title: '充放电分析', title: '充放电分析',
@@ -96,19 +130,19 @@ export default {
] ]
}, },
{ {
title: '电压与电流分析', title: '今日电压与电流分析',
type: 'line', type: 'line',
dataKey: 'stock', dataKey: 'stock',
infoKeys: [ infoKeys: [
{ {
key: 'key1', key: 'V',
label: '电压', label: '电压',
lineColor: '#3F80F2', lineColor: '#3F80F2',
colorStart: ' rgba(10, 250, 106, 0.15)', colorStart: ' rgba(10, 250, 106, 0.15)',
colorEnd: ' rgba(171, 255, 249, 0.3)' colorEnd: ' rgba(171, 255, 249, 0.3)'
}, },
{ {
key: 'key2', key: 'I',
label: '电流', label: '电流',
lineColor: '#A9A6FF', lineColor: '#A9A6FF',
colorStart: ' rgba(10, 250, 106, 0.15)', colorStart: ' rgba(10, 250, 106, 0.15)',
@@ -117,12 +151,12 @@ export default {
] ]
}, },
{ {
title: '功率分析', title: '今日功率分析',
type: 'line', type: 'line',
dataKey: 'yearly', dataKey: 'yearly',
infoKeys: [ infoKeys: [
{ {
key: 'key1', key: 'P',
label: '功率', label: '功率',
lineColor: '#00FFFB', lineColor: '#00FFFB',
colorStart: ' rgba(10, 250, 106, 0.15)', colorStart: ' rgba(10, 250, 106, 0.15)',
@@ -131,17 +165,16 @@ export default {
] ]
} }
], ],
chartData: {} chartData: {},
chartDatav: {},
}, },
1: { 2: {
chartOptions: [ chartOptions: [
{ {
title: '发电电量分析', title: '发电电量分析',
type: 'bar', type: 'bar',
dataKey: 'sales', dataKey: 'sales',
infoKeys: [ infoKeys: [{ key: 'storage_elect_in', label: '日发电电量', lineColor: '#2A82E4' }]
{ key: 'storage_elect_in', label: '日发电电量', lineColor: '#2A82E4' },
]
}, },
{ {
title: '运行状态分析', title: '运行状态分析',
@@ -153,19 +186,19 @@ export default {
] ]
}, },
{ {
title: '电压与电流分析', title: '今日电压与电流分析',
type: 'line', type: 'line',
dataKey: 'stock', dataKey: 'stock',
infoKeys: [ infoKeys: [
{ {
key: 'key1', key: 'V',
label: '电压', label: '电压',
lineColor: '#3F80F2', lineColor: '#3F80F2',
colorStart: ' rgba(10, 250, 106, 0.15)', colorStart: ' rgba(10, 250, 106, 0.15)',
colorEnd: ' rgba(171, 255, 249, 0.3)' colorEnd: ' rgba(171, 255, 249, 0.3)'
}, },
{ {
key: 'key2', key: 'I',
label: '电流', label: '电流',
lineColor: '#A9A6FF', lineColor: '#A9A6FF',
colorStart: ' rgba(10, 250, 106, 0.15)', colorStart: ' rgba(10, 250, 106, 0.15)',
@@ -174,12 +207,12 @@ export default {
] ]
}, },
{ {
title: '功率分析', title: '今日功率分析',
type: 'line', type: 'line',
dataKey: 'yearly', dataKey: 'yearly',
infoKeys: [ infoKeys: [
{ {
key: 'key1', key: 'P',
label: '功率', label: '功率',
lineColor: '#00FFFB', lineColor: '#00FFFB',
colorStart: ' rgba(10, 250, 106, 0.15)', colorStart: ' rgba(10, 250, 106, 0.15)',
@@ -190,15 +223,13 @@ export default {
], ],
chartData: {} chartData: {}
}, },
2: { 3: {
chartOptions: [ chartOptions: [
{ {
title: '充电分析', title: '充电分析',
type: 'bar', type: 'bar',
dataKey: 'sales', dataKey: 'sales',
infoKeys: [ infoKeys: [{ key: 'storage_elect_in', label: '日充电电量', lineColor: '#2A82E4' }]
{ key: 'storage_elect_in', label: '日充电电量', lineColor: '#2A82E4' },
]
}, },
{ {
title: '运行状态分析', title: '运行状态分析',
@@ -211,19 +242,19 @@ export default {
] ]
}, },
{ {
title: '电压与电流分析', title: '今日电压与电流分析',
type: 'line', type: 'line',
dataKey: 'stock', dataKey: 'stock',
infoKeys: [ infoKeys: [
{ {
key: 'key1', key: 'V',
label: '电压', label: '电压',
lineColor: '#3F80F2', lineColor: '#3F80F2',
colorStart: ' rgba(10, 250, 106, 0.15)', colorStart: ' rgba(10, 250, 106, 0.15)',
colorEnd: ' rgba(171, 255, 249, 0.3)' colorEnd: ' rgba(171, 255, 249, 0.3)'
}, },
{ {
key: 'key2', key: 'I',
label: '电流', label: '电流',
lineColor: '#A9A6FF', lineColor: '#A9A6FF',
colorStart: ' rgba(10, 250, 106, 0.15)', colorStart: ' rgba(10, 250, 106, 0.15)',
@@ -232,12 +263,12 @@ export default {
] ]
}, },
{ {
title: '功率分析', title: '今日功率分析',
type: 'line', type: 'line',
dataKey: 'yearly', dataKey: 'yearly',
infoKeys: [ infoKeys: [
{ {
key: 'key1', key: 'P',
label: '功率', label: '功率',
lineColor: '#00FFFB', lineColor: '#00FFFB',
colorStart: ' rgba(10, 250, 106, 0.15)', colorStart: ' rgba(10, 250, 106, 0.15)',
@@ -249,23 +280,24 @@ export default {
chartData: {} chartData: {}
} }
}, },
activeKey: 0, activeKey: 1,
interval:null,
tabList: [ tabList: [
{ {
key: 0, key: 1,
name: '储能设备' name: '储能设备'
}, },
{ {
key: 1, key: 2,
name: '光伏设备' name: '光伏设备'
}, },
{ {
key: 2, key: 3,
name: '充电设备' name: '充电设备'
} }
], ],
tableList: { tableList: {
0: { 1: {
columns: [ columns: [
{ {
title: '设备ID', title: '设备ID',
@@ -339,7 +371,7 @@ export default {
count: 1 count: 1
} }
}, },
1: { 2: {
columns: [ columns: [
{ {
title: '设备ID', title: '设备ID',
@@ -400,7 +432,7 @@ export default {
count: 1 count: 1
} }
}, },
2: { 3: {
columns: [ columns: [
{ {
title: '设备ID', title: '设备ID',
@@ -470,135 +502,299 @@ export default {
} }
} }
}, },
watch:{ watch: {
activeKey(newVal, oldVal) { activeKey: {
console.log(newVal, oldVal,"activeKey") handler(newVal) {
// 清空旧数据(可选) if (!newVal) return;
if( this.echartsInfo[oldVal]){
this.echartsInfo[oldVal].chartData = {};
this.tableList[oldVal].tableData = [];
// // 重新加载数据
this.getTableList()
this.getEchartsList()
}
// 清除之前的数据
this.resetDataForInactiveKey();
// 并行加载新数据
Promise.all([
this.getEchartsListForActiveKey(),
this.getTableListForActiveKey()
]).then(() => {
this.$nextTick(() => {
this.getStatCharts();
});
});
},
immediate: true // 添加立即执行
} }
}, },
async mounted() { async mounted() {
await Promise.all([this.getTableList(), this.getEchartsList()]) // 优先加载第一个页面(activeKey=1)所需的数据
await Promise.all([
this.getStationList(),
this.getEchartsListForActiveKey(),
this.getTableListForActiveKey()
]);
// 初始化实时刷新
this.startRealtimeRefresh();
},
beforeUnmount() {
console.log('beforeUnmount')
clearInterval(this.interval); // 组件销毁时清除定时器
}, },
beforeUnmount() {},
methods: { methods: {
forceRerender() {
this.renderKey += 1;
},
resetDataForInactiveKey() {
// 重置非当前激活页面的数据,减少内存占用
Object.keys(this.echartsInfo).forEach((key) => {
if (key != this.activeKey) {
this.echartsInfo[key].chartData={}
this.echartsInfo[key].chartDatav={}
}
});
Object.keys(this.tableList).forEach((key) => {
if (key != this.activeKey) {
this.echartsInfo[key].tableData={}
}
});
},
async getEchartsListForActiveKey() {
if (!this.activeKey) return;
this.loading.chart = true;
const currentInfo = this.echartsInfo[this.activeKey];
const query = {
...this.paramsDate,
category: this.activeKey
};
try {
const res = await getReq('/queryStatDayList', query);
if (res.errcode === 0) {
this.echartsInfo[this.activeKey].chartData=res.data
this.loading.chart = false;
} else {
throw res;
}
} catch (error) {
this.loading.chart = false;
this.echartsInfo[this.activeKey].chartData={}
}
},
// 专门获取当前激活页面的表格数据
async getTableListForActiveKey() {
this.loading.table = true;
if (!this.activeKey) return;
const currentInfo = this.tableList[this.activeKey];
const query = {
...this.paramsDate,
category: this.activeKey,
page_size: currentInfo.pageOption.pageSize,
pageNumber: currentInfo.pageOption.page
};
try {
const res = await getReq('/queryStatDayList', query);
if (res.errcode === 0) {
this.tableList[this.activeKey].tableData=res.data.list || res.data
this.tableList[this.activeKey].pageOption.count=res.data.count || 0
this.loading.table = false;
} else {
throw res;
}
} catch (error) {
this.tableList[this.activeKey].tableData=[]
this.tableList[this.activeKey].pageOption.count= 0
this.loading.table = false;
}
},
startRealtimeRefresh() {
this.interval = setInterval(() => {
if (this.activeKey) {
this.getStatCharts(); // 定时获取最新实时数据
}
}, 10000); // 30秒刷新一次
},
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
}
})
if (this.stationList.length) {
if (!this.stationId) {
this.stationId = this.stationList[0].value
}
//V I P
}
} else {
const err = { tip: res.errmsg }
throw err
}
} catch (error) {
//统一处理报错提示
}
},
pagesizeChange(e) { pagesizeChange(e) {
this.tableList[this.activeKey].pageOption.pageSize = e.pageSize this.tableList[this.activeKey].pageOption.pageSize = e.pageSize
this.tableList[this.activeKey].pageOption.page = e.page this.tableList[this.activeKey].pageOption.page = e.page
this.getTableList() this.getTableListForActiveKey()
}, },
onSearch(data) { onSearch(data) {
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] : ''
this.tableList[this.activeKey].pageOption.page = 1 this.tableList[this.activeKey].pageOption.page = 1
this.getStationList(),
this.getTableList() this.getEchartsListForActiveKey(),
this.getEchartsList() this.getTableListForActiveKey()
}, },
async getEchartsList() { changeStation() {
this.getStatCharts();
},
// async getEchartsList() {
// const key = activeKey || this.activeKey;
// if (!key) return;
// const currentInfo = this.echartsInfo[this.activeKey]
// const query = {
// ...this.paramsDate,
// category: this.activeKey
// }
// try {
// const res = await getReq('/queryStatDayList', query)
// if (res.errcode === 0) {
// this.echartsInfo[this.activeKey].chartData = res.data
// console.log(
// this.echartsInfo[this.activeKey].chartData,
// ' this.echartsInfo[this.activeKey].chartData'
// )
// } else {
// throw res
// }
// } catch (error) {
// this.echartsInfo[this.activeKey].chartData = {}
// }
// },
async getStatCharts() {
const currentInfo = this.echartsInfo[this.activeKey] const currentInfo = this.echartsInfo[this.activeKey]
const query = { const query = {
...this.paramsDate, dt: this.paramsDate.end_date,
category: this.categoryArr.map((item) => item.label == this.activeKey)[0].type, station_id: this.stationId,
// start_date: getDateDaysAgo(7 - 1), category: this.activeKey
// end_date: getDateDaysAgo(0)
} }
try { try {
const res = await getReq('/queryStatDayList', query) const res = await getReq('/queryStatCharts', query)
if (res.errcode === 0) { if (res.errcode === 0) {
this.echartsInfo[this.activeKey].chartData = res.data this.echartsInfo[this.activeKey].chartDatav = {
console.log( "V":[100.0,100.0,100.0], // 电压曲线
this.echartsInfo[this.activeKey].chartData, "I":[10.0,10.0,10.0], // 电流曲线
' this.echartsInfo[this.activeKey].chartData' "P":[1000.0,1000.0,1000.0], // 功率曲线
) }
// x轴0点到24点
} else { } else {
throw res throw res
} }
} catch (error) { } catch (error) {
this.echartsInfo[this.activeKey].chartData = {} this.echartsInfo[this.activeKey].chartDatav = {
"V":[100.0,100.0,100.0], // 电压曲线
"I":[10.0,10.0,10.0], // 电流曲线
"P":[1000.0,1000.0,1000.0], // 功率曲线
}
} }
}, },
async getTableList() { // async getTableList() {
const currentInfo = this.tableList[this.activeKey] // const currentInfo = this.tableList[this.activeKey]
const query = { // const query = {
...this.paramsDate, // ...this.paramsDate,
category: this.categoryArr.map((item) => item.label == this.activeKey)[0].type, // category: this.activeKey,
page_size: currentInfo.pageOption.pageSize, // page_size: currentInfo.pageOption.pageSize,
pageNumber: currentInfo.pageOption.page // pageNumber: currentInfo.pageOption.page
} // }
try { // try {
const res = await getReq('/queryStatDayList', query) // const res = await getReq('/queryStatDayList', query)
if (res.errcode === 0) { // if (res.errcode === 0) {
currentInfo.tableData = res.data // this.tableList[this.activeKey].pageOption.tableData = res.data
currentInfo.pageOption = { // this.tableList[this.activeKey].pageOption.pageOption = {
page: res.data.page, // page: res.data.page,
pageSize: res.data.page_size, // pageSize: res.data.page_size,
count: res.data.count // count: res.data.count
} // }
} else { // } else {
throw res // throw res
} // }
} catch (error) { // } catch (error) {
currentInfo.tableData = [ // this.tableList[this.activeKey].pageOption.tableData = [
{ // {
key1: '1515151515', // key1: '1515151515',
key2: '设备1111', // key2: '设备1111',
key3: '类型', // key3: '类型',
key4: '电量', // key4: '电量',
key5: '时长', // key5: '时长',
key6: '时长', // key6: '时长',
key7: 'dianl', // key7: 'dianl',
key8: '时长', // key8: '时长',
key9: '时长11' // key9: '时长11'
}, // },
{ // {
key1: '1515151515', // key1: '1515151515',
key2: '设备1111', // key2: '设备1111',
key3: '类型', // key3: '类型',
key4: '电量', // key4: '电量',
key5: '时长', // key5: '时长',
key6: '时长', // key6: '时长',
key7: 'dianl', // key7: 'dianl',
key8: '时长', // key8: '时长',
key9: '时长11' // key9: '时长11'
}, // },
{ // {
key1: '1515151515', // key1: '1515151515',
key2: '设备1111', // key2: '设备1111',
key3: '类型', // key3: '类型',
key4: '电量', // key4: '电量',
key5: '时长', // key5: '时长',
key6: '时长', // key6: '时长',
key7: 'dianl', // key7: 'dianl',
key8: '时长', // key8: '时长',
key9: '时长11' // key9: '时长11'
}, // },
{ // {
key1: '1515151515', // key1: '1515151515',
key2: '设备1111', // key2: '设备1111',
key3: '类型', // key3: '类型',
key4: '电量', // key4: '电量',
key5: '时长', // key5: '时长',
key6: '时长', // key6: '时长',
key7: 'dianl', // key7: 'dianl',
key8: '时长', // key8: '时长',
key9: '时长11' // key9: '时长11'
} // }
] // ]
} // }
} // }
} }
} }
</script> </script>
@@ -639,7 +835,7 @@ export default {
} }
.main_content { .main_content {
overflow: scroll; overflow: scroll;
height: calc(100% - 15px); height: calc(100% - 30px);
// margin-top: 10px; // margin-top: 10px;
} }
</style> </style>

View File

@@ -48,7 +48,7 @@ import Alarm from '@/components/Home/Alarm.vue'
import Map from '@/components/Home/Map.vue' import Map from '@/components/Home/Map.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';
export default { export default {
name: 'Home', name: 'Home',
components: { Map }, components: { Map },
@@ -62,38 +62,38 @@ export default {
{ {
title: '运行状况', title: '运行状况',
class: 'online-status', class: 'online-status',
componentId: onLine, componentId:markRaw(onLine),
infoKey: 'onLineTotal' infoKey: 'onLineTotal'
}, },
{ {
title: '运行分析', title: '运行分析',
class: 'stats-cards', class: 'stats-cards',
componentId: Operational, componentId:markRaw( Operational),
infoKey: '' infoKey: ''
}, },
{ {
title: '储能设备', title: '储能设备',
class: 'energy-status', class: 'energy-status',
componentId: Energy, componentId:markRaw( Energy),
infoKey: 'energy' infoKey: 'energy'
}, },
{ {
title: '充电设备', title: '充电设备',
class: 'charge-analysis', class: 'charge-analysis',
componentId: Charge, componentId:markRaw( Charge),
infoKey: 'charge' infoKey: 'charge'
}, },
{ {
title: '光伏设备', title: '光伏设备',
class: 'work-order', class: 'work-order',
componentId: Pv, componentId:markRaw( Pv),
infoKey: 'pv' infoKey: 'pv'
}, },
{ {
title: '告警信息', title: '告警信息',
class: 'alarm-stats', class: 'alarm-stats',
componentId: Alarm, componentId: markRaw(Alarm),
infoKey: 'alarm' infoKey: 'alarm'
} }
], ],

View File

@@ -13,7 +13,6 @@
ref="comTable" ref="comTable"
:table-option="tableOption" :table-option="tableOption"
:page-option="pageOption" :page-option="pageOption"
:table-h="tableH"
> >
<template #type="record"> <template #type="record">
<span>{{ ['其它','系统日志','操作日志','设备日志'][record.type] }}</span> <span>{{ ['其它','系统日志','操作日志','设备日志'][record.type] }}</span>

View File

@@ -13,7 +13,6 @@
ref="comTable" ref="comTable"
:table-option="tableOption" :table-option="tableOption"
:page-option="pageOption" :page-option="pageOption"
:table-h="tableH"
> >
<template #gender="record"> <template #gender="record">
<!-- 0:; 1: --> <!-- 0:; 1: -->

View File

@@ -15,7 +15,6 @@
ref="comTable" ref="comTable"
:table-option="tableOption" :table-option="tableOption"
:page-option="pageOption" :page-option="pageOption"
:table-h="tableH"
> >
<template #is_open="record"> <template #is_open="record">
<!-- 0:禁用; 1:启用 --> <!-- 0:禁用; 1:启用 -->
@@ -104,8 +103,14 @@ export default {
if (res.errcode === 0) { if (res.errcode === 0) {
this.$refs.comTable.loading = false this.$refs.comTable.loading = false
this.tableData = res.data // this.tableData = res.data
this.tableData =JSON.parse( localStorage.getItem('permission')).map((item)=>{
return {
...item,
key:item.permission_id,
}
})
console.log( this.tableData," this.tableData")
this.pageOption = { this.pageOption = {
page: res.page, page: res.page,
pageSize: res.page_size, pageSize: res.page_size,

View File

@@ -9,7 +9,6 @@
ref="comTable" ref="comTable"
:table-option="tableOption" :table-option="tableOption"
:page-option="pageOption" :page-option="pageOption"
:table-h="tableH"
> >
<template #type="record"> <template #type="record">
<div>{{ getPolicyType(record.type) }}</div> <div>{{ getPolicyType(record.type) }}</div>
@@ -117,7 +116,6 @@ export default {
pageSize: 10, pageSize: 10,
count: 0 count: 0
}, },
tableH: '',
formState: {}, formState: {},
formStatus: 'add', //表单状态辑状态 add:新增 edit:编辑 formStatus: 'add', //表单状态辑状态 add:新增 edit:编辑
operateList:[] operateList:[]

View File

@@ -15,7 +15,6 @@
ref="comTable" ref="comTable"
:table-option="tableOption" :table-option="tableOption"
:page-option="pageOption" :page-option="pageOption"
:table-h="tableH"
> >
<template #is_open="record"> <template #is_open="record">
<!-- 0:禁用; 1:启用 --> <!-- 0:禁用; 1:启用 -->
@@ -31,7 +30,7 @@
</template> </template>
</ComTable> </ComTable>
</div> </div>
<a-modal v-model:open="formModal" width="750px" style="top: 20px" :footer="null"> <a-modal v-model:open="formModal" width="950px" style="top: 20px" :footer="null" :destroy-on-close="true">
<!-- action:edit add --> <!-- action:edit add -->
<EditCom <EditCom
:show-flag="formModal" :show-flag="formModal"
@@ -50,7 +49,7 @@ import { getReq, postReq } from '@/request/api.js'
import ComTable from '@/components/ComTable' import ComTable from '@/components/ComTable'
import OperateCom from '@/components/OperateCom' import OperateCom from '@/components/OperateCom'
import EditCom from '@/components/EditCom.vue' import EditCom from '@/components/EditCom.vue'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue' import { ConsoleSqlOutlined, ExclamationCircleOutlined } from '@ant-design/icons-vue'
import { createVNode } from 'vue' import { createVNode } from 'vue'
import { Modal } from 'ant-design-vue' import { Modal } from 'ant-design-vue'
import searchBox from '@/components/SearchBox.vue' import searchBox from '@/components/SearchBox.vue'
@@ -73,7 +72,10 @@ export default {
page: 1 page: 1
}, },
btnOptionList: [], btnOptionList: [],
paramsDate: {} paramsDate: {},
tableOption: {
select:false
},
} }
}, },
computed: {}, computed: {},
@@ -126,24 +128,123 @@ export default {
//统一处理报错提示 //统一处理报错提示
} }
}, },
mergePermissionData(routeData, permissionData) {
// 创建权限ID快速索引
const permissionMap = new Map()
// 构建权限配置映射表(含子权限处理)
const flattenPermissions = (data) => {
data.forEach((item) => {
// 初始化权限项的默认值(关键修改)
const permissionItem = {
...item,
key: item.permission_id,
is_add: Boolean(+item.is_add) || false,
is_del: Boolean(+item.is_del )|| false,
is_edit: Boolean(+item.is_edit )|| false,
is_view: Boolean(+item.is_view )|| false,
// 确保子权限容器存在
children: item.children ? [...item.children] : []
}
permissionMap.set(item.permission_id, permissionItem)
// 递归处理子权限
if (item.children?.length) {
flattenPermissions(item.children)
}
})
}
// 初始化扁平化处理
flattenPermissions(permissionData)
// 递归构建合并后的树形结构
const buildTree = (data) => {
return data
.map((routeItem) => {
const permissionItem = permissionMap.get(routeItem.permission_id) || {
key: routeItem.permission_id,
is_add: false,
is_del: false,
is_edit: false,
is_view: false
}
// 基础合并:路由结构+权限配置
const mergedItem = {
...routeItem,
...permissionItem,
// 初始化子权限容器
children: routeItem.children ? buildTree(routeItem.children) : []
}
// 特殊处理:父级权限的联动计算
this.calculateParentPermissions(mergedItem)
return mergedItem
})
.filter(Boolean) // 过滤无效节点
}
return buildTree(routeData)
},
calculateParentPermissions(node) {
if (node.children?.length) {
node.is_view = node.children.some((child) => child.is_view === '1') ? true:false
node.is_add = node.children.some((child) => child.is_add === '1') ? true:false
node.is_edit = node.children.some((child) => child.is_edit === '1') ? true:false
node.is_del = node.children.some((child) => child.is_del === '1') ? true:false
}
},
async getPermissionList() { async getPermissionList() {
let arr = [] let arr = []
const res = await getReq('/queryPermissionList', { page_size: 1000, page: 1 })
const params = {
page_size: 1000,
page: 1
}
const res = await getReq('/queryPermissionList', params)
if (res.errcode === 0) { if (res.errcode === 0) {
arr = res.data arr = res.data
} else {
arr = [] // const permissionData = JSON.parse(localStorage.getItem('permission'));
// const permissionData = res.data
// arr = permissionData.map((item) => ({
// ...item,
// key: item.permission_id,
// // 转换操作权限为布尔值
// ...this.getPerOperBoolean(item),
// // 递归处理children
// children: item.children
// ? item.children.map((child) => ({
// ...child,
// ...this.getPerOperBoolean(child),
// key: child.permission_id,
// // 继续递归处理子项
// children: child.children
// ? child.children.map((grandchild) => ({
// ...grandchild,
// ...this.getPerOperBoolean(grandchild)
// }))
// : []
// }))
// : []
// }))
} }
return arr return arr
}, },
// 新增专用方法处理操作权限转换
getPerOperBoolean(data) {
return {
is_add: data ? Boolean(+data.is_add) : false,
is_del: data ? Boolean(+data.is_del) : false,
is_edit: data ? Boolean(+data.is_edit) : false,
is_view: data ? Boolean(+data.is_view ): false
}
},
operateForm(type, record = {}) { operateForm(type, record = {}) {
console.log(record, record.id, 'rrrrrrrrrr') console.log(record, 'rrrrrrrrrr')
this.formStatus = type this.formStatus = type
switch (type) { switch (type) {
case 'add': case 'add':
@@ -199,6 +300,7 @@ export default {
}) })
}, },
async getRuleFormInfo(record) { async getRuleFormInfo(record) {
function getInfo(data, url) { function getInfo(data, url) {
return new Promise((reslove, reject) => { return new Promise((reslove, reject) => {
getReq(data, url).then((res) => { getReq(data, url).then((res) => {
@@ -209,42 +311,53 @@ export default {
let row = {} let row = {}
if (record && record.role_id) { if (record && record.role_id) {
// row = await getInfo({ id: record.id },'/queryroleList')
this.record = record this.record = record
row = record row = record
// this.type='edit'
} }
const perList = await this.getPermissionList() const perList = await this.getPermissionList()
const permissionList=perList.map((item)=>{ this.processedData = this.mergePermissionData(
return{ perList,
key:+item.permission_id, record && record.permission.length ? record.permission : []
...item )
} const newData=JSON.parse(JSON.stringify( this.processedData))
})
console.log(permissionList, 'permissionList')
roleOptions.forEach((e, index) => { roleOptions.forEach((e, index) => {
e.list.forEach((i) => { e.list.forEach((i) => {
if (i.key == 'permission') { if (i.key == 'permission') {
i.tableData=permissionList i.tableData = newData
// .forEach((item)=>{ if(record&&record.role_id){
// .push({...item,key:item.permission_id}) i.selectTableData=this.extractAllIds( record.permission)
// }) }else {
if (record && record.role_id) { i.selectTableData=[]
i.selectTableData = row.permission
? row.permissionList.map((item) => item.permission_id)
: []
} else {
i.selectTableData = []
} }
} else { } else {
e.ruleForm[i.key] = row ? row[i.key] : '' e.ruleForm[i.key] = row ? row[i.key] : ''
} }
}) })
}) })
console.log(permissionList,"permissionList")
this.formModal = true this.formModal = true
},
// 定义提取所有ID的函数
extractAllIds(treeData) {
const idSet = new Set();
// 递归遍历函数
const traverse = (node) => {
// 添加当前节点ID
if (node.permission_id) {
idSet.add(node.permission_id);
}
// 递归处理子节点
if (node.children && node.children.length > 0) {
node.children.forEach((child) => traverse(child));
}
};
// 处理所有根节点
treeData.forEach((node) => traverse(node));
return Array.from(idSet);
}, },
handlePagesizeChange(pageOption) { handlePagesizeChange(pageOption) {
this.pageOption.pageSize = pageOption.pageSize this.pageOption.pageSize = pageOption.pageSize

View File

@@ -15,7 +15,6 @@
ref="comTable" ref="comTable"
:table-option="tableOption" :table-option="tableOption"
:page-option="pageOption" :page-option="pageOption"
:table-h="tableH"
> >
<template #is_open="record"> <template #is_open="record">
<span>{{ ['禁用', '启用'][record.is_open] }}</span> <span>{{ ['禁用', '启用'][record.is_open] }}</span>
@@ -56,6 +55,9 @@ export default {
props: {}, props: {},
data() { data() {
return { return {
tableOption: {
select:false
},
formModal: false, formModal: false,
formState: {}, formState: {},
formStatus: 'add', //表单状态辑状态 add:新增 edit:编辑 formStatus: 'add', //表单状态辑状态 add:新增 edit:编辑

View File

@@ -15,16 +15,15 @@
ref="comTable" ref="comTable"
:table-option="tableOption" :table-option="tableOption"
:page-option="pageOption" :page-option="pageOption"
:table-h="tableH"
> >
<template #status="record"> <template #status="record">
<span>{{ ['未启用', '启用'][record.status] }}</span> <span>{{ ['未启用', '启用'][record.status] }}</span>
</template> </template>
<template #work_mode="record"> <template #work_mode="record">
<span>{{workModeList.find(item=>record.value==item.value)?.label|| '' }}</span> <span>{{ workModeList.find((item) => record.value == item.value)?.label || '' }}</span>
</template> </template>
<template #policy_id="record"> <template #policy_id="record">
<span>{{policyList.find(item=>record.value==item.value)?.label|| ''}}</span> <span>{{ policyList.find((item) => record.value == item.value)?.label || '' }}</span>
</template> </template>
<template #action="record"> <template #action="record">
@@ -65,6 +64,9 @@ export default {
props: {}, props: {},
data() { data() {
return { return {
tableOption: {
select:false
},
formModal: false, formModal: false,
formState: {}, formState: {},
formStatus: 'add', //表单状态辑状态 add:新增 edit:编辑 formStatus: 'add', //表单状态辑状态 add:新增 edit:编辑
@@ -74,33 +76,33 @@ export default {
}, },
btnOptionList: [], btnOptionList: [],
paramsDate: {}, paramsDate: {},
workModeList:[ workModeList: [
{ {
label:'最优经济化', label: '最优经济化',
value:1 value: 1
}, },
{ {
label:'支撑电网稳定', label: '支撑电网稳定',
value:2 value: 2
}, },
{ {
label:'自定义', label: '自定义',
value:3 value: 3
}, }
], ],
policyList:[ policyList: [
{ {
label:'削峰套利', label: '削峰套利',
value:1 value: 1
}, },
{ {
label:'需求响应', label: '需求响应',
value:2 value: 2
}, },
{ {
label:'自发自用', label: '自发自用',
value:3 value: 3
}, }
] ]
} }
}, },
@@ -155,7 +157,7 @@ export default {
} }
}, },
operateForm(type, record = {}) { operateForm(type, record = {}) {
console.log(record,record.id,'rrrrrrrrrr') console.log(record, record.id, 'rrrrrrrrrr')
this.formStatus = type this.formStatus = type
switch (type) { switch (type) {
case 'add': case 'add':
@@ -172,7 +174,7 @@ export default {
break break
case 'del': case 'del':
this.handleDelete([record.station_id],this.getList) this.handleDelete([record.station_id], this.getList)
break break
@@ -186,7 +188,7 @@ export default {
} }
}, },
// 删除操作 // 删除操作
async handleDelete(id,callback) { async handleDelete(id, callback) {
const that = this const that = this
Modal.confirm({ Modal.confirm({
title: '你确认删除数据吗?', title: '你确认删除数据吗?',
@@ -194,10 +196,10 @@ export default {
async onOk() { async onOk() {
try { try {
const res = await getReq('/deleteStation',{station_id:id}) const res = await getReq('/deleteStation', { station_id: id })
if (res.errcode === 0) { if (res.errcode === 0) {
this.$message.success(res.errmsg) this.$message.success(res.errmsg)
this.pageOption.page=1 this.pageOption.page = 1
callback() callback()
} else { } else {
throw res throw res
@@ -230,7 +232,6 @@ export default {
} }
stationOptions.forEach((e, index) => { stationOptions.forEach((e, index) => {
e.list.forEach((i) => { e.list.forEach((i) => {
e.ruleForm[i.key] = row ? row[i.key] : '' e.ruleForm[i.key] = row ? row[i.key] : ''
e.ruleForm.id = row.id e.ruleForm.id = row.id
}) })

View File

@@ -15,7 +15,6 @@
ref="comTable" ref="comTable"
:table-option="tableOption" :table-option="tableOption"
:page-option="pageOption" :page-option="pageOption"
:table-h="tableH"
> >
<template #gender="record"> <template #gender="record">
<!-- 0:; 1: --> <!-- 0:; 1: -->
@@ -60,6 +59,9 @@ export default {
props: {}, props: {},
data() { data() {
return { return {
tableOption: {
select:false
},
formModal: false, formModal: false,
formState: {}, formState: {},
formStatus: 'add', //表单状态辑状态 add:新增 edit:编辑 formStatus: 'add', //表单状态辑状态 add:新增 edit:编辑