Browse Source

冲突修改

dev
wenlele 1 year ago
parent
commit
17abdd81f9
  1. 233
      api/app/lib/controllers/analysis/network.js
  2. 11
      api/app/lib/routes/analysis/network.js
  3. 6
      api/app/lib/schedule/workOrder.js
  4. 15
      api/config.js
  5. 2
      web/client/src/layout/containers/layout/index.jsx
  6. 57
      web/client/src/sections/analysis/actions/network.js
  7. 582
      web/client/src/sections/analysis/components/export-data.jsx
  8. 3
      web/client/src/sections/analysis/containers/network.jsx
  9. 330
      web/client/src/sections/analysis/containers/tableShow.jsx
  10. 2
      web/client/src/sections/install/containers/system.jsx
  11. 7
      web/client/src/sections/problem/components/tableData.jsx
  12. 9
      web/client/src/sections/projectGroup/containers/bigscreen.jsx
  13. 7
      web/client/src/utils/webapi.js
  14. 3
      web/package.json

233
api/app/lib/controllers/analysis/network.js

@ -1,5 +1,8 @@
'use strict';
const moment = require('moment')
const RAW_DATA = 'rawData';
const VBRAW_DATA = 'vbRawData';
const ALARM = 'alarm';
async function getOrganizationsStruc(ctx) {
@ -102,9 +105,239 @@ async function iotaLinkStatus (ctx, next) {
async function findDeviceMetaDeployed(ctx, next) {
let rslt = null;
const { iotaThingId } = ctx.params;
try {
let iotaResponse = await ctx.app.fs.iotRequest.get(`meta/things/${iotaThingId}/devices`)
rslt = JSON.parse(iotaResponse)
ctx.status = 200;
ctx.body = rslt;
} catch (err) {
ctx.status = 400;
ctx.body = {
"name": "FindError",
"message": "设备部署原型获取失败"
}
}
};
async function findDeviceLastData(ctx, deviceIds) {
let rslt = [];
const clientRaws = ctx.app.fs.esclient[RAW_DATA];
const clientVbraws = ctx.app.fs.esclient[VBRAW_DATA];
if (deviceIds) {
for (let id of deviceIds) {
let params = {
index: clientRaws.config.index,
type: clientRaws.config.type,
body: {
query: {
constant_score: {
filter: {
bool: {
must: [
{ term: { "iota_device": id } },
{ range: { "collect_time": { lte: moment().toISOString() } } }
]
}
}
}
},
sort: [
{
"collect_time": {
order: "desc"
}
}
],
size: 1
}
};
let res = await clientRaws.search(params);
if (res.hits.hits.length == 0) {
params.index = clientVbraws.config.index;
params.type = clientVbraws.config.type;
res = await clientVbraws.search(params);
}
let data = res.hits.hits.map(h => {
let source = h._source;
let data_ = source.data;
if (params.index == clientVbraws.config.index) {
let tempData = { "最大幅值": '_' };
if (data_.raw && data_.raw.length) {
let maxAmplitude = data_.raw[0];
for (let v of data_.raw) {
if (maxAmplitude < v) {
maxAmplitude = v;
}
}
tempData['最大幅值'] = maxAmplitude + '(gal)';
}
data_ = tempData;
}
return {
collectTime: source.collect_time,
iotaDevice: source.iota_device,
iotaDeviceName: source.iota_device_name,
data: data_
}
});
rslt.push({
sensorId: id,
data: data
});
}
}
return rslt;
}
async function findSensorLastData(ctx) {
try {
const sensorIds = ctx.request.body.sensorIds;
let rslt = await findDeviceLastData(ctx, sensorIds);
// let rslt = [{ sensorId: "2aa1cad1-a52d-4132-8d84-2475034d5bc8", data: [] },
// { sensorId: "9f1702ff-560d-484e-8572-ef188ef73916", data: [] },
// {
// sensorId: "360d9098-f2a5-4e1a-ab2b-0bcd3ddcef87", data: [{
// collectTime: "2021-07-12T05:30:44.000Z", data: { readingNumber: 228 },
// iotaDevice: "360d9098-f2a5-4e1a-ab2b-0bcd3ddcef87", iotaDeviceName: "水表"
// }]
// },
// { sensorId: "8c3a636b-9b62-4486-bf54-4ac835aee094", data: [] },
// {
// sensorId: "9ea4d6cd-f0dc-4604-bb85-112f2591d644", data: [{
// collectTime: "2021-07-17T05:53:35.783Z", data: { DI4: 0, DI7: 0, DI5: 0, DI1: 1, DI6: 0, DI2: 1, DI8: 0, DI3: 1 },
// iotaDevice: "9ea4d6cd-f0dc-4604-bb85-112f2591d644", iotaDeviceName: "控制器"
// }]
// },
// { sensorId: "e18060b4-3c7f-4fad-8a1a-202b5c0bf00c", data: [] }
// ]
ctx.status = 200;
ctx.body = rslt;
} catch (error) {
ctx.status = 400;
ctx.body = {
"name": "FindError",
"message": "原始数据查询失败"
}
}
}
async function findAlarmsDevices(ctx, next) {
let rslt = []
const deviceIds = ctx.request.body
const { limit, state } = ctx.query
try {
if (deviceIds.length) {
for (let deviceId of deviceIds) {
// es search
const client = ctx.app.fs.esclient[ALARM];//准备查询
let params = {
index: client.config.index,
type: client.config.type,
size: limit || 9999,
body: {
"query": {
"bool": {
"must": [
{
"match": {
"source_id": deviceId
}
},
{
"terms": {
"state": []
}
}
]
}
},
"sort": [
{
"start_time": {
"order": "desc"
}
}
]
}
}
if (state == 'new') {
let newState = [AlarmState.Creation, AlarmState.CountUpgrade, AlarmState.LevelUpgrade];
params.body.query.bool.must[1].terms.state = newState;
}
let alarms = await client.search(params);
const timer = ctx.app.fs.timer;
function filterAlarmMsg(oriMsg) {
let msg = [];
for (let s of oriMsg) {
msg.push({
alarmContent: s._source.alarm_content,
alarmCount: s._source.alarm_count,
deviceId: s._source.source_id,
startTime: timer.toCSTString(s._source.start_time),
endTime: timer.toCSTString(s._source.end_time),
})
}
return msg;
}
rslt = rslt.concat(filterAlarmMsg(alarms.hits.hits));
}
}
ctx.status = 200;
ctx.body = rslt;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: '告警信息查询失败'
}
}
}
async function findDevicesCardStatus(ctx, next) {
try {
let rlst = []
const { clickHouse } = ctx.app.fs
const { deviceIds } = ctx.request.body
if (deviceIds && deviceIds.length) {
const id = `(${deviceIds.map(id => `'${id}'`).join(',')})`
rlst = await clickHouse.dataAlarm.query(`
SELECT cs.DeviceId,cs.Status,MAX(cs.Time)
FROM alarm.CardStatus cs
WHERE cs.DeviceId in ${id}
GROUP BY cs.DeviceId,cs.Status`).toPromise()
}
ctx.status = 200;
ctx.body = rlst;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: '物联网卡状态查询失败'
}
}
}
module.exports = {
getOrganizationsStruc,
getThingsDeploy,
getDeviceMetaDeployed,
iotaLinkStatus,
findSensorLastData,
findDeviceMetaDeployed,
findAlarmsDevices,
findDevicesCardStatus
}

