Prechádzať zdrojové kódy

2023-02-14 update

1. 调整router.js 菜单
2. 新增光伏数据准备 -- 已完成  光伏数据分析(功率分析, pv分析, iv分析) -- 未完成
moccus 2 rokov pred
rodič
commit
71b1c06999
26 zmenil súbory, kde vykonal 5118 pridanie a 3 odobranie
  1. 1 0
      src/components/Sidebar.vue
  2. 109 0
      src/pages/dataFilter/lightPrepare/components/search.vue
  3. 53 0
      src/pages/dataFilter/lightPrepare/components/table.vue
  4. 196 0
      src/pages/dataFilter/lightPrepare/index.vue
  5. 398 0
      src/pages/lightAnalysis/glAnalysis/components/configStation.json
  6. 398 0
      src/pages/lightAnalysis/glAnalysis/components/current-scatter-chart.json
  7. 347 0
      src/pages/lightAnalysis/glAnalysis/components/current-scatter-chart.vue
  8. 109 0
      src/pages/lightAnalysis/glAnalysis/components/search.vue
  9. 1 0
      src/pages/lightAnalysis/glAnalysis/components/submitRES.json
  10. 53 0
      src/pages/lightAnalysis/glAnalysis/components/table.vue
  11. 237 0
      src/pages/lightAnalysis/glAnalysis/index.vue
  12. 398 0
      src/pages/lightAnalysis/ivAnalysis/components/configStation.json
  13. 398 0
      src/pages/lightAnalysis/ivAnalysis/components/current-scatter-chart.json
  14. 341 0
      src/pages/lightAnalysis/ivAnalysis/components/current-scatter-chart.vue
  15. 80 0
      src/pages/lightAnalysis/ivAnalysis/components/search.vue
  16. 1 0
      src/pages/lightAnalysis/ivAnalysis/components/submitRES.json
  17. 53 0
      src/pages/lightAnalysis/ivAnalysis/components/table.vue
  18. 304 0
      src/pages/lightAnalysis/ivAnalysis/index.vue
  19. 398 0
      src/pages/lightAnalysis/pvAnalysis/components/configStation.json
  20. 398 0
      src/pages/lightAnalysis/pvAnalysis/components/current-scatter-chart.json
  21. 341 0
      src/pages/lightAnalysis/pvAnalysis/components/current-scatter-chart.vue
  22. 80 0
      src/pages/lightAnalysis/pvAnalysis/components/search.vue
  23. 1 0
      src/pages/lightAnalysis/pvAnalysis/components/submitRES.json
  24. 53 0
      src/pages/lightAnalysis/pvAnalysis/components/table.vue
  25. 304 0
      src/pages/lightAnalysis/pvAnalysis/index.vue
  26. 66 3
      src/router/index.js

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 0
src/components/Sidebar.vue


+ 109 - 0
src/pages/dataFilter/lightPrepare/components/search.vue

@@ -0,0 +1,109 @@
+<script setup name="search">
+import { onMounted, reactive, ref } from 'vue'
+import request from '@/api/axios.js'
+import SubmitBtn from '@com/SubmitBtn.vue'
+
+const queryForm = reactive({
+	station: '',
+	wtIds: [],
+	st: Date.now() - 30 * 24 * 60 * 60 * 1000,
+	et: Date.now(),
+	// interval: 3
+})
+/**场站 */
+const stationList = ref([])
+const funGetStation = async () => {
+	const res = await request.get("/base/gfstation")
+	stationList.value = res.data
+	if (stationList.value.length) {
+		queryForm.station = 'HZJ_GDC'
+		funGetWind(queryForm.station)
+	}
+}
+const funStationChange = (stationId) => {
+	if (stationId) {
+		funGetWind(stationId)
+	} else {
+		windList.value = []
+	}
+}
+/**风机 */
+const checkAll = ref(true)
+const windList = ref([])
+const funGetWind = async (stationId) => {
+	const res = await request.get("base/inverter", {params: { stationId }})
+	windList.value = res.data
+	queryForm.wtIds = res.data.map(o => o.id)
+	checkAll.value = true
+}
+const funCheckAll = () => {
+	checkAll.value = !checkAll.value
+	if(checkAll.value){
+		queryForm.wtIds = windList.value.map(o => o.id)
+	}else{
+		queryForm.wtIds = []
+	}
+}
+/**导出 */
+const emits = defineEmits(['submit'])
+const funSubmit = async () => {
+	const startDate = new Date(queryForm.st).setHours(0,0,0,0)
+	const endDate = new Date(queryForm.et).setHours(0,0,0,0)
+	const query = {
+		station: queryForm.station,
+		wtIds: queryForm.wtIds.join(),
+		st: new Date(startDate).getTime(),
+		et: new Date(endDate).getTime(),
+		// interval: queryForm.interval
+	}
+	// switch (queryForm.interval) {
+	// 	case 2:
+	// 		query.interval = 60
+	// 		break;
+	// 	case 3:
+	// 		query.interval = 600
+	// 		break;
+	// 	case 4:
+	// 		query.interval = 900
+	// 		break;
+	// }
+	emits('submit', query)
+}
+/**created */
+funGetStation()
+</script>
+<template>
+	<div class="pl-[20px] flex items-center h-[80px] relative">
+		<div class="absolute top-[-7px] left-[20px] text-[#838383] text-[14px]">操作面板</div>
+		<el-form class="" :inline="true" :model="queryForm">
+			<el-form-item label="场站" class="!mb-0">
+				<el-select v-model="queryForm.station" class="w-[150px]" @change="funStationChange">
+					<el-option v-for="item in stationList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+				</el-select>
+			</el-form-item>
+			<el-form-item label="逆变器" class="!mb-0">
+				<el-select multiple clearable class="w-[150px]" v-model="queryForm.wtIds" @clear="checkAll = false" collapse-tags>
+					<el-option label="全选" :class="{'selected': checkAll}" @click="funCheckAll"></el-option>
+					<el-option v-for="item in windList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+				</el-select>
+			</el-form-item>
+			<el-form-item label="开始时间" class="!mb-0">
+				<el-date-picker type="date" class="!w-[150px]" v-model="queryForm.st"></el-date-picker>
+			</el-form-item>
+			<el-form-item label="结束时间" class="!mb-0">
+				<el-date-picker type="date" class="!w-[150px]" v-model="queryForm.et"></el-date-picker>
+			</el-form-item>
+			<!-- <el-form-item label="等间隔" class="!mb-0">
+				<el-radio-group v-model="queryForm.interval">
+					<el-radio :label="1">一秒钟</el-radio>
+					<el-radio :label="2">一分钟</el-radio>
+					<el-radio :label="3">十分钟</el-radio>
+					<el-radio :label="4">十五分钟</el-radio>
+				</el-radio-group>
+			</el-form-item> -->
+			<el-form-item class="!mb-0">
+				<submit-btn v-prevdbclick:5000="funSubmit" desc="执行"></submit-btn>
+			</el-form-item>
+		</el-form>
+	</div>
+</template>

+ 53 - 0
src/pages/dataFilter/lightPrepare/components/table.vue

@@ -0,0 +1,53 @@
+<script setup name="table">
+import {ref, computed} from 'vue'
+const props = defineProps({
+  height: {
+    type: String,
+    default: '800px'
+  },
+  data: {
+    type: Array,
+    default: () => ([]),
+  },
+  column: {
+    type: Array,
+    default: () => ([]),
+  },
+  tableName: {
+    type: String,
+    default: '',
+  },
+  tableId: {
+    type: String,
+    default: '',
+  },
+  loading: {
+    type: Boolean,
+    default: false,
+  }
+})
+const emits = defineEmits(['export'])
+const funExport = () => {
+  emits('export')
+}
+const tableRef = ref('')
+const tableHeight =  computed(() => {
+  return tableRef.value.offsetHeight? tableRef.value.offsetHeight - 46 : 739
+})
+</script>
+<template>
+  <div ref="tableRef" class="p-[10px] shadow rounded-[6px] shadow-blue-500"
+    :style="{ height: typeof props.height === 'string' ? props.height : props.height + 'px' }">
+    <div class="flex justify-between items-center pb-[10px]">
+      <h3>{{props.tableName}}</h3>
+      <!-- <el-button size="small" type="primary" @click="funExport" :disabled="!props.tableId">数据导出</el-button> -->
+    </div>
+    <el-table :data="props.data"
+      stripe
+      size="small" v-loading="props.loading"
+      :max-height="tableHeight"
+      :style="{ width: '100%'}">
+      <el-table-column align="center" show-overflow-tooltip v-for="item in props.column" :prop="item.prop" :label="item.label" sortable resizable :min-width="item.width? item.width : 80" />
+    </el-table>
+  </div>
+</template>

+ 196 - 0
src/pages/dataFilter/lightPrepare/index.vue

@@ -0,0 +1,196 @@
+<script setup name="prepare">
+import searchCop from './components/search.vue'
+import excelCop from '@/components/excel.vue'
+import treeCop from '@/components/tree.vue'
+import tableCop from './components/table.vue'
+import { ElMessage } from 'element-plus';
+import { onMounted, ref, onActivated } from 'vue'
+import request from '@/api/axios.js'
+import {baseURL, socketURL} from '@/api/axios.js'
+/**配置参数 */
+const treeHeight = ref(window.innerHeight - 260 + 'px') //tree高度
+const excelHeight = ref(window.innerHeight - 260 + 'px') //excel高度
+const tableHeight = ref(window.innerHeight - 260 + 'px')
+/**excel 开始 */
+const excelList = ref([])
+const funExcelChange = async (obj) => { //点击excel项时
+	tableShowId.value = obj.id
+	tableName.value = obj.name
+	tableLoading.value = true
+	const res = await request.get('/datas', { params: { filename: obj.id } })
+	if(res.code === 200){
+		tableColumn.value = res.data.title.map(o => {
+			return {
+				prop: o.key,
+				label: o.des,
+				width: o.des==='时间'? 100: 80,
+			}
+		})
+		tableData.value = res.data.data
+		tableLoading.value = false
+	}else{
+		tableLoading.value = false
+	}
+}
+/**tree 开始 */
+/**
+const treeData = ref([])
+const actTreeNode = ref(null) //当前激活的treeNode
+const funRepeatMap = (arr) => {
+	return arr.map(o => {
+		if (o.children) {
+			const findIndex = o.children.findIndex(p => !!p.type)
+			if (findIndex !== -1) {
+				o.childs = o.children
+				o.children = []
+				if(!actTreeNode.value){ //判断当且仅有process获取tree时 赋值
+					actTreeNode.value = o
+				}
+			}
+		}
+		return {
+			...o,
+			children: o.children?.length ? funRepeatMap(o.children) : []
+		}
+	})
+}
+const funGetTree = async () => {
+	actTreeNode.value = null
+	const res = await request.get("/power/prepare/tree")
+	treeData.value = funRepeatMap(res.data)
+	excelList.value = []
+	if(actTreeNode.value){
+		funCurrentChange({current: actTreeNode.value, currentNode: null})
+		const child = actTreeNode.value.childs[0]
+		const obj = {
+			id: child.id,
+			interval: child.interval,
+			path: child.path,
+			prepareid: child.prepareid,
+			station: child.station,
+			time: child.time,
+			type: child.type,
+			windturbine: child.windturbine,
+			name: child.path.substring(child.path.indexOf(child.station + '_') + (child.station + '_').length)
+		}
+		funExcelChange(obj)
+	}
+}
+const funCurrentChange = ({ current, currentNode }) => {
+	if (current.childs) {
+		excelList.value = current.childs.map(o => {
+			return {
+				id: o.id,
+				interval: o.interval,
+				path: o.path,
+				prepareid: o.prepareid,
+				station: o.station,
+				time: o.time,
+				type: o.type,
+				windturbine: o.windturbine,
+				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
+			}
+		})
+	} else {
+		excelList.value = []
+	}
+}
+ */
+/**table 开始 */
+const tableShowId = ref('')
+const tableName = ref('')
+const tableColumn = ref([])
+const tableLoading = ref(false)
+const tableData = ref([])
+const funExport = async () => {
+	const a = document.createElement('a')
+	a.href = baseURL + '/power/prepare/download?id=' + tableShowId.value
+	a.download = ''
+	a.click()
+}
+/**submit */
+const progress = ref(0)
+/** 
+const funWebSocket = () => {
+	const webSocket = new WebSocket(`${socketURL}/ws/powerfitting/admin`)
+	webSocket.onerror = () => setTimeout(() => { funWebSocket() }, 2000)
+
+	webSocket.onmessage = (event) => {
+		const message = JSON.parse(event.data)
+		if (message.code === 200) {
+			progress.value = Number(message.data) * 100
+			if (progress.value === 100) {
+				ElMessage.success('数据加载完成')
+				funGetTree()
+				progress.value = 0
+			}
+		}
+	}
+}
+*/
+const funSubmit = async (params) => {
+	const res = await request.get('/filelist', { params: {
+		station: params.station,
+		inverters: params.wtIds,
+		startdate: params.st,
+		enddate: params.et
+	} })
+	if (res.code === 200) {
+		ElMessage.success(res.msg)
+		if(res.data?.length){
+			excelList.value = res.data.map(o => {
+				return {
+					id: o,
+					name: o
+				}
+			})
+			funExcelChange(excelList.value[0])
+		}
+	}
+}
+/**created */
+// funGetTree()
+// funWebSocket()
+/**mounted */
+onMounted(() => {
+	tableHeight.value = window.innerHeight - 260 + 'px'
+	excelHeight.value = window.innerHeight - 260 + 'px'
+	treeHeight.value = window.innerHeight - 260 + 'px'
+	window.addEventListener('resize', () => {
+		tableHeight.value = window.innerHeight - 260 + 'px'
+		excelHeight.value = window.innerHeight - 260 + 'px'
+		treeHeight.value = window.innerHeight - 260 + 'px'
+	})
+})
+/**activated */
+onActivated(() => {
+	// funGetTree()
+})
+</script>
+<template>
+	<div class="bg-white py-[10px] px-[10px] relative">
+		<search-cop class="mb-[20px] shadow rounded-[6px] shadow-blue-500" @submit="funSubmit">
+		</search-cop>
+		<div class="relative shadow rounded-[6px] shadow-blue-500 px-[10px] pt-[20px] pb-[10px]">
+			<div class="text-[14px] absolute top-[-7px] text-[#838383] left-[20px]">数据展示</div>
+			<el-row :gutter="10">
+				<!-- <el-col :span="5">
+					<tree-cop :data="treeData" :height="treeHeight" @currentChange="funCurrentChange" @refresh="funGetTree">
+					</tree-cop>
+				</el-col> -->
+				<el-col :span="4">
+					<excel-cop :data="excelList" :height="excelHeight" @excelChange="funExcelChange"></excel-cop>
+				</el-col>
+				<el-col :span="20">
+					<div>
+						<table-cop class="" :data="tableData" :column="tableColumn" :loading="tableLoading"
+							:height="tableHeight" :tableId="tableShowId" :tableName="tableName" @export="funExport"></table-cop>
+					</div>
+				</el-col>
+			</el-row>
+		</div>
+
+		<el-progress :percentage="progress" v-if="progress" class="!absolute top-0 right-0 left-0" :indeterminate="false"
+			color="rgb(19,206,102)" :stroke-width="4" :show-text="false" />
+	</div>
+</template>

