Browse Source

feat:文件导出功能

dev
zhaobing’ 1 year ago
parent
commit
d15e168ed0
  1. 137
      api/app/lib/controllers/monitor/index.js
  2. 6
      web/client/src/sections/data/containers/dataDetail.jsx
  3. 34
      web/client/src/sections/data/containers/dataTableComponent.jsx
  4. 5
      web/client/src/sections/problem/components/tableData.jsx

137
api/app/lib/controllers/monitor/index.js

@ -1,5 +1,6 @@
const moment = require('moment');
const moment = require('moment')
const fs = require('fs')
async function getStructures(ctx) {
try {
@ -120,18 +121,19 @@ async function getSensors(ctx) {
}
//根据设备id和监测因素id查询监测数据
async function getMonitorData(ctx) {
try {
const { clickHouse } = ctx.app.fs
const { factorId, sensorId, startTime, endTime } = ctx.query
const projectId=sensorId.split('-')[0]
const { factorId, sensorId, startTime, endTime,toExport } = ctx.query
const projectId = sensorId.split('-')[0]
const factorsList = await clickHouse.alarmLocal.query(`SELECT FactorID,Items,ItemNames,ItemUnits FROM factors
WHERE FactorID=${factorId} AND Project='${projectId}'
`).toPromise() || []
const dataArray = sensorId.split(',')
const transformedArray = dataArray.map(item => {
return item.replace('-',':')+''
return item.replace('-', ':') + ''
})
const id=`(${transformedArray.map(id => `'${id}'`).join(',')})`
const id = `(${transformedArray.map(id => `'${id}'`).join(',')})`
const monitorData = await clickHouse.alarmLocal.query(`SELECT distinct SensorId,CollectTime,Values FROM themes
WHERE SensorId in ${id}
AND CollectTime >= toDate('${startTime}')
@ -146,20 +148,20 @@ async function getMonitorData(ctx) {
//因素名词
let factorNames = []
//单位
let c=[]
let c = []
factorsList.map(item => {
factors = item.ItemNames.split(',')
factorNames = item.Items.split(',')
c = item.ItemUnits.split(',')
factorNames.map((child,index)=> {
items[factorNames[index]] = { name:factors[index] , unit:c[index] }
factorNames.map((child, index) => {
items[factorNames[index]] = { name: factors[index], unit: c[index] }
})
})
}
//设备数据+数据
let sensors = []
let data=[]
if(sensor&&monitorData&&sensor.length && monitorData.length){
let data = []
if (sensor && monitorData && sensor.length && monitorData.length) {
sensor.forEach((item) => {
// 过滤与当前传感器相关的数据
const sensorDataArray = monitorData.filter((d) => d.SensorId == item.ID)
@ -184,8 +186,65 @@ async function getMonitorData(ctx) {
data.push(sensorDataItem)
})
}
//导出相关
if (toExport) {
let arr=items
let columns = []
columns.push({
title: '设备位置',
dataIndex: 'position',
key: 'position',
});
for (let index in arr) {
columns.push({
title: arr[index].name + '(' + arr[index].unit + ')',
dataIndex: index,
sorter: (a, b) => b[index] - a[index],
key: index,
})
};
columns.push({
title: '采集时间',
dataIndex: 'acqTime',
sorter: (a, b) => b['realTime'] - a['realTime'],
key: 'acqTime',
});
//设备
let data1 = []
let themeStations = data
for (let i = 0; i < themeStations.length; i++) {
for (let k = 0; k < themeStations[i].data.length; k++) {
let cdataT = {}
let startT = "";
let endT = "";
let dataTS = themeStations[i].data[k];
cdataT.key = `station-${themeStations[i].id}-${k}`;
cdataT.position = themeStations[i].name;
cdataT.acqTime = moment(dataTS.time).format('YYYY-MM-DD HH:mm:ss');
cdataT.realTime = moment(dataTS.time).valueOf();
if (startT == "") {
startT = dataTS.time;
endT = dataTS.time;
} else {
if (moment(startT) >= moment(dataTS.time))
startT = dataTS.time;
if (moment(endT) <= moment(dataTS.time))
endT = dataTS.time;
}
//动态列的值
for (let themeItem in arr) {
cdataT[themeItem] = dataTS.values[themeItem];
}
data1.push(cdataT)
}
}
await exportMaterialEnterList(ctx, data1, columns)
}
if(!toExport){
ctx.body = { items, sensors: data }
ctx.status = 200
}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`);
@ -196,11 +255,67 @@ async function getMonitorData(ctx) {
}
}
async function exportMaterialEnterList(ctx, data, columns) {
try {
let header = []
columns.forEach(item => {
header.push({ title: item.title, key: item.key })
})
const { utils: { simpleExcelDown } } = ctx.app.fs
// let exportData = []
// let item={}
// console.log(dataList[0].dataValues)
let siteName = '数据监控'
// for (let item of data) {
// for(let child of item){
// if(child!=key){
// item[child]=
// }
// }
// // item.outTime = moment(item.outTime).format('YYYY-MM-DD HH:mm:ss');
// // item.branchId = item.siteProcessBranch && item.siteProcessBranch.name ? item.siteProcessBranch.name : '-'
// // item.subItemId = item.siteProcessSubItem && item.siteProcessSubItem.name ? item.siteProcessSubItem.name : '-'
// // item.type = item.materialItem && item.materialItem.name ? item.materialItem.name : '-'
// // item.name = item.materialItem && item.materialItem.name ? item.materialItem.name : '-'
// // item.model = item.materialItem && item.materialItem.model ? item.materialItem.model : '-'
// // item.unit = item.materialItem && item.materialItem.unit ? item.materialItem.unit : '-'
// // item.providerId = item.materialProvider && item.materialProvider.name ? item.materialProvider.name : '-'
// // item.status = (item.status || item.status == 0) && data[item.status]
// exportData.push(item)
// }
const fileName = `${siteName}` + '.xls'
console.log('x11111111',data,fileName,header)
const filePath = await simpleExcelDown({ data: data, header, fileName: fileName, needIndexCell: false })
const fileData = fs.readFileSync(filePath)
ctx.status = 200
ctx.set('Content-Type', 'application/x-xls')
ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName))
ctx.body = fileData
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function exportFile(ctx) {
try {
const { data, columns } = ctx.query
await exportMaterialEnterList(ctx, data, columns)
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
module.exports = {
getStructures, getFactors, getSensors, getMonitorData
getStructures, getFactors, getSensors, getMonitorData, exportFile
}

6
web/client/src/sections/data/containers/dataDetail.jsx

@ -260,8 +260,12 @@ const DataDetail = (props) => {
</TabPane>
<TabPane tab={<span><IconBookOpenStroked />数据</span>} itemKey="2">
<Divider></Divider>
<DataTableComponent sensorId={sensorId&&sensorId.length>0?sensorId.map(item=>`${project}-${item}`).join(','):[-11]}
factorId={factorId?factorId:-1}
startTime={moment(dateRange[0]).format('YYYY-MM-DD HH:mm:ss')}
endTime={moment(dateRange[1]).format('YYYY-MM-DD HH:mm:ss')}
<DataTableComponent dataList={checkData}/>
dataList={checkData}/>
</TabPane>
</Tabs>
</Col>

34
web/client/src/sections/data/containers/dataTableComponent.jsx

@ -1,7 +1,4 @@
/*
* @Author: zhaobing
* @Date: 2023-11-02 09:32:25
*/
import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { Table, Button, Alert, Spin } from '@douyinfe/semi-ui';
@ -10,14 +7,21 @@ import FileSaver from 'file-saver';
import moment from 'moment';
const DataTableComponent = (props) => {
const {dataList}=props
const {dataList,dispatch,actions,user, sensorId,endTime,startTime,factorId}=props
const [currentPage, setCurrentPage] = useState(1);
const [exportingFlag, setExportingFlag] = useState(false);
const [isRequesting, setIsRequesting] = useState(false);
const [arr,setArr]=useState(dataList.items)
const [data,setData]=useState([])
const [exportUrl, setExportUrl] = useState('')
// const [list,setList]=useState(dataList.sensors)
const [columns,setColumns]=useState([])
// useEffect(() => {
// if (exportUrl) {
// <iframe src={`/_api/${exportUrl}`} style={{ display: 'none' }} />
// setIsRequesting(false)
// }
// }, [exportUrl])
//
useEffect(()=>{
setArr(dataList.items)
@ -90,8 +94,13 @@ const DataTableComponent = (props) => {
const exporting = () => {
setIsRequesting(true);
};
setIsRequesting(true)
let url=`structure/factors/sensors/data?token=${user.token}&sensorId=${sensorId}&timestamp=${moment().valueOf()}&toExport=1&factorId=${factorId}&startTime=${startTime}&endTime=${endTime}`
setExportUrl(url)
// await dispatch(actions.data.exportFile(data, columns))
setIsRequesting(false)
}
const pageChange = (page, pageSize) => {
setCurrentPage(page);
@ -118,14 +127,17 @@ const DataTableComponent = (props) => {
<div>
<Spin spinning={isRequesting}>
<div>
{/* <p style={{ textAlign: 'right', margin: 8 }}>
<p style={{ textAlign: 'right', margin: 8 }}>
{
data.length ? <Button type="ghost" onClick={exporting}>导出</Button> : null
data.length ? <Button type="tertiary" onClick={exporting}>导出</Button> : null
}
</p> */}
</p>
<Table dataSource={data} columns={columns} />
</div>
</Spin>
{
exportUrl ? <iframe src={`/_api/${exportUrl}`} style={{ display: 'none' }} /> : ''
}
</div>
);
};
@ -137,7 +149,7 @@ const mapStateToProps = (state) => {
actions: global.actions,
dataContinuityType: dataContinuityType.data || [],
dataContinuity: dataContinuity.data || [],
pepProjectId:global.pepProjectId
pepProjectId:global.pepProjectId,
};
};

5
web/client/src/sections/problem/components/tableData.jsx

@ -19,6 +19,7 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
const groupId = useRef()
let title = { dataLnterrupt: "数据中断详情", dataAbnormal: "数据异常详情", strategyHit: "策略命中详情", videoAbnormal: "视频异常详情", useAbnormal: "应用异常详情", deviceAbnormal: "设备异常详情" }
const [exportUrl, setExportUrl] = useState('')
useEffect(() => {
switch (route) {
case 'useAbnormal':
@ -472,9 +473,7 @@ const TableData = ({ route, dispatch, actions, collectData, setSetup, exhibition
</div> : ""}
</div>
{
exportUrl ? <iframe src={`/_api/${exportUrl}`} style={{ display: 'none' }} /> : ''
}
</div>
</>
)

Loading…
Cancel
Save