11
api/app/lib/routes/analysis/network.js

@ -14,6 +14,17 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['GET/metrics/things/:iotaThingId/devices/link_status'] = { content: '获取设备在线状态/以结构物id集体获取', visible: true };
router.get('/metrics/things/:iotaThingId/devices/link_status', network.iotaLinkStatus)
app.fs.api.logAttr['GET/meta/things/:iotaThingId/devices'] = { content: '原始数据查询失败', visible: false };
router.get('/meta/things/:iotaThingId/devices', network.findDeviceMetaDeployed)
app.fs.api.logAttr['POST/sensors/last/data'] = { content: '原始数据查询失败', visible: true };
router.post('/sensors/last/data', network.findSensorLastData)
app.fs.api.logAttr['POST/devices/alarms'] = { content: '获取多个设备的告警信息', visible: false };
router.post('/devices/alarms', network.findAlarmsDevices)
app.fs.api.logAttr['POST/devices/cardStatus'] = { content: '获取物联网卡状态', visible: false };
router.post('/devices/cardStatus', network.findDevicesCardStatus);
// app.fs.api.logAttr['GET/systemAvailability'] = { content: '获取系统可用性', visible: true };
// router.get('/systemAvailability', operationData.getSystemAvailability)

6
api/app/lib/schedule/workOrder.js

@ -3,7 +3,7 @@ const schedule = require('node-schedule');
const moment = require('moment')
const request = require('superagent');
let isDev = true
let isDev = false
module.exports = function (app, opts,ctx) {
const workOrder = app.fs.scheduleInit(
@ -15,7 +15,7 @@ module.exports = function (app, opts,ctx) {
async()=>{
try{
//前一次执行时间
console.log('工单数据抽取开始')
console.log('工单数据抽取开始',moment().format('YYYY-MM-DD HH:mm:ss'))
const username = "admin"
const password = "fs-workflow"
let lastExecutionTime = null;
@ -77,7 +77,7 @@ module.exports = function (app, opts,ctx) {
formData: JSON.parse(f.formData)
})
const res=await models.FormDataTable.create({
projectId:parseData.pomsProjectId.value || null,
projectId:parseData?parseData.pomsProjectId.value : null,
formname:procinstsVariables.body.find(t => t.name == 'fsEmisBusinessName') ? procinstsVariables.body.find(t => t.name == 'fsEmisBusinessName').value : '',
state: f.state||null,
endTime:f.endTime||null,

15
api/config.js

@ -360,6 +360,21 @@ const product = {
rootURL: ANXINCLOUD_ES_NODES_REST.split(','),
index: `${ES_CONTINUITY_NAME}_continue`,
type: flags.esType ? flags.esType : '_doc'
},
rawData: {
rootURL: ANXINCLOUD_ES_NODES_REST.split(','),
index: `${PLATFORM_NAME}_raws`,
type: flags.esType ? flags.esType : '_doc'
},
vbRawData: {
rootURL: ANXINCLOUD_ES_NODES_REST.split(','),
index: `${PLATFORM_NAME}_vbraws`,
type: flags.esType ? flags.esType : '_doc'
},
alarm: {
rootURL: ANXINCLOUD_ES_NODES_REST.split(','),
index: `${PLATFORM_NAME}_alarms`,
type: flags.esType ? flags.esType : '_doc'
},
}
}

2
web/client/src/layout/containers/layout/index.jsx

@ -114,7 +114,7 @@ const LayoutContainer = props => {
}
setAllItems(nextItems)
setHeaderItems(topItems)
console.log('topItems',topItems)
// console.log('topItems',topItems)
if (lastSelectedKeys) {//
for (let i = 0; i < nextItems.length; i++) {
if (JSON.parse(lastSelectedKeys)[0] == nextItems[i].itemKey) {

57
web/client/src/sections/analysis/actions/network.js

@ -49,6 +49,63 @@ export function getIotaThingsLlinkStatus (id) {
reducer: { name: '' }
})
}
export function findDeviceMetaDeployed (id) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'FIND_DEVICE_META_DEPLOYED',
url: `${ApiTable.findDeviceMetaDeployed.replace('{iotaThingId}', id)}`,
msg: { error: '获取单个结构物的设备信息失败' },
reducer: { name: 'deviceMetaDeployed',params: { noClear: true } },
})
}
export function findSensorLastData (data) {
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'FIND_SENSOR_LAST_DATA',
url: `${ApiTable.findSensorLastData}`,
msg: { error: '原始数据查询失败' },
reducer: { name: 'sensorLastData' }
})
}
export function getDevicesAlarms(deviceIds,query) {
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
data: deviceIds,
query: query,
actionType: 'REQUEST_POST_DEVICES_ALARMS',
url: `${ApiTable.getDevicesAlarms}?state=new`,
msg: {
error: '获取设备告警信息失败'
},
reducer: {
name: 'deviceListAlarms'
}
});
}
export function findDevicesCardStatus(deviceIds) {
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
data: deviceIds,
actionType: 'FIND_DEVICES_CARD_STATUS',
url: `${ApiTable.findDevicesCardStatus}`,
msg: {
error: '获取物联网卡信息失败'
},
reducer: {
name: 'devicesCardStatus'
}
});
}
// export function getSystemAvailability() {