+ 398 - 0
src/pages/lightAnalysis/glAnalysis/components/configStation.json

@@ -0,0 +1,398 @@
+{
+	"NSS_BT": {
+		"id": "NSS_BT",
+		"installedCapacity": 148.5,
+		"title": "牛首山第二风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "NSSDQN.NX_GD_NSSF_DQ_P1_L1_001_AI1019",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "NSSDQN.NX_GD_NSSF_DQ_P1_L1_001_AI1009",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "NSSDQN.NX_GD_NSSF_DQ_P1_L1_001_AI1010",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "NSSFCJSFW.NX_GD_NSSF_XX_XX_XXX_XXX_CI0193",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "NSSDQN.NX_GD_NSSF_DQ_P1_L1_001_AI1011",
+			"multiplier": 0.1,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "NSSFGL.NX_GD_NSSF_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"QS_BT": {
+		"id": "QS_BT",
+		"installedCapacity": 99.0,
+		"title": "麻黄山第六风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "QSDQ.NX_GD_QSF_DQ_P1_L1_001_AI1281",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "QSDQ.NX_GD_QSF_DQ_P1_L1_001_AI1282",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "QSDQ.NX_GD_QSF_DQ_P1_L1_001_AI1284",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "QSFCJSFW.NX_GD_QSF_FJ_P1_XXX_XXX_CI0192,QSFCJSFW.NX_GD_QSF_FJ_P2_XXX_XXX_CI0192",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "QSDQ.NX_GD_QSF_DQ_P1_L1_001_AI1285",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "QSFGL.NX_GD_QSF_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"XS_BT": {
+		"id": "XS_BT",
+		"installedCapacity": 99.0,
+		"title": "香山第五风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "XSDQ.NX_GD_XSF_DQ_P1_L1_001_AI0411",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "XSDQ.NX_GD_XSF_DQ_P1_L1_001_AI0415",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "XSDQ.NX_GD_XSF_DQ_P1_L1_001_AI0412",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "XSFCJSFW.NX_GD_XSF_XX_XX_XXX_XXX_CI0193",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "XSDQ.NX_GD_XSF_DQ_P1_L1_001_AI0413",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "XSFGL.NX_GD_XSF_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"MHS_BT": {
+		"id": "MHS_BT",
+		"installedCapacity": 69.5,
+		"title": "麻黄山第二风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "MHSDQ.NX_GD_MHSF_DQ_P1_L1_001_AI0296",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "MHSDQ.NX_GD_MHSF_DQ_P1_L1_001_AI0013",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "MHSDQ.NX_GD_MHSF_DQ_P1_L1_001_AI0294",
+			"multiplier": 0.1,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "MHSFCJSFW.NX_GD_MHSF_XX_XX_XXX_XXX_CI0193",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "MHSDQ.NX_GD_MHSF_DQ_P1_L1_001_AI0295",
+			"multiplier": 0.01,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "MHSFGL.NX_GD_MHSF_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"XH_BT": {
+		"id": "XH_BT",
+		"installedCapacity": 20.0,
+		"title": "宣和光伏电站",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "XHDQ.NX_GD_XHG_DQ_P1_L1_001_AI0204",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "XHDQ.NX_GD_XHG_DQ_P1_L1_001_AI0193",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "XHDQ.NX_GD_XHG_DQ_P1_L1_001_AI0194",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "XHGDCJSFW.NX_GD_XHG_XX_XX_XXX_XXX_CI0192",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "XHDQ.NX_GD_XHG_DQ_P1_L1_001_AI0195",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "XHGGL.NX_GD_XHG_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"SL_BT": {
+		"id": "SL_BT",
+		"installedCapacity": 49.5,
+		"title": "宋堡第六风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "SLAGC.NX_GD_QSF_DQ_P1_L1_001_AI0052",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "SLDQ.NX_GD_QSF_DQ_P1_L1_001_AI0013",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "SLAGC.NX_GD_QSF_DQ_P1_L1_001_AI0053",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "QSFCJSFW.NX_GD_QSF_FJ_P3_XXX_XXX_CI0192",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "SLAGC.NX_GD_QSF_DQ_P1_L1_001_AI0054",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "SLFGL.NX_GD_QSF_YC_P1_L1_001_LCDQ01",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"HZJ_BT": {
+		"id": "HZJ_BT",
+		"installedCapacity": 50.0,
+		"title": "海子井光伏电站",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0016",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0015",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0021",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0214",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0022",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "HZJGGL.NX_GD_HZJG_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"XN6_BT": {
+		"id": "XN6_BT",
+		"installedCapacity": 49.5,
+		"title": "星能第六风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0818",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0012",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0819",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0826",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0820",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0827",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"N5_BT": {
+		"id": "N5_BT",
+		"installedCapacity": 149.0,
+		"title": "牛首山第五风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0818",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0817",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0819",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0830",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0820",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0831",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"DWK_BT": {
+		"id": "DWK_BT",
+		"installedCapacity": 10.0,
+		"title": "大武口光伏电站",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "DWKDQ.NX_GD_DWKG_DQ_P1_L1_001_AI0838",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "DWKGDCJSFW.NX_GD_DWKG_XX_XX_XXX_XXX_CI0192",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "DWKDQ.NX_GD_DWKG_DQ_P1_L1_001_AI0839",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "DWKGGL.NX_GD_DWKG_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"PL_BT": {
+		"id": "PL_BT",
+		"installedCapacity": 30.0,
+		"title": "平罗光伏电站",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "PLSJ1.NX_GD_PLG_DQ_P1_L1_001_AI0838",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "PLSJ1.NX_GD_PLG_DQ_P1_L1_001_AI0835",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "PLSJ1.NX_GD_PLG_DQ_P1_L1_001_AI0836",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "PLGDCJSFW.NX_GD_PLG_XX_XX_XXX_XXX_CI0192",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "PLSJ1.NX_GD_PLG_DQ_P1_L1_001_AI0837",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "PLGGL.NX_GD_PLG_YC_P1_L1_001_CDQ0001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	}
+}

+ 398 - 0
src/pages/lightAnalysis/glAnalysis/components/current-scatter-chart.json

@@ -0,0 +1,398 @@
+
+{
+	"color": [
+			"#1C99FF",
+			"#FF8700",
+			"#e6b600d9",
+			"#0098d9",
+			"#3D54BE",
+			"#005eaa",
+			"#cda819",
+			"#32a487"
+	],
+	"textStyle": {},
+	"title": {
+			"textStyle": {
+					"color": "#333333"
+			},
+			"subtextStyle": {
+					"color": "#aaaaaa"
+			}
+	},
+	"line": {
+			"itemStyle": {
+					"borderWidth": 1
+			},
+			"lineStyle": {
+					"width": 2
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false
+	},
+	"radar": {
+			"itemStyle": {
+					"borderWidth": 1
+			},
+			"lineStyle": {
+					"width": 2
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false
+	},
+	"bar": {
+			"itemStyle": {
+					"barBorderWidth": 0,
+					"barBorderColor": "#ccc"
+			}
+	},
+	"pie": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"scatter": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"boxplot": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"parallel": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"sankey": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"funnel": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"gauge": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"candlestick": {
+			"itemStyle": {
+					"color": "#c12e34",
+					"color0": "#2b821d",
+					"borderColor": "#c12e34",
+					"borderColor0": "#2b821d",
+					"borderWidth": 1
+			}
+	},
+	"graph": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			},
+			"lineStyle": {
+					"width": 1,
+					"color": "#aaaaaa"
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false,
+			"color": [
+					"#c12e34",
+					"#e6b600",
+					"#0098d9",
+					"#50ec39",
+					"#005eaa",
+					"#339ca8",
+					"#cda819",
+					"#32a487"
+			],
+			"label": {
+					"color": "#eeeeee"
+			}
+	},
+	"map": {
+			"itemStyle": {
+					"areaColor": "#ddd",
+					"borderColor": "#eee",
+					"borderWidth": 0.5
+			},
+			"label": {
+					"color": "#c12e34"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"areaColor": "#e6b600",
+							"borderColor": "#ddd",
+							"borderWidth": 1
+					},
+					"label": {
+							"color": "#c12e34"
+					}
+			}
+	},
+	"geo": {
+			"itemStyle": {
+					"areaColor": "#ddd",
+					"borderColor": "#eee",
+					"borderWidth": 0.5
+			},
+			"label": {
+					"color": "#c12e34"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"areaColor": "#e6b600",
+							"borderColor": "#ddd",
+							"borderWidth": 1
+					},
+					"label": {
+							"color": "#c12e34"
+					}
+			}
+	},
+	"categoryAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#838383"
+			},
+			"splitLine": {
+					"show": false,
+					"lineStyle": {
+							"color": [
+									"#838383"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"valueAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#838383"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"logAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#333"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"timeAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#838383"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#838383"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"toolbox": {
+			"iconStyle": {
+					"borderColor": "#06467c"
+			},
+			"emphasis": {
+					"iconStyle": {
+							"borderColor": "#4187c2"
+					}
+			},
+			"textStyle": {
+				"color": "#838383"
+			}
+	},
+	"legend": {
+			"textStyle": {
+					"color": "#838383"
+			}
+	},
+	"tooltip": {
+			"axisPointer": {
+					"lineStyle": {
+							"color": "#cccccc",
+							"width": 1
+					},
+					"crossStyle": {
+							"color": "#cccccc",
+							"width": 1
+					}
+			}
+	},
+	"timeline": {
+			"lineStyle": {
+					"color": "#005eaa",
+					"width": 1
+			},
+			"itemStyle": {
+					"color": "#005eaa",
+					"borderWidth": 1
+			},
+			"controlStyle": {
+					"color": "#005eaa",
+					"borderColor": "#005eaa",
+					"borderWidth": 0.5
+			},
+			"checkpointStyle": {
+					"color": "#005eaa",
+					"borderColor": "#316bc2"
+			},
+			"label": {
+					"color": "#005eaa"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"color": "#005eaa"
+					},
+					"controlStyle": {
+							"color": "#005eaa",
+							"borderColor": "#005eaa",
+							"borderWidth": 0.5
+					},
+					"label": {
+							"color": "#005eaa"
+					}
+			}
+	},
+	"visualMap": {
+			"color": [
+					"#1790cf",
+					"#a2d4e6"
+			]
+	},
+	"dataZoom": {
+			"backgroundColor": "rgba(47,69,84,0)",
+			"dataBackgroundColor": "rgba(47,69,84,0.3)",
+			"fillerColor": "rgba(167,183,204,0.4)",
+			"handleColor": "#a7b7cc",
+			"handleSize": "100%",
+			"textStyle": {
+					"color": "#333333"
+			}
+	},
+	"markPoint": {
+			"label": {
+					"color": "#eeeeee"
+			},
+			"emphasis": {
+					"label": {
+							"color": "#eeeeee"
+					}
+			}
+	}
+}

+ 347 - 0
src/pages/lightAnalysis/glAnalysis/components/current-scatter-chart.vue

@@ -0,0 +1,347 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@tools/util";
+import partten from "@tools/partten";
+import * as echarts from "echarts";
+import chartTheme from './current-scatter-chart.json'
+
+export default {
+  name: 'currentScatterChart',
+  props: {
+    // 图表宽度
+    width: {
+      type: String,
+      default: "100%",
+    },
+    // 图表高度
+    height: {
+      type: String,
+      default: "350px",
+    },
+    // 图表主标题
+    chartTitle: {
+      type: String,
+      default: "自定义图表组件",
+    },
+    // X 轴配置项
+    xAxisData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    // Y 轴配置项
+    yAxisData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    dataSet: {
+      type: String,
+      default: ''
+    },
+    // 图表核心数据
+    seriesData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    // 是否显示图表图例
+    showLegend: {
+      type: Boolean,
+      default: true,
+    },
+    // 是否默认采用笔刷模式
+    brushSelected: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+      color: [
+        "#05bb4c",
+        "#4b55ae",
+        "#fa8c16",
+        "#f8de5b",
+        "#1a93cf",
+        "#c531c7",
+        "#bd3338",
+      ],
+      theme: 'light'
+    };
+  },
+  watch: {
+    height(){
+      if(this.chart){
+          this.chart.resize()
+      }
+    }
+  },
+  methods: {
+    resize() {},
+    initChart() {
+      const that = this;
+      echarts.registerTheme('chartTheme', chartTheme)
+      let myChart = echarts.init(document.getElementById(this.id), 'chartTheme');
+      that.chart = myChart
+      //指定图表的配置项和数据
+      const option = {
+        //标题
+        title: {
+          text: that.chartTitle,
+          right: 440,
+          top: 4,
+          textStyle: {
+            fontSize: 14,
+            color: that.theme === "dark" ? partten.getColor("grayl") : "#000",
+          },
+        },
+        // backgroundColor:
+        //   that.theme === "dark"
+        //     ? "rgba(0,0,0,0.4)"
+        //     : "rgba(255,255,255,0.5)",
+        //工具箱
+        color: [
+            "#0098d9",
+            "rgb(255,0,0)",
+            "#0a4468",
+            "#a9e3f199",
+            "#a9e3f199",
+            "#005eaa",
+            "#cda819",
+            "#32a487"
+        ],
+        toolbox: {
+          show: false,
+          x: "right",
+          position: [10, 10],
+          // backgroundColor:'rgba(0,0,0,0.4)',
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            fontSize: util.vh(16),
+            color: partten.getColor("gray")
+          },
+          iconStyle: {
+            borderColor:partten.getColor("gray")
+          },
+          emphasis: {
+            iconStyle: {
+              borderColor:partten.getColor("gray")
+            },
+          },
+        },
+        tooltip: {
+          trigger: "axis",
+          axisPointer: {
+            type: "cross",
+          },
+          // backgroundColor: "rgba(0,0,0,0.4)",
+          // borderColor: partten.getColor("gray"),
+          // textStyle: {
+          //   fontSize: util.vh(16),
+          //   color: partten.getColor("gray"),
+          // },
+          // formatter(params) {
+          //   return params.value?.x
+          //     ? `${params.seriesName}<br />风速:${params.value.x}m/s<br />功率:${params.value.y}kW`
+          //     : `${params.name}`;
+          // },
+        },
+        brush: {
+          seriesIndex: [2,3],
+          yAxisIndex: 0,
+          transformable: true,
+          throttleType: "debounce",
+          throttleDelay: 1000,
+          removeOnClick: true,
+          brushType: "polygon",
+          brushMode: "multiple",
+          brushStyle: {
+            borderWidth: 1,
+            borderColor: "#ff2424",
+          },
+        },
+        dataZoom: [
+          {
+            type: "inside", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+          {
+            type: "slider", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+        ],
+        textStyle: {
+          fontSize: util.vh(16),
+          color: that.theme === "dark" ? "#fff" : "#000",
+        },
+        //图例-每一条数据的名字
+        legend: {
+          show: that.showLegend,
+          // data: [ "拟合功率", "保证功率","无用点", "有用点", "Cp值"],
+          right: 170,
+          type: 'scroll',
+          top: "5",
+          // icon: "circle",
+          itemWidth: 6,
+          inactiveColor:
+            that.theme === "dark"
+              ? partten.getColor("gray")
+              : "#000",
+          textStyle: {
+            color:
+              that.theme === "dark"
+                ? partten.getColor("grayl")
+                : "#000",
+            fontSize: 12,
+          },
+          
+        },
+        grid: {
+          top: 58,
+          left: 40,
+          right: 48,
+          bottom: 24,
+        },
+        //x轴
+        xAxis: [
+          {
+            name: '时间',
+            nameTextStyle: {
+              color: '#838383'
+            },
+            type: "category",
+            boundaryGap: true,
+            data: that.xAxisData || [],
+            axisLabel: {
+              formatter: "{value}",
+            },
+            splitLine: {
+              show: false,
+            },
+            axisLine: {
+              onZero: false
+            },
+            smooth: true,
+            textStyle: {
+              color:
+                that.theme === "dark"
+                  ? partten.getColor("gray")
+                  : "#000",
+            },
+          },
+        ],
+        //y轴没有显式设置,根据值自动生成y轴
+        yAxis: [{
+          splitLine: { show: false },
+          position: 'left',
+          min: 0,
+          name: 'MW',
+          nameTextStyle: {
+            color: '#838383'
+          },
+          axisLine: {
+            onZero: false
+          },
+        }],
+        animation: true,
+        dataset: that.dataSet.length? JSON.parse(that.dataSet) : [],
+        //数据-data是最终要显示的数据
+        series: that.seriesData,
+      };
+
+      that.resize = function () {
+        myChart.resize();
+      };
+
+      window.addEventListener("resize", that.resize);
+
+      myChart.setOption(option);
+      // if (that.brushSelected) {
+      //   myChart.dispatchAction({
+      //     type: "takeGlobalCursor",
+      //     // 如果想变为“可刷选状态”,必须设置。不设置则会关闭“可刷选状态”。
+      //     key: "brush",
+      //     brushOption: {
+      //       seriesIndex: [2,3],
+      //       yAxisIndex: 0,
+      //       transformable: true,
+      //       throttleType: "debounce",
+      //       throttleDelay: 1000,
+      //       removeOnClick: true,
+      //       brushType: "polygon",
+      //       brushMode: "multiple",
+      //       brushStyle: {
+      //         borderWidth: 1,
+      //         color: "rgba(255,36,36,0.2)",
+      //         borderColor: "#ff2424",
+      //       },
+      //     },
+      //   });
+      // }
+      myChart.off("brushSelected");
+      myChart.on("brushSelected", (params) => {
+        that.$emit("getSelected", params.batch || []);
+      });
+      myChart.off('click')
+      myChart.on('click', params => {
+          // if(params.componentType === 'markArea'){
+          //   myChart.dispatchAction({
+          //     type: 'brush',
+          //     areas: [
+          //       {
+          //         xAxisIndex: 0,
+          //         brushType: 'lineX',
+          //         coordRange: [params.data.coord[0][0], params.data.coord[1][0]]
+          //       },
+          //     ]
+          //   });
+          // }
+        })
+    },
+  },
+  created() {
+    this.id = "chart-" + util.newGUID();
+  },
+  mounted() {
+    // this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+      this.initChart();
+    // });
+  },
+  updated() {
+    console.log('update')
+    let myChart = echarts.init(document.getElementById(this.id));
+    myChart.dispose();
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+  unmounted() {
+    window.removeEventListener("resize", this.resize);
+  },
+};
+</script>
+
+<style>
+.chart {
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+}
+</style>

+ 109 - 0
src/pages/lightAnalysis/glAnalysis/components/search.vue

@@ -0,0 +1,109 @@
+<script setup name="search">
+import { onMounted, reactive, ref } from 'vue'
+import request from '@/api/axios.js'
+import SubmitBtn from '@com/SubmitBtn.vue'
+
+const queryForm = reactive({
+	station: '',
+	wtIds: [],
+	st: Date.now() - 30 * 24 * 60 * 60 * 1000,
+	et: Date.now(),
+	// interval: 3
+})
+/**场站 */
+const stationList = ref([])
+const funGetStation = async () => {
+	const res = await request.get("/base/gfstation")
+	stationList.value = res.data
+	if (stationList.value.length) {
+		queryForm.station = 'HZJ_GDC'
+		funGetWind(queryForm.station)
+	}
+}
+const funStationChange = (stationId) => {
+	if (stationId) {
+		funGetWind(stationId)
+	} else {
+		windList.value = []
+	}
+}
+/**风机 */
+const checkAll = ref(true)
+const windList = ref([])
+const funGetWind = async (stationId) => {
+	const res = await request.get("base/inverter", {params: { stationId }})
+	windList.value = res.data
+	queryForm.wtIds = res.data.map(o => o.id)
+	checkAll.value = true
+}
+const funCheckAll = () => {
+	checkAll.value = !checkAll.value
+	if(checkAll.value){
+		queryForm.wtIds = windList.value.map(o => o.id)
+	}else{
+		queryForm.wtIds = []
+	}
+}
+/**导出 */
+const emits = defineEmits(['submit'])
+const funSubmit = async () => {
+	const startDate = new Date(queryForm.st).setHours(0,0,0,0)
+	const endDate = new Date(queryForm.et).setHours(0,0,0,0)
+	const query = {
+		station: queryForm.station,
+		wtIds: queryForm.wtIds.join(),
+		st: new Date(startDate).getTime(),
+		et: new Date(endDate).getTime(),
+		// interval: queryForm.interval
+	}
+	// switch (queryForm.interval) {
+	// 	case 2:
+	// 		query.interval = 60
+	// 		break;
+	// 	case 3:
+	// 		query.interval = 600
+	// 		break;
+	// 	case 4:
+	// 		query.interval = 900
+	// 		break;
+	// }
+	emits('submit', query)
+}
+/**created */
+funGetStation()
+</script>
+<template>
+	<div class="pl-[20px] flex items-center h-[80px] relative">
+		<div class="absolute top-[-7px] left-[20px] text-[#838383] text-[14px]">操作面板</div>
+		<el-form class="" :inline="true" :model="queryForm">
+			<el-form-item label="场站" class="!mb-0">
+				<el-select v-model="queryForm.station" class="w-[150px]" @change="funStationChange">
+					<el-option v-for="item in stationList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+				</el-select>
+			</el-form-item>
+			<el-form-item label="逆变器" class="!mb-0">
+				<el-select multiple clearable class="w-[150px]" v-model="queryForm.wtIds" @clear="checkAll = false" collapse-tags>
+					<el-option label="全选" :class="{'selected': checkAll}" @click="funCheckAll"></el-option>
+					<el-option v-for="item in windList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+				</el-select>
+			</el-form-item>
+			<el-form-item label="开始时间" class="!mb-0">
+				<el-date-picker type="date" class="!w-[150px]" v-model="queryForm.st"></el-date-picker>
+			</el-form-item>
+			<el-form-item label="结束时间" class="!mb-0">
+				<el-date-picker type="date" class="!w-[150px]" v-model="queryForm.et"></el-date-picker>
+			</el-form-item>
+			<!-- <el-form-item label="等间隔" class="!mb-0">
+				<el-radio-group v-model="queryForm.interval">
+					<el-radio :label="1">一秒钟</el-radio>
+					<el-radio :label="2">一分钟</el-radio>
+					<el-radio :label="3">十分钟</el-radio>
+					<el-radio :label="4">十五分钟</el-radio>
+				</el-radio-group>
+			</el-form-item> -->
+			<el-form-item class="!mb-0">
+				<submit-btn v-prevdbclick:5000="funSubmit" desc="执行"></submit-btn>
+			</el-form-item>
+		</el-form>
+	</div>
+</template>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 0
src/pages/lightAnalysis/glAnalysis/components/submitRES.json


+ 53 - 0
src/pages/lightAnalysis/glAnalysis/components/table.vue

@@ -0,0 +1,53 @@
+<script setup name="table">
+import {ref, computed} from 'vue'
+const props = defineProps({
+  height: {
+    type: String,
+    default: '800px'
+  },
+  data: {
+    type: Array,
+    default: () => ([]),
+  },
+  column: {
+    type: Array,
+    default: () => ([]),
+  },
+  tableName: {
+    type: String,
+    default: '',
+  },
+  tableId: {
+    type: String,
+    default: '',
+  },
+  loading: {
+    type: Boolean,
+    default: false,
+  }
+})
+const emits = defineEmits(['export'])
+const funExport = () => {
+  emits('export')
+}
+const tableRef = ref('')
+const tableHeight =  computed(() => {
+  return tableRef.value.offsetHeight? tableRef.value.offsetHeight - 12 : 739
+})
+</script>
+<template>
+  <div ref="tableRef" class="p-[10px]"
+    :style="{ height: typeof props.height === 'string' ? props.height : props.height + 'px' }">
+    <!-- <div class="flex justify-between items-center pb-[10px]"> -->
+      <!-- <h3>{{props.tableName}}</h3> -->
+      <!-- <el-button size="small" type="primary" @click="funExport" :disabled="!props.tableId">数据导出</el-button> -->
+    <!-- </div> -->
+    <el-table :data="props.data"
+      stripe
+      size="small" v-loading="props.loading"
+      :max-height="tableHeight"
+      :style="{ width: '100%'}">
+      <el-table-column align="center" show-overflow-tooltip v-for="item in props.column" :prop="item.prop" :label="item.label" sortable resizable :min-width="item.width? item.width : 80" />
+    </el-table>
+  </div>
+</template>

+ 237 - 0
src/pages/lightAnalysis/glAnalysis/index.vue

@@ -0,0 +1,237 @@
+<script setup name="prepare">
+import searchCop from './components/search.vue'
+import excelCop from '@/components/excel.vue'
+import treeCop from '@/components/tree.vue'
+import tableCop from './components/table.vue'
+import { ElMessage } from 'element-plus';
+import { onMounted, ref, onActivated } from 'vue'
+import CurrentScatterChart from './components/current-scatter-chart.vue'
+import request from '@/api/axios.js'
+import {baseURL, socketURL} from '@/api/axios.js'
+import dayjs from 'dayjs';
+/**配置参数 */
+const tableHeight = ref(window.innerHeight - 314 + 'px')
+const treeHeight = ref(window.innerHeight - 260 + 'px') //tree高度
+const excelHeight = ref(window.innerHeight - 260 + 'px') //excel高度
+/**excel 开始 */
+const excelList = ref([])
+const funExcelChange = async (obj) => { //点击excel项时
+	activeTab.value = '1'
+	tableShowId.value = obj.id
+	tableName.value = obj.name
+	tableLoading.value = true
+	const res = await request.get('/power/prepare/show', { params: { id: obj.id } })
+	if(res.code === 200){
+		tableColumn.value = res.data.title.map(o => {
+			return {
+				prop: o.key,
+				label: o.des,
+				width: o.des==='时间'? 100: 80,
+			}
+		})
+		tableData.value = res.data.data
+		tableLoading.value = false
+	}else{
+		tableLoading.value = false
+	}
+}
+/**tree 开始 */
+const treeData = ref([])
+const funRepeatMap = (arr) => {
+	return arr.map(o => {
+		if (o.children) {
+			const findIndex = o.children.findIndex(p => !!p.type)
+			if (findIndex !== -1) {
+				o.childs = o.children
+				o.children = []
+			}
+		}
+		return {
+			...o,
+			children: o.children?.length ? funRepeatMap(o.children) : []
+		}
+	})
+}
+const funGetTree = async () => {
+	const res = await request.get("/power/prepare/tree")
+	treeData.value = funRepeatMap(res.data)
+	excelList.value = []
+}
+const funCurrentChange = ({ current, currentNode }) => {
+	if (current.childs) {
+		excelList.value = current.childs.map(o => {
+			return {
+				id: o.id,
+				interval: o.interval,
+				path: o.path,
+				prepareid: o.prepareid,
+				station: o.station,
+				time: o.time,
+				type: o.type,
+				windturbine: o.windturbine,
+				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
+			}
+		})
+	} else {
+		excelList.value = []
+	}
+}
+/**table 开始 */
+const tableShowId = ref('')
+const tableName = ref('')
+const tableColumn = ref([])
+const tableLoading = ref(false)
+const tableData = ref([])
+const funExport = async () => {
+	const a = document.createElement('a')
+	a.href = baseURL + '/power/prepare/download?id=' + tableShowId.value
+	a.download = ''
+	a.click()
+}
+/**tab  */
+const activeTab = ref('1')
+/**chart Data */
+const xAxisData = ref([])
+const chartRef = ref() //chart 的ref
+const seriesData = ref([])
+const dataSet = ref('')
+const funChartSelect = async (batch) => {
+	return false
+}
+/**submit */
+const funSubmit = async (params) => {
+	activeTab.value = '2'
+	tableShowId.value = 1
+	tableName.value = ''
+	tableData.value = []
+	xAxisData.value = []
+	seriesData.value = []
+	tableLoading.value = true
+	const res = await request.get('/analysis/powertime', { params: {
+		station: params.station,
+		inverters: params.wtIds,
+		startdate: params.st,
+		enddate: params.et
+	} })
+	if(res.code === 200){
+		tableColumn.value = res.data.title.map(o => {
+			return {
+				prop: o.key,
+				label: o.des,
+				width: o.des==='时间'? 100: 80,
+			}
+		})
+		if(res.data.info?.length){
+			tableData.value = res.data.info
+			const llgl = []
+			const sjgl = []
+			res.data.info.forEach(o => {
+				xAxisData.value.push(o.datetime)
+				llgl.push(o.ideaP)
+				sjgl.push(o.actualP)
+			})
+			seriesData.value = [
+				{
+					name: "实际功率",
+					type: "line",
+					symbol: "line", //设定为实心点
+					symbolSize: 0, //设定实心点的大小
+					smooth: false, //这个是把线变成曲线
+					data: sjgl,
+					xAxisIndex: 0,
+				},
+				{
+					name: "理论功率",
+					type: "line",
+					symbol: "line", //设定为实心点
+					symbolSize: 0, //设定实心点的大小
+					smooth: false, //这个是把线变成曲线
+					data: llgl,
+					xAxisIndex: 0,
+				},
+			]
+		}else{
+			tableData.value = []
+		}
+		tableLoading.value = false
+
+	}else{
+		tableLoading.value = false
+	}
+
+	
+	// if (res.code === 200) {
+		// if(res.data.sjgl?.length){
+		// 	for(const wtObj of res.data.sjgl){
+		// 		seriesData.value.push(
+		// 			{
+		// 				name: wtObj.obj.windturbine + "\n实际功率",
+		// 				type: "line",
+		// 				symbol: "line", //设定为实心点
+		// 				symbolSize: 0, //设定实心点的大小
+		// 				smooth: true, //这个是把线变成曲线
+		// 				data: wtObj.sjgl || [],
+		// 				xAxisIndex: 0,
+		// 			},
+		// 		)
+		// 		wtData.value.push(wtObj.obj)
+		// 	}
+		// }
+	// }
+}
+/**created */
+// funGetTree()
+/**mounted */
+onMounted(() => {
+	tableHeight.value = window.innerHeight - 314 + 'px'
+	excelHeight.value = window.innerHeight - 260 + 'px'
+	treeHeight.value = window.innerHeight - 260 + 'px'
+	window.addEventListener('resize', () => {
+		tableHeight.value = window.innerHeight - 314 + 'px'
+		excelHeight.value = window.innerHeight - 260 + 'px'
+		treeHeight.value = window.innerHeight - 260 + 'px'
+	})
+})
+/**activated */
+onActivated(() => {
+	// funGetTree()
+	// funSubmit()
+})
+</script>
+<template>
+	<div class="bg-white py-[10px] px-[10px] relative">
+		<search-cop class="mb-[20px] shadow rounded-[6px] shadow-blue-500" @submit="funSubmit">
+		</search-cop>
+		<div class="relative shadow rounded-[6px] shadow-blue-500 px-[10px] pt-[20px] pb-[10px]">
+			<div class="text-[14px] absolute top-[-7px] text-[#838383] left-[20px]">数据展示</div>
+			<el-row :gutter="10">
+				<!-- <el-col :span="5">
+					<tree-cop :data="treeData" :height="treeHeight" @currentChange="funCurrentChange" @refresh="funGetTree">
+					</tree-cop>
+				</el-col>
+				<el-col :span="3">
+					<excel-cop :data="excelList" :height="excelHeight" @excelChange="funExcelChange"></excel-cop>
+				</el-col> -->
+				<el-col :span="24">
+					<div class="px-[10px] shadow rounded-[6px] shadow-blue-500 ">
+						<el-tabs v-model="activeTab">
+							<el-tab-pane label="表格数据" name="1">
+							</el-tab-pane>
+							<el-tab-pane label="图表展示" name="2">
+							</el-tab-pane>
+							<table-cop v-show="activeTab === '1'" :data="tableData" :loading="tableLoading" :column="tableColumn"
+								:height="tableHeight" :tableId="tableShowId" :tableName="tableName"></table-cop>
+							<div v-show="activeTab === '2'"
+								:style="{ height: typeof tableHeight === 'string' ? tableHeight : tableHeight + 'px' }"
+								class="p-[10px]">
+								<CurrentScatterChart ref="chartRef" width="100%" :height="`calc( ${tableHeight} - 20px )`" :chartTitle="''"
+									:xAxisData="xAxisData" :yAxisData="{ splitLine: { show: false } }" :seriesData="seriesData"
+									:showLegend="true" :brushSelected="false" :dataSet="dataSet" @getSelected="funChartSelect" />
+							</div>
+						</el-tabs>
+					</div>
+				</el-col>
+			</el-row>
+		</div>
+	</div>
+</template>

+ 398 - 0
src/pages/lightAnalysis/ivAnalysis/components/configStation.json

@@ -0,0 +1,398 @@
+{
+	"NSS_BT": {
+		"id": "NSS_BT",
+		"installedCapacity": 148.5,
+		"title": "牛首山第二风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "NSSDQN.NX_GD_NSSF_DQ_P1_L1_001_AI1019",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "NSSDQN.NX_GD_NSSF_DQ_P1_L1_001_AI1009",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "NSSDQN.NX_GD_NSSF_DQ_P1_L1_001_AI1010",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "NSSFCJSFW.NX_GD_NSSF_XX_XX_XXX_XXX_CI0193",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "NSSDQN.NX_GD_NSSF_DQ_P1_L1_001_AI1011",
+			"multiplier": 0.1,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "NSSFGL.NX_GD_NSSF_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"QS_BT": {
+		"id": "QS_BT",
+		"installedCapacity": 99.0,
+		"title": "麻黄山第六风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "QSDQ.NX_GD_QSF_DQ_P1_L1_001_AI1281",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "QSDQ.NX_GD_QSF_DQ_P1_L1_001_AI1282",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "QSDQ.NX_GD_QSF_DQ_P1_L1_001_AI1284",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "QSFCJSFW.NX_GD_QSF_FJ_P1_XXX_XXX_CI0192,QSFCJSFW.NX_GD_QSF_FJ_P2_XXX_XXX_CI0192",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "QSDQ.NX_GD_QSF_DQ_P1_L1_001_AI1285",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "QSFGL.NX_GD_QSF_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"XS_BT": {
+		"id": "XS_BT",
+		"installedCapacity": 99.0,
+		"title": "香山第五风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "XSDQ.NX_GD_XSF_DQ_P1_L1_001_AI0411",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "XSDQ.NX_GD_XSF_DQ_P1_L1_001_AI0415",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "XSDQ.NX_GD_XSF_DQ_P1_L1_001_AI0412",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "XSFCJSFW.NX_GD_XSF_XX_XX_XXX_XXX_CI0193",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "XSDQ.NX_GD_XSF_DQ_P1_L1_001_AI0413",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "XSFGL.NX_GD_XSF_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"MHS_BT": {
+		"id": "MHS_BT",
+		"installedCapacity": 69.5,
+		"title": "麻黄山第二风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "MHSDQ.NX_GD_MHSF_DQ_P1_L1_001_AI0296",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "MHSDQ.NX_GD_MHSF_DQ_P1_L1_001_AI0013",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "MHSDQ.NX_GD_MHSF_DQ_P1_L1_001_AI0294",
+			"multiplier": 0.1,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "MHSFCJSFW.NX_GD_MHSF_XX_XX_XXX_XXX_CI0193",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "MHSDQ.NX_GD_MHSF_DQ_P1_L1_001_AI0295",
+			"multiplier": 0.01,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "MHSFGL.NX_GD_MHSF_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"XH_BT": {
+		"id": "XH_BT",
+		"installedCapacity": 20.0,
+		"title": "宣和光伏电站",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "XHDQ.NX_GD_XHG_DQ_P1_L1_001_AI0204",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "XHDQ.NX_GD_XHG_DQ_P1_L1_001_AI0193",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "XHDQ.NX_GD_XHG_DQ_P1_L1_001_AI0194",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "XHGDCJSFW.NX_GD_XHG_XX_XX_XXX_XXX_CI0192",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "XHDQ.NX_GD_XHG_DQ_P1_L1_001_AI0195",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "XHGGL.NX_GD_XHG_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"SL_BT": {
+		"id": "SL_BT",
+		"installedCapacity": 49.5,
+		"title": "宋堡第六风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "SLAGC.NX_GD_QSF_DQ_P1_L1_001_AI0052",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "SLDQ.NX_GD_QSF_DQ_P1_L1_001_AI0013",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "SLAGC.NX_GD_QSF_DQ_P1_L1_001_AI0053",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "QSFCJSFW.NX_GD_QSF_FJ_P3_XXX_XXX_CI0192",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "SLAGC.NX_GD_QSF_DQ_P1_L1_001_AI0054",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "SLFGL.NX_GD_QSF_YC_P1_L1_001_LCDQ01",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"HZJ_BT": {
+		"id": "HZJ_BT",
+		"installedCapacity": 50.0,
+		"title": "海子井光伏电站",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0016",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0015",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0021",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0214",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0022",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "HZJGGL.NX_GD_HZJG_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"XN6_BT": {
+		"id": "XN6_BT",
+		"installedCapacity": 49.5,
+		"title": "星能第六风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0818",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0012",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0819",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0826",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0820",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0827",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"N5_BT": {
+		"id": "N5_BT",
+		"installedCapacity": 149.0,
+		"title": "牛首山第五风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0818",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0817",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0819",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0830",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0820",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0831",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"DWK_BT": {
+		"id": "DWK_BT",
+		"installedCapacity": 10.0,
+		"title": "大武口光伏电站",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "DWKDQ.NX_GD_DWKG_DQ_P1_L1_001_AI0838",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "DWKGDCJSFW.NX_GD_DWKG_XX_XX_XXX_XXX_CI0192",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "DWKDQ.NX_GD_DWKG_DQ_P1_L1_001_AI0839",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "DWKGGL.NX_GD_DWKG_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"PL_BT": {
+		"id": "PL_BT",
+		"installedCapacity": 30.0,
+		"title": "平罗光伏电站",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "PLSJ1.NX_GD_PLG_DQ_P1_L1_001_AI0838",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "PLSJ1.NX_GD_PLG_DQ_P1_L1_001_AI0835",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "PLSJ1.NX_GD_PLG_DQ_P1_L1_001_AI0836",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "PLGDCJSFW.NX_GD_PLG_XX_XX_XXX_XXX_CI0192",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "PLSJ1.NX_GD_PLG_DQ_P1_L1_001_AI0837",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "PLGGL.NX_GD_PLG_YC_P1_L1_001_CDQ0001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	}
+}

+ 398 - 0
src/pages/lightAnalysis/ivAnalysis/components/current-scatter-chart.json

@@ -0,0 +1,398 @@
+
+{
+	"color": [
+			"#1C99FF",
+			"#FF8700",
+			"#e6b600d9",
+			"#0098d9",
+			"#3D54BE",
+			"#005eaa",
+			"#cda819",
+			"#32a487"
+	],
+	"textStyle": {},
+	"title": {
+			"textStyle": {
+					"color": "#333333"
+			},
+			"subtextStyle": {
+					"color": "#aaaaaa"
+			}
+	},
+	"line": {
+			"itemStyle": {
+					"borderWidth": 1
+			},
+			"lineStyle": {
+					"width": 2
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false
+	},
+	"radar": {
+			"itemStyle": {
+					"borderWidth": 1
+			},
+			"lineStyle": {
+					"width": 2
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false
+	},
+	"bar": {
+			"itemStyle": {
+					"barBorderWidth": 0,
+					"barBorderColor": "#ccc"
+			}
+	},
+	"pie": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"scatter": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"boxplot": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"parallel": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"sankey": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"funnel": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"gauge": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"candlestick": {
+			"itemStyle": {
+					"color": "#c12e34",
+					"color0": "#2b821d",
+					"borderColor": "#c12e34",
+					"borderColor0": "#2b821d",
+					"borderWidth": 1
+			}
+	},
+	"graph": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			},
+			"lineStyle": {
+					"width": 1,
+					"color": "#aaaaaa"
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false,
+			"color": [
+					"#c12e34",
+					"#e6b600",
+					"#0098d9",
+					"#50ec39",
+					"#005eaa",
+					"#339ca8",
+					"#cda819",
+					"#32a487"
+			],
+			"label": {
+					"color": "#eeeeee"
+			}
+	},
+	"map": {
+			"itemStyle": {
+					"areaColor": "#ddd",
+					"borderColor": "#eee",
+					"borderWidth": 0.5
+			},
+			"label": {
+					"color": "#c12e34"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"areaColor": "#e6b600",
+							"borderColor": "#ddd",
+							"borderWidth": 1
+					},
+					"label": {
+							"color": "#c12e34"
+					}
+			}
+	},
+	"geo": {
+			"itemStyle": {
+					"areaColor": "#ddd",
+					"borderColor": "#eee",
+					"borderWidth": 0.5
+			},
+			"label": {
+					"color": "#c12e34"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"areaColor": "#e6b600",
+							"borderColor": "#ddd",
+							"borderWidth": 1
+					},
+					"label": {
+							"color": "#c12e34"
+					}
+			}
+	},
+	"categoryAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#838383"
+			},
+			"splitLine": {
+					"show": false,
+					"lineStyle": {
+							"color": [
+									"#838383"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"valueAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#838383"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"logAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#333"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"timeAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#838383"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#838383"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"toolbox": {
+			"iconStyle": {
+					"borderColor": "#06467c"
+			},
+			"emphasis": {
+					"iconStyle": {
+							"borderColor": "#4187c2"
+					}
+			},
+			"textStyle": {
+				"color": "#838383"
+			}
+	},
+	"legend": {
+			"textStyle": {
+					"color": "#838383"
+			}
+	},
+	"tooltip": {
+			"axisPointer": {
+					"lineStyle": {
+							"color": "#cccccc",
+							"width": 1
+					},
+					"crossStyle": {
+							"color": "#cccccc",
+							"width": 1
+					}
+			}
+	},
+	"timeline": {
+			"lineStyle": {
+					"color": "#005eaa",
+					"width": 1
+			},
+			"itemStyle": {
+					"color": "#005eaa",
+					"borderWidth": 1
+			},
+			"controlStyle": {
+					"color": "#005eaa",
+					"borderColor": "#005eaa",
+					"borderWidth": 0.5
+			},
+			"checkpointStyle": {
+					"color": "#005eaa",
+					"borderColor": "#316bc2"
+			},
+			"label": {
+					"color": "#005eaa"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"color": "#005eaa"
+					},
+					"controlStyle": {
+							"color": "#005eaa",
+							"borderColor": "#005eaa",
+							"borderWidth": 0.5
+					},
+					"label": {
+							"color": "#005eaa"
+					}
+			}
+	},
+	"visualMap": {
+			"color": [
+					"#1790cf",
+					"#a2d4e6"
+			]
+	},
+	"dataZoom": {
+			"backgroundColor": "rgba(47,69,84,0)",
+			"dataBackgroundColor": "rgba(47,69,84,0.3)",
+			"fillerColor": "rgba(167,183,204,0.4)",
+			"handleColor": "#a7b7cc",
+			"handleSize": "100%",
+			"textStyle": {
+					"color": "#333333"
+			}
+	},
+	"markPoint": {
+			"label": {
+					"color": "#eeeeee"
+			},
+			"emphasis": {
+					"label": {
+							"color": "#eeeeee"
+					}
+			}
+	}
+}

+ 341 - 0
src/pages/lightAnalysis/ivAnalysis/components/current-scatter-chart.vue

@@ -0,0 +1,341 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@tools/util";
+import partten from "@tools/partten";
+import * as echarts from "echarts";
+import chartTheme from './current-scatter-chart.json'
+
+export default {
+  name: 'currentScatterChart',
+  props: {
+    // 图表宽度
+    width: {
+      type: String,
+      default: "100%",
+    },
+    // 图表高度
+    height: {
+      type: String,
+      default: "350px",
+    },
+    // 图表主标题
+    chartTitle: {
+      type: String,
+      default: "自定义图表组件",
+    },
+    // X 轴配置项
+    xAxisData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    // Y 轴配置项
+    yAxisData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    dataSet: {
+      type: String,
+      default: ''
+    },
+    // 图表核心数据
+    seriesData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    // 是否显示图表图例
+    showLegend: {
+      type: Boolean,
+      default: true,
+    },
+    // 是否默认采用笔刷模式
+    brushSelected: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+      color: [
+        "#05bb4c",
+        "#4b55ae",
+        "#fa8c16",
+        "#f8de5b",
+        "#1a93cf",
+        "#c531c7",
+        "#bd3338",
+      ],
+      theme: 'light'
+    };
+  },
+  watch: {
+    height(){
+      if(this.chart){
+          this.chart.resize()
+      }
+    }
+  },
+  methods: {
+    resize() {},
+    initChart() {
+      const that = this;
+      echarts.registerTheme('chartTheme', chartTheme)
+      let myChart = echarts.init(document.getElementById(this.id), 'chartTheme');
+      that.chart = myChart
+      //指定图表的配置项和数据
+      const option = {
+        //标题
+        title: {
+          text: that.chartTitle,
+          right: 440,
+          top: 4,
+          textStyle: {
+            fontSize: 14,
+            color: that.theme === "dark" ? partten.getColor("grayl") : "#000",
+          },
+        },
+        // backgroundColor:
+        //   that.theme === "dark"
+        //     ? "rgba(0,0,0,0.4)"
+        //     : "rgba(255,255,255,0.5)",
+        //工具箱
+        color: [
+            "#0098d9",
+            "rgb(255,0,0)",
+            "#0a4468",
+            "#a9e3f199",
+            "#a9e3f199",
+            "#005eaa",
+            "#cda819",
+            "#32a487"
+        ],
+        toolbox: {
+          show: false,
+          x: "right",
+          position: [10, 10],
+          // backgroundColor:'rgba(0,0,0,0.4)',
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            fontSize: util.vh(16),
+            color: partten.getColor("gray")
+          },
+          iconStyle: {
+            borderColor:partten.getColor("gray")
+          },
+          emphasis: {
+            iconStyle: {
+              borderColor:partten.getColor("gray")
+            },
+          },
+        },
+        tooltip: {
+          trigger: "axis",
+          axisPointer: {
+            type: "cross",
+          },
+          // backgroundColor: "rgba(0,0,0,0.4)",
+          // borderColor: partten.getColor("gray"),
+          // textStyle: {
+          //   fontSize: util.vh(16),
+          //   color: partten.getColor("gray"),
+          // },
+          // formatter(params) {
+          //   return params.value?.x
+          //     ? `${params.seriesName}<br />风速:${params.value.x}m/s<br />功率:${params.value.y}kW`
+          //     : `${params.name}`;
+          // },
+        },
+        brush: {
+          seriesIndex: [2,3],
+          yAxisIndex: 0,
+          transformable: true,
+          throttleType: "debounce",
+          throttleDelay: 1000,
+          removeOnClick: true,
+          brushType: "polygon",
+          brushMode: "multiple",
+          brushStyle: {
+            borderWidth: 1,
+            borderColor: "#ff2424",
+          },
+        },
+        dataZoom: [
+          {
+            type: "inside", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+          {
+            type: "slider", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+        ],
+        textStyle: {
+          fontSize: util.vh(16),
+          color: that.theme === "dark" ? "#fff" : "#000",
+        },
+        //图例-每一条数据的名字
+        legend: {
+          show: that.showLegend,
+          // data: [ "拟合功率", "保证功率","无用点", "有用点", "Cp值"],
+          right: 170,
+          type: 'scroll',
+          top: "5",
+          // icon: "circle",
+          itemWidth: 6,
+          inactiveColor:
+            that.theme === "dark"
+              ? partten.getColor("gray")
+              : "#000",
+          textStyle: {
+            color:
+              that.theme === "dark"
+                ? partten.getColor("grayl")
+                : "#000",
+            fontSize: 12,
+          },
+          
+        },
+        grid: {
+          top: 58,
+          left: 40,
+          right: 48,
+          bottom: 24,
+        },
+        //x轴
+        xAxis: [
+          {
+            name: '时间',
+            nameTextStyle: {
+              color: '#838383'
+            },
+            type: "category",
+            boundaryGap: true,
+            data: that.xAxisData || [],
+            axisLabel: {
+              formatter: "{value}",
+            },
+            splitLine: {
+              show: false,
+            },
+            smooth: true,
+            textStyle: {
+              color:
+                that.theme === "dark"
+                  ? partten.getColor("gray")
+                  : "#000",
+            },
+          },
+        ],
+        //y轴没有显式设置,根据值自动生成y轴
+        yAxis: [{
+          splitLine: { show: false },
+          position: 'left',
+          min: 0,
+          name: 'MW',
+          nameTextStyle: {
+            color: '#838383'
+          },
+        }],
+        animation: true,
+        dataset: that.dataSet.length? JSON.parse(that.dataSet) : [],
+        //数据-data是最终要显示的数据
+        series: that.seriesData,
+      };
+
+      that.resize = function () {
+        myChart.resize();
+      };
+
+      window.addEventListener("resize", that.resize);
+
+      myChart.setOption(option);
+      // if (that.brushSelected) {
+      //   myChart.dispatchAction({
+      //     type: "takeGlobalCursor",
+      //     // 如果想变为“可刷选状态”,必须设置。不设置则会关闭“可刷选状态”。
+      //     key: "brush",
+      //     brushOption: {
+      //       seriesIndex: [2,3],
+      //       yAxisIndex: 0,
+      //       transformable: true,
+      //       throttleType: "debounce",
+      //       throttleDelay: 1000,
+      //       removeOnClick: true,
+      //       brushType: "polygon",
+      //       brushMode: "multiple",
+      //       brushStyle: {
+      //         borderWidth: 1,
+      //         color: "rgba(255,36,36,0.2)",
+      //         borderColor: "#ff2424",
+      //       },
+      //     },
+      //   });
+      // }
+      myChart.off("brushSelected");
+      myChart.on("brushSelected", (params) => {
+        that.$emit("getSelected", params.batch || []);
+      });
+      myChart.off('click')
+      myChart.on('click', params => {
+          // if(params.componentType === 'markArea'){
+          //   myChart.dispatchAction({
+          //     type: 'brush',
+          //     areas: [
+          //       {
+          //         xAxisIndex: 0,
+          //         brushType: 'lineX',
+          //         coordRange: [params.data.coord[0][0], params.data.coord[1][0]]
+          //       },
+          //     ]
+          //   });
+          // }
+        })
+    },
+  },
+  created() {
+    this.id = "chart-" + util.newGUID();
+  },
+  mounted() {
+    // this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+      this.initChart();
+    // });
+  },
+  updated() {
+    console.log('update')
+    let myChart = echarts.init(document.getElementById(this.id));
+    myChart.dispose();
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+  unmounted() {
+    window.removeEventListener("resize", this.resize);
+  },
+};
+</script>
+
+<style>
+.chart {
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+}
+</style>

+ 80 - 0
src/pages/lightAnalysis/ivAnalysis/components/search.vue

@@ -0,0 +1,80 @@
+<script setup name="search">
+import { onMounted, reactive, ref } from 'vue'
+import request from '@/api/axios.js'
+import SubmitBtn from '@com/SubmitBtn.vue'
+// import configStationJson from './configStation.json'
+
+const queryForm = reactive({
+	station: '',
+	st: Date.now() - 30 * 24 * 60 * 60 * 1000,
+	et: Date.now(),
+	interval: 3
+})
+/**场站 */
+const stationList = ref([])
+const funGetStation = async () => {
+	const res = await request.get("/agc/config")
+	// stationList.value = Object.values(configStationJson) // configStationJson
+	stationList.value = Object.values(res)
+	if (stationList.value.length) {
+		queryForm.station = stationList.value[0].id
+	}
+
+	funSubmit()
+}
+/**导出 */
+const emits = defineEmits(['submit'])
+const funSubmit = async () => {
+	const startDate = new Date(queryForm.st).setHours(0,0,0,0)
+	const endDate = new Date(queryForm.et).setHours(0,0,0,0)
+	const query = {
+		id: queryForm.station,
+		startTs: new Date(startDate).getTime(),
+		endTs: new Date(endDate).getTime(),
+		interval: queryForm.interval
+	}
+	switch (queryForm.interval) {
+		case 2:
+			query.interval = 60
+			break;
+		case 3:
+			query.interval = 600
+			break;
+		case 4:
+			query.interval = 900
+			break;
+	}
+	emits('submit', query)
+}
+/**created */
+funGetStation()
+</script>
+<template>
+	<div class="pl-[20px] flex items-center h-[80px] relative">
+		<div class="absolute top-[-7px] left-[20px] text-[#838383] text-[14px]">操作面板</div>
+		<el-form class="" :inline="true" :model="queryForm">
+			<el-form-item label="场站" class="!mb-0">
+				<el-select v-model="queryForm.station" class="w-[150px]">
+					<el-option v-for="item in stationList" :key="item.id" :label="item.title" :value="item.id"></el-option>
+				</el-select>
+			</el-form-item>
+			<el-form-item label="开始时间" class="!mb-0">
+				<el-date-picker type="date" class="!w-[150px]" v-model="queryForm.st"></el-date-picker>
+			</el-form-item>
+			<el-form-item label="结束时间" class="!mb-0">
+				<el-date-picker type="date" class="!w-[150px]" v-model="queryForm.et"></el-date-picker>
+			</el-form-item>
+			<el-form-item label="等间隔" class="!mb-0">
+				<el-radio-group v-model="queryForm.interval">
+					<el-radio :label="1">一秒钟</el-radio>
+					<el-radio :label="2">一分钟</el-radio>
+					<el-radio :label="3">十分钟</el-radio>
+					<el-radio :label="4">十五分钟</el-radio>
+				</el-radio-group>
+			</el-form-item>
+			<el-form-item class="!mb-0">
+				<submit-btn v-prevdbclick:5000="funSubmit" desc="执行"></submit-btn>
+			</el-form-item>
+		</el-form>
+	</div>
+</template>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 0
src/pages/lightAnalysis/ivAnalysis/components/submitRES.json


+ 53 - 0
src/pages/lightAnalysis/ivAnalysis/components/table.vue

@@ -0,0 +1,53 @@
+<script setup name="table">
+import {ref, computed} from 'vue'
+const props = defineProps({
+  height: {
+    type: String,
+    default: '800px'
+  },
+  data: {
+    type: Array,
+    default: () => ([]),
+  },
+  column: {
+    type: Array,
+    default: () => ([]),
+  },
+  tableName: {
+    type: String,
+    default: '',
+  },
+  tableId: {
+    type: String,
+    default: '',
+  },
+  loading: {
+    type: Boolean,
+    default: false,
+  }
+})
+const emits = defineEmits(['export'])
+const funExport = () => {
+  emits('export')
+}
+const tableRef = ref('')
+const tableHeight =  computed(() => {
+  return tableRef.value.offsetHeight? tableRef.value.offsetHeight - 12 : 739
+})
+</script>
+<template>
+  <div ref="tableRef" class="p-[10px]"
+    :style="{ height: typeof props.height === 'string' ? props.height : props.height + 'px' }">
+    <!-- <div class="flex justify-between items-center pb-[10px]"> -->
+      <!-- <h3>{{props.tableName}}</h3> -->
+      <!-- <el-button size="small" type="primary" @click="funExport" :disabled="!props.tableId">数据导出</el-button> -->
+    <!-- </div> -->
+    <el-table :data="props.data"
+      stripe
+      size="small" v-loading="props.loading"
+      :max-height="tableHeight"
+      :style="{ width: '100%'}">
+      <el-table-column align="center" show-overflow-tooltip v-for="item in props.column" :prop="item.prop" :label="item.label" sortable resizable :min-width="item.width? item.width : 80" />
+    </el-table>
+  </div>
+</template>

+ 304 - 0
src/pages/lightAnalysis/ivAnalysis/index.vue

@@ -0,0 +1,304 @@
+<script setup name="prepare">
+import searchCop from './components/search.vue'
+import excelCop from '@/components/excel.vue'
+import treeCop from '@/components/tree.vue'
+import tableCop from './components/table.vue'
+import { ElMessage } from 'element-plus';
+import { onMounted, ref, onActivated } from 'vue'
+import CurrentScatterChart from './components/current-scatter-chart.vue'
+import request from '@/api/axios.js'
+import {baseURL, socketURL} from '@/api/axios.js'
+import dayjs from 'dayjs';
+/**配置参数 */
+const tableHeight = ref(window.innerHeight - 314 + 'px')
+const treeHeight = ref(window.innerHeight - 260 + 'px') //tree高度
+const excelHeight = ref(window.innerHeight - 260 + 'px') //excel高度
+/**excel 开始 */
+const excelList = ref([])
+const funExcelChange = async (obj) => { //点击excel项时
+	activeTab.value = '1'
+	tableShowId.value = obj.id
+	tableName.value = obj.name
+	tableLoading.value = true
+	const res = await request.get('/power/prepare/show', { params: { id: obj.id } })
+	if(res.code === 200){
+		tableColumn.value = res.data.title.map(o => {
+			return {
+				prop: o.key,
+				label: o.des,
+				width: o.des==='时间'? 100: 80,
+			}
+		})
+		tableData.value = res.data.data
+		tableLoading.value = false
+	}else{
+		tableLoading.value = false
+	}
+}
+/**tree 开始 */
+const treeData = ref([])
+const funRepeatMap = (arr) => {
+	return arr.map(o => {
+		if (o.children) {
+			const findIndex = o.children.findIndex(p => !!p.type)
+			if (findIndex !== -1) {
+				o.childs = o.children
+				o.children = []
+			}
+		}
+		return {
+			...o,
+			children: o.children?.length ? funRepeatMap(o.children) : []
+		}
+	})
+}
+const funGetTree = async () => {
+	const res = await request.get("/power/prepare/tree")
+	treeData.value = funRepeatMap(res.data)
+	excelList.value = []
+}
+const funCurrentChange = ({ current, currentNode }) => {
+	if (current.childs) {
+		excelList.value = current.childs.map(o => {
+			return {
+				id: o.id,
+				interval: o.interval,
+				path: o.path,
+				prepareid: o.prepareid,
+				station: o.station,
+				time: o.time,
+				type: o.type,
+				windturbine: o.windturbine,
+				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
+			}
+		})
+	} else {
+		excelList.value = []
+	}
+}
+/**table 开始 */
+const tableShowId = ref('')
+const tableName = ref('')
+const tableColumn = ref([])
+const tableLoading = ref(false)
+const tableData = ref([])
+const funExport = async () => {
+	const a = document.createElement('a')
+	a.href = baseURL + '/power/prepare/download?id=' + tableShowId.value
+	a.download = ''
+	a.click()
+}
+/**tab  */
+const activeTab = ref('1')
+/**chart Data */
+const xAxisData = ref([])
+const chartRef = ref() //chart 的ref
+const seriesData = ref([])
+const dataSet = ref('')
+const funChartSelect = async (batch) => {
+	return false
+}
+/**submit */
+const funSubmit = async (params) => {
+	activeTab.value = '2'
+	tableShowId.value = 1
+	tableName.value = ''
+	tableLoading.value = true
+	const res = await request.get('/agc/deviate', { params: params })
+	tableColumn.value = [
+		{
+			prop: 'ts',
+			label: '时间',
+			width: 100,
+		},
+		{
+			prop: 'ygsdxz',
+			label: '有功设定限值',
+			width: 80,
+		},
+		{
+			prop: 'sfyg',
+			label: '实发有功',
+			width: 80,
+		},
+		{
+			prop: 'llgl',
+			label: '理论功率',
+			width: 80,
+		},
+		{
+			prop: 'pcsx',
+			label: '偏差上限',
+			width: 80,
+		},
+		{
+			prop: 'pcxx',
+			label: '偏差下限',
+			width: 100,
+		},
+	]
+	const tableArr = []
+	const tsArr = []
+	const ygsdxz = []
+	const sfyg = []
+	const llgl = []
+	const pcsx = []
+	const pcxx = []
+	res['有功设定限值'].values.map((o, index) => {
+		tsArr.push(dayjs(o.ts).format('YYYY-MM-DD HH:mm:ss'))
+		ygsdxz.push(Number(o.value).toFixed(2))
+		sfyg.push(Number(res['实发有功'].values[index].value).toFixed(2))
+		llgl.push(Number(res['理论功率'].values[index].value).toFixed(2))
+		pcsx.push(Number(res['偏差上限'].values[index].value).toFixed(2))
+		pcxx.push(Number(res['偏差下限'].values[index].value).toFixed(2))
+		tableArr.push({
+			ts: dayjs(o.ts).format('YYYY-MM-DD HH:mm:ss'),
+			ygsdxz: Number(o.value).toFixed(2),
+			sfyg: Number(res['实发有功'].values[index].value).toFixed(2),
+			llgl: Number(res['理论功率'].values[index].value).toFixed(2),
+			pcsx: Number(res['偏差上限'].values[index].value).toFixed(2),
+			pcxx: Number(res['偏差下限'].values[index].value).toFixed(2),
+		})
+	})
+	xAxisData.value = tableArr.map(o => o.ts)
+	seriesData.value = [
+		{
+			name: "有功设定限值",
+			type: "line",
+			symbol: "line", //设定为实心点
+			symbolSize: 0, //设定实心点的大小
+			smooth: false, //这个是把线变成曲线
+			data: ygsdxz,
+			xAxisIndex: 0,
+		},
+		{
+			name: "实发有功",
+			type: "line",
+			symbol: "line", //设定为实心点
+			symbolSize: 0, //设定实心点的大小
+			smooth: false, //这个是把线变成曲线
+			data: sfyg,
+			xAxisIndex: 0,
+		},
+		{
+			name: "理论功率",
+			type: "line",
+			symbol: "line", //设定为实心点
+			symbolSize: 0, //设定实心点的大小
+			smooth: false, //这个是把线变成曲线
+			data: llgl,
+			xAxisIndex: 0,
+		},
+		{
+			name: "偏差上限",
+			type: "line",
+			symbol: "line", //设定为实心点
+			symbolSize: 0, //设定实心点的大小
+			smooth: false, //这个是把线变成曲线
+			data: pcsx,
+			xAxisIndex: 0,
+			lineStyle: {
+            opacity: 0
+			},
+			areaStyle: {
+				color: '#ccc',
+			},
+			symbol: 'none'
+		},
+		{
+			name: "偏差下限",
+			type: "line",
+			symbol: "line", //设定为实心点
+			symbolSize: 0, //设定实心点的大小
+			smooth: false, //这个是把线变成曲线
+			data: pcxx,
+			xAxisIndex: 0,
+			lineStyle: {
+            opacity: 0
+			},
+			areaStyle: {
+				color: '#fff',
+				opacity: 1
+			},
+			symbol: 'none'
+		},
+	]
+	tableData.value = tableArr
+	tableLoading.value = false
+
+	
+	// if (res.code === 200) {
+		// if(res.data.sjgl?.length){
+		// 	for(const wtObj of res.data.sjgl){
+		// 		seriesData.value.push(
+		// 			{
+		// 				name: wtObj.obj.windturbine + "\n实际功率",
+		// 				type: "line",
+		// 				symbol: "line", //设定为实心点
+		// 				symbolSize: 0, //设定实心点的大小
+		// 				smooth: true, //这个是把线变成曲线
+		// 				data: wtObj.sjgl || [],
+		// 				xAxisIndex: 0,
+		// 			},
+		// 		)
+		// 		wtData.value.push(wtObj.obj)
+		// 	}
+		// }
+	// }
+}
+/**created */
+// funGetTree()
+/**mounted */
+onMounted(() => {
+	tableHeight.value = window.innerHeight - 314 + 'px'
+	excelHeight.value = window.innerHeight - 260 + 'px'
+	treeHeight.value = window.innerHeight - 260 + 'px'
+	window.addEventListener('resize', () => {
+		tableHeight.value = window.innerHeight - 314 + 'px'
+		excelHeight.value = window.innerHeight - 260 + 'px'
+		treeHeight.value = window.innerHeight - 260 + 'px'
+	})
+})
+/**activated */
+onActivated(() => {
+	// funGetTree()
+	// funSubmit()
+})
+</script>
+<template>
+	<div class="bg-white py-[10px] px-[10px] relative">
+		<search-cop class="mb-[20px] shadow rounded-[6px] shadow-blue-500" @submit="funSubmit">
+		</search-cop>
+		<div class="relative shadow rounded-[6px] shadow-blue-500 px-[10px] pt-[20px] pb-[10px]">
+			<div class="text-[14px] absolute top-[-7px] text-[#838383] left-[20px]">数据展示</div>
+			<el-row :gutter="10">
+				<!-- <el-col :span="5">
+					<tree-cop :data="treeData" :height="treeHeight" @currentChange="funCurrentChange" @refresh="funGetTree">
+					</tree-cop>
+				</el-col>
+				<el-col :span="3">
+					<excel-cop :data="excelList" :height="excelHeight" @excelChange="funExcelChange"></excel-cop>
+				</el-col> -->
+				<el-col :span="24">
+					<div class="px-[10px] shadow rounded-[6px] shadow-blue-500 ">
+						<el-tabs v-model="activeTab">
+							<el-tab-pane label="表格数据" name="1">
+							</el-tab-pane>
+							<el-tab-pane label="图表展示" name="2">
+							</el-tab-pane>
+							<table-cop v-show="activeTab === '1'" :data="tableData" :loading="tableLoading" :column="tableColumn"
+								:height="tableHeight" :tableId="tableShowId" :tableName="tableName"></table-cop>
+							<div v-show="activeTab === '2'"
+								:style="{ height: typeof tableHeight === 'string' ? tableHeight : tableHeight + 'px' }"
+								class="p-[10px]">
+								<CurrentScatterChart ref="chartRef" width="100%" :height="`calc( ${tableHeight} - 20px )`" :chartTitle="''"
+									:xAxisData="xAxisData" :yAxisData="{ splitLine: { show: false } }" :seriesData="seriesData"
+									:showLegend="true" :brushSelected="false" :dataSet="dataSet" @getSelected="funChartSelect" />
+							</div>
+						</el-tabs>
+					</div>
+				</el-col>
+			</el-row>
+		</div>
+	</div>
+</template>

+ 398 - 0
src/pages/lightAnalysis/pvAnalysis/components/configStation.json

@@ -0,0 +1,398 @@
+{
+	"NSS_BT": {
+		"id": "NSS_BT",
+		"installedCapacity": 148.5,
+		"title": "牛首山第二风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "NSSDQN.NX_GD_NSSF_DQ_P1_L1_001_AI1019",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "NSSDQN.NX_GD_NSSF_DQ_P1_L1_001_AI1009",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "NSSDQN.NX_GD_NSSF_DQ_P1_L1_001_AI1010",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "NSSFCJSFW.NX_GD_NSSF_XX_XX_XXX_XXX_CI0193",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "NSSDQN.NX_GD_NSSF_DQ_P1_L1_001_AI1011",
+			"multiplier": 0.1,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "NSSFGL.NX_GD_NSSF_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"QS_BT": {
+		"id": "QS_BT",
+		"installedCapacity": 99.0,
+		"title": "麻黄山第六风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "QSDQ.NX_GD_QSF_DQ_P1_L1_001_AI1281",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "QSDQ.NX_GD_QSF_DQ_P1_L1_001_AI1282",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "QSDQ.NX_GD_QSF_DQ_P1_L1_001_AI1284",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "QSFCJSFW.NX_GD_QSF_FJ_P1_XXX_XXX_CI0192,QSFCJSFW.NX_GD_QSF_FJ_P2_XXX_XXX_CI0192",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "QSDQ.NX_GD_QSF_DQ_P1_L1_001_AI1285",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "QSFGL.NX_GD_QSF_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"XS_BT": {
+		"id": "XS_BT",
+		"installedCapacity": 99.0,
+		"title": "香山第五风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "XSDQ.NX_GD_XSF_DQ_P1_L1_001_AI0411",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "XSDQ.NX_GD_XSF_DQ_P1_L1_001_AI0415",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "XSDQ.NX_GD_XSF_DQ_P1_L1_001_AI0412",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "XSFCJSFW.NX_GD_XSF_XX_XX_XXX_XXX_CI0193",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "XSDQ.NX_GD_XSF_DQ_P1_L1_001_AI0413",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "XSFGL.NX_GD_XSF_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"MHS_BT": {
+		"id": "MHS_BT",
+		"installedCapacity": 69.5,
+		"title": "麻黄山第二风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "MHSDQ.NX_GD_MHSF_DQ_P1_L1_001_AI0296",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "MHSDQ.NX_GD_MHSF_DQ_P1_L1_001_AI0013",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "MHSDQ.NX_GD_MHSF_DQ_P1_L1_001_AI0294",
+			"multiplier": 0.1,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "MHSFCJSFW.NX_GD_MHSF_XX_XX_XXX_XXX_CI0193",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "MHSDQ.NX_GD_MHSF_DQ_P1_L1_001_AI0295",
+			"multiplier": 0.01,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "MHSFGL.NX_GD_MHSF_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"XH_BT": {
+		"id": "XH_BT",
+		"installedCapacity": 20.0,
+		"title": "宣和光伏电站",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "XHDQ.NX_GD_XHG_DQ_P1_L1_001_AI0204",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "XHDQ.NX_GD_XHG_DQ_P1_L1_001_AI0193",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "XHDQ.NX_GD_XHG_DQ_P1_L1_001_AI0194",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "XHGDCJSFW.NX_GD_XHG_XX_XX_XXX_XXX_CI0192",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "XHDQ.NX_GD_XHG_DQ_P1_L1_001_AI0195",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "XHGGL.NX_GD_XHG_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"SL_BT": {
+		"id": "SL_BT",
+		"installedCapacity": 49.5,
+		"title": "宋堡第六风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "SLAGC.NX_GD_QSF_DQ_P1_L1_001_AI0052",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "SLDQ.NX_GD_QSF_DQ_P1_L1_001_AI0013",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "SLAGC.NX_GD_QSF_DQ_P1_L1_001_AI0053",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "QSFCJSFW.NX_GD_QSF_FJ_P3_XXX_XXX_CI0192",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "SLAGC.NX_GD_QSF_DQ_P1_L1_001_AI0054",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "SLFGL.NX_GD_QSF_YC_P1_L1_001_LCDQ01",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"HZJ_BT": {
+		"id": "HZJ_BT",
+		"installedCapacity": 50.0,
+		"title": "海子井光伏电站",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0016",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0015",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0021",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0214",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "HZJAGC.NX_GD_HZJG_DQ_P1_L1_001_AI0022",
+			"multiplier": 0.001,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "HZJGGL.NX_GD_HZJG_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"XN6_BT": {
+		"id": "XN6_BT",
+		"installedCapacity": 49.5,
+		"title": "星能第六风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0818",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0012",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0819",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0826",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0820",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "SBQXLDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0827",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"N5_BT": {
+		"id": "N5_BT",
+		"installedCapacity": 149.0,
+		"title": "牛首山第五风电场",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0818",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0817",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0819",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0830",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0820",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "SBQNWDQ.NX_GD_SBQF_DQ_P1_L1_001_AI0831",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"DWK_BT": {
+		"id": "DWK_BT",
+		"installedCapacity": 10.0,
+		"title": "大武口光伏电站",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "DWKDQ.NX_GD_DWKG_DQ_P1_L1_001_AI0838",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "DWKGDCJSFW.NX_GD_DWKG_XX_XX_XXX_XXX_CI0192",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "DWKDQ.NX_GD_DWKG_DQ_P1_L1_001_AI0839",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "DWKGGL.NX_GD_DWKG_YC_P1_L1_001_CDQ001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	},
+	"PL_BT": {
+		"id": "PL_BT",
+		"installedCapacity": 30.0,
+		"title": "平罗光伏电站",
+		"aiPoints": [{
+			"name": "有功设定限值",
+			"tag": "PLSJ1.NX_GD_PLG_DQ_P1_L1_001_AI0838",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "实发有功",
+			"tag": "PLSJ1.NX_GD_PLG_DQ_P1_L1_001_AI0835",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调上限",
+			"tag": "PLSJ1.NX_GD_PLG_DQ_P1_L1_001_AI0836",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "理论功率",
+			"tag": "PLGDCJSFW.NX_GD_PLG_XX_XX_XXX_XXX_CI0192",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "AGC可调下限",
+			"tag": "PLSJ1.NX_GD_PLG_DQ_P1_L1_001_AI0837",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}, {
+			"name": "预测功率",
+			"tag": "PLGGL.NX_GD_PLG_YC_P1_L1_001_CDQ0001",
+			"multiplier": 1.0,
+			"unit": "MW"
+		}]
+	}
+}

+ 398 - 0
src/pages/lightAnalysis/pvAnalysis/components/current-scatter-chart.json

@@ -0,0 +1,398 @@
+
+{
+	"color": [
+			"#1C99FF",
+			"#FF8700",
+			"#e6b600d9",
+			"#0098d9",
+			"#3D54BE",
+			"#005eaa",
+			"#cda819",
+			"#32a487"
+	],
+	"textStyle": {},
+	"title": {
+			"textStyle": {
+					"color": "#333333"
+			},
+			"subtextStyle": {
+					"color": "#aaaaaa"
+			}
+	},
+	"line": {
+			"itemStyle": {
+					"borderWidth": 1
+			},
+			"lineStyle": {
+					"width": 2
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false
+	},
+	"radar": {
+			"itemStyle": {
+					"borderWidth": 1
+			},
+			"lineStyle": {
+					"width": 2
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false
+	},
+	"bar": {
+			"itemStyle": {
+					"barBorderWidth": 0,
+					"barBorderColor": "#ccc"
+			}
+	},
+	"pie": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"scatter": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"boxplot": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"parallel": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"sankey": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"funnel": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"gauge": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			}
+	},
+	"candlestick": {
+			"itemStyle": {
+					"color": "#c12e34",
+					"color0": "#2b821d",
+					"borderColor": "#c12e34",
+					"borderColor0": "#2b821d",
+					"borderWidth": 1
+			}
+	},
+	"graph": {
+			"itemStyle": {
+					"borderWidth": 0,
+					"borderColor": "#ccc"
+			},
+			"lineStyle": {
+					"width": 1,
+					"color": "#aaaaaa"
+			},
+			"symbolSize": 4,
+			"symbol": "emptyCircle",
+			"smooth": false,
+			"color": [
+					"#c12e34",
+					"#e6b600",
+					"#0098d9",
+					"#50ec39",
+					"#005eaa",
+					"#339ca8",
+					"#cda819",
+					"#32a487"
+			],
+			"label": {
+					"color": "#eeeeee"
+			}
+	},
+	"map": {
+			"itemStyle": {
+					"areaColor": "#ddd",
+					"borderColor": "#eee",
+					"borderWidth": 0.5
+			},
+			"label": {
+					"color": "#c12e34"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"areaColor": "#e6b600",
+							"borderColor": "#ddd",
+							"borderWidth": 1
+					},
+					"label": {
+							"color": "#c12e34"
+					}
+			}
+	},
+	"geo": {
+			"itemStyle": {
+					"areaColor": "#ddd",
+					"borderColor": "#eee",
+					"borderWidth": 0.5
+			},
+			"label": {
+					"color": "#c12e34"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"areaColor": "#e6b600",
+							"borderColor": "#ddd",
+							"borderWidth": 1
+					},
+					"label": {
+							"color": "#c12e34"
+					}
+			}
+	},
+	"categoryAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#838383"
+			},
+			"splitLine": {
+					"show": false,
+					"lineStyle": {
+							"color": [
+									"#838383"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"valueAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#838383"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"logAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#333"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#333"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#ccc"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"timeAxis": {
+			"axisLine": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisTick": {
+					"show": true,
+					"lineStyle": {
+							"color": "#838383"
+					}
+			},
+			"axisLabel": {
+					"show": true,
+					"color": "#838383"
+			},
+			"splitLine": {
+					"show": true,
+					"lineStyle": {
+							"color": [
+									"#838383"
+							]
+					}
+			},
+			"splitArea": {
+					"show": false,
+					"areaStyle": {
+							"color": [
+									"rgba(250,250,250,0.3)",
+									"rgba(200,200,200,0.3)"
+							]
+					}
+			}
+	},
+	"toolbox": {
+			"iconStyle": {
+					"borderColor": "#06467c"
+			},
+			"emphasis": {
+					"iconStyle": {
+							"borderColor": "#4187c2"
+					}
+			},
+			"textStyle": {
+				"color": "#838383"
+			}
+	},
+	"legend": {
+			"textStyle": {
+					"color": "#838383"
+			}
+	},
+	"tooltip": {
+			"axisPointer": {
+					"lineStyle": {
+							"color": "#cccccc",
+							"width": 1
+					},
+					"crossStyle": {
+							"color": "#cccccc",
+							"width": 1
+					}
+			}
+	},
+	"timeline": {
+			"lineStyle": {
+					"color": "#005eaa",
+					"width": 1
+			},
+			"itemStyle": {
+					"color": "#005eaa",
+					"borderWidth": 1
+			},
+			"controlStyle": {
+					"color": "#005eaa",
+					"borderColor": "#005eaa",
+					"borderWidth": 0.5
+			},
+			"checkpointStyle": {
+					"color": "#005eaa",
+					"borderColor": "#316bc2"
+			},
+			"label": {
+					"color": "#005eaa"
+			},
+			"emphasis": {
+					"itemStyle": {
+							"color": "#005eaa"
+					},
+					"controlStyle": {
+							"color": "#005eaa",
+							"borderColor": "#005eaa",
+							"borderWidth": 0.5
+					},
+					"label": {
+							"color": "#005eaa"
+					}
+			}
+	},
+	"visualMap": {
+			"color": [
+					"#1790cf",
+					"#a2d4e6"
+			]
+	},
+	"dataZoom": {
+			"backgroundColor": "rgba(47,69,84,0)",
+			"dataBackgroundColor": "rgba(47,69,84,0.3)",
+			"fillerColor": "rgba(167,183,204,0.4)",
+			"handleColor": "#a7b7cc",
+			"handleSize": "100%",
+			"textStyle": {
+					"color": "#333333"
+			}
+	},
+	"markPoint": {
+			"label": {
+					"color": "#eeeeee"
+			},
+			"emphasis": {
+					"label": {
+							"color": "#eeeeee"
+					}
+			}
+	}
+}

+ 341 - 0
src/pages/lightAnalysis/pvAnalysis/components/current-scatter-chart.vue

@@ -0,0 +1,341 @@
+<template>
+  <div class="chart" :id="id"></div>
+</template>
+
+<script>
+import util from "@tools/util";
+import partten from "@tools/partten";
+import * as echarts from "echarts";
+import chartTheme from './current-scatter-chart.json'
+
+export default {
+  name: 'currentScatterChart',
+  props: {
+    // 图表宽度
+    width: {
+      type: String,
+      default: "100%",
+    },
+    // 图表高度
+    height: {
+      type: String,
+      default: "350px",
+    },
+    // 图表主标题
+    chartTitle: {
+      type: String,
+      default: "自定义图表组件",
+    },
+    // X 轴配置项
+    xAxisData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    // Y 轴配置项
+    yAxisData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    dataSet: {
+      type: String,
+      default: ''
+    },
+    // 图表核心数据
+    seriesData: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    // 是否显示图表图例
+    showLegend: {
+      type: Boolean,
+      default: true,
+    },
+    // 是否默认采用笔刷模式
+    brushSelected: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      id: "",
+      chart: null,
+      color: [
+        "#05bb4c",
+        "#4b55ae",
+        "#fa8c16",
+        "#f8de5b",
+        "#1a93cf",
+        "#c531c7",
+        "#bd3338",
+      ],
+      theme: 'light'
+    };
+  },
+  watch: {
+    height(){
+      if(this.chart){
+          this.chart.resize()
+      }
+    }
+  },
+  methods: {
+    resize() {},
+    initChart() {
+      const that = this;
+      echarts.registerTheme('chartTheme', chartTheme)
+      let myChart = echarts.init(document.getElementById(this.id), 'chartTheme');
+      that.chart = myChart
+      //指定图表的配置项和数据
+      const option = {
+        //标题
+        title: {
+          text: that.chartTitle,
+          right: 440,
+          top: 4,
+          textStyle: {
+            fontSize: 14,
+            color: that.theme === "dark" ? partten.getColor("grayl") : "#000",
+          },
+        },
+        // backgroundColor:
+        //   that.theme === "dark"
+        //     ? "rgba(0,0,0,0.4)"
+        //     : "rgba(255,255,255,0.5)",
+        //工具箱
+        color: [
+            "#0098d9",
+            "rgb(255,0,0)",
+            "#0a4468",
+            "#a9e3f199",
+            "#a9e3f199",
+            "#005eaa",
+            "#cda819",
+            "#32a487"
+        ],
+        toolbox: {
+          show: false,
+          x: "right",
+          position: [10, 10],
+          // backgroundColor:'rgba(0,0,0,0.4)',
+          borderColor: partten.getColor("gray"),
+          textStyle: {
+            fontSize: util.vh(16),
+            color: partten.getColor("gray")
+          },
+          iconStyle: {
+            borderColor:partten.getColor("gray")
+          },
+          emphasis: {
+            iconStyle: {
+              borderColor:partten.getColor("gray")
+            },
+          },
+        },
+        tooltip: {
+          trigger: "axis",
+          axisPointer: {
+            type: "cross",
+          },
+          // backgroundColor: "rgba(0,0,0,0.4)",
+          // borderColor: partten.getColor("gray"),
+          // textStyle: {
+          //   fontSize: util.vh(16),
+          //   color: partten.getColor("gray"),
+          // },
+          // formatter(params) {
+          //   return params.value?.x
+          //     ? `${params.seriesName}<br />风速:${params.value.x}m/s<br />功率:${params.value.y}kW`
+          //     : `${params.name}`;
+          // },
+        },
+        brush: {
+          seriesIndex: [2,3],
+          yAxisIndex: 0,
+          transformable: true,
+          throttleType: "debounce",
+          throttleDelay: 1000,
+          removeOnClick: true,
+          brushType: "polygon",
+          brushMode: "multiple",
+          brushStyle: {
+            borderWidth: 1,
+            borderColor: "#ff2424",
+          },
+        },
+        dataZoom: [
+          {
+            type: "inside", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+          {
+            type: "slider", //图表下方的伸缩条
+            show: false, //是否显示
+            realtime: true, //拖动时,是否实时更新系列的视图
+            start: 0, //伸缩条开始位置(1-100),可以随时更改
+            end: 100, //伸缩条结束位置(1-100),可以随时更改
+          },
+        ],
+        textStyle: {
+          fontSize: util.vh(16),
+          color: that.theme === "dark" ? "#fff" : "#000",
+        },
+        //图例-每一条数据的名字
+        legend: {
+          show: that.showLegend,
+          // data: [ "拟合功率", "保证功率","无用点", "有用点", "Cp值"],
+          right: 170,
+          type: 'scroll',
+          top: "5",
+          // icon: "circle",
+          itemWidth: 6,
+          inactiveColor:
+            that.theme === "dark"
+              ? partten.getColor("gray")
+              : "#000",
+          textStyle: {
+            color:
+              that.theme === "dark"
+                ? partten.getColor("grayl")
+                : "#000",
+            fontSize: 12,
+          },
+          
+        },
+        grid: {
+          top: 58,
+          left: 40,
+          right: 48,
+          bottom: 24,
+        },
+        //x轴
+        xAxis: [
+          {
+            name: '时间',
+            nameTextStyle: {
+              color: '#838383'
+            },
+            type: "category",
+            boundaryGap: true,
+            data: that.xAxisData || [],
+            axisLabel: {
+              formatter: "{value}",
+            },
+            splitLine: {
+              show: false,
+            },
+            smooth: true,
+            textStyle: {
+              color:
+                that.theme === "dark"
+                  ? partten.getColor("gray")
+                  : "#000",
+            },
+          },
+        ],
+        //y轴没有显式设置,根据值自动生成y轴
+        yAxis: [{
+          splitLine: { show: false },
+          position: 'left',
+          min: 0,
+          name: 'MW',
+          nameTextStyle: {
+            color: '#838383'
+          },
+        }],
+        animation: true,
+        dataset: that.dataSet.length? JSON.parse(that.dataSet) : [],
+        //数据-data是最终要显示的数据
+        series: that.seriesData,
+      };
+
+      that.resize = function () {
+        myChart.resize();
+      };
+
+      window.addEventListener("resize", that.resize);
+
+      myChart.setOption(option);
+      // if (that.brushSelected) {
+      //   myChart.dispatchAction({
+      //     type: "takeGlobalCursor",
+      //     // 如果想变为“可刷选状态”,必须设置。不设置则会关闭“可刷选状态”。
+      //     key: "brush",
+      //     brushOption: {
+      //       seriesIndex: [2,3],
+      //       yAxisIndex: 0,
+      //       transformable: true,
+      //       throttleType: "debounce",
+      //       throttleDelay: 1000,
+      //       removeOnClick: true,
+      //       brushType: "polygon",
+      //       brushMode: "multiple",
+      //       brushStyle: {
+      //         borderWidth: 1,
+      //         color: "rgba(255,36,36,0.2)",
+      //         borderColor: "#ff2424",
+      //       },
+      //     },
+      //   });
+      // }
+      myChart.off("brushSelected");
+      myChart.on("brushSelected", (params) => {
+        that.$emit("getSelected", params.batch || []);
+      });
+      myChart.off('click')
+      myChart.on('click', params => {
+          // if(params.componentType === 'markArea'){
+          //   myChart.dispatchAction({
+          //     type: 'brush',
+          //     areas: [
+          //       {
+          //         xAxisIndex: 0,
+          //         brushType: 'lineX',
+          //         coordRange: [params.data.coord[0][0], params.data.coord[1][0]]
+          //       },
+          //     ]
+          //   });
+          // }
+        })
+    },
+  },
+  created() {
+    this.id = "chart-" + util.newGUID();
+  },
+  mounted() {
+    // this.$nextTick(() => {
+      this.$el.style.width = this.width;
+      this.$el.style.height = this.height;
+      this.initChart();
+    // });
+  },
+  updated() {
+    console.log('update')
+    let myChart = echarts.init(document.getElementById(this.id));
+    myChart.dispose();
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+  unmounted() {
+    window.removeEventListener("resize", this.resize);
+  },
+};
+</script>
+
+<style>
+.chart {
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+}
+</style>

+ 80 - 0
src/pages/lightAnalysis/pvAnalysis/components/search.vue

@@ -0,0 +1,80 @@
+<script setup name="search">
+import { onMounted, reactive, ref } from 'vue'
+import request from '@/api/axios.js'
+import SubmitBtn from '@com/SubmitBtn.vue'
+// import configStationJson from './configStation.json'
+
+const queryForm = reactive({
+	station: '',
+	st: Date.now() - 30 * 24 * 60 * 60 * 1000,
+	et: Date.now(),
+	interval: 3
+})
+/**场站 */
+const stationList = ref([])
+const funGetStation = async () => {
+	const res = await request.get("/agc/config")
+	// stationList.value = Object.values(configStationJson) // configStationJson
+	stationList.value = Object.values(res)
+	if (stationList.value.length) {
+		queryForm.station = stationList.value[0].id
+	}
+
+	funSubmit()
+}
+/**导出 */
+const emits = defineEmits(['submit'])
+const funSubmit = async () => {
+	const startDate = new Date(queryForm.st).setHours(0,0,0,0)
+	const endDate = new Date(queryForm.et).setHours(0,0,0,0)
+	const query = {
+		id: queryForm.station,
+		startTs: new Date(startDate).getTime(),
+		endTs: new Date(endDate).getTime(),
+		interval: queryForm.interval
+	}
+	switch (queryForm.interval) {
+		case 2:
+			query.interval = 60
+			break;
+		case 3:
+			query.interval = 600
+			break;
+		case 4:
+			query.interval = 900
+			break;
+	}
+	emits('submit', query)
+}
+/**created */
+funGetStation()
+</script>
+<template>
+	<div class="pl-[20px] flex items-center h-[80px] relative">
+		<div class="absolute top-[-7px] left-[20px] text-[#838383] text-[14px]">操作面板</div>
+		<el-form class="" :inline="true" :model="queryForm">
+			<el-form-item label="场站" class="!mb-0">
+				<el-select v-model="queryForm.station" class="w-[150px]">
+					<el-option v-for="item in stationList" :key="item.id" :label="item.title" :value="item.id"></el-option>
+				</el-select>
+			</el-form-item>
+			<el-form-item label="开始时间" class="!mb-0">
+				<el-date-picker type="date" class="!w-[150px]" v-model="queryForm.st"></el-date-picker>
+			</el-form-item>
+			<el-form-item label="结束时间" class="!mb-0">
+				<el-date-picker type="date" class="!w-[150px]" v-model="queryForm.et"></el-date-picker>
+			</el-form-item>
+			<el-form-item label="等间隔" class="!mb-0">
+				<el-radio-group v-model="queryForm.interval">
+					<el-radio :label="1">一秒钟</el-radio>
+					<el-radio :label="2">一分钟</el-radio>
+					<el-radio :label="3">十分钟</el-radio>
+					<el-radio :label="4">十五分钟</el-radio>
+				</el-radio-group>
+			</el-form-item>
+			<el-form-item class="!mb-0">
+				<submit-btn v-prevdbclick:5000="funSubmit" desc="执行"></submit-btn>
+			</el-form-item>
+		</el-form>
+	</div>
+</template>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 0
src/pages/lightAnalysis/pvAnalysis/components/submitRES.json


+ 53 - 0
src/pages/lightAnalysis/pvAnalysis/components/table.vue

@@ -0,0 +1,53 @@
+<script setup name="table">
+import {ref, computed} from 'vue'
+const props = defineProps({
+  height: {
+    type: String,
+    default: '800px'
+  },
+  data: {
+    type: Array,
+    default: () => ([]),
+  },
+  column: {
+    type: Array,
+    default: () => ([]),
+  },
+  tableName: {
+    type: String,
+    default: '',
+  },
+  tableId: {
+    type: String,
+    default: '',
+  },
+  loading: {
+    type: Boolean,
+    default: false,
+  }
+})
+const emits = defineEmits(['export'])
+const funExport = () => {
+  emits('export')
+}
+const tableRef = ref('')
+const tableHeight =  computed(() => {
+  return tableRef.value.offsetHeight? tableRef.value.offsetHeight - 12 : 739
+})
+</script>
+<template>
+  <div ref="tableRef" class="p-[10px]"
+    :style="{ height: typeof props.height === 'string' ? props.height : props.height + 'px' }">
+    <!-- <div class="flex justify-between items-center pb-[10px]"> -->
+      <!-- <h3>{{props.tableName}}</h3> -->
+      <!-- <el-button size="small" type="primary" @click="funExport" :disabled="!props.tableId">数据导出</el-button> -->
+    <!-- </div> -->
+    <el-table :data="props.data"
+      stripe
+      size="small" v-loading="props.loading"
+      :max-height="tableHeight"
+      :style="{ width: '100%'}">
+      <el-table-column align="center" show-overflow-tooltip v-for="item in props.column" :prop="item.prop" :label="item.label" sortable resizable :min-width="item.width? item.width : 80" />
+    </el-table>
+  </div>
+</template>

+ 304 - 0
src/pages/lightAnalysis/pvAnalysis/index.vue

@@ -0,0 +1,304 @@
+<script setup name="prepare">
+import searchCop from './components/search.vue'
+import excelCop from '@/components/excel.vue'
+import treeCop from '@/components/tree.vue'
+import tableCop from './components/table.vue'
+import { ElMessage } from 'element-plus';
+import { onMounted, ref, onActivated } from 'vue'
+import CurrentScatterChart from './components/current-scatter-chart.vue'
+import request from '@/api/axios.js'
+import {baseURL, socketURL} from '@/api/axios.js'
+import dayjs from 'dayjs';
+/**配置参数 */
+const tableHeight = ref(window.innerHeight - 314 + 'px')
+const treeHeight = ref(window.innerHeight - 260 + 'px') //tree高度
+const excelHeight = ref(window.innerHeight - 260 + 'px') //excel高度
+/**excel 开始 */
+const excelList = ref([])
+const funExcelChange = async (obj) => { //点击excel项时
+	activeTab.value = '1'
+	tableShowId.value = obj.id
+	tableName.value = obj.name
+	tableLoading.value = true
+	const res = await request.get('/power/prepare/show', { params: { id: obj.id } })
+	if(res.code === 200){
+		tableColumn.value = res.data.title.map(o => {
+			return {
+				prop: o.key,
+				label: o.des,
+				width: o.des==='时间'? 100: 80,
+			}
+		})
+		tableData.value = res.data.data
+		tableLoading.value = false
+	}else{
+		tableLoading.value = false
+	}
+}
+/**tree 开始 */
+const treeData = ref([])
+const funRepeatMap = (arr) => {
+	return arr.map(o => {
+		if (o.children) {
+			const findIndex = o.children.findIndex(p => !!p.type)
+			if (findIndex !== -1) {
+				o.childs = o.children
+				o.children = []
+			}
+		}
+		return {
+			...o,
+			children: o.children?.length ? funRepeatMap(o.children) : []
+		}
+	})
+}
+const funGetTree = async () => {
+	const res = await request.get("/power/prepare/tree")
+	treeData.value = funRepeatMap(res.data)
+	excelList.value = []
+}
+const funCurrentChange = ({ current, currentNode }) => {
+	if (current.childs) {
+		excelList.value = current.childs.map(o => {
+			return {
+				id: o.id,
+				interval: o.interval,
+				path: o.path,
+				prepareid: o.prepareid,
+				station: o.station,
+				time: o.time,
+				type: o.type,
+				windturbine: o.windturbine,
+				name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
+			}
+		})
+	} else {
+		excelList.value = []
+	}
+}
+/**table 开始 */
+const tableShowId = ref('')
+const tableName = ref('')
+const tableColumn = ref([])
+const tableLoading = ref(false)
+const tableData = ref([])
+const funExport = async () => {
+	const a = document.createElement('a')
+	a.href = baseURL + '/power/prepare/download?id=' + tableShowId.value
+	a.download = ''
+	a.click()
+}
+/**tab  */
+const activeTab = ref('1')
+/**chart Data */
+const xAxisData = ref([])
+const chartRef = ref() //chart 的ref
+const seriesData = ref([])
+const dataSet = ref('')
+const funChartSelect = async (batch) => {
+	return false
+}
+/**submit */
+const funSubmit = async (params) => {
+	activeTab.value = '2'
+	tableShowId.value = 1
+	tableName.value = ''
+	tableLoading.value = true
+	const res = await request.get('/agc/deviate', { params: params })
+	tableColumn.value = [
+		{
+			prop: 'ts',
+			label: '时间',
+			width: 100,
+		},
+		{
+			prop: 'ygsdxz',
+			label: '有功设定限值',
+			width: 80,
+		},
+		{
+			prop: 'sfyg',
+			label: '实发有功',
+			width: 80,
+		},
+		{
+			prop: 'llgl',
+			label: '理论功率',
+			width: 80,
+		},
+		{
+			prop: 'pcsx',
+			label: '偏差上限',
+			width: 80,
+		},
+		{
+			prop: 'pcxx',
+			label: '偏差下限',
+			width: 100,
+		},
+	]
+	const tableArr = []
+	const tsArr = []
+	const ygsdxz = []
+	const sfyg = []
+	const llgl = []
+	const pcsx = []
+	const pcxx = []
+	res['有功设定限值'].values.map((o, index) => {
+		tsArr.push(dayjs(o.ts).format('YYYY-MM-DD HH:mm:ss'))
+		ygsdxz.push(Number(o.value).toFixed(2))
+		sfyg.push(Number(res['实发有功'].values[index].value).toFixed(2))
+		llgl.push(Number(res['理论功率'].values[index].value).toFixed(2))
+		pcsx.push(Number(res['偏差上限'].values[index].value).toFixed(2))
+		pcxx.push(Number(res['偏差下限'].values[index].value).toFixed(2))
+		tableArr.push({
+			ts: dayjs(o.ts).format('YYYY-MM-DD HH:mm:ss'),
+			ygsdxz: Number(o.value).toFixed(2),
+			sfyg: Number(res['实发有功'].values[index].value).toFixed(2),
+			llgl: Number(res['理论功率'].values[index].value).toFixed(2),
+			pcsx: Number(res['偏差上限'].values[index].value).toFixed(2),
+			pcxx: Number(res['偏差下限'].values[index].value).toFixed(2),
+		})
+	})
+	xAxisData.value = tableArr.map(o => o.ts)
+	seriesData.value = [
+		{
+			name: "有功设定限值",
+			type: "line",
+			symbol: "line", //设定为实心点
+			symbolSize: 0, //设定实心点的大小
+			smooth: false, //这个是把线变成曲线
+			data: ygsdxz,
+			xAxisIndex: 0,
+		},
+		{
+			name: "实发有功",
+			type: "line",
+			symbol: "line", //设定为实心点
+			symbolSize: 0, //设定实心点的大小
+			smooth: false, //这个是把线变成曲线
+			data: sfyg,
+			xAxisIndex: 0,
+		},
+		{
+			name: "理论功率",
+			type: "line",
+			symbol: "line", //设定为实心点
+			symbolSize: 0, //设定实心点的大小
+			smooth: false, //这个是把线变成曲线
+			data: llgl,
+			xAxisIndex: 0,
+		},
+		{
+			name: "偏差上限",
+			type: "line",
+			symbol: "line", //设定为实心点
+			symbolSize: 0, //设定实心点的大小
+			smooth: false, //这个是把线变成曲线
+			data: pcsx,
+			xAxisIndex: 0,
+			lineStyle: {
+            opacity: 0
+			},
+			areaStyle: {
+				color: '#ccc',
+			},
+			symbol: 'none'
+		},
+		{
+			name: "偏差下限",
+			type: "line",
+			symbol: "line", //设定为实心点
+			symbolSize: 0, //设定实心点的大小
+			smooth: false, //这个是把线变成曲线
+			data: pcxx,
+			xAxisIndex: 0,
+			lineStyle: {
+            opacity: 0
+			},
+			areaStyle: {
+				color: '#fff',
+				opacity: 1
+			},
+			symbol: 'none'
+		},
+	]
+	tableData.value = tableArr
+	tableLoading.value = false
+
+	
+	// if (res.code === 200) {
+		// if(res.data.sjgl?.length){
+		// 	for(const wtObj of res.data.sjgl){
+		// 		seriesData.value.push(
+		// 			{
+		// 				name: wtObj.obj.windturbine + "\n实际功率",
+		// 				type: "line",
+		// 				symbol: "line", //设定为实心点
+		// 				symbolSize: 0, //设定实心点的大小
+		// 				smooth: true, //这个是把线变成曲线
+		// 				data: wtObj.sjgl || [],
+		// 				xAxisIndex: 0,
+		// 			},
+		// 		)
+		// 		wtData.value.push(wtObj.obj)
+		// 	}
+		// }
+	// }
+}
+/**created */
+// funGetTree()
+/**mounted */
+onMounted(() => {
+	tableHeight.value = window.innerHeight - 314 + 'px'
+	excelHeight.value = window.innerHeight - 260 + 'px'
+	treeHeight.value = window.innerHeight - 260 + 'px'
+	window.addEventListener('resize', () => {
+		tableHeight.value = window.innerHeight - 314 + 'px'
+		excelHeight.value = window.innerHeight - 260 + 'px'
+		treeHeight.value = window.innerHeight - 260 + 'px'
+	})
+})
+/**activated */
+onActivated(() => {
+	// funGetTree()
+	// funSubmit()
+})
+</script>
+<template>
+	<div class="bg-white py-[10px] px-[10px] relative">
+		<search-cop class="mb-[20px] shadow rounded-[6px] shadow-blue-500" @submit="funSubmit">
+		</search-cop>
+		<div class="relative shadow rounded-[6px] shadow-blue-500 px-[10px] pt-[20px] pb-[10px]">
+			<div class="text-[14px] absolute top-[-7px] text-[#838383] left-[20px]">数据展示</div>
+			<el-row :gutter="10">
+				<!-- <el-col :span="5">
+					<tree-cop :data="treeData" :height="treeHeight" @currentChange="funCurrentChange" @refresh="funGetTree">
+					</tree-cop>
+				</el-col>
+				<el-col :span="3">
+					<excel-cop :data="excelList" :height="excelHeight" @excelChange="funExcelChange"></excel-cop>
+				</el-col> -->
+				<el-col :span="24">
+					<div class="px-[10px] shadow rounded-[6px] shadow-blue-500 ">
+						<el-tabs v-model="activeTab">
+							<el-tab-pane label="表格数据" name="1">
+							</el-tab-pane>
+							<el-tab-pane label="图表展示" name="2">
+							</el-tab-pane>
+							<table-cop v-show="activeTab === '1'" :data="tableData" :loading="tableLoading" :column="tableColumn"
+								:height="tableHeight" :tableId="tableShowId" :tableName="tableName"></table-cop>
+							<div v-show="activeTab === '2'"
+								:style="{ height: typeof tableHeight === 'string' ? tableHeight : tableHeight + 'px' }"
+								class="p-[10px]">
+								<CurrentScatterChart ref="chartRef" width="100%" :height="`calc( ${tableHeight} - 20px )`" :chartTitle="''"
+									:xAxisData="xAxisData" :yAxisData="{ splitLine: { show: false } }" :seriesData="seriesData"
+									:showLegend="true" :brushSelected="false" :dataSet="dataSet" @getSelected="funChartSelect" />
+							</div>
+						</el-tabs>
+					</div>
+				</el-col>
+			</el-row>
+		</div>
+	</div>
+</template>

+ 66 - 3
src/router/index.js

@@ -28,7 +28,7 @@ const routes = [{
                     path: '/dataFilter/prepare',
                     name: 'dataFilterPrepare',
                     meta: {
-                        title: '数据准备',
+                        title: '风电数据准备',
                     },
                     component: () =>
                         import(
@@ -40,13 +40,25 @@ const routes = [{
                     path: '/dataFilter/process',
                     name: 'dataFilterProcess',
                     meta: {
-                        title: '数据处理',
+                        title: '风电数据处理',
                     },
                     component: () =>
                         import(
                             '../pages/dataFilter/process/index.vue'
                         ),
                 },
+                {
+                    icon: 'el-icon-s-home',
+                    path: '/dataFilter/lightPrepare',
+                    name: 'dataFilterLightPrepare',
+                    meta: {
+                        title: '光伏数据准备',
+                    },
+                    component: () =>
+                        import(
+                            '../pages/dataFilter/lightPrepare/index.vue'
+                        ),
+                },
             ]
         },
         {
@@ -55,7 +67,7 @@ const routes = [{
             name: 'dataAnalysis',
             redirect: '/dataAnalysis/combine',
             meta: {
-                title: '数据分析',
+                title: '风电分析',
             },
             component: () =>
                 import(
@@ -136,6 +148,57 @@ const routes = [{
                 },
             ]
         },
+        {
+            icon: 'iconfont iconbaojingpeizhi',
+            path: '/lightAnalysis',
+            name: 'lightAnalysis',
+            redirect: '/lightAnalysis/glAnalysis',
+            meta: {
+                title: '光伏分析',
+            },
+            component: () =>
+                import(
+                    '../pages/routerViewss.vue'
+                ),
+            children: [
+                {
+                    icon: 'el-icon-s-home',
+                    path: '/lightAnalysis/glAnalysis',
+                    name: 'glAnalysis',
+                    meta: {
+                        title: '功率曲线分析',
+                    },
+                    component: () =>
+                        import(
+                            '../pages/lightAnalysis/glAnalysis/index.vue'
+                        ),
+                },
+                {
+                    icon: 'el-icon-s-home',
+                    path: '/lightAnalysis/pvAnalysis',
+                    name: 'pvAnalysis',
+                    meta: {
+                        title: 'PV曲线分析',
+                    },
+                    component: () =>
+                        import(
+                            '../pages/lightAnalysis/pvAnalysis/index.vue'
+                        ),
+                },
+                {
+                    icon: 'el-icon-s-home',
+                    path: '/lightAnalysis/ivAnalysis',
+                    name: 'ivAnalysis',
+                    meta: {
+                        title: 'iV曲线分析',
+                    },
+                    component: () =>
+                        import(
+                            '../pages/lightAnalysis/ivAnalysis/index.vue'
+                        ),
+                },
+            ]
+        },
     ],
 },