Merge branch 'main' of https://git.jsspisoft.com/ry-das
This commit is contained in:
commit
a2ffa5068c
@ -1,4 +1,5 @@
|
||||
#include "ry.h"
|
||||
#include <math.h>
|
||||
|
||||
CRYDevice::CRYDevice()
|
||||
{
|
||||
@ -275,10 +276,12 @@ BOOLEAN CRYDevice::websocket_msg_join(noPollMsg **msg, int msg_count, BYTE* &buf
|
||||
len += nopoll_msg_get_payload_size(msg[i]);
|
||||
}
|
||||
buffer[buffer_size] = 0;
|
||||
|
||||
vLog(LOG_DEBUG, "buffer size is: %ld.\n", buffer_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int CRYDevice::websocket_write(noPollConn* conn, const char * buffer, int buffer_len)
|
||||
int CRYDevice::websocket_write(const char * buffer, int buffer_len)
|
||||
{
|
||||
int result;
|
||||
result = nopoll_conn_send_text(conn, (const char *)buffer, buffer_len);
|
||||
@ -287,7 +290,7 @@ int CRYDevice::websocket_write(noPollConn* conn, const char * buffer, int buffer
|
||||
return (result == buffer_len) ? 0 : -1;
|
||||
}
|
||||
|
||||
bool CRYDevice::publish_sensor_data(noPollConn* conn, const std::string traceId, const char* command, const Json::Value payload)
|
||||
bool CRYDevice::publish_sensor_data(const std::string traceId, const char* command, const Json::Value payload)
|
||||
{
|
||||
Json::StreamWriterBuilder builder;
|
||||
builder["indentation"] = "";
|
||||
@ -311,8 +314,11 @@ bool CRYDevice::publish_sensor_data(noPollConn* conn, const std::string traceId,
|
||||
jsonRoot["data"] = payload;
|
||||
|
||||
std::string outputConfig = Json::writeString(builder, jsonRoot);
|
||||
vLog(LOG_DEBUG, "send cmd: %s, payload: %d\n", command, outputConfig.length());
|
||||
int rc = websocket_write(conn, outputConfig.c_str(), outputConfig.length());
|
||||
if (traceId != "")
|
||||
{
|
||||
vLog(LOG_DEBUG, "send cmd: %s, payload: %d, %128s\n", command, outputConfig.length(), outputConfig.c_str());
|
||||
}
|
||||
int rc = websocket_write(outputConfig.c_str(), outputConfig.length());
|
||||
if (rc != 0) {
|
||||
vLog(LOG_DEBUG, "websocket write is error<%d>,insert into database.\n", rc);
|
||||
//插入数据库
|
||||
@ -340,7 +346,39 @@ int CRYDevice::GetUnitYMCount(int uid)
|
||||
return config.units[uid].ymcount;
|
||||
}
|
||||
|
||||
float CRYDevice::GetUnitYCReal(int uid, int order)
|
||||
LONG CRYDevice::GetUnitYC(int uid, int order) const
|
||||
{
|
||||
int udb;
|
||||
LONG value;
|
||||
struUnit* pUnit;
|
||||
struUnitYC* pYC;
|
||||
|
||||
if (uid < 0 || uid >= UNIT_NUM) return 0;
|
||||
pUnit = &config.units[uid];
|
||||
if ((pUnit->state & 0x01) != TRUE) return 0;
|
||||
if (order < 0 || order >= pUnit->yccount) return 0;
|
||||
pYC = &pUnit->ycs[order];
|
||||
udb = pYC->order;
|
||||
if (udb < 0 || udb >= DATABASE_YC_NUM)
|
||||
{
|
||||
value = pYC->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = database.ycs[udb].value;
|
||||
pYC->value = value;
|
||||
pYC->update_time = database.ycs[udb].update_time;
|
||||
pYC->qds = database.ycs[udb].qds;
|
||||
}
|
||||
if (pYC->factor > 1 && (pUnit->type & 0x0f) == 0x00)
|
||||
{ //系数有效,且为转发单元
|
||||
value /= pYC->factor;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
float CRYDevice::GetUnitYCReal(int uid, int order) const
|
||||
{
|
||||
int udb;
|
||||
long value;
|
||||
@ -369,7 +407,7 @@ float CRYDevice::GetUnitYCReal(int uid, int order)
|
||||
return (float)((float)value * coef + base);
|
||||
}
|
||||
|
||||
float CRYDevice::GetUnitYCRealFromValue(int uid, int order, long value)
|
||||
float CRYDevice::GetUnitYCRealFromValue(int uid, int order, long value) const
|
||||
{
|
||||
int udb;
|
||||
float coef;
|
||||
@ -393,6 +431,64 @@ float CRYDevice::GetUnitYCRealFromValue(int uid, int order, long value)
|
||||
return (float)(value * coef + base);
|
||||
}
|
||||
|
||||
BOOLEAN CRYDevice::GetUnitYCIsFloat(int uid, int order) const
|
||||
{
|
||||
int udb;
|
||||
float coef = 1.0f;
|
||||
struUnit* pUnit;
|
||||
struUnitYC* pYC;
|
||||
if (uid < 0 || uid >= UNIT_NUM) return 0;
|
||||
pUnit = &config.units[uid];
|
||||
if ((pUnit->state & 0x01) != TRUE) return 0;
|
||||
if (order < 0 || order >= pUnit->yccount) return 0;
|
||||
pYC = &pUnit->ycs[order];
|
||||
udb = pYC->order;
|
||||
if (udb < 0 || udb >= DATABASE_YC_NUM)
|
||||
{
|
||||
coef = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
coef = pYC->coef;
|
||||
}
|
||||
|
||||
if (fabsf(coef) <= 1E-8) coef = 1.0f;
|
||||
if (fabsf(coef - 1.0f) <= 1E-8) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
float CRYDevice::GetUnitYCLimitReal(int uid, int order, int type) const
|
||||
{
|
||||
float limitValue;
|
||||
struUnit* pUnit;
|
||||
struUnitYC* pYC;
|
||||
if (uid < 0 || uid >= UNIT_NUM) return 0;
|
||||
pUnit = &config.units[uid];
|
||||
if ((pUnit->state & 0x01) != TRUE) return 0;
|
||||
if (order < 0 || order >= pUnit->yccount) return 0;
|
||||
pYC = &pUnit->ycs[order];
|
||||
|
||||
//1-越上限 2-越下限)
|
||||
if (type == 1)
|
||||
{
|
||||
limitValue = pYC->limit1High;
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
limitValue = pYC->limit1Low;
|
||||
}
|
||||
else if (type == 3)
|
||||
{
|
||||
limitValue = pYC->limit2High;
|
||||
}
|
||||
else if (type == 4)
|
||||
{
|
||||
limitValue = pYC->limit2Low;
|
||||
}
|
||||
|
||||
return limitValue;
|
||||
}
|
||||
|
||||
float CRYDevice::GetUnitYMReal(int uid, int order)
|
||||
{
|
||||
int udb;
|
||||
@ -444,10 +540,13 @@ BYTE CRYDevice::GetUnitYX(int uid, int point)
|
||||
return value;
|
||||
}
|
||||
|
||||
int CRYDevice::GetUnitYXBW(int& uid, BOOLEAN& value, BYTE& qds, int& type, unionCP56Time& st)
|
||||
int CRYDevice::GetUnitYXBW(int& uid, BOOLEAN& value, unionCP56Time& st)
|
||||
{
|
||||
int order;
|
||||
int point;
|
||||
int type;
|
||||
BYTE qds;
|
||||
|
||||
|
||||
while (yxbw.GetYXBW(m_yxbwload, st, order, value, qds, uid, point, type))
|
||||
{
|
||||
@ -470,10 +569,11 @@ int CRYDevice::GetUnitSOE(int& uid, BOOLEAN& value, BYTE& qds, unionCP56Time& st
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CRYDevice::GetUnitYCBW(int& uid, LONG& value, BYTE& qds, int& type, unionCP56Time& st)
|
||||
int CRYDevice::GetUnitYCBW(int& uid, LONG& value, int& type, unionCP56Time& st)
|
||||
{
|
||||
int order;
|
||||
int point;
|
||||
BYTE qds;
|
||||
|
||||
while (ycbw.GetYCBW(m_ycbwload, st, order, value, qds, uid, point, type)) {
|
||||
m_ycbwload++;
|
||||
@ -751,7 +851,7 @@ void CRYDevice::SetUnitYT(int uid, int order, DWORD value, BYTE act, BYTE result
|
||||
}
|
||||
}
|
||||
|
||||
int CRYDevice::MakeYKFrame(noPollConn* conn, int uid)
|
||||
int CRYDevice::MakeYKFrame(int uid)
|
||||
{
|
||||
int order;
|
||||
BYTE value, action, result;
|
||||
@ -790,13 +890,13 @@ int CRYDevice::MakeYKFrame(noPollConn* conn, int uid)
|
||||
jsonRoot["result"] = true;
|
||||
}
|
||||
|
||||
publish_sensor_data(conn, m_traceId, "deviceControlResp", jsonRoot);
|
||||
publish_sensor_data(m_traceId, "deviceControlResp", jsonRoot);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CRYDevice::MakeYTFrame(noPollConn* conn, int uid)
|
||||
int CRYDevice::MakeYTFrame(int uid)
|
||||
{
|
||||
int order;
|
||||
BYTE action, result;
|
||||
@ -834,7 +934,7 @@ int CRYDevice::MakeYTFrame(noPollConn* conn, int uid)
|
||||
jsonRoot["result"] = true;
|
||||
}
|
||||
|
||||
publish_sensor_data(conn, m_traceId, "deviceControlResp", jsonRoot);
|
||||
publish_sensor_data(m_traceId, "deviceControlResp", jsonRoot);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1081,13 +1181,13 @@ BOOLEAN CRYDevice::processModbusPointParam(const Json::Value jsonRoot, int uid,
|
||||
} else {
|
||||
config_config.units[uid].ycs[point].m_param[0] = 0;
|
||||
}
|
||||
if (jsonRoot["col3"].isString()) {
|
||||
BYTE dataType = (BYTE)atoi(jsonRoot["col3"].asCString());
|
||||
if (jsonRoot["col2"].isString()) {
|
||||
BYTE dataType = (BYTE)atoi(jsonRoot["col2"].asCString());
|
||||
config_config.units[uid].ycs[point].m_param[4] = dataType;
|
||||
if (dataType == 2 || dataType == 8) config_config.units[uid].ycs[point].m_param[3] = 1;
|
||||
else config_config.units[uid].ycs[point].m_param[3] = 2;
|
||||
} else if (jsonRoot["col3"].isInt()) {
|
||||
BYTE dataType = jsonRoot["col3"].asInt();
|
||||
} else if (jsonRoot["col2"].isInt()) {
|
||||
BYTE dataType = jsonRoot["col2"].asInt();
|
||||
config_config.units[uid].ycs[point].m_param[4] = dataType;
|
||||
if (dataType == 2 || dataType == 8) config_config.units[uid].ycs[point].m_param[3] = 1;
|
||||
else config_config.units[uid].ycs[point].m_param[3] = 2;
|
||||
@ -1095,11 +1195,11 @@ BOOLEAN CRYDevice::processModbusPointParam(const Json::Value jsonRoot, int uid,
|
||||
config_config.units[uid].ycs[point].m_param[4] = 0;
|
||||
config_config.units[uid].ycs[point].m_param[3] = 1;
|
||||
}
|
||||
if (jsonRoot["col2"].isString()) {
|
||||
BYTE signMark = (BYTE)atoi(jsonRoot["col2"].asCString());
|
||||
if (jsonRoot["col3"].isString()) {
|
||||
BYTE signMark = (BYTE)atoi(jsonRoot["col3"].asCString());
|
||||
config_config.units[uid].ycs[point].m_param[5] = signMark;
|
||||
} else if (jsonRoot["col2"].isInt()) {
|
||||
BYTE signMark = jsonRoot["col2"].asInt();
|
||||
} else if (jsonRoot["col3"].isInt()) {
|
||||
BYTE signMark = jsonRoot["col3"].asInt();
|
||||
config_config.units[uid].ycs[point].m_param[5] = signMark;
|
||||
} else {
|
||||
config_config.units[uid].ycs[point].m_param[5] = 0;
|
||||
@ -1693,7 +1793,7 @@ bool CRYDevice::dealConfigFile(const Json::Value jsonRoot)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CRYDevice::OnReceivedSystemAction(noPollConn* conn, const std::string cmdId, const std::string cmd, const Json::Value data)
|
||||
bool CRYDevice::OnReceivedSystemAction(const std::string cmdId, const std::string cmd, const Json::Value data)
|
||||
{
|
||||
do {
|
||||
if (cmd == "configUpdate") { //配置更新
|
||||
@ -1710,7 +1810,7 @@ bool CRYDevice::OnReceivedSystemAction(noPollConn* conn, const std::string cmdId
|
||||
return true;
|
||||
}
|
||||
|
||||
void CRYDevice::on_message(noPollConn* conn, const char *msg, const int size)
|
||||
void CRYDevice::on_message(const char *msg, const int size)
|
||||
{
|
||||
if (msg == NULL) return;
|
||||
if (size <= 0) return;
|
||||
@ -1742,11 +1842,11 @@ void CRYDevice::on_message(noPollConn* conn, const char *msg, const int size)
|
||||
Json::Int64 mtime = jsonRoot["time"].asInt64();
|
||||
#endif
|
||||
Json::Value datas = jsonRoot["data"];
|
||||
OnReceivedSystemAction(conn, cmdId, cmd, datas);
|
||||
OnReceivedSystemAction(cmdId, cmd, datas);
|
||||
} while (0);
|
||||
}
|
||||
|
||||
void CRYDevice::heart_beat(noPollConn* conn, int status)
|
||||
void CRYDevice::heart_beat(int status)
|
||||
{
|
||||
//发送心跳报文
|
||||
Json::Value payload;
|
||||
@ -1756,7 +1856,6 @@ void CRYDevice::heart_beat(noPollConn* conn, int status)
|
||||
if (status == 1) {
|
||||
Json::Value jsonItem;
|
||||
Json::Value jsonValue;
|
||||
//for (int i = 0; i < static_cast<int>(m_gLinkIDs.size()); i++) {
|
||||
for (int i = 0; i < PROCESSES_NUM - 1; i++) {
|
||||
if (config.processes[i].state == TRUE) {
|
||||
char linkId[32];
|
||||
@ -1771,11 +1870,11 @@ void CRYDevice::heart_beat(noPollConn* conn, int status)
|
||||
}
|
||||
}
|
||||
|
||||
publish_sensor_data(conn, "", "heartbeat", payload);
|
||||
publish_sensor_data("", "heartbeat", payload);
|
||||
}
|
||||
|
||||
|
||||
bool CRYDevice::publishinitDeviceData(noPollConn* conn, int uid)
|
||||
bool CRYDevice::publishinitDeviceData(int uid)
|
||||
{
|
||||
if (uid < 0 || uid >= UNIT_NUM) return false;
|
||||
|
||||
@ -1813,12 +1912,12 @@ bool CRYDevice::publishinitDeviceData(noPollConn* conn, int uid)
|
||||
root["values"] = values;
|
||||
|
||||
config.units[uid].state |= 0x40;
|
||||
return publish_sensor_data(conn, "", "initDeviceData", root);
|
||||
return publish_sensor_data("", "initDeviceData", root);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CRYDevice::publishAnalogData(noPollConn* conn, int uid)
|
||||
bool CRYDevice::publishAnalogData(int uid)
|
||||
{
|
||||
if (uid < 0 || uid >= UNIT_NUM) return false;
|
||||
Json::Value root;
|
||||
@ -1826,7 +1925,11 @@ bool CRYDevice::publishAnalogData(noPollConn* conn, int uid)
|
||||
int count = GetUnitYCCount(uid);
|
||||
if (count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
values[(const char *)config.units[uid].ycs[i].name] = GetUnitYCReal(uid, i);
|
||||
if (GetUnitYCIsFloat(uid, i)) {
|
||||
values[(const char *)config.units[uid].ycs[i].name] = GetUnitYCReal(uid, i);
|
||||
} else {
|
||||
values[(const char *)config.units[uid].ycs[i].name] = GetUnitYC(uid, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (values.size()) {
|
||||
@ -1835,12 +1938,12 @@ bool CRYDevice::publishAnalogData(noPollConn* conn, int uid)
|
||||
root["dataTime"] = datatime;
|
||||
root["deviceId"] = static_units[uid].deviceId;
|
||||
root["values"] = values;
|
||||
return publish_sensor_data(conn, "", "analogData", root);
|
||||
return publish_sensor_data("", "analogData", root);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CRYDevice::publishStateData(noPollConn* conn, int uid)
|
||||
bool CRYDevice::publishStateData(int uid)
|
||||
{
|
||||
if (uid < 0 || uid >= UNIT_NUM) return false;
|
||||
Json::Value root;
|
||||
@ -1857,35 +1960,65 @@ bool CRYDevice::publishStateData(noPollConn* conn, int uid)
|
||||
root["dataTime"] = datatime;
|
||||
root["deviceId"] = static_units[uid].deviceId;
|
||||
root["values"] = values;
|
||||
return publish_sensor_data(conn, "", "stateData", root);
|
||||
return publish_sensor_data("", "stateData", root);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CRYDevice::publishHistoryAnalogData(noPollConn* conn, int uid)
|
||||
bool CRYDevice::publishdeviceEventData(void)
|
||||
{
|
||||
if (uid < 0 || uid >= UNIT_NUM) return false;
|
||||
Json::Value root;
|
||||
Json::Value values;
|
||||
if (values.size()) {
|
||||
root["deviceId"] = static_units[uid].deviceId;
|
||||
root["values"] = values;
|
||||
return publish_sensor_data(conn, "", "historyAnalogData", root);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
int i;
|
||||
int uid;
|
||||
int yxbw_point;
|
||||
BOOLEAN yxbw_value;
|
||||
unionCP56Time yxbw_time;
|
||||
|
||||
bool CRYDevice::publishHistoryStateData(noPollConn* conn, int uid)
|
||||
{
|
||||
if (uid < 0 || uid >= UNIT_NUM) return false;
|
||||
Json::Value root;
|
||||
Json::Value values;
|
||||
if (values.size()) {
|
||||
root["deviceId"] = static_units[uid].deviceId;
|
||||
root["values"] = values;
|
||||
return publish_sensor_data(conn, "", "historyStateData", root);
|
||||
Json::Value value;
|
||||
|
||||
for (i = 0; i < DATABASE_YXBW_NUM; i++)
|
||||
{
|
||||
yxbw_point = GetUnitYXBW(uid, yxbw_value, yxbw_time);
|
||||
if (yxbw_point < 0) break;
|
||||
value["deviceId"] = static_units[uid].deviceId;
|
||||
value["attrCode"] = (const char *)config.units[uid].yxs[yxbw_point].name;
|
||||
value["attrValue"] = yxbw_value;
|
||||
value["eventType"] = 0;
|
||||
Json::Int64 datatime = (Json::Int64)time(NULL);
|
||||
datatime *= 1000;
|
||||
value["dataTime"] = datatime;
|
||||
value["limitValue"] = Json::Value::null;
|
||||
|
||||
root.append(value);
|
||||
}
|
||||
|
||||
int ycbw_point;
|
||||
int ycbw_type;
|
||||
LONG ycbw_value;
|
||||
unionCP56Time ycbw_time;
|
||||
|
||||
for (i = 0; i < DATABASE_YCBW_NUM; i++)
|
||||
{
|
||||
ycbw_point = GetUnitYCBW(uid, ycbw_value, ycbw_type, ycbw_time);
|
||||
if (ycbw_point < 0) break;
|
||||
value["deviceId"] = static_units[uid].deviceId;
|
||||
value["attrCode"] = (const char *)config.units[uid].ycs[ycbw_point].name;
|
||||
value["attrValue"] = ycbw_value;
|
||||
value["eventType"] = ycbw_type;
|
||||
Json::Int64 datatime = (Json::Int64)time(NULL);
|
||||
datatime *= 1000;
|
||||
value["dataTime"] = datatime;
|
||||
value["limitValue"] = GetUnitYCLimitReal(uid, ycbw_point, ycbw_type);
|
||||
|
||||
root.append(value);
|
||||
}
|
||||
|
||||
if (root.size()) {
|
||||
//return publish_sensor_data("", "deviceEvent", root);
|
||||
vLog(LOG_DEBUG, "%s", root.toStyledString().c_str());
|
||||
}
|
||||
return false;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void CRYDevice::releaseAllUnits(void)
|
||||
@ -1969,31 +2102,38 @@ bool CRYDevice::ry_run(void)
|
||||
nopoll_bool isOk = nopoll_conn_is_ready(conn);
|
||||
if (isOk) {
|
||||
last_connect_sec = system32.timers;
|
||||
int msg_count = 0;
|
||||
noPollMsg *msg[2048];
|
||||
|
||||
while ((msg[msg_count] = nopoll_conn_get_msg(conn)) != NULL) {
|
||||
vLog(LOG_DEBUG, "recv length = %d, %d\n", nopoll_msg_get_payload_size(msg[msg_count]), nopoll_msg_is_final(msg[msg_count]));
|
||||
vLog(LOG_DEBUG, "recv %d length = %d, %d\n", msg_count, nopoll_msg_get_payload_size(msg[msg_count]), nopoll_msg_is_final(msg[msg_count]));
|
||||
char pathN[256];
|
||||
snprintf(pathN, sizeof(pathN), "0/_%d.txt", msg_count);
|
||||
FILE* pf = fopen(pathN, "w+");
|
||||
if (pf) {
|
||||
fwrite(nopoll_msg_get_payload(msg[msg_count]), nopoll_msg_get_payload_size(msg[msg_count]), 1, pf);
|
||||
fclose(pf);
|
||||
}
|
||||
if (nopoll_msg_is_final(msg[msg_count])) {
|
||||
msg_count++;
|
||||
if (msg_count > 0) {
|
||||
int buffer_len;
|
||||
BYTE *buffer = NULL;
|
||||
if (websocket_msg_join(msg, msg_count, buffer, buffer_len)) {
|
||||
if (buffer) {
|
||||
on_message((const char *)buffer, buffer_len);
|
||||
delete [] buffer;
|
||||
buffer = NULL;
|
||||
}
|
||||
for (int i = 0; i < msg_count; i++) {
|
||||
nopoll_msg_unref(msg[i]);
|
||||
msg_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
msg_count++;
|
||||
}
|
||||
}
|
||||
if (msg_count > 0) {
|
||||
int buffer_len;
|
||||
BYTE *buffer = NULL;
|
||||
if (websocket_msg_join(msg, msg_count, buffer, buffer_len)) {
|
||||
if (buffer) {
|
||||
on_message(conn, (const char *)buffer, buffer_len);
|
||||
delete [] buffer;
|
||||
buffer = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < msg_count; i++) {
|
||||
nopoll_msg_unref(msg[i]);
|
||||
}
|
||||
} else {
|
||||
if (last_connect_sec > 0 && system32.timers > (last_connect_sec + 30)) {
|
||||
nopoll_conn_connect_timeout(ctx, 50000);
|
||||
@ -2015,19 +2155,20 @@ bool CRYDevice::ry_run(void)
|
||||
}
|
||||
if (sec_changed) {
|
||||
if ((last_sec % 20) == 0) {
|
||||
heart_beat(conn, status);
|
||||
heart_beat(status);
|
||||
}
|
||||
}
|
||||
publishdeviceEventData();
|
||||
for (int i = 0; i < UNIT_NUM; i++) {
|
||||
if ((config.units[i].state & 0x01) != TRUE) continue;
|
||||
MakeYKFrame(conn, i);
|
||||
MakeYTFrame(conn, i);
|
||||
MakeYKFrame(i);
|
||||
MakeYTFrame(i);
|
||||
if (sec_changed) {
|
||||
//publishinitDeviceData(conn, i);
|
||||
if ((last_sec % 60) == 0) { //更新数据
|
||||
publishAnalogData(conn, i);
|
||||
publishStateData(conn, i);
|
||||
}
|
||||
//publishinitDeviceData(i);
|
||||
// if ((last_sec % 10) == 0) { //更新数据
|
||||
publishAnalogData(i);
|
||||
publishStateData(i);
|
||||
// }
|
||||
}
|
||||
}
|
||||
return m_dataAcquisitionReload;
|
||||
|
@ -80,6 +80,9 @@ private:
|
||||
DWORD last_connect_sec = 0;
|
||||
int status;
|
||||
|
||||
int msg_count = 0;
|
||||
noPollMsg *msg[2048];
|
||||
|
||||
bool m_dataAcquisitionReload = false;
|
||||
|
||||
char m_host[256] = {"127.0.0.1"};
|
||||
@ -105,37 +108,43 @@ private:
|
||||
int GetUnitYXCount(int uid);
|
||||
int GetUnitYCCount(int uid);
|
||||
int GetUnitYMCount(int uid);
|
||||
float GetUnitYCReal(int uid, int order);
|
||||
float GetUnitYCRealFromValue(int uid, int order, long value);
|
||||
LONG GetUnitYC(int uid, int order) const;
|
||||
float GetUnitYCReal(int uid, int order) const;
|
||||
float GetUnitYCRealFromValue(int uid, int order, long value) const;
|
||||
BOOLEAN GetUnitYCIsFloat(int uid, int order) const;
|
||||
float GetUnitYCLimitReal(int uid, int order, int type = 1) const;
|
||||
float GetUnitYMReal(int uid, int order);
|
||||
BYTE GetUnitYX(int uid, int point);
|
||||
int GetUnitYXBW(int& uid, BOOLEAN& value, BYTE& qds, int& type, unionCP56Time& st);
|
||||
int GetUnitYXBW(int& uid, BOOLEAN& value, unionCP56Time& st);
|
||||
int GetUnitSOE(int& uid, BOOLEAN& value, BYTE& qds, unionCP56Time& st);
|
||||
int GetUnitYCBW(int& uid, LONG& value, BYTE& qds, int& type, unionCP56Time& st);
|
||||
int GetUnitYCBW(int& uid, LONG& value, int& type, unionCP56Time& st);
|
||||
BOOLEAN GetUnitYK(int uid, int& order, BYTE& value, BYTE& act, BYTE& result);
|
||||
void SetUnitYK(int uid, int order, BYTE value, BYTE act, BYTE result);
|
||||
BOOLEAN GetUnitYT(int uid, int& order, DWORD& value, BYTE& act, BYTE& result);
|
||||
void SetUnitYT(int uid, int order, DWORD value, BYTE act, BYTE result);
|
||||
int MakeYKFrame(noPollConn* conn, int uid);
|
||||
int MakeYTFrame(noPollConn* conn, int uid);
|
||||
int MakeYKFrame(int uid);
|
||||
int MakeYTFrame(int uid);
|
||||
bool OnReceivedDeviceCommand(const Json::Value jsonRoot);
|
||||
BOOLEAN processUartParam(const Json::Value jsonRoot, int ord);
|
||||
BOOLEAN processNetworkParam(const Json::Value jsonRoot, int pid);
|
||||
BOOLEAN processHostIEC104ProcessParam(const Json::Value jsonRoot, int pid);
|
||||
BOOLEAN processModbusPointParam(const Json::Value jsonRoot, int uid, int point, int type);
|
||||
bool dealConfigFile(const Json::Value jsonRoot);
|
||||
bool OnReceivedSystemAction(noPollConn* conn, const std::string cmdId, const std::string cmd, const Json::Value data);
|
||||
void on_message(noPollConn* conn, const char *msg, const int size);
|
||||
bool OnReceivedSystemAction(const std::string cmdId, const std::string cmd, const Json::Value data);
|
||||
void on_message(const char *msg, const int size);
|
||||
|
||||
void heart_beat(noPollConn* conn, int status);
|
||||
bool publishinitDeviceData(noPollConn* conn, int uid);
|
||||
bool publishAnalogData(noPollConn* conn, int uid);
|
||||
bool publishStateData(noPollConn* conn, int uid);
|
||||
bool publishHistoryAnalogData(noPollConn* conn, int uid);
|
||||
bool publishHistoryStateData(noPollConn* conn, int uid);
|
||||
void heart_beat(int status);
|
||||
bool publishinitDeviceData(int uid);
|
||||
bool publishAnalogData(int uid);
|
||||
bool publishStateData(int uid);
|
||||
bool publishHistoryAnalogData(int uid);
|
||||
bool publishHistoryStateData(int uid);
|
||||
bool publishdeviceEventData(void);
|
||||
BOOLEAN publishYXBWData(int uid);
|
||||
BOOLEAN publishYCBWData(int uid);
|
||||
|
||||
BOOLEAN websocket_msg_join(noPollMsg **msg, int msg_count, BYTE* &buffer, int &buffer_size);
|
||||
int websocket_write(noPollConn* conn, const char * buffer, int buffer_len);
|
||||
bool publish_sensor_data(noPollConn* conn, const std::string traceId, const char* command, const Json::Value payload);
|
||||
int websocket_write(const char * buffer, int buffer_len);
|
||||
bool publish_sensor_data(const std::string traceId, const char* command, const Json::Value payload);
|
||||
};
|
||||
#endif //_RY_H_
|
@ -879,8 +879,6 @@ float CProcess::GetUnitYCRealFromValue(int uid, int order, long value) const
|
||||
base = 0.0f;
|
||||
}
|
||||
else {
|
||||
// coef = database.ycs[udb].coef;
|
||||
// base = database.ycs[udb].base;
|
||||
coef = pYC->coef;
|
||||
base = pYC->base;
|
||||
}
|
||||
@ -906,7 +904,6 @@ float CProcess::GetUnitYCCoef(int uid, int order) const
|
||||
}
|
||||
else
|
||||
{
|
||||
// coef = database.ycs[udb].coef;
|
||||
coef = pYC->coef;
|
||||
}
|
||||
|
||||
@ -933,7 +930,6 @@ float CProcess::GetUnitYCBase(int uid, int order) const
|
||||
}
|
||||
else
|
||||
{
|
||||
// base = database.ycs[udb].base;
|
||||
base = pYC->base;
|
||||
}
|
||||
|
||||
@ -1022,7 +1018,6 @@ float CProcess::GetUnitYMCoef(int uid, int order) const
|
||||
}
|
||||
else
|
||||
{
|
||||
// coef = database.yms[udb].coef;
|
||||
coef = pYM->coef;
|
||||
}
|
||||
|
||||
@ -1049,7 +1044,6 @@ float CProcess::GetUnitYMBase(int uid, int order) const
|
||||
}
|
||||
else
|
||||
{
|
||||
// base = database.yms[udb].base;
|
||||
base = pYM->base;
|
||||
}
|
||||
|
||||
|
@ -3,11 +3,7 @@
|
||||
#include <math.h>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
//Valid slave device addresses are in the range of 0 锟?C 247 decimal. //
|
||||
//The individual slave devices are assigned addresses in the range of 1 锟?C 247. //
|
||||
//Address 0 is used for the broadcast address, which all slave devices recognize.//
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef HAVE_FTP_PROCESS
|
||||
|
||||
#define MODBUSP_READ_ID 100 //读取文件及文件夹ID
|
||||
@ -43,9 +39,9 @@ struct {
|
||||
{ 2, 205 },
|
||||
{ 2, 206 },
|
||||
{ 2, 207 },
|
||||
{ 2, 208 },
|
||||
{ 2, 209 },
|
||||
{ 2, 210 },
|
||||
{ 2, 208 },
|
||||
{ 2, 211 },
|
||||
{ 2, 212 },
|
||||
{ 2, 213 },
|
||||
@ -183,7 +179,14 @@ struct {
|
||||
{ 2, 358 },
|
||||
{ 2, 359 },
|
||||
{ 2, 360 },
|
||||
{ 2, 361 }
|
||||
{ 2, 361 },
|
||||
{ 2, 362 },
|
||||
{ 2, 363 },
|
||||
{ 2, 364 },
|
||||
{ 2, 365 },
|
||||
{ 2, 366 },
|
||||
{ 2, 367 },
|
||||
{ 2, 368 }
|
||||
};
|
||||
|
||||
#include <curl/curl.h>
|
||||
@ -218,7 +221,7 @@ static bool publish_sensor_data(const noPollConn* conn, const char* command, con
|
||||
|
||||
std::string outputConfig = Json::writeString(builder, jsonRoot);
|
||||
int rc = websocket_write(conn, outputConfig.c_str(), outputConfig.length());
|
||||
vLog(LOG_DEBUG, "send cmd: %s, payload: %d\n%s\n", command, outputConfig.length(), outputConfig.c_str());
|
||||
//vLog(LOG_DEBUG, "send cmd: %s, payload: %d\n", command, outputConfig.length()/*, outputConfig.c_str()*/);
|
||||
if (rc != 0) {
|
||||
vLog(LOG_DEBUG, "websocket write is error<%d>,insert into database.\n", rc);
|
||||
//插入数据库
|
||||
@ -490,7 +493,7 @@ static size_t writefunc(void* ptr, size_t size, size_t nmemb, FILE* stream)
|
||||
|
||||
static int ftpget(const char* remote, const char* local, const char* user, const char* pwd, const long timeout = 3, struct memory* chunk = NULL)
|
||||
{
|
||||
vLog(LOG_DEBUG, "start to get %s to local %s, with name: %s, and password: %s.\n", remote, local, user, pwd);
|
||||
//vLog(LOG_DEBUG, "start to get %s to local %s, with name: %s, and password: %s.\n", remote, local, user, pwd);
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
CURL* curl = curl_easy_init();
|
||||
|
||||
@ -536,17 +539,18 @@ static int ftpget(const char* remote, const char* local, const char* user, const
|
||||
ret = curl_easy_perform(curl);
|
||||
#endif
|
||||
//vLog(LOG_DEBUG, "curl easy perform return value is: %d, and OK is: %d.\n", ret, CURLE_OK);
|
||||
#if 0
|
||||
int curl_state = 0;
|
||||
if (ret == CURLE_OK) curl_state = 1;
|
||||
else {
|
||||
vLog(LOG_ERROR, "%d,%s\n", ret, curl_easy_strerror(ret));
|
||||
//vLog(LOG_ERROR, "%d,%s\n", ret, curl_easy_strerror(ret));
|
||||
curl_state = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
curl_easy_cleanup(curl);
|
||||
curl_global_cleanup();
|
||||
|
||||
return curl_state;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void* ryftp_process(void* param)
|
||||
@ -583,9 +587,10 @@ static void* ryftp_process(void* param)
|
||||
DWORD target_addr = mbt->target_addr;
|
||||
memset(ipaddress, '\0', sizeof(ipaddress));
|
||||
inet_ntop(AF_INET, &target_addr, ipaddress, 16);
|
||||
|
||||
#if 0
|
||||
struct timespec start, end;
|
||||
double elapsed_time = 0;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < sizeof(m_datalen_mbaddr) / sizeof(m_datalen_mbaddr[0]); i++) {
|
||||
m_datalen2mbaddr_map.insert(datalen2mbaddrmap::value_type(m_datalen_mbaddr[i].address, i + 1));
|
||||
@ -621,17 +626,17 @@ static void* ryftp_process(void* param)
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iYPLevel) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iYPLevel);
|
||||
len++;
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iGenSpeed1s) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iGenSpeed1s);
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iWindSpeed_1sec) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iWindSpeed_1sec);
|
||||
len++;
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iGenPower1s) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iGenPower1s);
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iGenSpeed_1sec) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iGenSpeed_1sec);
|
||||
len++;
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iWindSpeed1s) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iWindSpeed1s);
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iGenPower_1sec) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iGenPower_1sec);
|
||||
len++;
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iGenToruqe1s) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iGenToruqe1s);
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iGenToruqe_1sec) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iGenToruqe_1sec);
|
||||
len++;
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iRotorSpeed) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iRotorSpeed);
|
||||
@ -1044,6 +1049,27 @@ static void* ryftp_process(void* param)
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.SCW042) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.SCW042);
|
||||
len++;
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iGenSpeed_10sec) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iGenSpeed_10sec);
|
||||
len++;
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iGenSpeed_30sec) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iGenSpeed_30sec);
|
||||
len++;
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iGenPower_10sec) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iGenPower_10sec);
|
||||
len++;
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iGenPower_30sec) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iGenPower_30sec);
|
||||
len++;
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iWindSpeed_10sec) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iWindSpeed_10sec);
|
||||
len++;
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iWindSpeed_30sec) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iWindSpeed_30sec);
|
||||
len++;
|
||||
fields[len].start = reinterpret_cast<uintptr_t>(&t_data.iAvailablePower) - reinterpret_cast<uintptr_t>(&t_data);
|
||||
fields[len].length = sizeof(t_data.iAvailablePower);
|
||||
len++;
|
||||
|
||||
|
||||
//判断是否链接单元
|
||||
@ -1085,7 +1111,7 @@ static void* ryftp_process(void* param)
|
||||
}
|
||||
|
||||
//根据实际配置表将
|
||||
|
||||
WORD ftpget_retry_count = 0;
|
||||
while (TRUE) {
|
||||
sleep(1); //每秒执行一次
|
||||
//ftp获取文件
|
||||
@ -1096,11 +1122,15 @@ static void* ryftp_process(void* param)
|
||||
|
||||
snprintf(name, sizeof(name), "%s/%d", pathName, mbt->m_currentFileNo);
|
||||
snprintf(remote, sizeof(remote), "ftp://%s/Hard%20Disk2/data/rtdatalog/%d/%d", ipaddress, mbt->m_currentDirNo, mbt->m_currentFileNo);
|
||||
|
||||
#if 0
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
#endif
|
||||
struct memory chunk = {0}; // For storing the downloaded data
|
||||
if (ftpget(remote, name, user, password, 3, &chunk)) {
|
||||
int result = ftpget(remote, name, user, password, 3, &chunk);
|
||||
if (result == CURLE_OK) {
|
||||
//成功,处理文件
|
||||
vLog(LOG_DEBUG, "get %s to local %s, with name: %s, and password: %s okay.\n", remote, name, user, password);
|
||||
ftpget_retry_count = 0;
|
||||
struRYDeviceData *data = (struRYDeviceData *)chunk.response;
|
||||
unionCP56Time st;
|
||||
int uid = mbt->GetCurUnitID();
|
||||
@ -1173,11 +1203,11 @@ static void* ryftp_process(void* param)
|
||||
}
|
||||
}
|
||||
if (chunk.response) free(chunk.response);
|
||||
//vLog(LOG_DEBUG, "get a file, then send to ws.\n");
|
||||
#if 0
|
||||
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||
elapsed_time = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;
|
||||
vLog(LOG_DEBUG, "Elapsed time: %.6f seconds\n", elapsed_time);
|
||||
|
||||
#endif
|
||||
mbt->m_lastFileNo = mbt->m_currentFileNo;
|
||||
mbt->m_currentFileNo++;
|
||||
if ((mbt->m_currentFileNo - mbt->m_lastStartFileNo) % 1000 == 0) {
|
||||
@ -1191,6 +1221,15 @@ static void* ryftp_process(void* param)
|
||||
#endif
|
||||
//保存文件信息
|
||||
}
|
||||
} else if (result == CURLE_REMOTE_FILE_NOT_FOUND) {
|
||||
//文件不存在,尝试60次(1分钟,正常情况下PLC10s生成一个文件)
|
||||
ftpget_retry_count++;
|
||||
if (ftpget_retry_count >= 60) {
|
||||
//重新通过modbus程序获取文件夹和最新文件信息
|
||||
mbt->m_iv = 0;
|
||||
mbt->m_currentDirNo = -1;
|
||||
mbt->m_currentFileNo = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1642,9 +1681,8 @@ BOOLEAN CHostModbusTcpProcess::OnPreCreate(int id)
|
||||
m_nTimeout = 200;
|
||||
calc2();
|
||||
|
||||
vLog(LOG_DEBUG, "file size is: %d\n", sizeof(struRYDeviceData) * 250 / 1024);
|
||||
|
||||
#ifdef HAVE_FTP_PROCESS
|
||||
vLog(LOG_DEBUG, "file size is: %d\n", sizeof(struRYDeviceData) * 250 / 1024);
|
||||
//启动后,创建ftp线程
|
||||
if (m_pid <= 0) {
|
||||
vLog(LOG_DEBUG, "create a ftp thread.\n");
|
||||
@ -2271,12 +2309,7 @@ BOOLEAN CHostModbusTcpProcess::OnReceiveIDData(CHostModbusTcpProcessItem *pItem,
|
||||
//当前文件夹下第一个文件
|
||||
m_lastStartFileNo = (DWORD)((pBuf[2] << 24) | (pBuf[3] << 16) | (pBuf[0] << 8) | pBuf[1]); pBuf += 4;
|
||||
|
||||
#if 0
|
||||
m_currentDirNo = 37;
|
||||
m_currentFileNo = 26901;
|
||||
m_lastStartFileNo = 26901;
|
||||
#endif
|
||||
vLog(LOG_DEBUG, "dir: %ld, file: %ld: start: %ld\n", m_currentDirNo, m_currentFileNo, m_lastStartFileNo);
|
||||
vLog(LOG_DEBUG, "最新文件夹编号: %ld, 最新文件名编号: %ld: 最新文件夹中第一个文件的编号: %ld\n", m_currentDirNo, m_currentFileNo, m_lastStartFileNo);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -2392,6 +2425,7 @@ BOOLEAN CHostModbusTcpProcess::OnReceiveYCData(CHostModbusTcpProcessItem *pItem,
|
||||
reg_count = pParam[3];
|
||||
value_type = pParam[4];
|
||||
sign_mark = pParam[5];
|
||||
//vLog(LOG_DEBUG, "here count is: %d, value type is: %d, and ", reg_count, value_type);
|
||||
if ((1 == reg_count) && (2 == value_type))
|
||||
{ //16位归一化值
|
||||
if (2 == value_type)
|
||||
@ -2399,6 +2433,7 @@ BOOLEAN CHostModbusTcpProcess::OnReceiveYCData(CHostModbusTcpProcessItem *pItem,
|
||||
if (sign_mark == 0) nValue = (DWORD)(WORD)((pBuf[0] << 8) | pBuf[1]);
|
||||
else nValue = (DWORD)(short)((pBuf[0] << 8) | pBuf[1]);
|
||||
SetUnitYC(uid, point, (LONG)nValue);
|
||||
//vLog(LOG_DEBUG, "value is: %ld.\n", nValue);
|
||||
}
|
||||
else if (8 == value_type)
|
||||
{
|
||||
@ -2429,6 +2464,7 @@ BOOLEAN CHostModbusTcpProcess::OnReceiveYCData(CHostModbusTcpProcessItem *pItem,
|
||||
{ //归一化值,高位在第一个寄存器
|
||||
nValue = (DWORD)(pBuf[0] << 24 | pBuf[1] << 16 | pBuf[2] << 8 | pBuf[3]);
|
||||
SetUnitYC(uid, point, (LONG)nValue);
|
||||
//vLog(LOG_DEBUG, "value is: %ld.\n", nValue);
|
||||
}
|
||||
else if (4 == value_type)
|
||||
{ //归一化值,高位在第二个寄存器
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "netproc.h"
|
||||
#include "modbus_def.h"
|
||||
|
||||
#define HAVE_FTP_PROCESS
|
||||
//#define HAVE_FTP_PROCESS
|
||||
#ifdef HAVE_FTP_PROCESS
|
||||
#include <dirent.h>
|
||||
#include <nopoll.h>
|
||||
@ -21,10 +21,10 @@ typedef struct {
|
||||
WORD iTurbineOperationMode;// 运行模式 2 205 1 需要解析 1s 控制系统
|
||||
WORD iBPLevel;// 刹车等级 2 206 1 需要解析 1s 控制系统
|
||||
WORD iYPLevel;// 偏航运行模式 2 207 1 需要解析 1s 控制系统
|
||||
WORD iGenSpeed1s;// 发电机转速1秒均值 2 209 0.1 转/分 1s 控制系统
|
||||
WORD iGenPower1s;// 机组有功1秒均值 2 210 0.1 千瓦 1s 控制系统
|
||||
WORD iWindSpeed1s;// 风速1秒均值 2 208 0.01 米/秒 1s 控制系统
|
||||
WORD iGenToruqe1s;// 发电机扭矩1秒均值 2 211 0.1 牛米 1s 控制系统
|
||||
WORD iWindSpeed_1sec;// 风速1秒均值 2 208 0.01 米/秒 1s 控制系统
|
||||
WORD iGenSpeed_1sec;// 发电机转速1秒均值 2 209 0.1 转/分 1s 控制系统
|
||||
WORD iGenPower_1sec;// 机组有功1秒均值 2 210 0.1 千瓦 1s 控制系统
|
||||
WORD iGenToruqe_1sec;// 发电机扭矩1秒均值 2 211 0.1 牛米 1s 控制系统
|
||||
WORD iRotorSpeed;// 风轮转速 2 212 0.1 转/分 1s 控制系统
|
||||
WORD iTheoreticalPower;// 理论有功功率 2 213 0.1 千瓦 1s 控制系统
|
||||
WORD iReactivePower;// 无功功率 2 214 0.1 千乏 1s 控制系统
|
||||
@ -161,7 +161,14 @@ typedef struct {
|
||||
WORD SCW039;// 故障代码字39 2 358 1 1s 控制系统
|
||||
WORD SCW040;// 故障代码字40 2 359 1 1s 控制系统
|
||||
WORD SCW041;// 故障代码字41 2 360 1 1s 控制系统
|
||||
WORD SCW042;// 故障代码字42 2 361 1 1s 控制系统
|
||||
WORD SCW042;// 故障代码字42 2 361 1 1s 控制系统
|
||||
WORD iGenSpeed_10sec;// 发电机转速10秒均值 2 362
|
||||
WORD iGenSpeed_30sec;// 发电机转速30秒均值 2 363
|
||||
WORD iGenPower_10sec;// 机组有功10秒均值 2 364
|
||||
WORD iGenPower_30sec;// 机组有功30秒均值 2 365
|
||||
WORD iWindSpeed_10sec;// 风速10秒均值 2 366
|
||||
WORD iWindSpeed_30sec;// 风速30秒均值 2 367
|
||||
WORD iAvailablePower;// 可用有功功率 2 368
|
||||
} struRYDeviceData;
|
||||
#pragma pack()
|
||||
|
||||
|
@ -402,20 +402,52 @@ public:
|
||||
}
|
||||
} else if (database.ycs[udb].value != value) { //update value
|
||||
//此处增加越线判断
|
||||
float coef = pUnit->ycs[point].coef;
|
||||
float base = pUnit->ycs[point].base;
|
||||
float fValue = (float)((float)value * coef + base);
|
||||
if (pUnit->ycs[point].limit1Enable) {
|
||||
|
||||
}
|
||||
if (pUnit->ycs[point].limit2Enable) {
|
||||
|
||||
if (fValue > pUnit->ycs[point].limit1High) { //越上限
|
||||
if (!pUnit->ycs[point].ycbw) {
|
||||
pUnit->ycs[point].ycbw = TRUE;
|
||||
ycbw.PushYCBW(system32.now, udb, value, qds, uid, point, 1);
|
||||
}
|
||||
} else if (fValue < pUnit->ycs[point].limit1Low) { //越下限
|
||||
if (!pUnit->ycs[point].ycbw) {
|
||||
pUnit->ycs[point].ycbw = TRUE;
|
||||
ycbw.PushYCBW(system32.now, udb, value, qds, uid, point, 2);
|
||||
}
|
||||
} else { //不越限
|
||||
if (pUnit->ycs[point].ycbw) {
|
||||
pUnit->ycs[point].ycbw = FALSE;
|
||||
ycbw.PushYCBW(system32.now, udb, value, qds, uid, point, 5);
|
||||
}
|
||||
}
|
||||
//默认二级越限必须大于一级越限
|
||||
if (pUnit->ycs[point].limit2Enable) {
|
||||
if (fValue > pUnit->ycs[point].limit2High) { //越上限
|
||||
if (!pUnit->ycs[point].ycbw) {
|
||||
pUnit->ycs[point].ycbw = TRUE;
|
||||
ycbw.PushYCBW(system32.now, udb, value, qds, uid, point, 3);
|
||||
}
|
||||
} else if (fValue < pUnit->ycs[point].limit2Low) { //越下限
|
||||
if (!pUnit->ycs[point].ycbw) {
|
||||
pUnit->ycs[point].ycbw = TRUE;
|
||||
ycbw.PushYCBW(system32.now, udb, value, qds, uid, point, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pUnit->ycs[point].value = value;
|
||||
pUnit->ycs[point].update_time = system32.timers;
|
||||
#if 0
|
||||
if (pUnit->ycs[point].change_pos >= 0 && bAddYCBW) {
|
||||
if (abs(pUnit->ycs[point].value - database.ycs[udb].value) >= pUnit->ycs[point].change_pos) { //40码值变化量认为是遥测变位
|
||||
pUnit->ycs[point].ycbw = TRUE;
|
||||
ycbw.PushYCBW(system32.now, udb, value, qds, uid, point, YCBWT_AUTO);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
database.ycs[udb].value = value;
|
||||
database.ycs[udb].op_unit = uid;
|
||||
database.ycs[udb].update_time = system32.timers; //设置刷新时间
|
||||
@ -458,12 +490,14 @@ public:
|
||||
}
|
||||
pUnit->ycs[point].value = nvalue;
|
||||
pUnit->ycs[point].update_time = system32.timers;
|
||||
#if 0
|
||||
if (pUnit->ycs[point].change_pos >= 0 && bAddYCBW) {
|
||||
if (abs(pUnit->ycs[point].value - database.ycs[udb].value) >= pUnit->ycs[point].change_pos) { //40码值变化量认为是遥测变位
|
||||
pUnit->ycs[point].ycbw = TRUE;
|
||||
ycbw.PushYCBW(system32.now, udb, nvalue, qds, uid, point, YCBWT_AUTO);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
database.ycs[udb].value = nvalue;
|
||||
database.ycs[udb].op_unit = uid;
|
||||
database.ycs[udb].update_time = system32.timers; //设置刷新时间
|
||||
|
@ -75,7 +75,7 @@ typedef int SOCKET;
|
||||
#define MAX_DISPLAY_BUFFER_SIZE 0x8000
|
||||
|
||||
#define HARDWARE_PORTS_NUM 20
|
||||
#define PROCESSES_NUM 64
|
||||
#define PROCESSES_NUM 256
|
||||
#define PROCESS_UNIT_NUM 256
|
||||
#define UNIT_NUM 256
|
||||
#define UNIT_YX_MAX 0x1500
|
||||
|
@ -38,4 +38,8 @@ public interface SysEquipmentMapper extends BaseMapperPlus<SysEquipment, SysEqui
|
||||
List<String> queryBelongLines(@Param("objectType") Long objectType);
|
||||
|
||||
List<SysEquipmentVo> querySysEquipmentList(@Param("info") SysEquipmentDto sysEquipmentDto);
|
||||
|
||||
SysEquipmentVo queryWindFarm(@Param("info") SysEquipmentDto sysEquipmentDto);
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.das.modules.equipment.service.impl;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.poi.excel.ExcelReader;
|
||||
import cn.hutool.poi.excel.ExcelUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
@ -78,9 +78,10 @@ public class SysIotModelServiceImpl implements SysIotModelService {
|
||||
|
||||
sysIotModel.setRevision(1);
|
||||
sysIotModelMapper.insert(sysIotModel);
|
||||
addModelCache(sysIotModel);
|
||||
SysIotModelVo sysIotModelVo = new SysIotModelVo();
|
||||
BeanCopyUtils.copy(sysIotModel, sysIotModelVo);
|
||||
sysIotModelVo.setIotModelCode(sysIotModelDto.getIotModelCode().toLowerCase());
|
||||
sysIotModelVo.setIotModelCode(sysIotModelDto.getIotModelCode());
|
||||
return sysIotModelVo;
|
||||
}
|
||||
|
||||
@ -101,7 +102,7 @@ public class SysIotModelServiceImpl implements SysIotModelService {
|
||||
}
|
||||
sysIotModel.setUpdatedTime(new Date());
|
||||
sysIotModel.setUpdatedBy(sysUserVo.getAccount());
|
||||
sysIotModel.setIotModelCode(sysIotModelDto.getIotModelCode().toLowerCase());
|
||||
sysIotModel.setIotModelCode(sysIotModelDto.getIotModelCode());
|
||||
sysIotModelMapper.updateById(sysIotModel);
|
||||
SysIotModelVo sysIotModelVo = new SysIotModelVo();
|
||||
BeanCopyUtils.copy(sysIotModel, sysIotModelVo);
|
||||
@ -115,6 +116,7 @@ public class SysIotModelServiceImpl implements SysIotModelService {
|
||||
throw new RuntimeException("该物模型下面有类型,不能删除");
|
||||
}
|
||||
sysIotModelMapper.deleteById(sysIotModelDto.getId());
|
||||
deleteModelCache(sysIotModelDto.getId());
|
||||
|
||||
}
|
||||
|
||||
@ -181,7 +183,7 @@ public class SysIotModelServiceImpl implements SysIotModelService {
|
||||
addModelFieldCache(sysIotModelField);
|
||||
SysIotModelFieldVo sysIotModelFieldVo = new SysIotModelFieldVo();
|
||||
BeanCopyUtils.copy(sysIotModelField, sysIotModelFieldVo);
|
||||
sysIotModelFieldVo.setAttributeCode(sysIotModelFieldDto.getAttributeCode().toLowerCase());
|
||||
sysIotModelFieldVo.setAttributeCode(sysIotModelFieldDto.getAttributeCode());
|
||||
return sysIotModelFieldVo;
|
||||
}
|
||||
|
||||
@ -192,7 +194,7 @@ public class SysIotModelServiceImpl implements SysIotModelService {
|
||||
SysUserVo sysUserVo = (SysUserVo) StpUtil.getTokenSession().get(SessionUtil.SESSION_USER_KEY);
|
||||
sysIotModelField.setUpdatedTime(new Date());
|
||||
sysIotModelField.setUpdatedBy(sysUserVo.getAccount());
|
||||
sysIotModelField.setAttributeCode(sysIotModelFieldDto.getAttributeCode().toLowerCase());
|
||||
sysIotModelField.setAttributeCode(sysIotModelFieldDto.getAttributeCode());
|
||||
if (sysIotModelFieldDto.getAttributeType() == 140) {
|
||||
sysIotModelField.setDataType("tinyint");
|
||||
}
|
||||
@ -255,7 +257,7 @@ public class SysIotModelServiceImpl implements SysIotModelService {
|
||||
sysIotModelServiceMapper.insert(sysIotModelServices);
|
||||
SysIotModelServiceVo sysIotModelServiceVo = new SysIotModelServiceVo();
|
||||
BeanCopyUtils.copy(sysIotModelServices, sysIotModelServiceVo);
|
||||
sysIotModelServiceVo.setServiceCode(sysIotModelServiceDto.getServiceCode().toLowerCase());
|
||||
sysIotModelServiceVo.setServiceCode(sysIotModelServiceDto.getServiceCode());
|
||||
return sysIotModelServiceVo;
|
||||
}
|
||||
|
||||
@ -266,7 +268,7 @@ public class SysIotModelServiceImpl implements SysIotModelService {
|
||||
SysUserVo sysUserVo = (SysUserVo) StpUtil.getTokenSession().get(SessionUtil.SESSION_USER_KEY);
|
||||
sysIotModelServices.setUpdatedTime(new Date());
|
||||
sysIotModelServices.setUpdatedBy(sysUserVo.getAccount());
|
||||
sysIotModelServices.setServiceCode(sysIotModelServiceDto.getServiceCode().toLowerCase());
|
||||
sysIotModelServices.setServiceCode(sysIotModelServiceDto.getServiceCode());
|
||||
|
||||
SysIotModelServiceVo sysIotModelServiceQuery = sysIotModelServiceMapper.selectByServiceCode(sysIotModelServiceDto.getIotModelId(), sysIotModelServiceDto.getServiceCode());
|
||||
if (!(sysIotModelServiceQuery == null)) {
|
||||
@ -360,7 +362,7 @@ public class SysIotModelServiceImpl implements SysIotModelService {
|
||||
for (List<Object> row : list) {
|
||||
// 遍历sheet页中记录,构造需要导入的对象
|
||||
SysIotModelServices services = new SysIotModelServices();
|
||||
services.setServiceCode(row.get(3).toString().toLowerCase());
|
||||
services.setServiceCode(row.get(3).toString());
|
||||
services.setServiceName(row.get(4).toString());
|
||||
services.setServiceType(Integer.valueOf(row.get(5).toString()));
|
||||
services.setPorder(Integer.valueOf(row.get(6).toString()));
|
||||
@ -497,17 +499,20 @@ public class SysIotModelServiceImpl implements SysIotModelService {
|
||||
}
|
||||
|
||||
private static void buildFieldInfo(String iotModelId, List<Object> row, SysIotModelField field) {
|
||||
if (row.get(3).equals("") || row.get(4).equals("") || row.get(5).equals("") || row.get(7).equals("") || row.get(9).equals("") || row.get(11).equals("")) {
|
||||
//参数校验
|
||||
boolean allNotEmpty = ObjectUtil.isAllNotEmpty(row.get(3), row.get(4), row.get(5), row.get(7), row.get(9), row.get(11));
|
||||
if (!allNotEmpty) {
|
||||
throw new ServiceException("字段不可为空,请检查excel文件{}" + row);
|
||||
}
|
||||
field.setAttributeCode(row.get(3).toString().toLowerCase());
|
||||
field.setAttributeCode(row.get(3).toString());
|
||||
field.setAttributeName(row.get(4).toString());
|
||||
field.setAttributeType(Integer.valueOf(row.get(5).toString()));
|
||||
field.setUnit(row.get(6).equals("") ? null : row.get(6).toString());
|
||||
//row6,8,10 转换前校验
|
||||
field.setUnit(ObjectUtil.isEmpty(row.get(6)) ? null : row.get(6).toString());
|
||||
field.setPorder(Integer.valueOf(row.get(7).toString()));
|
||||
field.setSubSystem(row.get(8).equals("") ? null : row.get(8).toString());
|
||||
field.setSubSystem(ObjectUtil.isEmpty(row.get(8)) ? null : row.get(8).toString());
|
||||
field.setDataType(row.get(9).toString());
|
||||
field.setVisible(row.get(10).equals("") ? null : Integer.valueOf(row.get(10).toString()));
|
||||
field.setVisible(ObjectUtil.isEmpty(row.get(10)) ? null : Integer.valueOf(row.get(10).toString()));
|
||||
field.setHighSpeed(Integer.valueOf(row.get(11).toString()));
|
||||
field.setIotModelId(Long.valueOf(iotModelId));
|
||||
}
|
||||
@ -591,11 +596,24 @@ public class SysIotModelServiceImpl implements SysIotModelService {
|
||||
String modelCode = dataService.iotModelMap.get(sysIotModelField.getIotModelId().toString());
|
||||
if (sysIotModelField.getHighSpeed() == 0) {
|
||||
Map<String, Object> map = dataService.lowIotFieldMap.get(modelCode);
|
||||
map.put(sysIotModelField.getAttributeCode(), sysIotModelField.getDataType());
|
||||
if (map == null){
|
||||
Map<String, Object> cacheFieldMap = new HashMap<>();
|
||||
cacheFieldMap.put(sysIotModelField.getAttributeCode(), sysIotModelField.getDataType());
|
||||
dataService.lowIotFieldMap.put(modelCode,cacheFieldMap);
|
||||
}
|
||||
else {
|
||||
map.put(sysIotModelField.getAttributeCode(), sysIotModelField.getDataType());
|
||||
}
|
||||
}
|
||||
if (sysIotModelField.getHighSpeed() == 1) {
|
||||
Map<String, Object> map = dataService.highIotFieldMap.get(modelCode);
|
||||
map.put(sysIotModelField.getAttributeCode(), sysIotModelField.getDataType());
|
||||
if (map == null){
|
||||
Map<String, Object> cacheFieldMap = new HashMap<>();
|
||||
cacheFieldMap.put(sysIotModelField.getAttributeCode(), sysIotModelField.getDataType());
|
||||
dataService.highIotFieldMap.put(modelCode,cacheFieldMap);
|
||||
}else {
|
||||
map.put(sysIotModelField.getAttributeCode(), sysIotModelField.getDataType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -621,4 +639,11 @@ public class SysIotModelServiceImpl implements SysIotModelService {
|
||||
}
|
||||
}
|
||||
|
||||
private void addModelCache(SysIotModel sysIotModel){
|
||||
dataService.iotModelMap.put(sysIotModel.getId().toString(), sysIotModel.getIotModelCode());
|
||||
}
|
||||
|
||||
private void deleteModelCache(Long irn){
|
||||
dataService.iotModelMap.remove(irn.toString());
|
||||
}
|
||||
}
|
||||
|
@ -85,8 +85,8 @@ public class SysNodeController {
|
||||
|
||||
/** 配置下发 */
|
||||
@PostMapping("/configUpdate")
|
||||
public R<?> configUpdate() {
|
||||
dataService.sendTerminalConfig(Long.valueOf(1));
|
||||
public R<?> configUpdate(@RequestBody SysNodeDto sysNodeDto) {
|
||||
dataService.sendTerminalConfig(sysNodeDto.getId());
|
||||
return R.success();
|
||||
}
|
||||
|
||||
|
@ -462,7 +462,7 @@ public class TDEngineService {
|
||||
List<Long> timeList = new ArrayList<>();
|
||||
timeList.add(rs.getTimestamp(1).getTime());
|
||||
List<Object> valueList = new ArrayList<>();
|
||||
valueList.add(rs.getObject(fieldList.get(i)));
|
||||
valueList.add(rs.getObject(fieldList.get(i).toLowerCase()));
|
||||
map.put("times",timeList);
|
||||
map.put("values",valueList);
|
||||
valueMap.put(fieldList.get(i),map);
|
||||
@ -471,7 +471,7 @@ public class TDEngineService {
|
||||
List<Long> times = (List<Long>) map.get("times");
|
||||
List<Object> values = (List<Object>) map.get("values");
|
||||
times.add(rs.getTimestamp(1).getTime());
|
||||
values.add(rs.getObject(fieldList.get(i)));
|
||||
values.add(rs.getObject(fieldList.get(i).toLowerCase()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,49 @@
|
||||
package com.das.modules.page.controller;
|
||||
|
||||
import com.das.common.result.R;
|
||||
import com.das.modules.page.domian.HomeWindFarmRealDataVo;
|
||||
import com.das.modules.page.domian.HomeWindTurbineMatrixDataVoVo;
|
||||
import com.das.modules.page.domian.dto.WindFarmRealDataDto;
|
||||
import com.das.modules.page.service.HomeService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 首页相关Controller
|
||||
*/
|
||||
@Slf4j
|
||||
@RequestMapping("/api/home")
|
||||
@RestController
|
||||
public class HomeController {
|
||||
|
||||
@Autowired
|
||||
private HomeService homeService;
|
||||
|
||||
/**
|
||||
* 首页风机矩阵数据
|
||||
* @return 风机矩阵数据
|
||||
*/
|
||||
@PostMapping("/getWindTurbineMatrixData")
|
||||
public R<List<HomeWindTurbineMatrixDataVoVo>> getWindTurbineMatrixData() {
|
||||
return R.success(homeService.getWindTurbineMatrixData());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取风电场的实时数据
|
||||
* @param windFarmRealDataDto
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/getWindFarmRealData")
|
||||
public R<HomeWindFarmRealDataVo> getWindFarmRealData(@RequestBody WindFarmRealDataDto windFarmRealDataDto) {
|
||||
return R.success(homeService.getWindFarmRealData(windFarmRealDataDto));
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.das.modules.page.domian;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class HomeWindFarmRealDataVo {
|
||||
|
||||
/**
|
||||
* 风电场id
|
||||
*/
|
||||
private Long windFarmId;
|
||||
|
||||
private Map<String,Object> attributeMap;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.das.modules.page.domian;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 首页风机矩阵
|
||||
*/
|
||||
@Data
|
||||
public class HomeWindTurbineMatrixDataVoVo {
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long irn;
|
||||
|
||||
private String name;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long modelId;
|
||||
|
||||
private String model;
|
||||
|
||||
private String belongLine;
|
||||
|
||||
/**
|
||||
* 是否为标杆机组
|
||||
*/
|
||||
private Integer standard;
|
||||
|
||||
/**
|
||||
* 额定容量
|
||||
*/
|
||||
private Double nominalCapacity;
|
||||
|
||||
private Map<String,Object> attributeMap;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.das.modules.page.domian.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class WindFarmRealDataDto implements Serializable {
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 风场id
|
||||
*/
|
||||
private Long windFarmId;
|
||||
|
||||
/**
|
||||
* 风场名称
|
||||
*/
|
||||
private String WindFarmName;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.das.modules.page.service;
|
||||
|
||||
import com.das.modules.page.domian.HomeWindFarmRealDataVo;
|
||||
import com.das.modules.page.domian.HomeWindTurbineMatrixDataVoVo;
|
||||
import com.das.modules.page.domian.dto.WindFarmRealDataDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface HomeService {
|
||||
/**
|
||||
* 接口1: 首页风机矩阵数据
|
||||
* @return 风机矩阵数据
|
||||
*/
|
||||
List<HomeWindTurbineMatrixDataVoVo> getWindTurbineMatrixData();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 接口2: 获取风电场的实时数据
|
||||
* @param windFarmRealDataDto
|
||||
* @return 页面左上角【风场概况】,页面右上角【发电量概况】
|
||||
*/
|
||||
HomeWindFarmRealDataVo getWindFarmRealData(WindFarmRealDataDto windFarmRealDataDto);
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
package com.das.modules.page.service.impl;
|
||||
|
||||
|
||||
import com.das.common.constant.EquipmentTypeIds;
|
||||
import com.das.modules.data.domain.SnapshotValueQueryParam;
|
||||
import com.das.modules.data.service.DataService;
|
||||
import com.das.modules.equipment.domain.dto.SysEquipmentDto;
|
||||
import com.das.modules.equipment.domain.vo.SysEquipmentVo;
|
||||
import com.das.modules.equipment.mapper.SysEquipmentMapper;
|
||||
import com.das.modules.page.domian.HomeWindFarmRealDataVo;
|
||||
import com.das.modules.page.domian.HomeWindTurbineMatrixDataVoVo;
|
||||
import com.das.modules.page.domian.dto.WindFarmRealDataDto;
|
||||
import com.das.modules.page.service.HomeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class HomeServiceImpl implements HomeService {
|
||||
|
||||
@Autowired
|
||||
SysEquipmentMapper sysEquipmentMapper;
|
||||
|
||||
@Autowired
|
||||
private DataService dataService;
|
||||
|
||||
|
||||
/**
|
||||
* 接口1: 首页风机矩阵数据
|
||||
*
|
||||
* @return 风机矩阵数据
|
||||
*/
|
||||
@Override
|
||||
public List<HomeWindTurbineMatrixDataVoVo> getWindTurbineMatrixData() {
|
||||
SysEquipmentDto sysEquipmentDto = new SysEquipmentDto();
|
||||
sysEquipmentDto.setObjectType(EquipmentTypeIds.EQUIPMENT_TYPE_STATION_WTG);
|
||||
//获取所有风机设备
|
||||
List<SysEquipmentVo> sysEquipmentVos = sysEquipmentMapper.querySysEquipmentList(sysEquipmentDto);
|
||||
//风机返回数据列表
|
||||
List<HomeWindTurbineMatrixDataVoVo> homeWindRealTimeVoList = new ArrayList<>();
|
||||
List<SnapshotValueQueryParam> paramList = new ArrayList<>();
|
||||
//构建需要查询的物模型属 性
|
||||
List<String> attributesList = new ArrayList<>();
|
||||
//风速
|
||||
attributesList.add("iwindspeed");
|
||||
|
||||
//风机状态判断条件所需的字段iturbineoperationmode、iYPLevel、GridLostDetected(可能会调整)
|
||||
//风机状态
|
||||
attributesList.add("iturbineoperationmode");
|
||||
//偏航运行模式
|
||||
attributesList.add("iYPLevel");
|
||||
//风机电网掉电
|
||||
attributesList.add("GridLostDetected");
|
||||
|
||||
//有功功率(MW)
|
||||
attributesList.add("igenpower");
|
||||
//当天可利用率
|
||||
//attributesList.add("iavailabillitytoday");
|
||||
//日发电量(kwh)
|
||||
attributesList.add("ikwhthisday");
|
||||
//总发电量(万kwh)
|
||||
//attributesList.add("ikwhoverall");
|
||||
for (SysEquipmentVo item : sysEquipmentVos) {
|
||||
//构建查询属性参数
|
||||
SnapshotValueQueryParam snapshotValueQueryParam = new SnapshotValueQueryParam();
|
||||
snapshotValueQueryParam.setAttributes(attributesList);
|
||||
snapshotValueQueryParam.setDeviceId(item.getId().toString());
|
||||
paramList.add(snapshotValueQueryParam);
|
||||
//构建风机数据返回
|
||||
HomeWindTurbineMatrixDataVoVo homeWindRealTimeVoResult = new HomeWindTurbineMatrixDataVoVo();
|
||||
homeWindRealTimeVoResult.setIrn(item.getId());
|
||||
homeWindRealTimeVoResult.setName(item.getName());
|
||||
homeWindRealTimeVoResult.setModel(item.getModel());
|
||||
homeWindRealTimeVoResult.setModelId(item.getIotModelId());
|
||||
homeWindRealTimeVoResult.setBelongLine(item.getBelongLine());
|
||||
homeWindRealTimeVoResult.setStandard(item.getStandard());
|
||||
homeWindRealTimeVoResult.setNominalCapacity(item.getNominalCapacity());
|
||||
homeWindRealTimeVoList.add(homeWindRealTimeVoResult);
|
||||
}
|
||||
//获取设备测点数据
|
||||
Map<String, Map<String, Object>> map = dataService.querySnapshotValues(paramList);
|
||||
for (HomeWindTurbineMatrixDataVoVo item : homeWindRealTimeVoList) {
|
||||
item.setAttributeMap(map.get(item.getIrn().toString()));
|
||||
}
|
||||
return homeWindRealTimeVoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 接口2: 获取风电场的实时数据
|
||||
* @param windFarmRealDataDto
|
||||
* @return 页面左上角【风场概况】,页面右上角【发电量概况】
|
||||
*/
|
||||
@Override
|
||||
public HomeWindFarmRealDataVo getWindFarmRealData(WindFarmRealDataDto windFarmRealDataDto) {
|
||||
Long windFarmId = windFarmRealDataDto.getWindFarmId();
|
||||
//查询数据库中风电场设备,取第一个风电场
|
||||
if (windFarmId == null) {
|
||||
SysEquipmentDto sysEquipmentDto = new SysEquipmentDto();
|
||||
sysEquipmentDto.setObjectType(EquipmentTypeIds.EQUIPMENT_TYPE_WIND_FARM);
|
||||
SysEquipmentVo sysEquipmentVo1 = sysEquipmentMapper.queryWindFarm(sysEquipmentDto);
|
||||
windFarmId = sysEquipmentVo1.getId();
|
||||
}
|
||||
List<SnapshotValueQueryParam> paramList = new ArrayList<>();
|
||||
//构建需要查询的物模型属 性
|
||||
List<String> attributesList = new ArrayList<>();
|
||||
//功率
|
||||
attributesList.add("windfarmactivepower");
|
||||
//平均风速
|
||||
attributesList.add("windfarmavgwindspeed");
|
||||
//日利用小时
|
||||
attributesList.add("windfarmdayoperationhours");
|
||||
//月利用小时
|
||||
attributesList.add("windfarmmonthoperationhours");
|
||||
//日发电量
|
||||
attributesList.add("windfarmdayprodenergy");
|
||||
//月发电量
|
||||
attributesList.add("windfarmmonthprodenergy");
|
||||
//年发电量
|
||||
attributesList.add("windfarmyearprodenergy");
|
||||
//总发电量
|
||||
attributesList.add("windfarmtotalprodenergy");
|
||||
//构建查询属性参数
|
||||
SnapshotValueQueryParam snapshotValueQueryParam = new SnapshotValueQueryParam();
|
||||
snapshotValueQueryParam.setAttributes(attributesList);
|
||||
snapshotValueQueryParam.setDeviceId(windFarmId.toString());
|
||||
paramList.add(snapshotValueQueryParam);
|
||||
//获取设备测点数据
|
||||
Map<String, Map<String, Object>> map = dataService.querySnapshotValues(paramList);
|
||||
HomeWindFarmRealDataVo homeWindFarmRealDataVo = new HomeWindFarmRealDataVo();
|
||||
homeWindFarmRealDataVo.setWindFarmId(windFarmId);
|
||||
if (map !=null){
|
||||
homeWindFarmRealDataVo.setAttributeMap(map.get(windFarmId.toString()));
|
||||
}
|
||||
return homeWindFarmRealDataVo;
|
||||
}
|
||||
}
|
@ -141,5 +141,33 @@
|
||||
select se.id as irn,se.name,se.model,se.belong_line as belongLine, se.iot_model_id as modelId from sys_equipment se where se.object_type = #{objectType} order by se.name
|
||||
</select>
|
||||
|
||||
<select id="queryWindFarm" resultMap="SysEquipmentMap">
|
||||
select t.* from sys_equipment t
|
||||
<where>
|
||||
<if test="info.iotModelId != null and info.iotModelId != ''">
|
||||
and t.iot_model_id = #{info.iotModelId}
|
||||
</if>
|
||||
<if test="info.orgId != null and info.orgId != ''">
|
||||
and t.org_id = #{info.orgId}
|
||||
</if>
|
||||
<if test="info.parentEquipmentId != null and info.parentEquipmentId != ''">
|
||||
and t.parent_equipment_id = #{info.parentEquipmentId}
|
||||
</if>
|
||||
<if test="info.name != null and info.name != ''">
|
||||
and t.name like concat('%',#{info.name},'%')
|
||||
</if>
|
||||
<if test="info.code != null and info.code != ''">
|
||||
and t.code like concat('%',#{info.code},'%')
|
||||
</if>
|
||||
<if test="info.objectType != null and info.objectType != ''">
|
||||
and t.object_type = #{info.objectType}
|
||||
</if>
|
||||
<if test="info.id != null and info.id != ''">
|
||||
and t.id = #{info.id}
|
||||
</if>
|
||||
</where>
|
||||
order by t.name
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
@ -25,13 +25,12 @@
|
||||
<if test="info.attributeCode != null and info.attributeCode != ''">
|
||||
and t.attribute_code like concat('%',#{info.attributeCode},'%')
|
||||
</if>
|
||||
<if test="info.orderColumn != null and info.orderType != ''">
|
||||
order by ${info.orderColumn} ${info.orderType}
|
||||
</if>
|
||||
<if test="info.attributeType != null and info.attributeType != ''">
|
||||
and t.attribute_type = #{info.attributeType}
|
||||
</if>
|
||||
|
||||
<if test="info.orderColumn != null and info.orderType != ''">
|
||||
order by ${info.orderColumn} ${info.orderType}
|
||||
</if>
|
||||
<if test="info.orderColumn == null or info.orderColumn == '' or info.orderType == null or info.orderType == ''">
|
||||
order by t.porder asc
|
||||
</if>
|
||||
|
37
ui/dasadmin/src/api/backend/statAnalysis/request.ts
Normal file
37
ui/dasadmin/src/api/backend/statAnalysis/request.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import createAxios from '/@/utils/axios'
|
||||
|
||||
export const queryWindTurbinesPages = () => {
|
||||
return createAxios({
|
||||
url: '/api/page/turbines/queryWindTurbinesPages',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
export const historyReq = (data: {
|
||||
devices: {
|
||||
deviceId: string
|
||||
attributes: string
|
||||
}
|
||||
startTime: string
|
||||
endTime: string
|
||||
}) => {
|
||||
return createAxios({
|
||||
url: '/api/data/history',
|
||||
method: 'post',
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
export const runAirBlowerReq = (
|
||||
data: {
|
||||
deviceId: string
|
||||
serviceName: string
|
||||
opValue: 1 | 0
|
||||
}[]
|
||||
) => {
|
||||
return createAxios({
|
||||
url: '/api/page/turbines/windTurbinesControl',
|
||||
method: 'post',
|
||||
data: data,
|
||||
})
|
||||
}
|
15
ui/dasadmin/src/lang/common/zh-cn/statAnalysis.ts
Normal file
15
ui/dasadmin/src/lang/common/zh-cn/statAnalysis.ts
Normal file
@ -0,0 +1,15 @@
|
||||
export default {
|
||||
PowerCurveAnalysis: '功率曲线分析',
|
||||
trendAnalysis: '趋势分析',
|
||||
trendComparison: '趋势对比',
|
||||
deviceId: '风机',
|
||||
attributes: '测点名称',
|
||||
interval: '间隔',
|
||||
search: '查询',
|
||||
import: '下载',
|
||||
export: '导出',
|
||||
time: '时间',
|
||||
max: '最大值',
|
||||
min: '最小值',
|
||||
average: '平均值',
|
||||
}
|
@ -70,18 +70,30 @@ import { ElMessage, TableInstance, TreeInstance } from 'element-plus'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { AlarmsFieldsEnums, AlarmsTableType, GetAlarmsTableParam } from './type'
|
||||
import { getAlarmListReq } from '/@/api/backend/alarms/request'
|
||||
import { equipList } from '/@/api/backend/realData/request.ts'
|
||||
import { debounce, cloneDeep } from 'lodash'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { t } = useI18n()
|
||||
import { useAdminInfo } from '/@/stores/adminInfo'
|
||||
const adminInfo = useAdminInfo()
|
||||
|
||||
// 告警时间
|
||||
|
||||
const timeRange = ref([])
|
||||
const shortcuts = [
|
||||
{
|
||||
text: '今天',
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '昨天',
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
end.setDate(end.getDate() - 1)
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 1)
|
||||
return [start, end]
|
||||
@ -92,36 +104,27 @@ const shortcuts = [
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 3)
|
||||
start.setDate(start.getDate() - 2)
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '上周',
|
||||
text: '本周',
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 7)
|
||||
return [start, end]
|
||||
return getDateRange('week')
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '上个月',
|
||||
text: '本月',
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setMonth(start.getMonth() - 1)
|
||||
return [start, end]
|
||||
return getDateRange('month')
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
// 风机编号
|
||||
const airBlowerNumberValue = ref('')
|
||||
const airBlowerList = ref([
|
||||
{ label: 'sc-001', value: '001' },
|
||||
{ label: 'sc-001', value: '002' },
|
||||
])
|
||||
const airBlowerList = ref([{ label: '', value: '' }])
|
||||
// 类别
|
||||
const alarmTypeValue = ref('')
|
||||
const alarmTypes = ref([
|
||||
@ -147,9 +150,9 @@ const alarmsTableData = ref<AlarmsTableType[]>([])
|
||||
// 告警列表
|
||||
const paginationOptions = reactive({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
pageSizes: [10, 20, 30],
|
||||
pageSizes: [20, 50, 100],
|
||||
})
|
||||
const getcurrentPage = () => {
|
||||
getalarmsList()
|
||||
@ -201,27 +204,41 @@ const okSubmit = (val) => {
|
||||
console.log(val)
|
||||
getalarmsList()
|
||||
}
|
||||
const getTodayAndYesterday = () => {
|
||||
const getDateRange = (type: 'week' | 'month') => {
|
||||
const today = new Date()
|
||||
const yesterday = new Date()
|
||||
yesterday.setDate(today.getDate() - 1)
|
||||
const formatDate = (date) => {
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
return `${year}-${month}-${day}`
|
||||
if (type === 'week') {
|
||||
const dayOfWeek = today.getDay()
|
||||
const startOfWeek = new Date(today)
|
||||
startOfWeek.setDate(today.getDate() - dayOfWeek + (dayOfWeek === 0 ? -6 : 1))
|
||||
startOfWeek.setHours(0, 0, 0, 0)
|
||||
const endOfWeek = new Date(startOfWeek)
|
||||
endOfWeek.setDate(startOfWeek.getDate() + 6)
|
||||
endOfWeek.setHours(23, 59, 59, 999)
|
||||
return [startOfWeek, endOfWeek]
|
||||
}
|
||||
|
||||
return {
|
||||
today: formatDate(today),
|
||||
yesterday: formatDate(yesterday),
|
||||
if (type === 'month') {
|
||||
const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1)
|
||||
startOfMonth.setHours(0, 0, 0, 0)
|
||||
const endOfMonth = new Date(today.getFullYear(), today.getMonth() + 1, 0)
|
||||
endOfMonth.setHours(23, 59, 59, 999)
|
||||
return [startOfMonth, endOfMonth]
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
console.log(getTodayAndYesterday(), 999)
|
||||
|
||||
// timeRange[0] = getTodayAndYesterday().yesterday
|
||||
// timeRange[1] = getTodayAndYesterday().today
|
||||
onMounted(() => {
|
||||
equipList({
|
||||
// orgId: adminInfo.orgid,
|
||||
objectType: 10002,
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
airBlowerList.value = res.data.map((item) => {
|
||||
return {
|
||||
label: item.code,
|
||||
value: item.id,
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
getalarmsList()
|
||||
})
|
||||
</script>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<div class="transferLeft">
|
||||
<div class="transferHeader">
|
||||
<span class="transferTitle">可添加的测点</span>
|
||||
<el-radio-group v-model="radioActiveName" @change="handleradioClose">
|
||||
<el-radio-group v-model="radioActiveName" @change="handleradioChange">
|
||||
<el-radio value="138">模拟量</el-radio>
|
||||
<el-radio value="140">状态量</el-radio>
|
||||
</el-radio-group>
|
||||
@ -16,21 +16,24 @@
|
||||
<el-table class="tablePart"
|
||||
ref="tableRef"
|
||||
:data="modalTbleData"
|
||||
@selectionChange="selectTable">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="attributeCode" label="名称" />
|
||||
<el-table-column prop="attributeName" label="描述" />
|
||||
@selectionChange="selectTable"
|
||||
:row-key="getRowKey">
|
||||
<el-table-column type="selection" width="55" :reserve-selection="true"/>
|
||||
<el-table-column prop="porder" label="序号" width="60" />
|
||||
<el-table-column prop="attributeCode" sortable label="名称" />
|
||||
<el-table-column prop="attributeName" sortable label="描述" />
|
||||
</el-table>
|
||||
<div class="mainFooter" style="display: flex; justify-content: left">
|
||||
<el-pagination
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="currentPageSize"
|
||||
:total="pageTotal"
|
||||
:page-sizes="pagePagination"
|
||||
background
|
||||
:pager-count="6"
|
||||
:pager-count="5"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
layout="prev, pager, next"
|
||||
layout="prev, pager, next,sizes"
|
||||
></el-pagination>
|
||||
</div>
|
||||
</el-main>
|
||||
@ -83,7 +86,7 @@
|
||||
<div class="realConter">
|
||||
<div class="header">
|
||||
<el-button type="primary" :icon="Crop" class="defaultBtn" @click="openMeasure">测点选择</el-button>
|
||||
<el-button style="color: rgb(0, 100, 170);;" :icon="Download" class="defaultBtn" @click="downFun(tableColumn,tableDatadown)">数据导出</el-button>
|
||||
<el-button style="color: rgb(0, 100, 170);;" :icon="Download" class="defaultBtn" @click="downFun(tableColumn,tableData)">数据导出</el-button>
|
||||
<div class="selectPart">
|
||||
<span>自动更新:</span>
|
||||
<el-switch
|
||||
@ -109,21 +112,80 @@ import {Crop,Download,Top,Bottom} from '@element-plus/icons-vue'
|
||||
import {onMounted, onUnmounted, reactive, ref, watch,computed} from 'vue'
|
||||
import {ElMessage} from 'element-plus'
|
||||
import {equipList,getModelAttributeList,getsnapshotData} from "/@/api/backend/realData/request.ts";
|
||||
import * as console from "console";
|
||||
|
||||
const tableData = ref()
|
||||
const tableItem0: any = {
|
||||
label: '风机列表',
|
||||
prop: 'code',
|
||||
align: 'center',
|
||||
}
|
||||
const tableColumn=ref([
|
||||
{ ...tableItem0 }
|
||||
])
|
||||
const tableDownData=ref()
|
||||
const tableItem0: any = [
|
||||
{
|
||||
label: '风机列表',
|
||||
prop: 'code',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
label: '风速 (m/s)',
|
||||
prop: 'iwindspeed',
|
||||
align: 'center',
|
||||
custom: 'header',
|
||||
},
|
||||
{
|
||||
label: '有功功率 (MW)',
|
||||
prop: 'igenpower',
|
||||
align: 'center',
|
||||
custom: 'header',
|
||||
},
|
||||
{
|
||||
label: '日发电量 (kWh)',
|
||||
prop: 'ikwhthisday',
|
||||
align: 'center',
|
||||
custom: 'header',
|
||||
},
|
||||
{
|
||||
label: '总发电量 (万kWh)',
|
||||
prop: 'ikwhoverall',
|
||||
align: 'center',
|
||||
custom: 'header',
|
||||
},
|
||||
{
|
||||
label: '机舱角度',
|
||||
prop: 'ivanedirection',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
label: '叶轮转速 (rmp)',
|
||||
prop: 'irotorspeed',
|
||||
align: 'center',
|
||||
custom: 'header',
|
||||
},
|
||||
{
|
||||
label: '发电机转速 (rmp)',
|
||||
prop: 'igenspeed',
|
||||
align: 'center',
|
||||
custom: 'header',
|
||||
},
|
||||
{
|
||||
label: '机舱温度 (℃)',
|
||||
prop: 'itempnacelle_1sec',
|
||||
align: 'center',
|
||||
custom: 'header',
|
||||
},
|
||||
{
|
||||
label: '主油路压力 (kpa)',
|
||||
prop: 'ihydrpress',
|
||||
align: 'center',
|
||||
custom: 'header',
|
||||
},
|
||||
{
|
||||
label: '变桨角度',
|
||||
prop: 'ipitchangle',
|
||||
align: 'center',
|
||||
}
|
||||
]
|
||||
const tableColumn=ref(
|
||||
tableItem0
|
||||
)
|
||||
|
||||
const deviceList = ref()
|
||||
const tableList=ref()
|
||||
var modalTbleData=ref()
|
||||
const modalTbleData=ref<any[]>([])
|
||||
const devicelistData = reactive({
|
||||
objectType: 10002,
|
||||
})
|
||||
@ -136,15 +198,45 @@ const deviceQuery = (data: any) => {
|
||||
deviceList.value = res.data
|
||||
tableData.value = res.data
|
||||
iotModelId.value=res.data[0].iotModelId
|
||||
tableList.value = res.data
|
||||
const deviceId=deviceList.value.map((item) => item.id);
|
||||
deviceId.forEach((item,index) => {
|
||||
objparms.deviceId=item
|
||||
objparms.attributes=tableColumn.value.map((item1)=>item1.prop)
|
||||
snapshotParms.push({...objparms})
|
||||
})
|
||||
getsnapshotData(snapshotParms).then((res) => {
|
||||
if (res.code == 200) {
|
||||
const tsnapshotVoObject: any = res.data;
|
||||
const tsnapshotVoMap = new Map(Object.entries(tsnapshotVoObject));
|
||||
const updatedTableData = tableColumn.value.reduce((acc, item1) => {
|
||||
acc.forEach((item, i) => {
|
||||
const itemKey = item.id;
|
||||
if (tsnapshotVoMap.has(itemKey)) {
|
||||
const tsnapshotVoItem = tsnapshotVoMap.get(itemKey);
|
||||
//const attributeCodeLower = item1.attributeCode?.toLowerCase();
|
||||
const attributeCodeLower = item1.prop;
|
||||
if(attributeCodeLower!='code'){
|
||||
if (attributeCodeLower) {
|
||||
const value = tsnapshotVoItem[attributeCodeLower];
|
||||
const formattedValue = value !== undefined ? (value % 1 === 0 ? value : value.toFixed(3)) : '-';
|
||||
acc[i] = { ...item, [attributeCodeLower]: formattedValue };
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
return acc;
|
||||
}, [...tableData.value]);
|
||||
tableData.value = updatedTableData;
|
||||
} else {
|
||||
ElMessage.error({
|
||||
message: res.msg,
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
/*const filteredItems = computed(() => {
|
||||
return tableList.value.map(item => ({
|
||||
code: item.code
|
||||
}));
|
||||
});*/
|
||||
|
||||
|
||||
const queryListData = reactive({
|
||||
pageSize: 20,
|
||||
@ -166,7 +258,7 @@ const modelAttributeList=(data: any) =>{
|
||||
})
|
||||
}
|
||||
|
||||
const Statistic=ref(0)
|
||||
|
||||
|
||||
interface TableType {
|
||||
attributeCode:string
|
||||
@ -183,12 +275,26 @@ interface TableType {
|
||||
visible:number | null
|
||||
|
||||
}
|
||||
|
||||
const tableRef=ref()
|
||||
const multipleSelection = ref<TableType[]>([])
|
||||
const selectTable = (selected: TableType[]) => {
|
||||
Statistic.value=selected.length
|
||||
multipleSelection.value =selected
|
||||
selectpageTotal.value=selected.length
|
||||
const Statistic = computed(() => multipleSelection.value.length)
|
||||
const selectTable = (selected: TableType[] | null) => {
|
||||
if (!selected) {
|
||||
console.error('Selected is null or undefined')
|
||||
return
|
||||
}
|
||||
multipleSelection.value = selected
|
||||
}
|
||||
const getRowKey = (row) => row.id;
|
||||
const visible = ref(false)
|
||||
const openMeasure=() =>{
|
||||
visible.value=true
|
||||
queryListData.iotModelId=iotModelId.value
|
||||
queryListData.attributeType=radioActiveName.value
|
||||
modelAttributeList(queryListData)
|
||||
}
|
||||
|
||||
const moveUp = (index:number) => {
|
||||
if (index > 0) {
|
||||
const temp = multipleSelection.value[index];
|
||||
@ -209,12 +315,13 @@ const moveDown = (index:number) => {
|
||||
const clearList=() => {
|
||||
Statistic.value=0
|
||||
multipleSelection.value = [];
|
||||
tableRef.value.clearSelection()
|
||||
queryListData.iotModelId=iotModelId.value
|
||||
queryListData.attributeType=radioActiveName.value
|
||||
modelAttributeList(queryListData)
|
||||
}
|
||||
const handleradioClose=() => {
|
||||
multipleSelection.value = [];
|
||||
const handleradioChange=() => {
|
||||
//multipleSelection.value = [];
|
||||
queryListData.iotModelId=iotModelId.value
|
||||
queryListData.attributeType=radioActiveName.value
|
||||
modelAttributeList(queryListData)
|
||||
@ -226,6 +333,7 @@ watch(autoUpdate, (newVal: boolean) => {
|
||||
if (autoUpdateInterval.value) return
|
||||
ElMessage.success('开启自动刷新')
|
||||
autoUpdateInterval.value = setInterval(() => {
|
||||
deviceQuery(devicelistData)
|
||||
getTableData()
|
||||
}, 2000)
|
||||
} else {
|
||||
@ -238,6 +346,7 @@ watch(autoUpdate, (newVal: boolean) => {
|
||||
const currentPage = ref(1)
|
||||
const currentPageSize = ref(20)
|
||||
const pageTotal = ref(0)
|
||||
const pagePagination = ref([20, 50, 100])
|
||||
const handleSizeChange = (val: number) => {
|
||||
queryListData.pageSize = val
|
||||
queryListData.iotModelId=iotModelId.value
|
||||
@ -265,13 +374,7 @@ const selecthandleCurrentChange = (val: number) => {
|
||||
modelAttributeList(queryListData)*/
|
||||
}
|
||||
|
||||
const visible = ref(false)
|
||||
const openMeasure=() =>{
|
||||
visible.value=true
|
||||
queryListData.iotModelId=iotModelId.value
|
||||
queryListData.attributeType=radioActiveName.value
|
||||
modelAttributeList(queryListData)
|
||||
}
|
||||
|
||||
|
||||
const handleClose = (done: () => void) => {
|
||||
visible.value = false
|
||||
@ -284,18 +387,41 @@ const objparms = reactive({
|
||||
})
|
||||
|
||||
|
||||
const tableDatadown=ref()
|
||||
const getTableData = () => {
|
||||
const deviceId=deviceList.value.map((item) => item.id);
|
||||
let tableColumnEnds: any = [];
|
||||
multipleSelection.value.map((item) => {
|
||||
tableColumnEnds.push({
|
||||
label: item.attributeName,
|
||||
prop: item.attributeCode.toLowerCase(),
|
||||
align: 'center',
|
||||
})
|
||||
})
|
||||
tableColumn.value = [ { ...tableItem0}, ...tableColumnEnds ];
|
||||
const tableColumnEnds = ref([]);
|
||||
const tableColumnup = ref([]);
|
||||
const tableColumnMap = new Map();
|
||||
tableColumn.value.forEach(item1 => {
|
||||
if (item1.prop) {
|
||||
tableColumnMap.set(item1.prop, item1);
|
||||
tableColumnup.value.push({
|
||||
label: item1.label,
|
||||
prop: item1.prop,
|
||||
align: 'center',
|
||||
});
|
||||
}
|
||||
});
|
||||
if(multipleSelection.value.length === 0){
|
||||
tableColumn.value = [...tableItem0, ...tableColumnEnds.value];
|
||||
}else{
|
||||
multipleSelection.value.forEach(item => {
|
||||
if (item.attributeCode) {
|
||||
const attributeCodeLower = item.attributeCode.toLowerCase();
|
||||
if (!tableColumnMap.has(attributeCodeLower)) {
|
||||
tableColumnEnds.value.push({
|
||||
label: item.attributeName+'\n'+item.unit,
|
||||
prop: attributeCodeLower,
|
||||
align: 'center',
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
tableColumn.value = [...tableColumnup.value, ...tableColumnEnds.value];
|
||||
}
|
||||
|
||||
|
||||
//tableColumn.value = [...tableItem0, ...tableColumnEnds.value];
|
||||
deviceId.forEach((item,index) => {
|
||||
objparms.deviceId=item
|
||||
objparms.attributes=multipleSelection.value.map((item) => item.attributeCode)
|
||||
@ -306,25 +432,12 @@ const getTableData = () => {
|
||||
const tsnapshotVoObject: any = res.data;
|
||||
multipleSelection.value.map((item1: any) => {
|
||||
tableData.value.forEach((item: any, i: number, arr: any) => {
|
||||
debugger
|
||||
for (const itemKey in tsnapshotVoObject) {
|
||||
if (item.id === itemKey) {
|
||||
const attributeCodeLower = item1.attributeCode?.toLowerCase();
|
||||
const value = tsnapshotVoObject[itemKey]?.[attributeCodeLower];
|
||||
const formattedValue =value ? (value % 1 === 0 ? value : value.toFixed(3)) : '-';
|
||||
const { code } = item;
|
||||
arr[i] = { ...item, [attributeCodeLower]: formattedValue };
|
||||
/*tableList.value.map(item => ({
|
||||
code: item.code,
|
||||
[attributeCodeLower]:formattedValue
|
||||
}));*/
|
||||
// tableList.value.forEach((item2: any, j: number, arr2: any) => {
|
||||
// return{
|
||||
// code: item2.code,
|
||||
// [attributeCodeLower]:formattedValue
|
||||
// }
|
||||
// })
|
||||
//tableDatadown.value=tableList.value
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -342,125 +455,45 @@ const sureBtn = (done: () => void) => {
|
||||
getTableData()
|
||||
visible.value = false
|
||||
}
|
||||
const transferred = (data:any) => {
|
||||
return data.replace(/<br>/g, "\r\n").replace(/>/g, ">");
|
||||
}
|
||||
/*const downFun=(tableColumn,tableData)=>{
|
||||
debugger
|
||||
const downFun=(tableColumn,tableData)=>{
|
||||
const itemsWithoutAge = tableData.map(item => {
|
||||
const { id, belongLine, iotModelId, location,madeinFactory,model,name,nominalCapacity,objectType,parentEquipmentId,remarks,standard,...rest } = item;
|
||||
return rest;
|
||||
});
|
||||
let addobj = {}
|
||||
// 2.1获取表头内容 以rowData形式重新赋值
|
||||
try {
|
||||
tableColumn.map((v, i) => {
|
||||
//addobj['rowData' + i] = v.prop
|
||||
addobj['rowData' + i] = v.label
|
||||
})
|
||||
} catch (error) {
|
||||
ElMessage.error('请填写tableLable表头属性')
|
||||
return
|
||||
}
|
||||
/!*if(tableData.length == 0) {
|
||||
ElMessage.error('请填写tableData表格数据属性')
|
||||
return
|
||||
}*!/
|
||||
// 2.2用JSON转义清理对象的内存地址关联 来获取表格数据
|
||||
let tableDatadown = JSON.parse(JSON.stringify(tableData))
|
||||
// 2.3把表头添加到表格数据的最前面充当表头
|
||||
tableColumn.map((v, i) => {
|
||||
addobj['rowData' + i] = v.label
|
||||
})
|
||||
let tableDatadown = JSON.parse(JSON.stringify(itemsWithoutAge))
|
||||
tableDatadown.unshift(addobj)
|
||||
/!*if (tableDatadown.length === 0) {
|
||||
return '';
|
||||
}
|
||||
let lines = [];*!/
|
||||
// 2.4列标题,逗号隔开,每一个逗号就是隔开一个单元格
|
||||
let str = ``;
|
||||
/!* for (let i = 0; i < tableDatadown.length; i++) {
|
||||
let row = [];
|
||||
for (let item in tableDatadown[i]) {
|
||||
let value = tableDatadown[i][item];
|
||||
if (typeof value === 'string') {
|
||||
value = value.replace(/\n/g, ' ').replace(/,/g, ',');
|
||||
} else {
|
||||
value = String(value).replace(/\n/g, ' ').replace(/,/g, ',');
|
||||
}
|
||||
row.push(value);
|
||||
}
|
||||
lines.push(row.join('\t'));
|
||||
}
|
||||
|
||||
let str = lines.join('\n');*!/
|
||||
// 2.5增加\t为了不让表格显示科学计数法或者其他格式
|
||||
for(let i = 0; i < tableDatadown.length; i++) {
|
||||
for(let item in tableDatadown[i]) {
|
||||
// 2.5.1 注意要将本身就有换行或者英文逗号的内容进行变换 否则表格内容会错乱
|
||||
//tableDatadown[i][item] = tableDatadown[i][item].replace(/\n/g, ' ')
|
||||
//tableDatadown[i][item] = tableDatadown[i][item].replace(/,/g, ',') // 英文替换为中文
|
||||
if (typeof tableDatadown[i][item] === 'string') {
|
||||
tableDatadown[i][item] = tableDatadown[i][item].replace(/[\n,]/g, match => match === '\n' ? ' ' : ',');
|
||||
} else {
|
||||
console.warn(`tableDatadown[${i}][${item}] is not a string`);
|
||||
}
|
||||
str += `${tableDatadown[i][item] + '\t'},`;
|
||||
}
|
||||
str += '\n';
|
||||
}
|
||||
// 2.6encodeURIComponent解决中文乱码
|
||||
let uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(str);
|
||||
// 2.7通过创建a标签实现
|
||||
let link = document.createElement('a');
|
||||
link.href = uri;
|
||||
// 2.8对下载的文件命名
|
||||
link.download = Date.now() + ".csv";
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
/!*let fileName = Date.now() + ".csv";//使用当前时间戳作为文件名
|
||||
var columnDelimiter = ","; //列分割符
|
||||
var lineDelimiter = "\r\n"; //行分割符
|
||||
var table__header = document.getElementsByClassName(
|
||||
"el-table__header"
|
||||
)[0];//获取表头
|
||||
var table__body = document.getElementsByClassName("el-table__body")[0];//获取tbody
|
||||
var head = table__header.tHead;
|
||||
let result = "";// 最终结果的字符串
|
||||
var ths = head.getElementsByTagName("span");
|
||||
for (let i = 0, l = ths.length; i < l; i++) {
|
||||
result +=
|
||||
transferred('"' + ths[i].innerHTML + '"') + columnDelimiter;//每一列用逗号分隔
|
||||
}
|
||||
result += lineDelimiter;// 每一行使用"\r\n"分隔
|
||||
var trs = table__body.getElementsByTagName("tr");
|
||||
for (let i = 0, l = trs.length; i < l; i++) {
|
||||
let spandata = trs[i].getElementsByTagName("span");
|
||||
for (let i = 0, l = spandata.length; i < l; i++) {
|
||||
result +=
|
||||
transferred('"' + spandata[i].innerHTML + '"') +
|
||||
columnDelimiter;
|
||||
}
|
||||
result += lineDelimiter;
|
||||
}
|
||||
var blob = new Blob(["\uFEFF" + result], { type: "text/csv;" });//记得将编码格式设置一下,避免最终下载的文件出现乱码
|
||||
var downloadLink = document.createElement("a");
|
||||
if ("download" in downloadLink) {
|
||||
var url = URL.createObjectURL(blob);
|
||||
downloadLink.href = url;
|
||||
downloadLink.download = fileName;
|
||||
downloadLink.hidden = true;
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
document.body.removeChild(downloadLink);
|
||||
}*!/
|
||||
/!*else {
|
||||
if (navigator.msSaveBlob) {
|
||||
//IE10+
|
||||
navigator.msSaveBlob(blob, fileName);
|
||||
}
|
||||
}*!/
|
||||
|
||||
|
||||
|
||||
}*/
|
||||
}
|
||||
onUnmounted(() => {
|
||||
autoUpdateInterval.value && clearInterval(autoUpdateInterval.value)
|
||||
autoUpdateInterval.value = null
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
//deviceQuery(objectType)
|
||||
deviceQuery(devicelistData)
|
||||
modelAttributeList(queryListData)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<div class="measurement">
|
||||
<el-table :columns="tableColumn" :data="tableData" @sort-change="sortChange" max-height="495">
|
||||
<el-table-column
|
||||
v-for="item in tableColumn"
|
||||
:key="item.prop"
|
||||
:label="item.label"
|
||||
:prop="item.prop"
|
||||
:width="item.width ?? ''"
|
||||
:align="item.align"
|
||||
:sortable="item.sortable"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-radio
|
||||
v-if="item.prop === 'index'"
|
||||
:label="scope.$index"
|
||||
v-model="selectedIndex"
|
||||
@change="handleRadioChange(scope.$index, scope.row)"
|
||||
> </el-radio
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div>
|
||||
<el-pagination
|
||||
v-model:current-page="pageSetting.current"
|
||||
v-model:page-size="pageSetting.pageSize"
|
||||
:total="pageSetting.total"
|
||||
:page-sizes="pageSetting.pageSizes"
|
||||
background
|
||||
:pager-count="7"
|
||||
layout="prev, pager, next, jumper,sizes,total"
|
||||
@change="getcurrentPage"
|
||||
></el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, watch, defineEmits } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { ModelAttributeFieldsEnums, GetModelAttributeType } from '/@/views/backend/auth/model/type'
|
||||
import { getModelAttributeListReq, getRealValueListReq } from '/@/api/backend/deviceModel/request'
|
||||
|
||||
const props = defineProps({
|
||||
iotModelId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
deviceId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
const selectedIndex = ref(null)
|
||||
const tableColumn = [
|
||||
{
|
||||
type: 'selection',
|
||||
prop: 'index',
|
||||
width: 55,
|
||||
},
|
||||
{
|
||||
label: '序号',
|
||||
prop: 'porder',
|
||||
width: 76,
|
||||
align: 'center',
|
||||
sortable: 'custom',
|
||||
},
|
||||
{
|
||||
label: '属性名称',
|
||||
prop: 'attributeName',
|
||||
align: 'left',
|
||||
sortable: 'custom',
|
||||
},
|
||||
{
|
||||
label: '属性编码',
|
||||
prop: 'attributeCode',
|
||||
align: 'left',
|
||||
width: 200,
|
||||
sortable: 'custom',
|
||||
},
|
||||
{
|
||||
label: '子系统',
|
||||
prop: 'subSystem',
|
||||
align: 'left',
|
||||
width: 110,
|
||||
sortable: false,
|
||||
},
|
||||
]
|
||||
const tableData = ref<any[]>([])
|
||||
const emit = defineEmits(['handleRadioChange'])
|
||||
const handleRadioChange = (index, row) => {
|
||||
emit('handleRadioChange', row)
|
||||
console.log(row)
|
||||
}
|
||||
const getAttributeList = () => {
|
||||
console.log(props)
|
||||
const requestData: GetModelAttributeType = {
|
||||
iotModelId: props.iotModelId,
|
||||
pageNum: pageSetting.current,
|
||||
pageSize: pageSetting.pageSize,
|
||||
attributeType: '138',
|
||||
orderColumn: sortData.orderColumn,
|
||||
orderType: sortData.orderType,
|
||||
}
|
||||
console.log('🚀 ~ getAttributeList ~ requestData:', requestData)
|
||||
console.log(requestData)
|
||||
return new Promise((resolve) => {
|
||||
getModelAttributeListReq(requestData)
|
||||
.then((res) => {
|
||||
if (res.rows && res.rows.length > 0) {
|
||||
const codeList: any = []
|
||||
const data = res.rows!.map((item) => {
|
||||
codeList.push(item.attributeCode)
|
||||
return {
|
||||
...item,
|
||||
attributeTypeName:
|
||||
item.attributeType === 138
|
||||
? '模拟量'
|
||||
: item.attributeType === 139
|
||||
? '累积量'
|
||||
: item.attributeType === 140
|
||||
? '离散量'
|
||||
: item.attributeType!,
|
||||
}
|
||||
})
|
||||
pageSetting.total = res.total
|
||||
resolve({ data, codeList })
|
||||
} else {
|
||||
if (res.rows && res.rows.length === 0) {
|
||||
tableData.value = []
|
||||
} else {
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err?.response?.data?.msg ?? '查询失败')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const getRealValueList = (data: { deviceId: string; attributes: string[] }, list?: any) => {
|
||||
return new Promise((resolve) => {
|
||||
getRealValueListReq([data]).then((res) => {
|
||||
if (res.success && res.data) {
|
||||
resolve({ realVal: res.data, list })
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const getCompleteData = () => {
|
||||
getAttributeList()
|
||||
.then(({ data, codeList }: any) => {
|
||||
return getRealValueList({ deviceId: props.deviceId, attributes: codeList }, data)
|
||||
})
|
||||
.then((realData: any) => {
|
||||
console.log(realData)
|
||||
|
||||
const data = realData.list.map((item: any) => {
|
||||
const realValItem = realData.realVal[props.deviceId]?.[item.attributeCode?.toLowerCase()]
|
||||
return {
|
||||
...item,
|
||||
realTimeValue: realValItem ? (realValItem % 1 === 0 ? realValItem : realValItem.toFixed(3)) : '-',
|
||||
}
|
||||
})
|
||||
|
||||
tableData.value = data
|
||||
})
|
||||
}
|
||||
|
||||
const sortData = reactive<{ orderColumn?: keyof typeof ModelAttributeFieldsEnums; orderType?: 'asc' | 'desc' }>({
|
||||
orderColumn: 'porder',
|
||||
orderType: 'asc',
|
||||
})
|
||||
|
||||
const sortChange = ({ prop, order }: { prop: keyof typeof ModelAttributeFieldsEnums; order: 'ascending' | 'descending' | null }) => {
|
||||
const propEnums = {
|
||||
attributeCode: 'attribute_code',
|
||||
attributeName: 'attribute_name',
|
||||
attributeTypeName: 'attribute_type',
|
||||
porder: 'porder',
|
||||
serviceCode: 'service_code',
|
||||
serviceName: 'service_name',
|
||||
serviceTypeName: 'service_type',
|
||||
}
|
||||
const orderType = order === 'ascending' ? 'asc' : order === 'descending' ? 'desc' : undefined
|
||||
const filed = propEnums[prop as keyof typeof propEnums] as keyof typeof ModelAttributeFieldsEnums
|
||||
sortData.orderColumn = orderType ? filed : undefined
|
||||
sortData.orderType = orderType
|
||||
getCompleteData()
|
||||
}
|
||||
|
||||
const pageSetting = reactive({
|
||||
current: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
pageSizes: [10, 20, 30],
|
||||
})
|
||||
|
||||
const getcurrentPage = () => {
|
||||
getCompleteData()
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
getCompleteData()
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
513
ui/dasadmin/src/views/backend/statAnalysis/index.vue
Normal file
513
ui/dasadmin/src/views/backend/statAnalysis/index.vue
Normal file
@ -0,0 +1,513 @@
|
||||
<template>
|
||||
<div class="statAnalysis">
|
||||
<el-menu :default-active="activeIndex" class="headerList" mode="horizontal" @select="handleSelect">
|
||||
<el-menu-item v-for="(item, index) in headerList" :index="index" :key="index"> {{ item }} </el-menu-item>
|
||||
</el-menu>
|
||||
<div class="contain">
|
||||
<el-header class="headerPart">
|
||||
<div class="topLeft">
|
||||
<div class="selectPart">
|
||||
<span>{{ t('statAnalysis.deviceId') }}</span>
|
||||
<el-select
|
||||
v-model="statAnalysisSelect.deviceId"
|
||||
@change="selectstatAnalysis('deviceId')"
|
||||
:placeholder="'请选择' + t('statAnalysis.deviceId')"
|
||||
class="statAnalysisSelect"
|
||||
>
|
||||
<el-option v-for="v in statAnalysisSelectOptions.deviceId" :key="v.value" :label="v.label" :value="v.value"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="selectPart">
|
||||
<span>{{ t('statAnalysis.attributes') }}</span>
|
||||
<el-input
|
||||
class="statAnalysisSelect"
|
||||
v-model="statAnalysisSelect.attributes"
|
||||
@click="showMeasure = true"
|
||||
:placeholder="'请选择' + t('statAnalysis.attributes')"
|
||||
></el-input>
|
||||
</div>
|
||||
<div class="selectPart">
|
||||
<span>{{ t('statAnalysis.interval') }}</span>
|
||||
<el-select
|
||||
v-model="statAnalysisSelect.interval"
|
||||
@change="selectstatAnalysis('interval')"
|
||||
:placeholder="'请选择' + t('statAnalysis.interval')"
|
||||
class="statAnalysisSelect"
|
||||
>
|
||||
<el-option v-for="v in statAnalysisSelectOptions.interval" :key="v.value" :label="v.label" :value="v.value"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="topRight">
|
||||
<el-button type="primary" @click="statAnalysisOperate()">{{ t('statAnalysis.search') }}</el-button>
|
||||
<el-button style="color: #0064aa" @click="statAnalysiImport()">{{ t('statAnalysis.import') }}</el-button>
|
||||
<el-button style="color: #0064aa" @click="statAnalysisExport()">{{ t('statAnalysis.export') }}</el-button>
|
||||
</div>
|
||||
</el-header>
|
||||
<div class="timeColumns" :class="{ expand: isExpand }">
|
||||
<div class="headerPart" v-for="(time, index) in times" :key="index">
|
||||
<div class="topLeft">
|
||||
<div class="selectPart">
|
||||
<span>{{ customName }}</span>
|
||||
<span>{{ t('statAnalysis.time') }}</span>
|
||||
<el-date-picker
|
||||
class="datetime-picker"
|
||||
v-model="times[index]"
|
||||
:type="statAnalysisSelect.interval == '1d' ? 'daterange' : 'datetimerange'"
|
||||
:value-format="statAnalysisSelect.interval == '1d' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'"
|
||||
:teleported="false"
|
||||
:shortcuts="shortcuts"
|
||||
@change="timechange(index)"
|
||||
/>
|
||||
</div>
|
||||
<div class="topLeft">
|
||||
<div class="selectPart" v-if="index === times.length - 1">
|
||||
<el-button type="primary" size="small" :icon="Plus" circle @click="addTime(index)"> </el-button>
|
||||
</div>
|
||||
<div class="selectPart" v-if="index !== 0">
|
||||
<el-button type="danger" size="small" :icon="Delete" @click="switchTime(index)" circle />
|
||||
</div>
|
||||
<div class="selectPart">
|
||||
<span>{{ t('statAnalysis.max') }}</span>
|
||||
<span class="max">11</span>
|
||||
</div>
|
||||
<div class="selectPart">
|
||||
<span>{{ t('statAnalysis.min') }}</span>
|
||||
<span class="min">22</span>
|
||||
</div>
|
||||
<div class="selectPart">
|
||||
<span>{{ t('statAnalysis.average') }}</span>
|
||||
<span class="average">33</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="times.length > 2" class="ralIcon" @click="handleClick">
|
||||
<el-icon :size="20" color="#0064AA"><DArrowRight /></el-icon>
|
||||
</div>
|
||||
<div ref="chartContainer" style="width: 100%; height: 400px"></div>
|
||||
<el-dialog v-model="showMeasure" title="测点名称" :width="800">
|
||||
<template #header>
|
||||
<div class="measureSlotHeader">
|
||||
<span style="font-size: 20px">测点名称</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="measureSlot">
|
||||
<MeasurementPage :show="showMeasure" :iotModelId="iotModelId" @handleRadioChange="handleRadioChange"></MeasurementPage>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="showMeasure = false">取消</el-button>
|
||||
<el-button type="primary" @click="selectstatAnalysisAttributes"> 确认 </el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { SelectTypeObjType, SelectTypeKeyUnionType, TableDataObjType, TableColumnType } from './type'
|
||||
import { onUnmounted, reactive, ref, watch, nextTick, onMounted, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { queryWindTurbinesPages, historyReq } from '/@/api/backend/statAnalysis/request'
|
||||
import { ElMessage, TableInstance, ElMenu } from 'element-plus'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useConfig } from '/@/stores/config'
|
||||
import { DArrowRight, Plus, Delete } from '@element-plus/icons-vue'
|
||||
import MeasurementPage from './analysisAttributes.vue'
|
||||
import * as echarts from 'echarts'
|
||||
const config = useConfig()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const activeIndex = ref(0)
|
||||
const { t } = useI18n()
|
||||
const headerList = [t('statAnalysis.PowerCurveAnalysis'), t('statAnalysis.trendAnalysis'), t('statAnalysis.trendComparison')]
|
||||
const statAnalysisSelect = reactive({
|
||||
deviceId: '',
|
||||
attributes: '',
|
||||
attributeCode: '',
|
||||
interval: '',
|
||||
time: '',
|
||||
})
|
||||
const times = reactive([{ time: '' }])
|
||||
const addTime = (index) => {
|
||||
console.log(index)
|
||||
console.log(times)
|
||||
times.push({ time: '' })
|
||||
}
|
||||
const switchTime = (index) => {
|
||||
times.splice(index, 1)
|
||||
}
|
||||
const timechange = (value) => {
|
||||
const count = getTimeIntervals(times[0][0], times[0][1])
|
||||
const count1 = getTimeIntervals(times[value][0], times[value][1])
|
||||
if (count !== count1) {
|
||||
times[value] = { time: '' }
|
||||
value = ElMessage.warning('查询时间点错误,请重新舒服')
|
||||
}
|
||||
console.log('🚀 ~ timechange ~ count:', count)
|
||||
}
|
||||
const isExpand = ref(false)
|
||||
const handleClick = () => {
|
||||
isExpand.value = !isExpand.value
|
||||
console.log(isExpand)
|
||||
}
|
||||
|
||||
const iotModelId = ref('')
|
||||
watch(
|
||||
() => statAnalysisSelect.deviceId,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
const row = statAnalysisSelectOptions.deviceId.filter((item) => {
|
||||
console.log(item.value == newVal)
|
||||
return item.value == newVal
|
||||
})
|
||||
console.log()
|
||||
iotModelId.value = row[0].iotModelId
|
||||
console.log('🚀 ~ iotModelId:', iotModelId)
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
)
|
||||
|
||||
const showMeasure = ref(false)
|
||||
const selectedAttrRow = ref({
|
||||
attributeCode: '',
|
||||
attributeName: '',
|
||||
})
|
||||
const handleRadioChange = (value) => {
|
||||
const { attributeCode, attributeName } = { ...value }
|
||||
selectedAttrRow.attributeCode = attributeCode
|
||||
selectedAttrRow.attributeName = attributeName
|
||||
}
|
||||
const selectstatAnalysisAttributes = () => {
|
||||
statAnalysisSelect.attributes = selectedAttrRow.attributeName
|
||||
console.log('🚀 ~ selectstatAnalysisAttributes ~ selectedAttrRow:', selectedAttrRow)
|
||||
statAnalysisSelect.attributeCode = selectedAttrRow.attributeCode
|
||||
showMeasure.value = false
|
||||
}
|
||||
|
||||
const chartContainer = ref<HTMLElement | null>(null)
|
||||
|
||||
const option = {
|
||||
// dataZoom: [
|
||||
// {
|
||||
// type: 'inside',
|
||||
// start: 0,
|
||||
// end: 100,
|
||||
// },
|
||||
// {
|
||||
// start: 0,
|
||||
// },
|
||||
// ],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
// axisPointer: {
|
||||
// type: 'cross',
|
||||
// label: {
|
||||
// backgroundColor: '#6a7985',
|
||||
// },
|
||||
// },
|
||||
},
|
||||
legend: {
|
||||
right: 10,
|
||||
top: 0,
|
||||
icon: 'rect',
|
||||
itemGap: 20,
|
||||
itemWidth: 8,
|
||||
itemHeight: 8,
|
||||
data: [],
|
||||
selected: {},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: [],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [],
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '3%',
|
||||
},
|
||||
}
|
||||
|
||||
const statAnalysisSelectOptions = reactive({
|
||||
interval: [
|
||||
{ label: '五分钟', value: '5m' },
|
||||
{ label: '十五分钟', value: '15m' },
|
||||
{ label: '一小时', value: '1h' },
|
||||
{ label: '一天', value: '1d' },
|
||||
{ label: '原始', value: 'NONE' },
|
||||
],
|
||||
deviceId: [],
|
||||
})
|
||||
const customName = ref('第一条数据')
|
||||
const chart = ref(null)
|
||||
onMounted(() => {
|
||||
if (chartContainer.value) {
|
||||
chart.value = echarts.init(chartContainer.value)
|
||||
chart.value.setOption(option)
|
||||
}
|
||||
queryWindTurbines()
|
||||
})
|
||||
const queryWindTurbines = () => {
|
||||
queryWindTurbinesPages().then((res) => {
|
||||
if (res.code == 200) {
|
||||
statAnalysisSelectOptions.deviceId = res.data.map((item) => {
|
||||
return {
|
||||
value: item.irn,
|
||||
label: item.name ?? '-',
|
||||
iotModelId: item.modelId,
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
window.onresize = () => {
|
||||
chart.resize()
|
||||
}
|
||||
|
||||
const handleSelect = () => {}
|
||||
const selectstatAnalysis = () => {}
|
||||
|
||||
const shortcuts = [
|
||||
{
|
||||
text: '昨日',
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24)
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '前三天',
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 3)
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '前七天',
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '上个月',
|
||||
value: () => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
|
||||
return [start, end]
|
||||
},
|
||||
},
|
||||
]
|
||||
const getTimeIntervals = (startTimestamp, endTimestamp) => {
|
||||
const startDate = new Date(startTimestamp)
|
||||
const endDate = new Date(endTimestamp)
|
||||
let count = 0
|
||||
|
||||
switch (statAnalysisSelect.interval) {
|
||||
case 'NONE':
|
||||
count = Math.floor((endDate - startDate) / 1000)
|
||||
break
|
||||
case '5m':
|
||||
count = Math.floor((endDate - startDate) / (5 * 60 * 1000))
|
||||
break
|
||||
case '15m':
|
||||
count = Math.floor((endDate - startDate) / (15 * 60 * 1000))
|
||||
break
|
||||
case '1h':
|
||||
count = Math.floor((endDate - startDate) / (1 * 60 * 60 * 1000))
|
||||
break
|
||||
case '1d':
|
||||
count = Math.floor((endDate - startDate) / (1 * 24 * 60 * 60 * 1000))
|
||||
break
|
||||
// default:
|
||||
// throw new Error('Invalid interval')
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
const statAnalysisOperate = () => {
|
||||
console.log(statAnalysisSelect)
|
||||
console.log(times)
|
||||
times.forEach((time) => {
|
||||
if (time[0] && time[1]) {
|
||||
const requestData = {
|
||||
devices: [
|
||||
{
|
||||
deviceId: statAnalysisSelect.deviceId,
|
||||
attributes: [statAnalysisSelect.attributeCode],
|
||||
},
|
||||
],
|
||||
interval: statAnalysisSelect.interval,
|
||||
startTime: new Date(time[0]).getTime(),
|
||||
endTime: new Date(time[1]).getTime(),
|
||||
}
|
||||
historyDataReq(requestData)
|
||||
console.log(requestData)
|
||||
}
|
||||
})
|
||||
}
|
||||
const historyDataReq = (data) => {
|
||||
// historyReq(data).then((res) => {
|
||||
// console.log(res)
|
||||
const res = {
|
||||
//设备ID
|
||||
'129476828342323': {
|
||||
//属性名
|
||||
power: {
|
||||
//时间戳列表
|
||||
times: [123452435924242, 123452435924342, 123452435924442, 123452435924542],
|
||||
//值列表
|
||||
values: [123.23, 35.21, 34.56, 67],
|
||||
},
|
||||
},
|
||||
}
|
||||
const deviceId = statAnalysisSelect.deviceId
|
||||
const attributeCode = statAnalysisSelect.attributeCode
|
||||
const resData = res['129476828342323']['power']
|
||||
|
||||
const xData = resData['times']
|
||||
const yData = resData['values']
|
||||
option.tooltip = {
|
||||
trigger: 'axis',
|
||||
show: true,
|
||||
formatter: function (params) {
|
||||
console.log('🚀 ~ //historyReq ~ params:', params)
|
||||
return params
|
||||
.map((item) => {
|
||||
return `${item.seriesName} (${xData[item.dataIndex]}): ${item.data}`
|
||||
})
|
||||
.join('<br/>')
|
||||
},
|
||||
}
|
||||
option.xAxis.data = Array.from({ length: xData.length }, (_, index) => index)
|
||||
|
||||
option.series = [
|
||||
{
|
||||
name: '',
|
||||
type: 'line',
|
||||
data: yData,
|
||||
},
|
||||
]
|
||||
console.log('🚀 ~ //historyReq ~ option:', option)
|
||||
chart.value.setOption(option)
|
||||
// })
|
||||
}
|
||||
|
||||
const statAnalysisExport = () => {}
|
||||
const statAnalysiImport = () => {}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.statAnalysis {
|
||||
height: 100%;
|
||||
.headerList {
|
||||
border: none;
|
||||
--el-menu-bg-color: v-bind('config.getColorVal("menuBackground")');
|
||||
--el-menu-text-color: v-bind('config.getColorVal("menuColor")');
|
||||
--el-menu-active-color: v-bind('config.getColorVal("menuActiveColor")');
|
||||
}
|
||||
.headerPart {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.topLeft {
|
||||
display: flex;
|
||||
.selectPart {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
margin-right: 20px;
|
||||
span {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.statAnalysisSelect {
|
||||
width: 200px;
|
||||
:deep(.el-select__wrapper) {
|
||||
height: 40px;
|
||||
}
|
||||
:deep(.el-input__inner) {
|
||||
height: 38px;
|
||||
}
|
||||
}
|
||||
.max,
|
||||
.min,
|
||||
.average {
|
||||
border-radius: 6px;
|
||||
height: 40px;
|
||||
width: 72px;
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
}
|
||||
.max {
|
||||
background: rgba(254, 55, 49, 0.2);
|
||||
border: 1px solid #fe3731;
|
||||
color: #fe3731;
|
||||
}
|
||||
.min {
|
||||
background: rgba(0, 160, 150, 0.2);
|
||||
border: 1px solid #00a096;
|
||||
color: #00a096;
|
||||
}
|
||||
.average {
|
||||
background: rgba(0, 100, 170, 0.2);
|
||||
border: 1px solid #0064aa;
|
||||
color: #0064aa;
|
||||
}
|
||||
}
|
||||
.dialog-footer button:first-child {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.topRight {
|
||||
// width: 436px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.el-button {
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.timeColumns {
|
||||
max-height: 120px;
|
||||
overflow: hidden;
|
||||
.headerPart {
|
||||
padding: 10px;
|
||||
}
|
||||
&.expand {
|
||||
max-height: max-content;
|
||||
height: auto;
|
||||
overflow: inherit;
|
||||
}
|
||||
}
|
||||
.timeColumns.expand + div.ralIcon {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
.ralIcon {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
#myEChart {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user