582
web/client/src/sections/analysis/components/export-data.jsx

@ -0,0 +1,582 @@
'use strict';
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Button, Notification } from "@douyinfe/semi-ui";
import moment from 'moment';
import XLSX from 'xlsx';
import { fromJS } from 'immutable';
import { Request } from '@peace/utils';
import FileSaver from 'file-saver';
import { IconArrowDown } from '@douyinfe/semi-icons';
// 使propTypes
const ExportData = ({...props}) => {
//const [form] = Form.useForm();
const [exportLoading, setExportLoading] = useState(false);
const { customRender, title, exportType, style, showIcon } = props;
const loop = (data, keypath, values) => { // deal with array
let dkey = keypath.slice(0, 1)[0];
if (dkey) {
let dvalue = data[dkey];
let otherKeypath = keypath.slice(1);
if (Array.isArray(dvalue)) {
if (otherKeypath.length) {
let immutableData = fromJS(data);
for (let index = 0; index < dvalue.length; index++) {
let tmp = immutableData.getIn([dkey, index]).toJS();
loop(tmp, otherKeypath, values);
}
}
} else {
values.push(dvalue);
}
}
return values;
};
const getColumnData = (opts) => {
const { data, keypath, render, spliter, rawdata, valueEnum } = opts;
let v = null;
let outer = data[keypath[0]];
if (Array.isArray(outer)) {
let values = loop(data, keypath, []);
v = rawdata ? values : values.join(spliter || ',');
} else {
v = fromJS(data).getIn(keypath)
}
//proTable
if(valueEnum && valueEnum[v]?.text){
v = valueEnum[v]?.text;
}
//render
// if (render && typeof render === 'function') {
// v = render(outer, data);
// }
return v;
};
const getDataSource = (attrs, filterData) => {
debugger
let dataSource = filterData.map(item => {
let record = {};
attrs.forEach(attr => {
const { key, dataIndex, render, child, valueEnum } = attr;
if (child) {
record[key] = getDataSource(child, item[key] || []);
} else {
let v = getColumnData({
data: item,
keypath: Array.isArray(dataIndex) ? dataIndex : [dataIndex],
render: render || null,
valueEnum: valueEnum
});
record[key] = v;
}
});
return record;
});
return dataSource;
};
const getNewColumns = (attrs) => {
return attrs.filter(f=> f.dataIndex).map(v=>{
const { dataIndex } = v;
return {
...v,
key: Array.isArray(dataIndex) ? dataIndex.reduce((p,c)=>{
p = `${p}${c.trim().replace(c[0], c[0].toUpperCase())}`;
return p
},'') : dataIndex
}
})
}
//
const getFlatData = (attrs, filterData, dataToAoa, deep = 0) => {
filterData.map(item => {
let cur = dataToAoa[deep]
if (!cur) {
cur = dataToAoa[deep] = []
}
attrs.map((attr, index) => {
const { key, child } = attr;
if (child) {
if (Array.isArray(item[key])) {
//getFlatData(child,item[key],dataToAoa,deep)
item[key].map((s, i) => {
if (i == 0) {
child.map(c => {
cur.push(s[c.key]);
})
} else {
deep++
let childCur = dataToAoa[deep] = []
pushNull(childCur, index);
child.map(c => {
childCur.push(s[c.key]);
});
}
})
}
} else {
cur.push(item[key]);
}
});
deep++
});
};
const getHeader = (headers, excelHeader, deep, perOffset) => {
let offset = 0
let cur = excelHeader[deep]
if (!cur) {
cur = excelHeader[deep] = []
}
pushNull(cur, perOffset - cur.length)
for (let i = 0; i < headers.length; i++) {
let head = headers[i]
cur.push(head.name)
if (head.hasOwnProperty('child') && Array.isArray(head.child) && head.child.length > 0) {
let childOffset = getHeader(head.child, excelHeader, deep + 1, cur.length - 1)
pushNull(cur, childOffset - 1)
offset += childOffset
} else {
offset++
}
}
return offset;
}
const pushNull = (arr, count) => {
for (let i = 0; i < count; i++) {
arr.push(null)
}
}
const fillNull = (arr) => {
let max = Math.max(...(arr.map(a => a.length)))
arr.filter(e => e.length < max).forEach(e => pushNull(e, max - e.length))
}
const doMerges = (arr) => {
//
let deep = arr.length;
let merges = [];
for (let y = 0; y < deep; y++) {
//
let row = arr[y];
let colSpan = 0
for (let x = 0; x < row.length; x++) {
if (row[x] === null) {
colSpan++
if (((x + 1) === row.length) && (colSpan > 0 && x > colSpan)) {
merges.push({ s: { r: y, c: x - colSpan }, e: { r: y, c: x } })
}
} else if (colSpan > 0 && x > colSpan) {
merges.push({ s: { r: y, c: x - colSpan - 1 }, e: { r: y, c: x - 1 } })
colSpan = 0
} else {
colSpan = 0
}
}
}
//
let colLength = arr[0].length
for (let x = 0; x < colLength; x++) {
let rowSpan = 0
for (let y = 0; y < deep; y++) {
if (arr[y][x] != null) {
rowSpan = 0
} else {
rowSpan++;
}
}
if (rowSpan > 0) {
merges.push({ s: { r: deep - rowSpan - 1, c: x }, e: { r: deep - 1, c: x } })
}
}
return merges;
}
//
const doContetMerges = (arr, headerLength) => {
let deep = arr.length;
let merges = [];
//
let colLength = arr[0].length
for (let x = 0; x < colLength; x++) {
let rowSpan = 0;
let mergY = 0;
for (let y = 0; y < deep; y++) {
if (rowSpan > 0) {
//null
if (arr[y][x] === null) {
rowSpan = rowSpan + 1
} else {
//null merge
merges.push({ s: { r: headerLength + (y - rowSpan - 1), c: x }, e: { r: headerLength + y - 1, c: x } });
rowSpan = 0;
}
} else {
if (arr[y][x] === null) {
rowSpan = rowSpan + 1
}
}
}
if (rowSpan > 0) {
merges.push({ s: { r: headerLength + (deep - rowSpan - 1), c: x }, e: { r: headerLength + deep - 1, c: x } })
rowSpan = 0;
}
}
return merges;
}
// 使
const exportMergeExcel = async () => {
setExportLoading(true)
const { columns, data, fileName, exportUrl, exportQuery, exportBody, requestType, header, showYearMouth } = props || {};
let resultData = [];
if (exportUrl) {
resultData = requestType == 'post' ? await Request.post(exportUrl, exportBody || {}, exportQuery || {}).then(data => {
// rows
if (typeof data === 'object' && data.rows) {
return data.rows
} else {
return data;
}
}, err => {
Notification.error({
content: '获取数据失败,导出失败!',
duration: 3,
})
}) : await Request.get(exportUrl, exportQuery || {}).then(data => {
if (typeof data === 'object' && data.rows) {
return data.rows
} else {
return data;
}
}, err => {
Notification.error({
content: '获取数据失败,导出失败!',
duration: 3,
})
});
if (!resultData) {
return;
}
} else {
resultData = data
}
let excelHeader = [];
const newColumns = getNewColumns(columns);
getHeader(newColumns, excelHeader, 0, 0);
fillNull(excelHeader);
//console.log(excelHeader);
let loopData = getDataSource(newColumns, resultData);
//console.log(loopData)
let dataToAoa = [];
getFlatData(newColumns, loopData, dataToAoa, 0);
fillNull(dataToAoa);
//console.log(dataToAoa);
let aoa = [].concat(excelHeader, dataToAoa);
//console.log(aoa)
let headerMerges = doMerges(excelHeader);
let contentMerages = doContetMerges(dataToAoa, excelHeader.length);
let merges = [].concat(headerMerges, contentMerages);
// console.log(contentMerages)
// let opts = {
// defaultCellStyle: {
// font: { name: "", sz: 11, color: { auto: 1 } },
// border: {
// color: { auto: 1 }
// },
// alignment: {
// ///
// wrapText: 1,
// //
// horizontal: "center",
// vertical: "center",
// indent: 0
// }
// }
// }
let sheet = XLSX.utils.aoa_to_sheet(aoa);
// let newSheet = {};
// for (let [key, value] of Object.entries(sheet)) {
// if(key == '!ref'){
// newSheet[key] = value
// }else if(typeof value === 'object'){
// newSheet[key] = {
// ...value,
// s: opts.defaultCellStyle
// }
// }
// }
const wpx = columns.map(c => {
return {
wpx: Number.parseInt(c.wpx) ? Number.parseInt(c.wpx) : 100
}
})
sheet['!cols'] = wpx;
sheet['!merges'] = merges;
// workbook
const workbook = XLSX.utils.book_new();
const time = moment().format('YYYY-MM-DD');
XLSX.utils.book_append_sheet(workbook, sheet, 'mySheet');
// Excel
XLSX.writeFile(workbook, fileName ? `${fileName}-${time}.xlsx` : `导出数据-${time}.xlsx`);
setExportLoading(false);
Notification.success({
content: `成功导出了 ${loopData.length || 0} 条数据`,
duration: 3,
})
}
//FileSaver columns headStyle, rowStyle
const exportFileSaver = async () => {
setExportLoading(true)
const { columns, data, fileName, exportUrl, exportQuery, exportBody, requestType } = props || {};
let resultData = [];
if (exportUrl) {
resultData = requestType == 'post' ? await Request.post(exportUrl, exportBody || {}, exportQuery || {}).then(data => {
// rows
if (typeof data === 'object') {
return data.data ? data.data : data.rows
} else {
return data;
}
}, err => {
Notification.error({
content: '获取数据失败,导出失败!',
duration: 3,
})
}) : await Request.get(exportUrl, exportQuery || {}).then(data => {
if (typeof data === 'object' && data.rows) {
return data.rows
} else {
return data;
}
}, err => {
Notification.error({
content: '获取数据失败,导出失败!',
duration: 3,
})
});
if (!resultData) {
return;
}
} else {
resultData = data
}
const newColumns = getNewColumns(columns);
const loopData = getDataSource(newColumns, resultData);
let content = '';
let header = '<tr>';
//header += `<th><div></div></th>`;
newColumns.map(colum => {
header += `<th style="${colum.headStyle || ''}"><div>${colum.title}</div></th>`
});
header += '</tr>';
loopData.map(data => {
content += `<tr>`;
newColumns.map(c => {
if (c.style) {
content += `<th style="${c.rowStyle || ''}"><div>${data[c.key] || ''}</div></th>`
} else {
content += `<th><div>${data[c.key] || ''}</div></th>`
}
});
content += `</tr>`;
})
let exportTable = `\uFEFF
<table style='text-alagin:center' border="1">
${header}
${content}
</table>
`;
const time = moment().format('YYYY-MM-DD');
let tempStrs = new Blob([exportTable], { type: 'text/xls' })
FileSaver.saveAs(tempStrs, fileName ? `${fileName}-${time}.xls` : `导出数据-${time}.xlsx`);
setExportLoading(false);
Notification.success({
content: `成功导出了 ${loopData.length || 0} 条数据`,
duration: 3,
})
}
//XLSX
const exportExcel = async () => {
setExportLoading(true)
const { columns, data, fileName, exportUrl, exportQuery, exportBody, requestType } = props || {};
const newColumns = getNewColumns(columns);
const _headers = newColumns
.map((item, i) => Object.assign({}, { key: item.key, title: item.title, position: String.fromCharCode(65 + i) + 1 }))
.reduce((prev, next) => Object.assign({}, prev, { [next.position]: { key: next.key, v: next.title } }), {});
let resultData = [];
if (exportUrl) {
resultData = requestType == 'post' ? await Request.post(exportUrl, exportBody || {}, exportQuery || {}).then(data => {
// rows
if (typeof data === 'object' && (data.rows || data.data)) {
return data.data ? data.data : data.rows
} else {
return data;
}
}, err => {
Notification.error({
content: '获取数据失败,导出失败!',
duration: 3,
})
}) : await Request.get(exportUrl, exportQuery || {}).then(data => {
if (typeof data === 'object' && data.rows) {
return data.rows
} else {
return data;
}
}, err => {
Notification.error({
content: '获取数据失败,导出失败!',
duration: 3,
})
});
if (!resultData) {
return;
}
} else {
resultData = data
}
const loopData = getDataSource(newColumns, resultData);
const wpx = newColumns.map(c => {
return {
wpx: Number.parseInt(c.wpx) ? Number.parseInt(c.wpx) : 100
}
})
if (!(loopData.length > 0)) {
setExportLoading(false);
return;
}
const _data = loopData
.map((item, i) => newColumns.map((key, j) => Object.assign({}, { content: item[key.key], position: String.fromCharCode(65 + j) + (i + 2) })))
//
.reduce((prev, next) => prev.concat(next))
// worksheet
.reduce((prev, next) => Object.assign({}, prev, { [next.position]: { v: next.content } }), {});
// columns data
const output = Object.assign({}, _headers, _data);
//
const outputPos = Object.keys(output);
// ,["A1",..., "H2"]
const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`;
// workbook
const workbook = {
SheetNames: ['mySheet'],
Sheets: {
mySheet: Object.assign(
{},
output,
{
'!ref': ref,
'!cols': wpx,
},
),
},
};
const time = moment().format('YYYY-MM-DD');
// Excel
XLSX.writeFile(workbook, fileName ? `${fileName}-${time}.xlsx` : `导出数据-${time}.xlsx`);
setExportLoading(false);
Notification.success({
content: `成功导出了 ${loopData.length || 0} 条数据`,
duration: 3,
})
}
const handleExport = async () => {
switch (exportType) {
case 'fileSaver':
await exportFileSaver();
break;
case 'xlsx':
await exportExcel();
break;
case 'merge':
await exportMergeExcel();
break;
default:
await exportExcel();
break;
}
}
return (
customRender ?
<span style={style} loading={exportLoading} onClick={handleExport}>
{customRender}
</span> :
<Button style={style} loading={exportLoading} onClick={handleExport}>
{title || '导出'}
{showIcon && <IconArrowDown />}
</Button>
)
}
ExportData.propTypes = {
fileName: PropTypes.string, //
showIcon: PropTypes.bool, //icon
customRender: PropTypes.element, //
style: PropTypes.object,//style
title: PropTypes.string, //
columns: PropTypes.array.isRequired, //header antd columns tableprotablecolumns使 columnswpxexecl 100
data: PropTypes.array.isRequired, // antd table exportUrl
exportUrl: PropTypes.string, //url 1columns 2rows
exportBody: PropTypes.object, //body
exportQuery: PropTypes.object, //url
requestType: PropTypes.string, // getpostget
exportType: PropTypes.string, // 'fileSaver','xlsx','merge'
};
export default ExportData;

3
web/client/src/sections/analysis/containers/network.jsx

@ -154,7 +154,8 @@ const Network = ({
}
>
{show == 'tree' && <TreeShow thingId={thingId} />}
{show == 'table' && <TableShow thingId={thingId} />}
{show == 'table' && <TableShow thingId={thingId} project={projectValue} />
}
</Card>
</div>

330
web/client/src/sections/analysis/containers/tableShow.jsx

@ -1,66 +1,340 @@
import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'react-redux';
import ReactECharts from 'echarts-for-react';
import echarts from 'echarts';
import { Spin, Card, CardGroup, Form, Button,Table } from '@douyinfe/semi-ui';
import React, { useEffect, useState, useRef, useMemo } from 'react'
import { connect } from 'react-redux'
import { Spin, Card, CardGroup, Form, Button, Table, Pagination, Tooltip } from '@douyinfe/semi-ui'
import ExportData from '../components/export-data'
import moment from 'moment'
const Network = props => {
const { dispatch, actions, user, clientHeight, thingId, deviceListAlarms, devicesCardStatusList, project } = props
const { analysis } = actions
const form = useRef() //
const [deployData, setDeployData] = useState([])
const [deviceData, setDeviceData] = useState([])
const [deviceMetasDeployed, setDeviceMetasDeployed] = useState([])
const [sensorId, setSensorId] = useState([])
const [sensorsDataItems, setSensorsDataItems] = useState({})
const [tableData, setTableData] = useState([]) //
const [lastData, setLastData] = useState([]) //
const [lastDataCopy, setLastDataCopy] = useState([]) //
const [searchType, setSearchType] = useState('')
const [searchName, setSearchName] = useState('')
const [typeList, setTypeList] = useState([])
const [query, setQuery] = useState({ limit: 10, page: 0 }) //
const DeviceTypes = {
'DTU': 'DTU',
'gateway': '网关',
'sensor': '传感器',
'acqUnit': '采集单元',
'dau.gateway': '分布式智能云采集网关',
'dau.node': '分布式智能云采集节点',
'tcp.dtu': '工作站',
}
const Network = (props) => {
const { dispatch, actions, user, clientHeight } = props
useEffect(() => {
setLastData([])
setLastDataCopy([])
}, [project])
const form = useRef();//
useEffect(() => {
if (thingId) {
let dataList = []
dispatch(analysis.getThingsDeploy(thingId)).then(rs => {
if (rs.success) {
setDeployData(rs.payload.data)
dataList = rs.payload.data
//
let da = []
if (dataList.instances) {
Object.keys(dataList.instances).forEach(i => {
if (dataList.instances[i].type == 's.d') {
da.push({
sensorId: i,
sensorName: dataList.instances[i]?.name,
deviceType: dataList?.instances[i]?.instance?.properties?.deviceType,
collectTime: '--',
data: '--',
iotCardStatus: '--',
status: '--',
option: '--',
})
}
})
}
dispatch(analysis.findDeviceMetaDeployed(thingId)).then(res => {
if (res.success) {
setDeviceMetasDeployed(res.payload.data)
const deviceMetaDeployed = res.payload.data
if (deviceMetaDeployed && dataList && deviceMetaDeployed.devices) {
const sensorsId = []
let alarmSensorId = [] //id
const sensorsDataItems = {}
for (const id in dataList.instances) {
alarmSensorId.push(id)
const instances = dataList.instances[id]
useEffect(() => {
if (instances.type == 's.d' && instances.instance.properties.deviceType == 'sensor') {
const meta = deviceMetaDeployed.devices.find(m => m.id == instances.instance.deviceMetaId)
sensorsDataItems[id] = {
items: {},
deviceName: instances.name,
}
if (meta) {
sensorsDataItems[id].items = meta.capabilities[0].properties.reduce((p, n) => {
if (n.category == 'Output') {
p[n.name] = { name: n.showName, unit: n.unit }
}
return p
}, {})
}
sensorsId.push(id)
}
}
dispatch(analysis.getDevicesAlarms({ deviceIds: alarmSensorId }, { limit: 5 }))
dispatch(analysis.findDevicesCardStatus({ deviceIds: alarmSensorId }))
setSensorsDataItems(sensorsDataItems)
setSensorId(sensorsId)
setDeviceData(da)
}
}
})
}
})
}
}, [thingId])
useEffect(async () => {
if (sensorId && sensorId.length && sensorsDataItems) {
const rs = await dispatch(analysis.findSensorLastData(sensorId))
const tableData = []
if (rs.success) {
rs.payload.data.forEach(sd => {
if (Object.keys(sensorsDataItems).length) {
let sensorDataItem = sensorsDataItems[sd.sensorId]
let sensorName = sensorDataItem && sensorDataItem.deviceName ? sensorDataItem.deviceName : ''
let msg = sd.data.length
? sd.data[0]
: {
collectTime: null,
sensorName: sensorName,
data: { noData: '暂无数据' },
}
let dataStr = ''
let dataKeys = Object.keys(msg.data)
dataKeys.forEach(k => {
let item = sensorDataItem && sensorDataItem.items ? sensorDataItem.items[k] : null
if (item) {
dataStr += `${item.name}${msg.data[k]}${item.unit}); `
} else if (k == 'noData') {
dataStr += msg.data[k]
} else {
dataStr += `${k}${msg.data[k]}`
}
})
let collectTime = msg.collectTime ? moment(msg.collectTime).format('YYYY-MM-DD HH:mm:ss') : '--'
tableData.push({
sensorId: sd.sensorId,
sensorName: sensorName,
collectTime: collectTime,
data: dataStr,
deviceType: 'sensor', //
iotCardStatus: '--',
status: '--',
option: '--',
})
}
})
}
setTableData(tableData)
}
}, [sensorId])
useEffect(() => {
if (deviceData && deviceData.length && tableData && tableData.length) {
const dataD = deviceData?.map(p => {
const objRslt = tableData.find(q => q.sensorId == p.sensorId)
return {
sensorId: objRslt ? objRslt.sensorId : p.sensorId,
sensorName: objRslt ? objRslt.sensorName : p.sensorName,
collectTime: objRslt ? objRslt.collectTime : p.collectTime,
data: objRslt ? objRslt.data : p.data,
deviceType: DeviceTypes[objRslt ? objRslt.deviceType : p.deviceType],
iotCardStatus:
devicesCardStatusList && devicesCardStatusList.length
? devicesCardStatusList.find(v => v.deviceId == p.sensorId).status === 0
? '正常'
: devicesCardStatusList.find(v => v.deviceId == p.sensorId).status === 1
? '未激活'
: '停机'
: '--',
status:
deviceListAlarms && deviceListAlarms.length
? deviceListAlarms?.find(v => v.deviceId == p.sensorId)
? '异常'
: '正常'
: '正常',
option: objRslt ? objRslt.option : p.option,
}
})
const typeList = dataD.reduce((p, c) => {
let isExist = p.some(q => q.label === c.deviceType)
if (!isExist) {
p.push({ label: c.deviceType, value: c.sensorId })
}
return p
}, [])
setTypeList(typeList)
setLastData(dataD)
setLastDataCopy(dataD)
}
}, [deviceData, tableData])
// const lastDataCopy=useMemo(()=>{
// return lastData
// },[thingId])
// const scroll = useMemo(() => ({ y: 400 }), [])
//
const inputChange = e => {
setSearchName(e)
}
//
const selectChange = e => {
setSearchType(typeList.find(f => f.value == e)?.label)
}
//
const searchHandler = () => {
setLastData(
searchName || searchType
? lastDataCopy.filter(f => f.sensorName.includes(searchName) && f.deviceType.includes(searchType))
: lastDataCopy
)
}
const columns = [
{
title: '设备名称',
dataIndex: 'deviceName',
dataIndex: 'sensorName',
width: 200,
key:'deviceName'
key: 'sensorName',
render: (_, r) => {
return (
<>
<Tooltip content={r.sensorName}>
<div>{r.sensorName.length > 7 ? `${r.sensorName.substr(0, 7)}...` : r.sensorName}</div>
</Tooltip>
</>
)
},
},
{
title: '设备类型',
dataIndex: 'deviceType',
width: 200,
key:'deviceType'
key: 'deviceType',
},
{
title: '最后采集时间',
dataIndex: 'collectTime',
width: 200,
key:'collectTime'
key: 'collectTime',
},
{
title: '更新日期',
dataIndex: 'updateTime',
sorter: (a, b) => (a.updateTime - b.updateTime > 0 ? 1 : -1),
render: value => {
return dateFns.format(new Date(value), 'yyyy-MM-dd');
title: '数据',
dataIndex: 'data',
width: 200,
key: 'data',
render: (_, r) => {
return (
<>
<Tooltip content={r.data}>
<div>{r.data.length > 6 ? `${r.data.substr(0, 6)}...` : r.data}</div>
</Tooltip>
</>
)
},
},
];
{
title: '物联网卡状态',
width: 200,
dataIndex: 'iotCardStatus',
key: 'iotCardStatus',
},
{
title: '状态',
width: 200,
dataIndex: 'status',
key: 'status',
},
{
title: '操作',
width: 200,
dataIndex: 'option',
key: 'option',
},
]
return (
<>
<div style={{ marginBottom: 12, display: 'flex' }}>
<div>
<Form>
<Form.Input
// suffix={<IconSearch />}
field='name'
pure
showClear
label='名称'
style={{ width: 260, marginRight: 12 }}
placeholder='请输入设备名称'
onChange={inputChange}
/>
<Form.Select
optionList={typeList}
field='type'
pure
showClear
label='设备类型'
onChange={selectChange}
style={{ width: 260, marginLeft: 12, marginRight: 12 }}
placeholder='请选择设备类型'
/>
<Button theme='solid' type='primary' htmlType='submit' onClick={searchHandler}>
查询
</Button>
</Form>
</div>
<div style={{ marginLeft: 10 }}>
{' '}
{lastData.length ? (
<ExportData
// showIcon
fileName='设备列表'
exportType='fileSaver'
data={lastData}
columns={columns}
key='export'
/>
) : (
''
)}
</div>
</div>
<Table
// scroll={scroll}
columns={columns}
dataSource={dataSource}
></Table>
dataSource={lastData}></Table>
</>
)
}
function mapStateToProps(state) {
const { auth, global, members, webSocket } = state;
const { auth, global, members, webSocket, deviceListAlarms, devicesCardStatus } = state
return {
user: auth.user,
actions: global.actions,
clientHeight: global.clientHeight
};
clientHeight: global.clientHeight,
deviceListAlarms: deviceListAlarms?.data || [],
devicesCardStatusList: devicesCardStatus?.data || [],
}
}
export default connect(mapStateToProps)(Network);
export default connect(mapStateToProps)(Network)

2
web/client/src/sections/install/containers/system.jsx

@ -196,7 +196,7 @@ const Example = (props) => {
// )
row.anxinProject.length >= 2 ? (
<Tooltip content={item.name}>
<div style={{ width: item.name.length > 7 ? '112px' : '', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', display: index > 2 ? 'none' : '', color: item.projectState == -1 ? '#F93920' : '' }}>
<div style={{ width: item.name.length > 4 ? '70px' : '', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', display: index > 2 ? 'none' : '', color: item.projectState == -1 ? '#F93920' : '' }}>
{item.name}
</div>
</Tooltip>):(

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

@ -19,7 +19,6 @@ const TableData = ({alarmDataGroup, route, dispatch, actions, collectData, setSe
const groupId = useRef()
let title = { dataLnterrupt: "数据中断详情", dataAbnormal: "数据异常详情", strategyHit: "策略命中详情", videoAbnormal: "视频异常详情", useAbnormal: "应用异常详情", deviceAbnormal: "设备异常详情" }
const [exportUrl, setExportUrl] = useState('')
useEffect(() => {
switch (route) {
case 'useAbnormal':
@ -27,6 +26,7 @@ const TableData = ({alarmDataGroup, route, dispatch, actions, collectData, setSe
if (res.success) {
let typeData = { element: "元素异常", apiError: "接口报错 ", timeout: "加载超时" }
let tableDatas = res.payload.data?.rows.map(v => ({
key: v.id,
id: v.id,
projectName: v.app?.projectCorrelations?.map(r => (r.name ? { id: r.id, name: r.name, state: 'PMOS' } : {
id: r.id, name: r.pepProject?.projectName, state: r.pepProject?.constructionStatus
@ -52,6 +52,7 @@ const TableData = ({alarmDataGroup, route, dispatch, actions, collectData, setSe
dispatch(problem.getAlarmVideoList({ ...search.current, pepProjectId: pepProjectId })).then((res) => {
if (res.success) {
let tableDatas = res.payload.data?.map(v => ({
key: v.alarmId,
id: v.alarmId,
StructureName: v.struc,
projectName: v.pomsProject?.map(r => (r.name ? { id: r.id, name: r.name, state: 'PMOS' } : {
@ -86,6 +87,7 @@ const TableData = ({alarmDataGroup, route, dispatch, actions, collectData, setSe
if (res.success) {
setCount(res.payload.data?.count || 0)
let tableDatas = res.payload.data?.rows?.map(v => ({
key: v.AlarmId,
id: v.AlarmId,
StructureName: v.StructureName,
projectName: v.pomsProject?.map(r => (r.name ? { id: r.id, name: r.name, state: 'PMOS' } : {
@ -234,7 +236,6 @@ const TableData = ({alarmDataGroup, route, dispatch, actions, collectData, setSe
break;
}
}
return (
<>
<div style={{ backgroundColor: '#FFFFFF', margin: "20px 12px 12px", padding: "20px 20px 40px" }}>
@ -408,6 +409,7 @@ const TableData = ({alarmDataGroup, route, dispatch, actions, collectData, setSe
// name: record.name,
}),
onSelect: (record, selected) => {
// console.log(`select row: ${selected}`, record);
},
// onSelectAll: (selected, selectedRows) => {
@ -417,6 +419,7 @@ const TableData = ({alarmDataGroup, route, dispatch, actions, collectData, setSe
// console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
setSelected(selectedRows?.map(v => v.id))
},
}}
/>
})()}

9
web/client/src/sections/projectGroup/containers/bigscreen.jsx

@ -36,7 +36,6 @@ const Bigscreen = (props) => {
const [interruptData,setInterruptData]=useState([])
const [avgTmes,setAvgTimes]=useState([])//
// const [queryUserId, setQueryUserId] = useState('')
useEffect(() => {
@ -160,7 +159,7 @@ const Bigscreen = (props) => {
})
dispatch(actions.projectGroup.getWorkOrdersRepairRank({ projectIds: query })).then(res => {
if (res.success) {
setGroupProject(res.payload.data?.slice(0, 10).map(v => ({ name: v.formname, startTime: moment(v?.startTime).format('YYYY-MM-DD'), duration: moment(v?.endTime).add(8, 'hours').diff(v?.startTime, 'hours') })) || [])
setGroupProject(res.payload.data?.slice(0, 10).map(v => ({ name: v.formname, startTime: moment(v?.startTime).format('YYYY-MM-DD'), duration: Math.round(moment(v?.endTime).add(8, 'hours').diff(v?.startTime, 'hours',true)) })) || [])
}
})
//
@ -168,7 +167,7 @@ const Bigscreen = (props) => {
if (res.success) {
const data=res.payload.data?.map(v=>{
return {projectName:allProjects?.find(item => item.value == v.project_id)?.label,
avgTime: Math.ceil(v.avgTime / 60 / 60),
avgTime: Math.round(v.avgTime / 60 / 60),
project_id:v.project_id
}
})
@ -313,7 +312,7 @@ const Bigscreen = (props) => {
},
tooltip: {
trigger: 'axis',
position: 'inside',
confine:true,//
formatter: function (params) {
//
// console.log(params);
@ -359,7 +358,7 @@ const Bigscreen = (props) => {
areaStyle: {
color: '#0e9cff26',
},
data: v.online?.map(f => [moment(f.collect_time).format('YYYY-MM-DD HH'), f.rate.toFixed(1)]) || []
data: v.online.sort((a,b)=>new Date(b.collect_time)-new Date(a.collect_time))?.map(f => [moment(f.collect_time).format('YYYY-MM-DD HH'), f.rate.toFixed(1)]) || []
})) || []
}}
notMerge={true}

7
web/client/src/utils/webapi.js

@ -156,9 +156,16 @@ export const ApiTable = {
thingsDeploy: 'things/{iotaThingId}/deploy',//获取设备部署信息-组网数据
deviceMetaDeployed: "meta/things/{iotaThingId}/devices", //获取部署设备原型
getIotaThingsLlinkStatus: 'metrics/things/{iotaThingId}/devices/link_status', //获取设备在线状态/以结构物id集体获取
thingsDeploy: 'things/{iotaThingId}/deploy',//获取设备部署信息-组网数据
findSensorLastData:'sensors/last/data',//原始数据查询
findDeviceMetaDeployed:'meta/things/{iotaThingId}/devices',//按找thingId查询数据
getDevicesAlarms: 'devices/alarms',//告警数据
findDevicesCardStatus:'devices/cardStatus',//查询物联网卡状态
respondRecord: 'respond-record',
//待办工单
workOrders: 'unfinished',
//获取设备型号

3
web/package.json

@ -86,6 +86,7 @@
"webpack-cli": "^4.2.0",
"webpack-dev-middleware": "^4.0.2",
"webpack-dev-server": "^3.11.2",
"webpack-hot-middleware": "^2.25.0"
"webpack-hot-middleware": "^2.25.0",
"xlsx": "^0.18.5"
}
}

Loading…
Cancel
Save