diff --git a/hx-ai-intelligent/public/asset/file/emissionSource.xlsx b/hx-ai-intelligent/public/asset/file/emissionSource.xlsx index 306414b..57d82b0 100644 Binary files a/hx-ai-intelligent/public/asset/file/emissionSource.xlsx and b/hx-ai-intelligent/public/asset/file/emissionSource.xlsx differ diff --git a/hx-ai-intelligent/public/asset/file/energyConsumption.xlsx b/hx-ai-intelligent/public/asset/file/energyConsumption.xlsx index a9eae6e..5edee96 100644 Binary files a/hx-ai-intelligent/public/asset/file/energyConsumption.xlsx and b/hx-ai-intelligent/public/asset/file/energyConsumption.xlsx differ diff --git a/hx-ai-intelligent/src/api/coldAndHeatSources.ts b/hx-ai-intelligent/src/api/coldAndHeatSources.ts new file mode 100644 index 0000000..6169a7c --- /dev/null +++ b/hx-ai-intelligent/src/api/coldAndHeatSources.ts @@ -0,0 +1,10 @@ +import { BASE_URL } from './index'; + +export enum coldAndHeatSourcesApi { + getUserWaterPumpState = `${BASE_URL}/api/tempSysCtrl/getUserWaterPumpState`, // 用户水泵查询最新状态 + getLandWaterPumpState = `${BASE_URL}/api/tempSysCtrl/getLandWaterPumpState`, // 地源水泵查询最新状态 + getLandHeatPumpState = `${BASE_URL}/api/tempSysCtrl/getLandHeatPumpState`, //螺旋式地源热泵 - 查询最新状态 + getEnergyTankState = `${BASE_URL}/api/tempSysCtrl/getEnergyTankState`, //冷热水双蓄储能罐 - 查询最新状态 + getCoolPumpState = `${BASE_URL}/api/tempSysCtrl/getCoolPumpState`, //释冷泵 - 查询最新状态 + getAirHeatPumpState = `${BASE_URL}/api/tempSysCtrl/getAirHeatPumpState`, //空气源热泵 - 查询最新状态 +} diff --git a/hx-ai-intelligent/src/api/waterSystem.ts b/hx-ai-intelligent/src/api/waterSystem.ts index e8c282c..fb56ab3 100644 --- a/hx-ai-intelligent/src/api/waterSystem.ts +++ b/hx-ai-intelligent/src/api/waterSystem.ts @@ -2,6 +2,8 @@ const prefix = '/carbon-smart/api'; // 通风系统相关接口 export enum waterSys { + // 首页 ==================================================== + // 获得污水池状态 getPool1 = prefix + '/waterSysCtrl/getSewagePoolState', // 获得阀门状态 @@ -10,4 +12,15 @@ export enum waterSys { getPool2 = prefix + '/waterSysCtrl/getCollectPoolState', // 获得水泵状态 getPump = prefix + '/waterSysCtrl/getPumpState', + // 提交场景模式修改 + submitList = prefix + '/waterSysCtrl/changeToSceneMode', + + // 计划 tab1 =============================================== + submitTableData = prefix + '/waterSysCtrl/refreshPlanStatus', + + // 日志 tab2 =============================================== + // 获得设备日志 + getLog = prefix + '/waterSysInfo/pageAbleLog', + // 获得日志详情 + getLogDetail = prefix + '/waterSysInfo/fullLog', } diff --git a/hx-ai-intelligent/src/router/equipmentControl.ts b/hx-ai-intelligent/src/router/equipmentControl.ts index 9d4dd25..52703dd 100644 --- a/hx-ai-intelligent/src/router/equipmentControl.ts +++ b/hx-ai-intelligent/src/router/equipmentControl.ts @@ -119,25 +119,25 @@ const equipmentControl = { }, ], }, - // { - // path: 'waterSystem', - // name: 'waterSystem', - // meta: { title: '给排水系统', hideChildren: true, icon: 'shebeiqunkong' }, - // component: Base, - // redirect: { name: 'waternControlSystemIndex' }, - // children: [ - // { - // path: 'index', - // name: 'waternControlSystemIndex', - // component: () => import('/@/view/equipmentControl/waterSystem/index.vue'), - // meta: { - // title: '给排水系统', - // keepAlive: false, - // // backApi: [], - // }, - // }, - // ], - // }, + { + path: 'waterSystem', + name: 'waterSystem', + meta: { title: '给排水系统', hideChildren: true, icon: 'shebeiqunkong' }, + component: Base, + redirect: { name: 'waternControlSystemIndex' }, + children: [ + { + path: 'index', + name: 'waternControlSystemIndex', + component: () => import('/@/view/equipmentControl/waterSystem/index.vue'), + meta: { + title: '给排水系统', + keepAlive: false, + // backApi: [], + }, + }, + ], + }, { path: 'planToAdd', name: 'planToAdd', diff --git a/hx-ai-intelligent/src/util/ExcelUtil.js b/hx-ai-intelligent/src/util/ExcelUtil.js index 85296e2..db76c78 100644 --- a/hx-ai-intelligent/src/util/ExcelUtil.js +++ b/hx-ai-intelligent/src/util/ExcelUtil.js @@ -10,10 +10,43 @@ import FileSaver from 'file-saver'; // export default exportExcel; // 导出excel文件 -export function exportExcel (tableColumns,data,fillName,isMerge,start,end) { +/** + * + * @param {*} tableColumns 表头 + * @param {*} data 数据 + * @param {*} fillName 文件名 + * @param {*} isMerge 是否合并单元格 + * @param {*} firstKey 第一个字段的key,用来判断序号列是否合并 + * @param {*} start 合并单元格开始列 + * @param {*} end 合并单元格结束列 + * @returns + */ +export function exportExcel (tableColumns,data,fillName,isMerge = false, firstKey = '',start = 0, end = 0) { + debugger if (!data || data.length == 0) { return; } + if (isMerge) { + // 需要合并序号 + for (let i = 0; i < data.length; i++) { + // 自定义单元格内容,这里返回序号 + if (i == 0) { + data[i].index = 1; + // return 1; + } else if (data[i - 1][firstKey] == data[i][firstKey]) { + data[i].index = data[i - 1].index; + // return data.value[index].index; + } else { + data[i].index = data[i - 1].index + 1; + } + } + } else { + // 不需要合并序号 + for (let i = 0; i < data.length; i++) { + data[i].index = i + 1; + } + } + // 创建工作簿 const workbook = new ExcelJS.Workbook(); // 添加工作表,名为sheet1 @@ -33,27 +66,22 @@ export function exportExcel (tableColumns,data,fillName,isMerge,start,end) { columns.push({ header: tableColumns[i].title, key: tableColumns[i].dataIndex, - width: tableColumns[i].width / 5, + width: tableColumns[i].width ? tableColumns[i].width / 5 : 20, }); } } //传入的数据 const list = data; + //格式化数据 const datas = formatJson(filterVal, list); - // // 导出数据列表 - // const data = [ - // { 姓名: '张三', 年龄: 18, 身高: 175, 体重: 74 }, - // { 姓名: '李四', 年龄: 22, 身高: 177, 体重: 84 }, - // { 姓名: '王五', 年龄: 53, 身高: 155, 体重: 64 }, - // ]; // 获取表头所有键 // const headers = Object.keys(data[0]); + // 获取表头 sheet1.columns = columns; - // // 将标题写入第一行 - // sheet1.addRow(tHeader); + // 将数据写入工作表 datas.forEach((row) => { // const values = Object.values(row); @@ -62,80 +90,30 @@ export function exportExcel (tableColumns,data,fillName,isMerge,start,end) { // 判断是否合并单元格 if (isMerge) { - debugger - // 遍历列,从第一列到 end 列 + // 遍历列,从 start 列到 end 列 for (let col = start; col <= end; col++) { - // let mergeStartRow = 2; // 每次新列开始时,重置起始行 for (let row = 3; row <= datas.length + 1; row++) { const currentCellValue = sheet1.getCell(row, col).value; const previousCellValue = sheet1.getCell(row - 1, col).value; - let currentCellValue_1 = '' - let previousCellValue_1 = '' + // 从第二列开始就要看前一列是否已经合并 + let isMerged = true if (col > 1) { - currentCellValue_1 = sheet1.getCell(row, col-1).value; - previousCellValue_1 = sheet1.getCell(row - 1, col-1).value; + isMerged = ifMerged(sheet1,row - 1, col-1,row, col-1) } - if (currentCellValue === previousCellValue && currentCellValue_1 === previousCellValue_1) { - // 当前列有变化,检查是否需要合并前面的单元格 - // if (mergeStartRow < row - 1) { - // 只有在前面的行有超过1个时才合并 - sheet1.mergeCells(row, col, row - 1, col); - // } - // 更新起始行 - // mergeStartRow = row; + if (currentCellValue === previousCellValue && isMerged) { + // 检查是上边需要合并的单元格是否已经合并 + const mergeInfo = getMergeInfo(sheet1, row - 1, col) + if ( mergeInfo.isMerged ) { + sheet1.unMergeCells( mergeInfo.startRow, col, row - 1, col); + sheet1.mergeCells(mergeInfo.startRow, col, row, col); + } else { + sheet1.mergeCells(row, col, row - 1, col); + } } - - // // 如果是最后一行,检查是否需要合并 - // if (row === datas.length + 1 && mergeStartRow < row) { - // sheet1.mergeCells(mergeStartRow, col, row, col); - // } } } - // 从第一列开始逐列检查,前提是前面的列已合并 - // for (let col = start; col <= end; col++) { - // let startRow = 2; // 从数据开始的第二行开始检查 - // let endRow = 2; - - // while (endRow <= sheet1.rowCount) { - // let currentValue = sheet1.getCell(endRow, col).value; - // let prevValue = sheet1.getCell(endRow - 1, col).value; - - // // 如果当前值等于前一个值,且前面的列是合并的,则继续合并 - // if (currentValue === prevValue) { - // let mergeAllowed = true; - // for (let prevCol = 1; prevCol < col; prevCol++) { - // let range = sheet1.getCell(endRow - 1, prevCol).master; - // if (range && range.row !== startRow) { - // mergeAllowed = false; - // break; - // } - // } - - // if (mergeAllowed) { - // endRow++; - // } else { - // // 不允许合并,直接移动起始行到当前行 - // startRow = endRow; - // endRow++; - // } - // } else { - // // 当前值不等于前一个值或合并不允许,进行合并操作 - // if (startRow < endRow - 1) { - // sheet1.mergeCells(startRow, col, endRow - 1, col); - // } - // startRow = endRow; - // endRow++; - // } - // } - - // // 处理最后一段相同的单元格 - // if (startRow < endRow - 1) { - // sheet1.mergeCells(startRow, col, endRow - 1, col); - // } - // } - } @@ -208,3 +186,43 @@ function formatJson (filterVal, jsonData) { return jsonData.map((v) => filterVal.map((j) => v[j])); }; +/** + * 获取给定行和列的单元格是否为合并单元格,并返回合并起始行 + * @param {Worksheet} worksheet - ExcelJS 工作表对象 + * @param {number} row - 单元格的行号 (从 1 开始) + * @param {number} col - 单元格的列号 (从 1 开始) + * @returns {Object} - 返回一个对象,包含 isMerged 和 startRow 属性 + */ +function getMergeInfo(worksheet, row, col) { + // 遍历所有的合并范围 + for (const mergeRange in worksheet._merges) { + if (worksheet._merges.hasOwnProperty(mergeRange)) { + const { top, left, bottom, right } = worksheet._merges[mergeRange]; + + // 检查行列是否在当前合并范围内 + if (row >= top && row <= bottom && col >= left && col <= right) { + return { isMerged: true, startRow: top }; // 找到合并范围,返回合并信息 + } + } + } + return { isMerged: false, startRow: null }; // 单元格不在任何合并范围内 +} + + +// 函数:检查两个单元格是否属于同一个合并区域 +function ifMerged(worksheet, row1, col1, row2, col2) { + const merges = worksheet._merges; // 获取所有的合并区域 + for (let mergeAddress in merges) { + const mergeRange = merges[mergeAddress]; + const { top, left, bottom, right } = mergeRange; + + const isCell1InRange = (row1 >= top && row1 <= bottom && col1 >= left && col1 <= right); + const isCell2InRange = (row2 >= top && row2 <= bottom && col2 >= left && col2 <= right); + + if (isCell1InRange && isCell2InRange) { + return true; + } + } + return false; +} + diff --git a/hx-ai-intelligent/src/view/carbonEmissionManage/carbonAssets/carbonAssetsDetail/index.vue b/hx-ai-intelligent/src/view/carbonEmissionManage/carbonAssets/carbonAssetsDetail/index.vue index fcc3dab..fe7571b 100644 --- a/hx-ai-intelligent/src/view/carbonEmissionManage/carbonAssets/carbonAssetsDetail/index.vue +++ b/hx-ai-intelligent/src/view/carbonEmissionManage/carbonAssets/carbonAssetsDetail/index.vue @@ -48,7 +48,7 @@ -
+
+ + {{ truncatedName(data.energyType + data.code) }} + {{ truncatedName(data.energyType) }}
@@ -130,8 +132,8 @@ diff --git a/hx-ai-intelligent/src/view/equipmentControl/waterSystem/component/planTab.vue b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/component/planTab.vue new file mode 100644 index 0000000..51643b2 --- /dev/null +++ b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/component/planTab.vue @@ -0,0 +1,381 @@ + + + + diff --git a/hx-ai-intelligent/src/view/equipmentControl/waterSystem/device.ts b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/device.ts new file mode 100644 index 0000000..4278f5e --- /dev/null +++ b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/device.ts @@ -0,0 +1,282 @@ +import { ref } from 'vue'; +// 流动线条样式与定位 +export const linePosition = [ + // 雨水池 - 控制阀 + { + left: '4%', + top: '44%', + transform: 'rotateZ(-30deg)', + transformOrigin: 'left', + zIndex: '6', + width: '6%', + }, + { + left: '4%', + top: '84%', + transform: 'rotateZ(-30deg)', + transformOrigin: 'left', + zIndex: '6', + width: '6%', + }, + // 控制阀 - 进水阀 + { left: '12%', top: '34%', width: '10%' }, + { left: '12%', top: '74%', width: '10%' }, + // 进水阀 - 集水池 + { left: '23%', top: '34%', width: '8%' }, + { left: '23%', top: '74%', width: '8%' }, + // 集水池 - 排水泵 - 横线 + { left: '35%', top: '34%', width: '4%' }, + { left: '35%', top: '74%', width: '4%' }, + // 上半集水池右侧分线 + { left: '39%', top: '34%', transform: 'rotateZ(90deg)', transformOrigin: 'left', width: '4%' }, + { left: '39%', top: '34%', transform: 'rotateZ(-90deg)', transformOrigin: 'left', width: '4%' }, + // 下半集水池右侧分线 + { left: '39%', top: '74%', transform: 'rotateZ(90deg)', transformOrigin: 'left', width: '4%' }, + { left: '39%', top: '74%', transform: 'rotateZ(-90deg)', transformOrigin: 'left', width: '4%' }, + // 上半-左侧水泵分线 + { left: '39%', top: '25%', width: '8%' }, + { left: '39%', top: '43%', width: '8%' }, + // 下半-左侧水泵分线 + { left: '39%', top: '65%', width: '8%' }, + { left: '39%', top: '83%', width: '8%' }, + // 水泵右侧合线 下半 + { left: '47%', top: '83%', transform: 'rotateZ(-90deg)', transformOrigin: 'left', width: '14%' }, + // 水泵右侧合线 上半 + { left: '47%', top: '25%', transform: 'rotateZ(90deg)', transformOrigin: 'left', width: '12%' }, + // 汇入总闸连线 + { left: '47%', top: '52%', width: '4%' }, + // 汇入总集水池 + { left: '51%', top: '52%', transform: 'rotateZ(-25deg)', transformOrigin: 'left', width: '7%' }, + // 汇入总排水闸 + { left: '58%', top: '45%', width: '9%' }, + // 汇入市政管道 - 途径水泵2 + { left: '68%', top: '45%', width: '28%' }, + // 总排水闸 - 总排水泵1 上半 + { left: '75%', top: '45%', transform: 'rotateZ(-90deg)', transformOrigin: 'left', width: '10%' }, + { left: '75%', top: '23%', width: '11%' }, + { left: '86%', top: '22.5%', transform: 'rotateZ(90deg)', transformOrigin: 'left', width: '10%' }, + // 总排水闸 - 总排水泵3 下半 + { left: '75%', top: '45%', transform: 'rotateZ(90deg)', transformOrigin: 'left', width: '9%' }, + { left: '75%', top: '65%', width: '11%' }, + { + left: '86%', + top: '65%', + transform: 'rotateZ(-90deg)', + transformOrigin: 'left', + width: '9%', + }, +]; + +/** + * 1. 设备数量是固定的 + * 2. 设备顺序是固定的 + * 3. 此处数据用于渲染设备图标,后端返回数据后,将依次插入 + * @param icon 决定调用的设备图标:污水池=1/集水池=2/控制阀=3//进水阀=4//排水泵=5 + * @param type 设备类型:污水池=1/阀门=2/集水池=3/水泵=4 + * @param open 水泵的开关状态 开=true/关=false + * @param control 是否可以被操作(是否显示顶部按钮,水池为false) + * @param edited 是否已经被编辑(决定显示编辑 或 撤销) + */ +// 污水池 +export const device1 = ref([ + { + control: false, + type: 1, + icon: 1, + styleObject: { + left: '1%', + top: '40%', + zIndex: '9', + }, + }, + { + control: false, + type: 1, + icon: 1, + styleObject: { + left: '1%', + top: '80%', + zIndex: '9', + }, + }, +]); +// 阀门 +export const device2 = ref([ + { + control: true, + open: true, + type: 2, + icon: 3, + edited: false, + styleObject: { + left: '8%', + top: '28%', + }, + }, + { + control: true, + open: false, + type: 2, + icon: 3, + edited: false, + styleObject: { + left: '8%', + top: '68%', + }, + }, + { + control: true, + open: true, + type: 2, + icon: 4, + edited: false, + styleObject: { + left: '20%', + top: '28%', + }, + }, + { + control: true, + open: true, + type: 2, + icon: 4, + edited: false, + styleObject: { + left: '20%', + top: '68%', + }, + }, + { + control: true, + open: true, + type: 2, + icon: 3, + edited: false, + styleObject: { + left: '48%', + top: '46%', + }, + }, + { + control: true, + open: true, + type: 2, + icon: 3, + edited: false, + styleObject: { + left: '65%', + top: '38%', + }, + }, +]); +// 集水池 +export const device3 = ref([ + { + control: false, + type: 3, + icon: 2, + styleObject: { + left: '30%', + top: '68%', + }, + }, + { + control: false, + type: 3, + icon: 2, + styleObject: { + left: '30%', + top: '28%', + }, + }, + { + control: false, + type: 3, + icon: 2, + styleObject: { + left: '56%', + top: '40%', + }, + }, +]); +// 水泵 +export const device4 = ref([ + { + control: true, + open: false, + type: 4, + icon: 5, + edited: false, + styleObject: { + left: '40%', + top: '20%', + }, + }, + { + control: true, + open: true, + type: 4, + icon: 5, + edited: false, + styleObject: { + left: '40%', + top: '40%', + }, + }, + { + control: true, + open: true, + type: 4, + icon: 5, + edited: false, + styleObject: { + left: '40%', + top: '60%', + }, + }, + { + control: true, + open: true, + type: 4, + icon: 5, + edited: false, + styleObject: { + left: '40%', + top: '80%', + }, + }, + // 右上3水泵 + { + control: true, + open: true, + type: 4, + icon: 5, + edited: false, + styleObject: { + left: '78%', + top: '20%', + }, + }, + { + control: true, + open: true, + type: 4, + icon: 5, + edited: false, + styleObject: { + left: '78%', + top: '40%', + }, + }, + { + control: true, + open: true, + type: 4, + icon: 5, + edited: false, + styleObject: { + left: '78%', + top: '60%', + }, + }, +]); diff --git a/hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceInfo.vue b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceInfo.vue new file mode 100644 index 0000000..8f7232c --- /dev/null +++ b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceInfo.vue @@ -0,0 +1,150 @@ + + + diff --git a/hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceItem.vue b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceItem.vue new file mode 100644 index 0000000..e8b0b3a --- /dev/null +++ b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceItem.vue @@ -0,0 +1,291 @@ + + + diff --git a/hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceLine.vue b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceLine.vue new file mode 100644 index 0000000..245957c --- /dev/null +++ b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/deviceLine.vue @@ -0,0 +1,30 @@ + + + diff --git a/hx-ai-intelligent/src/view/equipmentControl/waterSystem/images/open.png b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/images/open.png new file mode 100644 index 0000000..99fb1d0 Binary files /dev/null and b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/images/open.png differ diff --git a/hx-ai-intelligent/src/view/equipmentControl/waterSystem/index.vue b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/index.vue new file mode 100644 index 0000000..df8efa1 --- /dev/null +++ b/hx-ai-intelligent/src/view/equipmentControl/waterSystem/index.vue @@ -0,0 +1,663 @@ + + + diff --git a/hx-ai-intelligent/src/view/monitor/deviceMonitor/page.vue b/hx-ai-intelligent/src/view/monitor/deviceMonitor/page.vue index 73f7abc..7b8759b 100644 --- a/hx-ai-intelligent/src/view/monitor/deviceMonitor/page.vue +++ b/hx-ai-intelligent/src/view/monitor/deviceMonitor/page.vue @@ -52,6 +52,10 @@ if (graphRef.value) { graphRef.value.downloadChart(); } + } else { + if (tableRef.value) { + tableRef.value.export1(); + } } }; diff --git a/hx-ai-intelligent/src/view/monitor/deviceMonitor/table/index.vue b/hx-ai-intelligent/src/view/monitor/deviceMonitor/table/index.vue index be0f37f..eb18c17 100644 --- a/hx-ai-intelligent/src/view/monitor/deviceMonitor/table/index.vue +++ b/hx-ai-intelligent/src/view/monitor/deviceMonitor/table/index.vue @@ -16,6 +16,7 @@