上传项目代码

This commit is contained in:
lixiaoyuan
2025-05-19 09:54:33 +08:00
commit 4a198a7271
589 changed files with 993786 additions and 0 deletions

60
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,60 @@
cmake_minimum_required(VERSION 3.23)
set(PROJECT_NAME EES)
project(${PROJECT_NAME})
set(CMAKE_CXX_STANDARD 17)
# 【注意】visual studio编译时的字符编码问题配置属性 --> C/C++ --> 命令行 --> 其它选项: /utf-8 或添加如下指令
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
# Qt_PATH 为 Qt 的安装地址
set(QT_PATH "D:/Programs/Qt5/5.15.2/msvc2019_64")
set(CMAKE_PREFIX_PATH ${QT_PATH}/lib/cmake)
# 开启自动编译
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
find_package(Qt5 COMPONENTS Widgets AxContainer Network SerialBus SerialPort Charts WebEngineWidgets REQUIRED)
add_definitions(-DWIN32_LEAN_AND_MEAN)
set(ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
set(THIRDPARTY_PATH ${ROOT_PATH}/../thirdparty)
include_directories(
${ROOT_PATH}
${ROOT_PATH}/app
${ROOT_PATH}/common
${ROOT_PATH}/widgets
${THIRDPARTY_PATH}
${THIRDPARTY_PATH}/mysql/include
)
macro(ADD_SOURCE_GROUP srcpath)
file(GLOB src_h ${PROJECT_SOURCE_DIR}/${srcpath}/*.h)
file(GLOB src_cpp ${PROJECT_SOURCE_DIR}/${srcpath}/*.cpp)
set(src_tmp ${src_h} ${src_cpp})
source_group(src/${srcpath} FILES ${src_tmp})
list(APPEND SOURCE_FILE ${src_tmp})
endmacro(ADD_SOURCE_GROUP)
# 设置编译源文件
ADD_SOURCE_GROUP(./)
ADD_SOURCE_GROUP(common)
ADD_SOURCE_GROUP(app)
ADD_SOURCE_GROUP(database)
ADD_SOURCE_GROUP(protocol)
ADD_SOURCE_GROUP(widgets)
ADD_SOURCE_GROUP(widgets/pages)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../bin)
add_executable(${PROJECT_NAME} ${SOURCE_FILE})
target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::AxContainer Qt5::Network Qt5::SerialBus Qt5::SerialPort Qt5::Charts Qt5::WebEngineWidgets)
target_link_libraries(${PROJECT_NAME}
ws2_32 iphlpapi
${THIRDPARTY_PATH}/mysql/lib/x64/libmysql.lib
)

0
src/app/AppSetting.cpp Normal file
View File

12
src/app/AppSetting.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
class AppSetting
{
public:
static AppSetting& instance() {
static AppSetting inst;
return inst;
}
};

21
src/app/Application.cpp Normal file
View File

@@ -0,0 +1,21 @@
#include "Application.h"
#include "common/Utils.h"
void Application::init()
{
std::thread([=]()
{
while (!isQuit()) { runThreadMain(); }
}).detach();
}
void Application::runThreadMain()
{
static TimeTick tt;
tt.elapse(1000);
//XLOGD() << "HelloWorld";
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}

28
src/app/Application.h Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include <thread>
#include "common/Logger.h"
#include "Operator.h"
class Application
{
public:
static Application& instance()
{
static Application app;
return app;
}
void init();
bool isQuit() { return isQuit_; }
Operator& getOperator() { return op_; }
void runThreadMain();
private:
bool isQuit_ = false;
// 登录的管理员信息
Operator op_;
};

147
src/app/Dao.cpp Normal file
View File

@@ -0,0 +1,147 @@
#include "Dao.h"
#include "common/Logger.h"
#include "common/Utils.h"
#include "common/Snowflake.h"
enum class EnDatabaseErr
{
SUCCESS = 0,
};
std::shared_ptr<DaoEntity> DAO::get(std::string tableName)
{
return std::make_shared<DaoEntity>(tableName);
}
bool DAO::login(std::shared_ptr<DaoEntity> dao, std::string account, std::string passwd, std::string& err)
{
std::string t = Utils::timeNowStr();
if (!dao)
{
dao = std::make_shared<DaoEntity>("");
}
if (!dao->isConnected())
{
err = "数据库连接错误";
DAO::writeSystemLog(dao, 2, "", account, "用户登录失败:" + err);
return false;
}
std::string sql = "SELECT * FROM user WHERE account='" + account + "';";
std::vector<DataFields> res;
bool ret = dao->exec(sql, res);
if (!ret)
{
err = "数据库操作错误";
DAO::writeSystemLog(dao, 2, "", account, "用户登录失败:" + err);
return false;
}
if (res.size() <=0)
{
err = "用户不存在";
DAO::writeSystemLog(dao, 2, "", account, "用户登录失败:" + err);
return false;
}
DataFields& fields = res[0];
std::string userId = fields.get_str("user_id");
int loginCount = fields.get_int("login_count");
// 判断密码
if (passwd != fields.get_str("passwd"))
{
err = "密码错误";
DAO::writeSystemLog(dao, 2, userId, account, "用户登录失败:" + err);
return false;
}
err = "登录成功";
// 数据库更新用户登录信息
sql = "UPDATE user SET login_time='" + t + "', login_count='" + std::to_string(loginCount + 1) + "' WHERE user_id = '" + userId + "'; ";
ret = dao->exec(sql);
if (!ret)
{
XLOGE() << "更新用户登录信息失败sql=" << sql;
}
DAO::writeSystemLog(dao, 2, userId, account, "用户登录成功");
return true;
}
bool DAO::writeSystemLog(std::shared_ptr<DaoEntity> dao, int type, std::string userId, std::string account, std::string text)
{
if (!dao)
{
dao = std::make_shared<DaoEntity>("");
}
if (!dao->isConnected())
{
return false;
}
// 数据库写入登录日志
dao->setTableName("system_log");
DataFields fieldsLog;
fieldsLog.set("id", Snowflake::instance().nextIdStr());
fieldsLog.set("type", 2);
fieldsLog.set("user_id", userId);
fieldsLog.set("user_account", account);
fieldsLog.set("content", text);
fieldsLog.set("log_time", Utils::timeNowStr());
bool ret = dao->insertFields({fieldsLog});
return ret;
}
bool DAO::queryUser(std::vector<DataFields>& res)
{
std::shared_ptr<DaoEntity> dao = std::make_shared<DaoEntity>("");
if (!dao->isConnected())
{
return false;
}
std::string sql = "SELECT u.*, r.role_id, r.name role_name from USER u LEFT JOIN user_role ur ON u.user_id = ur.user_id LEFT JOIN `role` r ON r.role_id = ur.role_id;";
bool ret = dao->exec(sql, res);
return ret;
}
int DAO::insertUser(DataFields& fields)
{
std::shared_ptr<DaoEntity> dao = std::make_shared<DaoEntity>("user");
if (!dao->isConnected())
{
return 1;
}
std::string account = fields.get_str("account");
// step1: 查询
std::vector<DataFields> res;
bool ret = dao->exec("SELECT * from user WHERE account='" + account + "';", res);
if (!ret)
{
return 1;
}
if (res.size() > 0)
{
return 1;
}
fields.set("user_id", Snowflake::instance().nextIdStr());
fields.set("create_time", Utils::timeNowStr());
ret = dao->insertFields(fields);
return (ret) ? 0 : 1;
}
int DAO::updateUserById(std::string id, DataFields& fields)
{
std::shared_ptr<DaoEntity> dao = std::make_shared<DaoEntity>("user");
if (!dao->isConnected())
{
return 1;
}
string sqlC = "WHERE user_id='" + id + "'";
bool ret = dao->updateFields(fields, sqlC);
return (ret) ? 0 : 1;
}

30
src/app/Dao.h Normal file
View File

@@ -0,0 +1,30 @@
#include "database/DaoEntity.h"
class DAO
{
public:
static std::shared_ptr<DaoEntity> get(std::string tableName="");
static bool login(std::shared_ptr<DaoEntity> dao, std::string account, std::string passwd, std::string& err);
static bool writeSystemLog(std::shared_ptr<DaoEntity> dao, int type, std::string userId, std::string account, std::string text);
// =======================================================================
// 用户管理数据操作
/**
* 查询用户
*/
static bool queryUser(std::vector<DataFields>& res);
/**
* 新增用户
*/
static int insertUser(DataFields& fields);
/**
* 修改用户信息
*/
static int updateUserById(std::string id, DataFields& fields);
};

0
src/app/Device.cpp Normal file
View File

7
src/app/Device.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
class Device
{
public:
static bool init();
};

18
src/app/Operator.cpp Normal file
View File

@@ -0,0 +1,18 @@
#include "Operator.h"
#include "DAO.h"
#include "common/Logger.h"
bool Operator::login(std::string account, std::string passwd, std::string& err)
{
bool ret = DAO::login(nullptr, account, passwd, err);
if (ret)
{
XLOGD() << "用户[" + account + "]登录成功";
}
else
{
XLOGD() << "用户[" + account + "]登录失败: " << err;
}
return ret;
}

16
src/app/Operator.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
#include <string>
class Operator
{
public:
bool login(std::string account, std::string passwd, std::string& err);
bool logout(std::string& err);
std::string account_;
std::string passwd_;
};

10
src/cmake_msvc2019.bat Normal file
View File

@@ -0,0 +1,10 @@
cd %~dp0
cd ..
@REM rd /S /Q .build
mkdir #buildmsvc2019
cd #buildmsvc2019
@REM Visual Studio 16 2019/Visual Studio 17 2022
@REM Win32/x64
cmake ../src -G "Visual Studio 16 2019" -A x64

197
src/common/DataFields.cpp Normal file
View File

@@ -0,0 +1,197 @@
#include "DataFields.h"
#include "common/Utils.h"
void DataFields::set(string key, string val)
{
map_fields_[key] = val;
}
void DataFields::set(string key, float val)
{
map_fields_[key] = std::to_string(val);
}
void DataFields::set(string key, int val)
{
map_fields_[key] = std::to_string(val);
}
void DataFields::set(string key, int64_t val)
{
map_fields_[key] = std::to_string(val);
}
string DataFields::get_str(string key)
{
if (map_fields_.count(key) > 0)
{
return map_fields_[key];
}
else
{
return "";
}
}
int DataFields::get_int(string key)
{
return map_fields_.count(key) > 0 ? Utils::toInt(map_fields_[key]) : 0;
}
float DataFields::get_float(string key)
{
return map_fields_.count(key) > 0 ? Utils::toFloat(map_fields_[key]) : 0.0f;
}
void DataFields::remove(string key)
{
auto it = map_fields_.find(key);
if (it != map_fields_.end())
{
map_fields_.erase(it);
}
}
void DataFields::append(DataFields& datafield)
{
auto& map_f = datafield.fields();
for (auto it = map_f.begin(); it != map_f.end(); it++)
{
map_fields_[it->first] = it->second;
}
}
map<string, string>& DataFields::fields()
{
return map_fields_;
}
void DataFields::check(string key, string val, string d)
{
if (map_fields_.count(key) > 0 && map_fields_[key] == val)
{
map_fields_[key] = d;
}
}
string DataFields::get_insert_sql(string tbname)
{
string key;
string val;
for (auto it = map_fields_.begin(); it != map_fields_.end(); it++)
{
if (!key.empty())
{
key += ",";
val += ",";
}
key += ("`" + it->first + "`");
if (it->second == "null" || it->second == "NULL")
{
val += "NULL";
}
else
{
val += ("'" + it->second + "'");
}
}
return "INSERT INTO `" + tbname + "` (" + key + ") VALUES(" + val + ");";
}
string DataFields::get_update_sql(string tbname, string sql_c)
{
ostringstream oss;
oss << "update " << tbname << " set ";
for (auto iter = map_fields_.begin(); iter != map_fields_.end(); iter++)
{
if (iter != map_fields_.begin())
{
oss << ",";
};
oss << "`" << iter->first << "`=";
if (iter->second == "null" || iter->second == "NULL")
{
oss << "NULL";
}
else
{
oss << "'" << iter->second << "'";
}
}
oss << " " << sql_c << ";";
return oss.str();
}
string DataFields::get_update_sql(string tbname, std::vector<std::string> vec_keys, string sql_c)
{
std::map<std::string, bool> map_keys;
for (auto& k : vec_keys) { map_keys[k] = true; }
ostringstream oss;
oss << "update " << tbname << " set ";
for (auto iter = map_fields_.begin(); iter != map_fields_.end(); iter++)
{
auto& k = iter->first;
auto& v = iter->second;
if (!map_keys[k]) { continue; }
if (iter != map_fields_.begin())
{
oss << ",";
};
oss << "`" << k << "`=";
if (v == "null" || v == "NULL")
{
oss << "NULL";
}
else
{
oss << "'" << v << "'";
}
}
oss << " " << sql_c << ";";
return oss.str();
}
void DataFields::foreach_item(function<void(string key, string val)> on_foraach)
{
for (auto it = map_fields_.begin(); it != map_fields_.end(); it++)
{
if (on_foraach)
{
on_foraach(it->first, it->second);
}
}
}
bool DataFields::is_empty(string key)
{
auto& s = map_fields_[key];
return s.empty();
}
bool DataFields::is_float_number(string key)
{
auto& s = map_fields_[key];
if (s.empty())
{
return false;
}
for (auto& c : s)
{
if (std::isdigit(c) == 0 && c != '.')
{
return false;
}
}
return true;
}
string DataFields::to_str()
{
string s;
for (auto it = map_fields_.begin(); it != map_fields_.end(); it++)
{
s += ("[" + it->first + ":" + it->second + "] ");
}
return s;
}
int DataFields::size()
{
return map_fields_.size();
}
void DataFields::clear()
{
map_fields_.clear();
}

149
src/common/DataFields.h Normal file
View File

@@ -0,0 +1,149 @@
#ifndef _DataFields_H_
#define _DataFields_H_
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
#include <functional>
using namespace std;
struct PageInfo
{
int total = 0;
int page_id = 1;
int page_size = 10;
int page_max = 0;
};
class DataFields
{
public:
/**
* 设置索引名称和值
* @param: [string key] 索引名称
* @param: [string val] 值
*/
void set(string key, string val);
/**
* 设置索引名称和值
* @param: [string key] 索引名称
* @param: [float val] 值
*/
void set(string key, float val);
/**
* 设置索引名称和值
* @param: [string key] 索引名称
* @param: [int val] 值
*/
void set(string key, int val);
/**
* 设置索引名称和值
* @param: [string key] 索引名称
* @param: [int64_t val] 值
*/
void set(string key, int64_t val);
/**
* 获取 string 值
* @param: [string key] 索引名称
*/
string get_str(string key);
/**
* 获取 int 值
* @param: [string key] 索引名称
*/
int get_int(string key);
/**
* 获取 float 值
* @param: [string key] 索引名称
*/
float get_float(string key);
/**
* 删除指定索引的值
* @param: [string key] 索引名称
*/
void remove(string key);
/**
* 追加合并
* @param: [DataFields& fields] 要合并的数据
*/
void append(DataFields& fields);
/**
* 获取数据项map
*/
map<string, string>& fields();
/**
* 检查某一数据项的值进行替换如果该项的值是val则替换成成d
* @param: [string key] 索引名称
* @param: [string val] 要检查的值
* @param: [string d] 替换的值
*/
void check(string key, string val, string d);
/**
* 转换成插入数据的 sql 语句
* @param: [string tbname] 数据表名称
*/
string get_insert_sql(string tbname);
/**
* 转换成更新数据的 sql 语句
* @param: [string tbname] 数据表名称
* @param: [string sql_c] sql的更新条件例如 where id='1'
*/
string get_update_sql(string tbname, string sql_c);
/**
* 转换成更新数据的 sql 语句
* @param: [string tbname] 数据表名称
* @param: [string vec_keys] 需要更新的字段名称
* @param: [string sql_c] sql的更新条件例如 where id='1'
*/
string get_update_sql(string tbname, std::vector<std::string> vec_keys, string sql_c);
/**
* 遍历数据项
* @param: [function... on_foraach] 回调函数
*/
void foreach_item(function<void(string key, string val)> on_foraach);
/**
* 判断是否含有数据项
* @param: [string key] 索引名称
*/
bool is_empty(string key);
/**
* 判断数据项是否是float数值类型
* @param: [string key] 索引名称
*/
bool is_float_number(string key);
/**
* 转换成键值对的字符串格式
*/
string to_str();
/**
* 获取数据项的大小
*/
int size();
void clear();
private:
map<string, string> map_fields_;
};
#endif

71
src/common/Logger.cpp Normal file
View File

@@ -0,0 +1,71 @@
#include "Logger.h"
#include <windows.h>
#include <mutex>
#include "Utils.h"
//#include "common/spdlogger.h"
std::mutex g_mutex;
Logger::Logger(Logger::ELogType logtype, std::string filename, int line) : line_(line)
{
auto index = filename.find_last_of('\\');
if (index != std::string::npos)
{
filename_ = filename.substr(index + 1);
}
else
{
filename_ = filename;
}
log_type_ = logtype;
}
Logger::~Logger()
{
if (log_type_ == ELogType::E_LOG_OFF)
{
return;
}
static std::string strLogType[int(ELogType::E_LOG_OFF)] = { "DEBUG", "INFO", "WARN", "ERROR" };
// std::lock_guard<std::mutex> lock(g_mutex); // 虚构时自动解锁
g_mutex.lock();
//BACKGROUND代表背景FOREGROUND代表前景
//SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);//设置黄色(红色+绿色)
//SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
std::string text = oss_.str();
if (log_type_ == ELogType::E_LOG_DEBUG)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN);
//Spdlogger::debug(text.c_str());
}
else if (log_type_ == ELogType::E_LOG_INFO)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_BLUE | FOREGROUND_GREEN);
//Spdlogger::info(text.c_str());
}
else if (log_type_ == ELogType::E_LOG_WARN)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN);
//Spdlogger::warn(text.c_str());
}
else if (log_type_ == ELogType::E_LOG_ERROR)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED);
//Spdlogger::error(text.c_str());
}
else
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}
//std::cout << "[" << filename_ << ":" << line_ << "] [" << Utils::time_now_string_ms() << "][" << strLogType[int(log_type_)] << "] ";
std::cout << "[" << Utils::timeNowStrMS() << "][" << strLogType[int(log_type_)] << "] ";
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
std::cout << "- " << text << std::endl << std::flush;
g_mutex.unlock();
}

38
src/common/Logger.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef _Logger_H_
#define _Logger_H_
#include <sstream>
#include <iostream>
#include <ostream>
#include <string>
class Logger
{
public:
enum class ELogType
{
E_LOG_DEBUG = 0,
E_LOG_INFO,
E_LOG_WARN,
E_LOG_ERROR,
E_LOG_OFF
};
public:
Logger(Logger::ELogType logType, std::string filename, int line);
~Logger();
std::stringstream& Stream() { return oss_; }
private:
std::stringstream oss_;
ELogType log_type_;
std::string filename_;
int line_;
};
#define XLOGD() Logger(Logger::ELogType::E_LOG_DEBUG, __FILE__, __LINE__).Stream()
#define XLOGI() Logger(Logger::ELogType::E_LOG_INFO, __FILE__, __LINE__).Stream()
#define XLOGW() Logger(Logger::ELogType::E_LOG_WARN, __FILE__, __LINE__).Stream()
#define XLOGE() Logger(Logger::ELogType::E_LOG_ERROR, __FILE__, __LINE__).Stream()
#endif

227
src/common/Snowflake.h Normal file
View File

@@ -0,0 +1,227 @@
#ifndef _JW_CORE_ID_WORKER_H_
#define _JW_CORE_ID_WORKER_H_
#include <mutex>
#include <atomic>
#include <chrono>
#include <exception>
#include <sstream>
#include <string>
// 如果不使用 mutex, 则开启下面这个定义, 但是我发现, 还是开启 mutex 功能, 速度比较快
// #define SNOWFLAKE_ID_WORKER_NO_LOCK
/**
* @brief 分布式id生成类
* https://segmentfault.com/a/1190000011282426
* https://github.com/twitter/snowflake/blob/snowflake-2010/src/main/scala/com/twitter/service/snowflake/IdWorker.scala
*
* 64bit id: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
* || || || | | |
* |└---------------------------时间戳--------------------------┘└中心-┘└机器-┘ └----序列号----┘
* |
* 不用
* SnowFlake的优点: 整体上按照时间自增排序, 并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分), 并且效率较高, 经测试, SnowFlake每秒能够产生26万ID左右.
*/
class Snowflake
{
public:
static Snowflake& instance()
{
static Snowflake sf;
return sf;
}
typedef unsigned int UInt;
typedef unsigned long long int UInt64;
#ifdef SNOWFLAKE_ID_WORKER_NO_LOCK
typedef std::atomic<UInt> AtomicUInt;
typedef std::atomic<UInt64> AtomicUInt64;
#else
typedef UInt AtomicUInt;
typedef UInt64 AtomicUInt64;
#endif
void set_worker_id(UInt workerId)
{
this->workerId = workerId;
}
void set_datacenter_id(UInt datacenterId)
{
this->datacenterId = datacenterId;
}
string nextIdStr()
{
return std::to_string(next_id());
}
/**
* 获得下一个ID (该方法是线程安全的)
*
* @return SnowflakeId
*/
UInt64 next_id()
{
#ifndef SNOWFLAKE_ID_WORKER_NO_LOCK
std::unique_lock<std::mutex> lock {mutex};
AtomicUInt64 timestamp {0};
#else
static AtomicUInt64 timestamp {0};
#endif
timestamp = time_now_ms();
// 如果当前时间小于上一次ID生成的时间戳说明系统时钟回退过这个时候应当抛出异常
if (timestamp < lastTimestamp)
{
std::ostringstream s;
s << "clock moved backwards. Refusing to generate id for " << lastTimestamp - timestamp << " milliseconds";
throw std::exception(std::runtime_error(s.str()));
}
if (lastTimestamp == timestamp)
{
// 如果是同一时间生成的,则进行毫秒内序列
sequence = (sequence + 1) & sequenceMask;
if (0 == sequence)
{
// 毫秒内序列溢出, 阻塞到下一个毫秒,获得新的时间戳
timestamp = next_millis(lastTimestamp);
}
}
else
{
sequence = 0;
}
#ifndef SNOWFLAKE_ID_WORKER_NO_LOCK
lastTimestamp = timestamp;
#else
lastTimestamp = timestamp.load();
#endif
// 移位并通过或运算拼到一起组成64位的ID
//return ((timestamp - twepoch) << timestampLeftShift)
// | (datacenterId << datacenterIdShift)
// | (workerId << workerIdShift)
// | sequence;
return ((timestamp - twepoch) << sequenceBits)
//| (datacenterId << datacenterIdShift)
//| (workerId << workerIdShift)
| sequence;
}
protected:
Snowflake() : workerId(0), datacenterId(0), sequence(0), lastTimestamp(0)
{
}
/**
* 返回以毫秒为单位的当前时间
*
* @return 当前时间(毫秒)
*/
UInt64 time_now_ms() const
{
//auto t = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now());
auto t = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
return t.time_since_epoch().count();
}
/**
* 阻塞到下一个毫秒,直到获得新的时间戳
*
* @param lastTimestamp 上次生成ID的时间截
* @return 当前时间戳
*/
UInt64 next_millis(UInt64 lastTimestamp) const
{
UInt64 timestamp = time_now_ms();
while (timestamp <= lastTimestamp)
{
timestamp = time_now_ms();
}
return timestamp;
}
private:
#ifndef SNOWFLAKE_ID_WORKER_NO_LOCK
std::mutex mutex;
#endif
/**
* 开始时间截 (2010-01-01 00:00:00.000) 1262275200000
*/
const UInt64 twepoch = 1262275200000;
/**
* 机器id所占的位数
*/
const UInt workerIdBits = 5;
/**
* 数据中心id所占的位数
*/
const UInt datacenterIdBits = 5;
/**
* 序列所占的位数
*/
const UInt sequenceBits = 12;
/**
* 机器ID向左移12位
*/
const UInt workerIdShift = sequenceBits;
/**
* 数据标识id向左移17位
*/
const UInt datacenterIdShift = workerIdShift + workerIdBits;
/**
* 时间截向左移22位
*/
const UInt timestampLeftShift = datacenterIdShift + datacenterIdBits;
/**
* 支持的最大机器id结果是31
*/
const UInt maxWorkerId = -1 ^ (-1 << workerIdBits);
/**
* 支持的最大数据中心id结果是31
*/
const UInt maxDatacenterId = -1 ^ (-1 << datacenterIdBits);
/**
* 生成序列的掩码这里为4095
*/
const UInt sequenceMask = -1 ^ (-1 << sequenceBits);
/**
* 工作机器id(0~31)
*/
UInt workerId;
/**
* 数据中心id(0~31)
*/
UInt datacenterId;
/**
* 毫秒内序列(0~4095)
*/
AtomicUInt sequence {0};
/**
* 上次生成ID的时间截
*/
AtomicUInt64 lastTimestamp {0};
};
#endif // _JW_CORE_ID_WORKER_H_

115
src/common/TimeUtils.cpp Normal file
View File

@@ -0,0 +1,115 @@
#include "TimeUtils.h"
#include <chrono>
#include <sstream>
#include <iomanip>
int64_t TimeUtils::now()
{
// return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
return std::chrono::time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now()).time_since_epoch().count();
}
int64_t TimeUtils::now_ms()
{
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
//return std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
}
std::string TimeUtils::now_datetime(char c1/* = '/'*/, char c2/* = ':'*/, char c3/* = ' '*/)
{
std::stringstream ss;
ss << "%Y" << c1 << "%m" << c1 << "%d" << c3 << "%H" << c2 << "%M" << c2 << "%S";
std::string fmt = ss.str();
ss.str("");
auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
ss << std::put_time(std::localtime(&t), fmt.c_str());
return ss.str();
}
std::string TimeUtils::now_date(char c1/* = '/'*/)
{
std::stringstream ss;
ss << "%Y" << c1 << "%m" << c1 << "%d";
std::string fmt = ss.str();
ss.str("");
auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
ss << std::put_time(std::localtime(&t), fmt.c_str());
return ss.str();
}
int64_t TimeUtils::datetime2ts(std::string s)
{
// YYYY-mm-dd HH:MM:SS
if (s.size() < 19) { return 0; }
s[4] = s[7] = '-';
s[10] = ' ';
s[13] = s[16] = ':';
std::tm t;
std::stringstream ss(s);
ss >> std::get_time(&t, "%Y-%m-%d %H:%M:%S");
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&t));
return std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch()).count();
}
int64_t TimeUtils::datetime2tms(std::string s)
{
if (s.size() < 19) { return 0; }
s[4] = s[7] = '-';
s[10] = ' ';
s[13] = s[16] = ':';
std::tm t;
std::stringstream ss(s);
ss >> std::get_time(&t, "%Y-%m-%d %H:%M:%S");
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&t));
return std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch()).count();
}
std::string TimeUtils::ts2datetime(int64_t ts, std::string fmt /*= "%Y-%m-%d %H:%M:%S"*/)
{
// std::localtime : 本地时区的时间
// std::gmtime : 格林威治时间
time_t t(ts);
std::stringstream ss;
ss << std::put_time(std::localtime(&t), fmt.c_str());
return ss.str();
}
std::string TimeUtils::ts2date(int64_t ts)
{
time_t t(ts);
std::stringstream ss;
ss << std::put_time(std::localtime(&t), "%Y-%m-%d");
return ss.str();
}
std::string TimeUtils::duration_str(int64_t t)
{
auto h = t / 3600;
auto m = (t % 3600) / 60;
auto s = (t % 3600) % 60;
std::string str = std::to_string(s) + "";
if (m > 0 || h > 0)
{
str = std::to_string(m) + "" + str;
}
if (h > 0)
{
str = std::to_string(h) + "小时" + str;
}
return str;
}
int64_t TimeUtils::tick(std::function<void()> func)
{
if (!func)
{
return 0;
}
auto start = std::chrono::steady_clock::now();
func();
auto end = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
}

28
src/common/TimeUtils.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef _TimeUtils_H_
#define _TimeUtils_H_
#include <string>
#include <functional>
class TimeUtils
{
public:
static int64_t now();
static int64_t now_ms();
static std::string now_datetime(char c1 = '-', char c2 = ':', char c3 = ' ');
static std::string now_date(char c1 = '-');
static int64_t datetime2ts(std::string s);
static int64_t datetime2tms(std::string s);
static std::string ts2datetime(int64_t ts, std::string fmt = "%Y-%m-%d %H:%M:%S");
static std::string ts2date(int64_t ts);
static std::string duration_str(int64_t t);
static int64_t tick(std::function<void()> func);
};
#endif // !_TimeUtils_H_

429
src/common/Utils.cpp Normal file
View File

@@ -0,0 +1,429 @@
#include "Utils.h"
#include <thread>
#include <chrono>
#include <iostream>
using namespace std;
string Utils::toStr(int v)
{
return std::to_string(v);
}
string Utils::toStr(float v, int precision)
{
stringstream ss;
ss.precision(precision);
ss.setf(std::ios::fixed);
ss << v;
return ss.str();
}
string Utils::toStr(double v, int precision)
{
stringstream ss;
ss.precision(precision);
ss.setf(std::ios::fixed);
ss << v;
return ss.str();
}
int Utils::toInt(const std::string& str)
{
stringstream ss(str);
int ret = 0;
ss >> ret;
return ret;
}
float Utils::toFloat(const string& str)
{
stringstream ss(str);
float ret = 0.0f;
ss >> ret;
return ret;
}
double Utils::toDouble(const std::string& str)
{
stringstream ss(str);
double ret = 0.0;
ss >> ret;
return ret;
}
int64_t Utils::hexbinToInt(const string& str, bool swap/*=false*/)
{
int64_t v = 0;
for (size_t i = 0; i < str.size(); i++)
{
if (swap)
{
v = v + (str[str.size() - 1 - i] << (str.size() - 1 - i) * 8);
}
else
{
v = v + (str[i] << (str.size() - 1 - i) * 8);
}
}
return v;
}
int Utils::hexstrToInt(const std::string& str)
{
stringstream ss;
int ret;
ss << hex << str.c_str();
ss >> ret;
return ret;
}
#include <iostream>
string Utils::from_hex_text(string s)
{
vector<unsigned char> result;
string tmp;
stringstream ss;
int v;
for (auto ch : s)
{
if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))
{
tmp += ch;
if (tmp.size() == 2)
{
ss.clear();
ss.str("");
ss << hex << tmp;
ss >> v;
result.emplace_back((unsigned char)v);
tmp.clear();
}
}
}
return string(result.begin(), result.end());
}
//string Utils::fromHexText1(string s)
//{
// vector<unsigned char> result;
// string tmp = s;
// stringstream ss;
// int v;
// size_t pos = 0;
// while (!tmp.empty())
// {
// if (pos >= tmp.size()) {
// ss.clear();
// ss.str("");
// ss << hex << tmp;
// ss >> v;
// result.emplace_back((unsigned char)v);
// tmp = "";
// break;
// }
// auto& ch = tmp[pos];
// bool flag = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
// if (!flag) {
// ss.clear();
// ss.str("");
// ss << hex << tmp.substr(0, pos);
// ss >> v;
// tmp = tmp.substr(pos + 1);
// result.emplace_back((unsigned char)v);
// pos = 0;
// }
// ++pos;
// }
// return string(result.begin(), result.end());
//}
string Utils::to_hex_text(string s, string d/* = " "*/)
{
stringstream ss;
for (unsigned int i = 0; i < s.size(); ++i)
{
unsigned char ch = s[i];
ss << std::setw(2) << std::setfill('0') << std::hex << std::uppercase << (int)ch << ((i < s.size() - 1) ? d : "");
}
return ss.str();
}
void time_point_to_duration()
{
auto tp = std::chrono::system_clock::now();
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch());
cout << seconds.count() << " s" << endl;//seconds from 1970
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
cout << ms.count() << " ms" << endl;
auto us = std::chrono::duration_cast<std::chrono::microseconds>(tp.time_since_epoch());
cout << us.count() << " us" << endl;
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(tp.time_since_epoch());
cout << ns.count() << " ns" << endl;
cout << tp.time_since_epoch().count() << " default is ns" << endl;
}
void duration_to_time_point()
{
std::uint64_t ticker = 1609756793160376465;
auto ns = std::chrono::nanoseconds(ticker);
auto tp1 = std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>(ns);
auto tp2 = tp1 - std::chrono::hours(1);//time point before one hour
cout << "tp1=" << tp1.time_since_epoch().count() << endl << "tp2=" << tp2.time_since_epoch().count() << endl;
}
void format_time_point()
{
auto tp = std::chrono::system_clock::now();
auto time = std::chrono::system_clock::to_time_t(tp);
std::stringstream ss;
ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S");
cout << ss.str() << endl;
}
void parse_from_string()
{
std::stringstream ss;
ss << "2021-01-06 18:47:35";
std::tm tm{};
ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
cout << tp.time_since_epoch().count() << endl;
}
int64_t Utils::timeNow()
{
// return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
return std::chrono::time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now()).time_since_epoch().count();
}
int64_t Utils::timeNowMS()
{
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
//return std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
}
string Utils::timeNowStr(std::string fmt /*= "%Y-%m-%dT%H:%M:%S"*/)
{
auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::stringstream ss;
ss << std::put_time(std::localtime(&t), fmt.c_str());
return ss.str();
}
string Utils::timeNowStrMS(std::string fmt /*= "%Y-%m-%dT%H:%M:%S"*/)
{
auto tpNow = std::chrono::system_clock::now();
auto time = std::chrono::system_clock::to_time_t(tpNow);
std::stringstream ss;
ss << std::put_time(std::localtime(&time), fmt.c_str());
auto tms = std::chrono::duration_cast<std::chrono::milliseconds>(tpNow.time_since_epoch());
auto tseconds = std::chrono::duration_cast<std::chrono::seconds>(tpNow.time_since_epoch());
ss << "." << std::setfill('0') << std::setw(3) << (tms - tseconds).count();
return ss.str();
}
string Utils::timeStr(int64_t ts, std::string fmt /*= "%Y-%m-%d %H:%M:%S"*/)
{
// std::localtime : 本地时区的时间
// std::gmtime : 格林威治时间
time_t t(ts);
std::stringstream ss;
ss << std::put_time(std::localtime(&t), fmt.c_str());
return ss.str();
}
string Utils::time_to_string(int64_t dt, std::string fmt /*= "%Y-%m-%d %H:%M:%S"*/)
{
auto ms = std::chrono::milliseconds(dt);
auto tp = std::chrono::time_point<std::chrono::system_clock>(ms);
time_t t = std::chrono::system_clock::to_time_t(tp);
std::stringstream ss;
ss << std::put_time(std::localtime(&t), fmt.c_str());
return ss.str();
}
// 2023-12-12 12:12:12
int64_t Utils::time(string dt, int zone)
{
if (dt.empty())
{
return std::chrono::time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now()).time_since_epoch().count();
}
else
{
static string FMT_D = "yyyy-MM-dd";
static string FMT_DT = "yyyy-MM-dd HH:mm:ss";
static string FMT_DS = "yyyy-MM-dd HH:mm:ss.SSS";
string fmt;
if (dt.size() == FMT_D.size())
{
fmt = "%Y-%m-%d";
dt[4] = dt[7] = '-';
}
else if (dt.size() == FMT_DT.size())
{
fmt = "%Y-%m-%d %H:%M:%S";
dt[4] = dt[7] = '-';
dt[10] = ' ';
dt[13] = dt[16] = ':';
}
else if (dt.size() == FMT_DT.size())
{
}
else
{
return -1;
}
stringstream ss(dt);
std::tm t {};
ss >> std::get_time(&t, fmt.c_str());
t.tm_hour += zone;
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&t));
return std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch()).count();
//return std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch()).count();
}
}
bool Utils::time_string_to_tm(string dt, std::tm& t)
{
t.tm_year = 1900;
t.tm_mon = 1;
t.tm_mday = 1;
static string FORMAT_D = "yyyy-mm-dd";
static string FORMAT_DT = "yyyy-mm-dd HH:MM:SS";
string fmt;
if (dt.size() == FORMAT_D.size())
{
fmt = "%Y-%m-%d";
dt[4] = dt[7] = '-';
}
else if (dt.size() >= FORMAT_DT.size())
{
fmt = "%Y-%m-%d %H:%M:%S";
dt[4] = dt[7] = '-';
dt[10] = ' ';
dt[13] = dt[16] = ':';
}
else
{
return false;
}
stringstream ss;
ss << dt;
ss >> std::get_time(&t, fmt.c_str());
t.tm_year += 1900;
t.tm_mon += 1;
return true;
}
void Utils::sleep_ms(int ms)
{
// 计算时间间隔:
//auto start = std::chrono::high_resolution_clock::now();
//auto end = std::chrono::high_resolution_clock::now();
//std::chrono::duration<double, std::milli> elapsed = end - start;
//int64_t t = elapsed.count();
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}
#include <Windows.h>
unsigned short Utils::crc16(unsigned char* data, unsigned int len)
{
if (data == NULL || len == 0)
{
return 0;
}
unsigned short crc = 0xffff;
unsigned short FACTOR = 0xa001;
for (int i = 0; i < len; i++)
{
crc ^= data[i];
for (int j = 0; j < 8; j++)
{
if ((crc & 0x0001) != 0)
{
crc >>= 1;
crc ^= FACTOR;
}
else
{
crc >>= 1;
}
}
}
//(unsigned char)(CRC & 0x00ff);
//(unsigned char)(CRC >> 8);
return crc;
}
string Utils::gbkToUtf8(string s)
{
int n = MultiByteToWideChar(CP_ACP, 0, s.c_str(), -1, NULL, 0);
WCHAR* str1 = new WCHAR[n];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), -1, str1, n);
n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL);
vector<char> s_utf8(n, 0);
WideCharToMultiByte(CP_UTF8, 0, str1, -1, &s_utf8[0], n, NULL, NULL);
delete[]str1;
str1 = NULL;
return string(s_utf8.begin(), s_utf8.end());
}
string Utils::utf8ToGbk(string s)
{
string s_gbk = "";
int n = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0);
WCHAR* str1 = new WCHAR[n];
MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, str1, n);
n = WideCharToMultiByte(CP_ACP, 0, str1, -1, NULL, 0, NULL, NULL);
char* str2 = new char[n];
WideCharToMultiByte(CP_ACP, 0, str1, -1, str2, n, NULL, NULL);
s_gbk = str2;
delete[] str1;
str1 = NULL;
delete[] str2;
str2 = NULL;
return s_gbk;
}
#include <random>
int Utils::random(int min, int max)
{
//生成 a 到 b 之间(包含)均匀分布的随机数
uniform_int_distribution<unsigned> rand_u(min, max);
static default_random_engine rand_e; // 生成无符号随机整数
return rand_u(rand_e);
}
void Utils::split(string buf, string c, vector<string>& res)
{
if (buf.size() == 0 || c.size() == 0)
{
return;
}
string tmp = buf;
while (true)
{
auto pos = tmp.find(c);
if (pos == string::npos)
{
res.push_back(tmp);
break;
}
res.push_back((pos == 0) ? "" : tmp.substr(0, pos));
tmp = tmp.substr(pos + c.size());
}
}

111
src/common/Utils.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef _Utils_H_
#define _Utils_H_
#include <vector>
#include <string>
#include <sstream>
#include <string.h>
#include <iomanip>
#include <functional>
#include <thread>
//#include "Crypto.h"
using namespace std;
class Utils
{
public:
static string toStr(int v);
static string toStr(float v, int precision = 2);
static string toStr(double v, int precision = 2);
static int toInt(const std::string& str);
static float toFloat(const string& str);
static double toDouble(const string& str);
static int64_t hexbinToInt(const string& str, bool swap = false);
static int hexstrToInt(const string& str);
static string from_hex_text(string s);
static string to_hex_text(string s, string d = " ");
template<typename T>
static void append_bytes(vector<unsigned char>& dest, const T& src, int len)
{
int start = static_cast<int>(dest.size());
dest.resize(start + len);
memcpy_s(&dest[start], len, &src, len);
}
static int64_t timeNow();
static int64_t timeNowMS();
static string timeNowStr(std::string fmt = "%Y-%m-%d %H:%M:%S");
static string timeNowStrMS(std::string fmt = "%Y-%m-%d %H:%M:%S");
static string timeStr(int64_t ts, std::string fmt = "%Y-%m-%d %H:%M:%S");
static int64_t time(string dt="", int zone = 0);
static string time_to_string(int64_t dt, std::string fmt="%Y-%m-%d %H:%M:%S");
static bool time_string_to_tm(string dt, std::tm& t);
std::string duration_str(int64_t t)
{
auto h = t / 3600;
auto m = (t % 3600) / 60;
auto s = (t % 3600) % 60;
std::string str = std::to_string(s) + "";
if (m > 0 || h > 0)
{
str = std::to_string(m) + "" + str;
}
if (h > 0)
{
str = std::to_string(h) + "小时" + str;
}
return str;
}
static unsigned short crc16(unsigned char* data, unsigned int len);
static string Utils::gbkToUtf8(string s);
static string Utils::utf8ToGbk(string s);
static void sleep_ms(int ms);
static int random(int min, int max);
static void split(string buf, string c, vector<string>& res);
};
class TimeTick
{
public:
int64_t tickMS_ = 0;
TimeTick()
{
tickMS_ = Utils::timeNowMS();
}
bool elapse(int64_t ms, bool reset = true)
{
auto tick_now = Utils::timeNowMS();
bool res = tick_now - tickMS_ > ms;
if (res && reset)
{
tickMS_ = tick_now;
}
return res;
}
void reset()
{
tickMS_ = Utils::timeNowMS();
}
};
#endif // !!! _Utils_H_

View File

@@ -0,0 +1,76 @@
#include "DbSqlite.h"
#include <iostream>
#include <string>
#include "common/Spdlogger.h"
DbSqlite::DbSqlite(const char* dbName)
{
if (SQLITE_OK != sqlite3_open(dbName, &sqlite_))
{
Spdlogger::error("open sqlite failed");
}
else
{
Spdlogger::info("open sqlite success");
}
}
DbSqlite::~DbSqlite()
{
this->close();
}
void DbSqlite::open(const char* dbname)
{}
void DbSqlite::close()
{
if (sqlite_ != nullptr)
{
sqlite3_close(sqlite_);
}
}
bool DbSqlite::exec(const char* sql)
{
char* errMsg;//操作失败的原因。
//std::string ssql="CREATE TABLE T_USER(username varchar(30) unique)";
if (SQLITE_OK != sqlite3_exec(sqlite_, sql, 0, 0, &errMsg))
{
Spdlogger::error("create table failed:{}", errMsg);
return false;
}
return true;
}
bool DbSqlite::prepare_step(const char* sql, CallbackSqliteRowData& cb)
{
sqlite3_stmt* stmt = nullptr;
if (SQLITE_OK != sqlite3_prepare_v2(sqlite_, sql, -1, &stmt, 0))
{
Spdlogger::error("sqlite3_prepare_v2 failed:");
return false;
}
Spdlogger::info("sqlite3 step sql=", sql);
while (SQLITE_ROW == sqlite3_step(stmt))
{
Spdlogger::info("sqlite3_step row data:");
if (cb) { cb(stmt); }
}
sqlite3_finalize(stmt);
return true;
}
int DbSqlite::get_int(sqlite3_stmt* stmt, int index)
{
return sqlite3_column_int(stmt, index);
}
double DbSqlite::get_double(sqlite3_stmt* stmt, int index)
{
return sqlite3_column_double(stmt, index);
}
std::string DbSqlite::get_text(sqlite3_stmt* stmt, int index)
{
return (char*)sqlite3_column_text(stmt, index);
}

32
src/database/0/DbSqlite.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef _DbSqlite_H_
#define _DbSqlite_H_
#include "sqlite3.h"
#include <string>
#include <functional>
using CallbackSqliteRowData = std::function<void(sqlite3_stmt*)>;
class DbSqlite
{
public:
DbSqlite(const char* dbname);
~DbSqlite();
void open(const char* dbname);
bool exec(const char* sql);
bool prepare_step(const char* sql, CallbackSqliteRowData& cb);
void close();
int get_int(sqlite3_stmt* stmt, int index);
double get_double(sqlite3_stmt* stmt, int index);
std::string get_text(sqlite3_stmt* stmt, int index);
private:
sqlite3* sqlite_ = nullptr;
};
#endif // !!! _DbSqlite_H_

218
src/database/DaoEntity.cpp Normal file
View File

@@ -0,0 +1,218 @@
#include "DaoEntity.h"
//#include "PvInstance.h"
//#include "spdlogger.h"
MysqlOptions DaoEntity::options_;
DaoEntity::DaoEntity(string tb_name)
{
//MysqlOptions opts;
//opts.host = "localhost";
//opts.user = "root";
//opts.password = "123456";
//opts.port = 3306;
//opts.dbname = "pvb";
db_ = make_shared<MysqlClient>(DaoEntity::options_);
if (!db_->isConnected())
{
//Global::data().status_msg = "数据库连接异常!";
//PvInstance::send_user_event(nullptr, EUserEvent::ALARM_DB, "数据库连接异常!");
}
tableName_ = tb_name;
}
DaoEntity::~DaoEntity()
{
db_ = nullptr;
}
MysqlOptions& DaoEntity::mysqlOptions()
{
return DaoEntity::options_;
}
std::shared_ptr<DaoEntity> DaoEntity::create(string tb_name)
{
std::shared_ptr<DaoEntity> dao = std::make_shared<DaoEntity>(tb_name);
return (dao->isConnected() ? dao : nullptr);
}
bool DaoEntity::execOnce(string sql)
{
auto db = make_shared<MysqlClient>(DaoEntity::options_);
return db->exec(sql);
}
bool DaoEntity::execOnce(string sql, vector<DataFields>& result)
{
auto db = make_shared<MysqlClient>(DaoEntity::options_);
return db->exec(sql, result);
}
void DaoEntity::setTableName(string tb_name)
{
tableName_ = tb_name;
}
bool DaoEntity::isConnected()
{
return db_->isConnected();
}
bool DaoEntity::exec(string sql)
{
return db_->exec(sql);
}
bool DaoEntity::exec(string sql, vector<DataFields>& result)
{
return db_->exec(sql, result);
}
bool DaoEntity::insertFields(DataFields& fields)
{
string sql = fields.get_insert_sql(tableName_);
return this->db_->exec(sql);
}
bool DaoEntity::insertFields(vector<DataFields>& vec_fields)
{
//"insert into TABLE () values ()";
string sql = "insert into " + tableName_;
bool first = true;
string keys;
string values;
for (auto& field : vec_fields)
{
keys = "";
values = "";
for (auto& item : field.fields())
{
const string& k = item.first;
const string& v = item.second;
if (first)
{
if (!keys.empty())
{
keys += ",";
}
keys += k;
}
if (!values.empty())
{
values += ",";
}
values += ("'" + v + "'");
}
if (first)
{
sql += (" (" + keys + ")");
sql += (" values (" + values + ")");
first = !first;
}
else
{
sql += (",(" + values + ")");
}
}
sql += ";";
return this->db_->exec(sql);
}
bool DaoEntity::duplicateUpdate(DataFields& fields, vector<string>& keys)
{
//insert into device_attr(device_id, attr_id, attr_val) values('26', 'model', '型号1') on duplicate key update attr_val='型号1';
string s_key;
string s_val;
for (auto& item : fields.fields())
{
if (!s_key.empty())
{
s_key += ","; s_val += ",";
}
s_key += (item.first);
s_val += ("'" + item.second + "'");
}
string s_data;
for (auto& k : keys)
{
if (!s_data.empty())
{
s_data += ",";
}
s_data += (k + "='" + fields.get_str(k) + "'");
}
string sql = "INSERT INTO " + tableName_ + "(" + s_key + ") VALUES (" + s_val + ") ON duplicate KEY UPDATE " + s_data;
return this->db_->exec(sql);
}
//void DaoEntity::queryFields(const string& condition, DaoPageinfo& pageinfo, vector<map<string, string>>& result)
//{
// this->query_by_page(condition, pageinfo, [&](map<string, string>& row) mutable {
// result.push_back(row);
// });
//}
bool DaoEntity::queryFields(string keys, const string& sql_c, vector<DataFields>& result)
{
ostringstream oss;
oss << "SELECT " + keys + " FROM " << tableName_ << (" " + sql_c) << "; ";
return this->db_->exec(oss.str(), result);
}
bool DaoEntity::queryFields(string keys, const string& sql_c, PageInfo& pageinfo, vector<DataFields>& result)
{
ostringstream oss;
oss << "SELECT count(1) total FROM `" << tableName_ << "` " << sql_c << ";";
vector<DataFields> res_total;
if (!this->db_->exec(oss.str().c_str(), res_total))
{
return false;
}
if (res_total.size() <= 0)
{
pageinfo.total = 0;
return true;
}
pageinfo.total = res_total[0].get_int("total");
if (pageinfo.total <= 0)
{
return true;
}
pageinfo.page_max = pageinfo.total / pageinfo.page_size + (pageinfo.total % pageinfo.page_size > 0 ? 1 : 0);
oss.str("");
if (pageinfo.page_id <= 0)
{
pageinfo.page_id = 1;
}
int start = (pageinfo.page_id - 1) * pageinfo.page_size;
oss << "SELECT " << keys << " FROM `" << tableName_ << "` " << sql_c << " LIMIT " << start << "," << pageinfo.page_size << ";";
return this->db_->exec(oss.str().c_str(), result);
}
bool DaoEntity::updateFields(DataFields& fields, const string& sql_c)
{
string sql = fields.get_update_sql(tableName_, sql_c);
if (sql_c.empty())
{
//Spdlogger::error("[DB] update condition is empty, not exec, sql={}", sql);
return false;
}
return this->db_->exec(sql.c_str());
}
bool DaoEntity::updateFields(DataFields& fields, vector<string> vec_keys, const string& sql_c)
{
string sql = fields.get_update_sql(tableName_, vec_keys, sql_c);
if (sql_c.empty())
{
//Spdlogger::error("[DB] update condition is empty, not exec, sql={}", sql);
return false;
}
return this->db_->exec(sql.c_str());
}

111
src/database/DaoEntity.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef _DaoBase_H_
#define _DaoBase_H_
#include "MysqlClient.h"
class DaoEntity
{
public:
DaoEntity(string tableName);
~DaoEntity();
static MysqlOptions& mysqlOptions();
static std::shared_ptr<DaoEntity> create(string tableName);
/**
* 执行sql语句
* @param: sql 要执行的完整 sql 语句
*/
static bool execOnce(string sql);
/**
* 执行sql语句返回结果数据集
* @param: sql 要执行的完整 sql 语句
* @param: result 返回的结果数据集
*/
static bool execOnce(string sql, vector<DataFields>& result);
/**
* 设置数据库表名称
* @param: tableName 数据表名
*/
void setTableName(string tableName);
/**
* 设置数据库表名称
* @return: bool true: 连接成功false未连接/连接失败
*/
bool isConnected();
/**
* 执行sql语句
*/
bool exec(string sql);
/**
* 执行sql语句并返回执行查询的结果集
*/
bool exec(string sql, vector<DataFields>& result);
/**
* 数据库插入一条数据, 需要先指定数据表名称
* @param: fields 写入的数据字段和值
*/
bool insertFields(DataFields& vecFields);
/**
* 数据库插入多条数据, 需要先指定数据表名称
* @param: vecFields 写入的数据字段和值的集合
*/
bool insertFields(vector<DataFields>& vecFields);
/**
* 数据库插入多条数据UNIQUE索引或PRIMARY KEY重复时执行更新数据, 需要先指定数据表名称
* @param: vecFields 写入的数据字段和值的集合
* @param: keys 数据重复时需要更新的字段
*/
bool duplicateUpdate(DataFields& vecFields, vector<string>& keys);
/**
* 数据库查询,需要先指定数据表名称
* @param: sql_c 查询条件,例:"where id='1'"
* @param: result 查询的数据结果集
*/
bool queryFields(string keys, const string& sql_c, vector<DataFields>& result);
/**
* 数据库查询,需要先指定数据表名称
* @param: sql_c 查询条件,例:"where id='1'"
* @param: pageinfo 分页信息
* @param: result 查询的数据结果集
*/
bool queryFields(string keys, const string& sql_c, PageInfo& pageinfo, vector<DataFields>& result);
/**
* 数据库更新,需要先指定数据表名称
* @param: fields 要更新的数据字段和值
* @param: sql_c 更新条件
*/
bool updateFields(DataFields& fields, const string& sql_c);
/**
* 数据库更新,需要先指定数据表名称
* @param: fields 要更新的数据值
* @param: vecKeys 要更新的字段名称
* @param: cond 更新条件
*/
bool updateFields(DataFields& fields, vector<string> vecKeys, const string& cond);
protected:
static MysqlOptions options_;
// mysql 数据库操作对象
std::shared_ptr<MysqlClient> db_ = nullptr;
// 数据库表名称
string tableName_;
};
#endif // !!! _DaoBase_H_

View File

@@ -0,0 +1,122 @@
#include "MysqlClient.h"
#include "common/Utils.h"
//#include "Spdlogger.h"
#include "Logger.h"
MysqlClient::MysqlClient(MysqlOptions opts) : options_(opts)
{
conn();
}
MysqlClient::~MysqlClient()
{
this->close();
}
int MysqlClient::conn()
{
if (mysql_)
{
return 0;
}
mysql_ = mysql_init(nullptr);
MYSQL* ret = mysql_real_connect(mysql_, options_.host.c_str(), options_.user.c_str(), options_.password.c_str(), options_.dbname.c_str(), options_.port, NULL, 0);
if (ret == NULL)
{
//Spdlogger::info("[mysql] connect failed: {}", mysql_error(mysql_));
mysql_ = nullptr;
}
else
{
mysql_query(mysql_, "set names 'utf8';");
}
return 0;
}
bool MysqlClient::isConnected()
{
return (mysql_ != nullptr);
}
void MysqlClient::close()
{
if (mysql_)
{
mysql_close(mysql_);
mysql_ = nullptr;
}
}
bool MysqlClient::exec(std::string sql)
{
XLOGD() << "Mysql exec sql=" << sql;
if (!mysql_)
{
XLOGE() << "Mysql exec error, database is not connected.";
return false;
}
int ret = mysql_query(mysql_, sql.c_str());
if (0 != ret)
{
XLOGE() << "Mysql exec error: " << mysql_error(mysql_) << ", sql=" << sql;
return false;
}
return true;
}
bool MysqlClient::exec(std::string sql, vector<DataFields>& result)
{
result.clear();
if (!mysql_)
{
return false;
}
int ret = mysql_query(mysql_, sql.c_str());
if (0 != ret)
{
//Spdlogger::error("[mysql] mysql_query failed!! error ret={:d}, sql={}", ret, sql);
XLOGE() << "mysql error: " << sql;
return false;
}
else
{
//Spdlogger::info("[mysql] query success. sql={}", sql);
}
MYSQL_RES* res = mysql_store_result(mysql_);
if (!res)
{
return false;
}
vector<string> field_names;
while (true)
{
MYSQL_FIELD* field = mysql_fetch_field(res);
if (!field)
{
break;
}
field_names.push_back(field->name);
}
while (true)
{
MYSQL_ROW row = mysql_fetch_row(res);
if (!row)
{
break;
}
DataFields row_data;
for (size_t i = 0; i < field_names.size(); ++i)
{
string field_text = (row[i] == NULL) ? "" : row[i];
row_data.set(field_names[i], field_text);
}
result.push_back(row_data);
}
// 释放结果集
mysql_free_result(res);
return true;
}

View File

@@ -0,0 +1,68 @@
#ifndef _DbMysql_H_
#define _DbMysql_H_
#pragma warning(disable:4100)
#include <sstream>
#include <memory>
#include <iostream>
#include <functional>
#include <string>
#include <map>
#include <vector>
#include "mysql.h"
#include "DataFields.h"
using namespace std;
struct MysqlOptions
{
std::string host;
std::string user;
std::string password;
std::string dbname;
int port;
};
class MysqlClient
{
public:
MysqlClient(MysqlOptions options);
~MysqlClient();
/**
* @brief: 连接MYSQL数据库
* return: [int]
*/
int conn();
/**
* @brief 是否成功连接数据库
* @return true:连接成功false:未连接或连接失败
*/
bool isConnected();
/**
* @brief: 关闭数据库连接
*/
void close();
/**
* @brief: 执行sql语句
*/
bool exec(std::string sql);
/**
* @brief: 执行sql语句, 获取查询结果集
*/
bool exec(std::string, vector<DataFields>& result);
private:
// mysql数据库连接对象
MYSQL* mysql_ = nullptr;
// 数据库连接信息
MysqlOptions options_;
};
#endif // !!! _DbMysql_H_

88
src/database/SQL.h Normal file
View File

@@ -0,0 +1,88 @@
#pragma once
#include <string>
class SQL
{
public:
enum class TYPE
{
insert = 1,
select,
update,
del,
};
SQL(TYPE t = TYPE::select) : type(t)
{
}
std::string str()
{
if (type == TYPE::select)
{
// SELECT * from t_tabname WHERE id='1';
if (sql_k.empty()) {}
std::string s = "SELECT " + (sql_k.empty() ? "*" : sql_k) + " FROM `" + tabname + "`";
if (!sql_c.empty()) { s += (" WHERE" + sql_c); }
return s + ";";
}
else if (type == TYPE::update)
{
// UPDATE t_tabname SET a='1', b='2' WHERE id='1';
std::string s = "UPDATE `" + tabname + "` SET " + sql_k + " WHERE" + sql_c;
return s + ";";
}
else if (type == TYPE::insert)
{
// INSERT INTO t_tabname (a,b,c) VALUES('1','2','3');
std::string s = "INSERT INTO `" + tabname + "` (" + sql_k + ") VALUES(" + sql_v + ");";
return s;
}
else if (type == TYPE::del)
{
return "";
}
return "";
}
SQL& table(std::string t)
{
tabname = t;
return *this;
}
SQL& select(std::string k)
{
if (!sql_k.empty()) { sql_k += ","; }
sql_k += k;
return *this;
}
SQL& where(std::string expr)
{
sql_c += (" " + expr);
return *this;
}
SQL& update(std::string k, std::string v)
{
if (!sql_k.empty()) { sql_k += ","; }
sql_k += ("`" + k + "`='" + v + "'");
return *this;
}
SQL& insert(std::string k, std::string v)
{
if (!sql_k.empty()) { sql_k += ","; }
sql_k += ("`" + k + "`");
if (!sql_v.empty()) { sql_v += ","; }
sql_v += ("'" + v + "'");
return *this;
}
private:
TYPE type = TYPE::select;
std::string tabname;
std::string sql_k;
std::string sql_v;
std::string sql_c;
};

View File

@@ -0,0 +1,120 @@
#include "DaoAdmin.h"
#include "Crypto.h"
#include "database/DaoEntity.h"
#include "common/Snowflake.h"
bool DaoAdmin::insert_operator(DataFields& fields)
{
// 数据库 id 自增
fields.remove(DMOperator::FID_ID);
DaoEntity dao(DMOperator::TABLENAME);
return dao.insert_fields(fields);
}
bool DaoAdmin::update_operator_by_id(DataFields& fields)
{
string id = fields.get_str(DMOperator::FID_ID);
fields.remove(DMOperator::FID_ID);
fields.remove(DMOperator::FID_CREATETIME);
fields.remove(DMOperator::FID_UPDATETIME);
fields.set(DMOperator::FID_PASSWD, Crypto::md5("123456"));
DaoEntity dao(DMOperator::TABLENAME);
return dao.update_fields(fields, "WHERE id='" + id + "'");
}
bool DaoAdmin::query_operator_page(PageInfo& pageinfo, vector<DataFields>& result)
{
DaoEntity dao(DMOperator::TABLENAME);
return dao.query_fields("*", "", pageinfo, result);
}
bool DaoAdmin::query_operator_by_name(string name, vector<DataFields>& result)
{
string sql_c = "where username = '" + name + "';";
DaoEntity dao(DMOperator::TABLENAME);
return dao.query_fields("*", sql_c, result);
}
static void LogDaoResult(vector<DataFields>& vec_fields)
{
for (int i = 0; i < vec_fields.size(); i++)
{
string s = "{";
vec_fields[i].foreach_item([&](string key, string val)
{
s += (key + ":" + val + ", ");
});
s = s.substr(0, s.size() - 2);
s += "}";
}
}
bool DaoAdmin::query_role(vector<DataFields>& result)
{
DaoEntity dao(DMRole::TABLENAME);
dao.query_fields("*", "", result);
LogDaoResult(result);
return true;
}
bool DaoAdmin::update_role_by_id(DataFields& fields)
{
string id = fields.get_str(DMRole::FID_ID);
fields.remove(DMRole::FID_ID);
string sql_c = "where " + DMRole::FID_ID + "='" + id + "'";
DaoEntity dao(DMRole::TABLENAME);
return dao.update_fields(fields, sql_c);
}
int DaoAdmin::insert_permission(DataFields& fields)
{
DaoEntity dao(DMPermission::TABLENAME);
return dao.insert_fields(fields);
}
bool DaoAdmin::query_permission(PageInfo& pageinfo, vector<DataFields>& result, string sql_c)
{
DaoEntity dao(DMPermission::TABLENAME);
return dao.query_fields("*", sql_c, pageinfo, result);
}
bool DaoAdmin::update_permission(DataFields& fields, const string& sql_c)
{
fields.remove(DMPermission::FID_ID);
DaoEntity dao(DMPermission::TABLENAME);
return dao.update_fields(fields, sql_c);
}
bool DaoAdmin::query_admin_permission(string account, vector<DataFields>& result)
{
string sql = "select role.role_name, role_permission.*, permission.func from operator "
"left join role on operator.role_name = role.role_name "
"left join role_permission on role_permission.role_id = role.id "
"left join permission on permission.id = role_permission.permission_id "
"where operator.username = '" + account + "' order by permission_id; ";
return DaoEntity::exec_once(sql, result);
}
int DaoAdmin::insert_policy(DataFields& fields)
{
DaoEntity dao(DMPolicy::TABLENAME);
return dao.insert_fields(fields);
}
bool DaoAdmin::query_policy(PageInfo& pageinfo, vector<DataFields>& result, string sql_c)
{
DaoEntity dao(DMPolicy::TABLENAME);
return dao.query_fields("*", sql_c, pageinfo, result);
}
bool DaoAdmin::update_policy(DataFields& fields, const string& sql_c)
{
fields.remove(DMPolicy::FID_ID);
fields.remove(DMPolicy::FID_UPDATE_TIME);
DaoEntity dao(DMPolicy::TABLENAME);
return dao.update_fields(fields, sql_c);
}

118
src/database/dao/DaoAdmin.h Normal file
View File

@@ -0,0 +1,118 @@
#pragma once
#include "DataFields.h"
struct PageInfo;
namespace DMOperator
{
const string TABLENAME = "operator";
const string FID_ID = "id";
const string FID_USERNAME = "username";
const string FID_PASSWD = "passwd";
const string FID_REALNAME = "real_name";
const string FID_PHONE = "phone";
const string FID_ROLE = "role_name";
const string FID_CREATETIME = "create_time";
const string FID_UPDATETIME = "update_time";
}
namespace DMRole
{
const string TABLENAME = "role";
const string FID_ID = "id";
const string FID_ROLE_NAME = "role_name";
const string FID_ROLE_NO = "role_no";
const string FID_TYPE = "type";
const string FID_DESCRIBE = "describe";
const string FID_IS_OPEN = "is_open";
}
namespace DMPermission
{
const string TABLENAME = "permission";
const string FID_ID = "id";
const string FID_FUNC = "func";
const string FID_URL = "url";
const string FID_REMARK = "remark";
}
namespace DMRolePermission
{
const string TABLENAME = "role_permission";
const string FID_ID = "id";
const string FID_ROLE_ID = "role_id";
const string FID_PERMISSION_ID = "permission_id";
}
namespace DMPolicy
{
const string TABLENAME = "policy";
const string FID_ID = "id";
const string FID_TYPE = "type";
const string FID_CODE = "code";
const string FID_NAME = "name";
const string FID_VALUE = "value";
const string FID_REMARK = "remark";
const string FID_IS_OPEN = "is_open";
const string FID_UPDATE_TIME = "update_time";
}
class DaoAdmin
{
public:
// ************************************************************************************************
// 操作员账号管理
/**
* 更新操作员信息
* @param: fields 更新的字段信息
* @param: sql_c 更新条件, 例:"where id='1'"
*/
static bool insert_operator(DataFields& fields);
/**
* 更新操作员信息
* @param: fields 更新的字段信息
*/
static bool update_operator_by_id(DataFields& fields);
/**
* 分页查询操作员信息
* @param: pageinfo 分页信息
* @paramresult 查询结果数据集
*/
static bool query_operator_page(PageInfo& pageinfo, vector<DataFields>& result);
static bool query_operator_by_name(string name, vector<DataFields>& result);
// ************************************************************************************************
// 权限管理
//
static int insert_permission(DataFields& fields);
static bool query_permission(PageInfo& pageinfo, vector<DataFields>& result, string sql_c);
static bool update_permission(DataFields& fields, const string& sql_c);
// ************************************************************************************************
// 角色管理
static bool query_role(vector<DataFields>& result);
static bool update_role_by_id(DataFields& fields);
static bool query_admin_permission(string account, vector<DataFields>& result);
// ************************************************************************************************
// 策略管理
static int insert_policy(DataFields& fields);
static bool query_policy(PageInfo& pageinfo, vector<DataFields>& result, string sql_c);
static bool update_policy(DataFields& fields, const string& sql_c);
};

View File

@@ -0,0 +1,81 @@
#include "DaoBattery.h"
#include "database/DaoEntity.h"
void DaoBattery::insert_battery(DataFields& fields)
{
// ID为自增
fields.remove(DMBattery::ID);
fields.check(DMBattery::BATTERY_NUM, "", "0");
DaoEntity dao(DMBattery::TABLENAME);
dao.insert_fields(fields);
}
void DaoBattery::query_battery(PageInfo& pageinfo, vector<DataFields>& result, string sql_c)
{
DaoEntity dao(DMBattery::TABLENAME);
dao.query_fields("*", sql_c, pageinfo, result);
}
void DaoBattery::query_battery(vector<DataFields>& result)
{
PageInfo pageinfo;
pageinfo.page_id = 0;
pageinfo.page_size = 100;
DaoEntity dao(DMBattery::TABLENAME);
dao.query_fields("*", "", pageinfo, result);
}
void DaoBattery::query_battery_by_code(string code, vector<DataFields>& result)
{
DaoEntity dao(DMBattery::TABLENAME);
string sql_c = "where code='" + code + "'";
dao.query_fields("*", sql_c, result);
}
bool DaoBattery::query_battery_by_pos(string storage_id, vector<DataFields>& result)
{
string sql = "select * from " + DMBattery::TABLENAME + " where " + DMBattery::ID + "='" + storage_id + "'";
return DaoEntity::exec_once(sql, result);
}
int DaoBattery::update_battery(DataFields& fields, string condition)
{
DaoEntity dao(DMBattery::TABLENAME);
fields.check("business_time", "", "NULL");
fields.check("cool_type", "", "NULL");
fields.check("status", "", "NULL");
return dao.update_fields(fields, condition);
}
bool DaoBattery::insert_battery_data(DataFields& fields)
{
DaoEntity dao(DMBatteryData::TABLENAME);
return dao.insert_fields(fields);
}
bool DaoBattery::update_battery_bms(std::string batt_code, DataFields& fields)
{
string sql_c = " WHERE " + DMBatteryData::FID_BATTERY_CODE + "='" + batt_code + "'";
vector<DataFields> result;
DaoEntity dao(DMBatteryData::TABLENAME);
string sql = "select count(1) count from " + DMBatteryData::TABLENAME + sql_c;
bool ret = dao.exec(sql, result);
if (!ret)
{
return false;
}
if (result.size() > 0)
{
if (result[0].get_int("count") > 0)
{
// UPDATE
return dao.update_fields(fields, sql_c);
}
}
// INSERT
fields.set(DMBatteryData::FID_BATTERY_CODE, batt_code);
return dao.insert_fields(fields);
}

View File

@@ -0,0 +1,57 @@
#pragma once
#include "DataFields.h"
namespace DMBattery
{
const string TABLENAME = "battery";
const string ID = "id";
const string CODE = "code";
const string MODEL = "model";
const string TYPE = "type";
const string LOCK_TYPE = "lock_type";
const string FACTOR = "factory";
const string CAPACITY = "rated_capacity"; // 额定容量
const string RATED_VOLTAGE = "rated_voltage"; // 额定电压
const string TOTALENERGY = "rated_total_energy"; // 额定总能量
const string VOLTAGE_MAX = "voltage_max"; // 最高充电电压
const string BATTERY_NUM = "battery_num"; // 单体电池个数
}
namespace DMBatteryData
{
const string TABLENAME = "battery_status";
const string FID_ID = "id";
const string FID_BATTERY_CODE = "battery_code";
const string FID_POSID = "storehouse_id";
const string FID_VOLTAGE = "voltage";
const string FID_CURRENT = "current";
const string FID_POWER = "power";
const string FID_SOC = "soc";
const string FID_SOH = "soh";
const string FID_MAX_VOLTAGE = "max_voltage";
const string FID_MAX_VOLTAGE_ID = "max_voltage_id";
const string FID_MIN_VOLTAGE = "min_voltage";
const string FID_MIN_VOLTAGE_ID = "min_voltage_id";
const string FID_MAX_TEMP = "max_temp";
const string FID_MAX_TEMP_ID = "max_temp_id";
const string FID_MIN_TEMP = "min_temp";
const string FID_MIN_TEMP_ID = "min_temp_id";
const string FID_CREATE_TIME = "cteate_time";
}
class DaoBattery
{
public:
static void insert_battery(DataFields& fields);
static void query_battery(PageInfo& pageinfo, vector<DataFields>& result, string condition = "");
static void query_battery(vector<DataFields>& result);
static void query_battery_by_code(string code, vector<DataFields>& result);
static bool query_battery_by_pos(string storage_id, vector<DataFields>& result);
static int update_battery(DataFields& fields, string condition);
static bool insert_battery_data(DataFields& fields);
static bool update_battery_bms(std::string batt_code, DataFields& fields);
};

View File

@@ -0,0 +1,49 @@
#include "DaoCar.h"
#include "database/DaoEntity.h"
#include "database/dao/DaoDevice.h"
bool DaoCar::query_car_page(PageInfo& pageinfo, vector<DataFields>& result)
{
// 查询数据库
DaoEntity dao(DMCar::TABLENAME);
return dao.query_fields("*", "", pageinfo, result);
}
bool DaoCar::query_car_by_userid(string userid, vector<DataFields>& result)
{
string sql = "select * from car where user_id='" + userid + "';";
return DaoEntity::exec_once(sql, result);
}
bool DaoCar::query_car_by_carnum(string carnum, vector<DataFields>& result)
{
string sql = "select * from car where car_no='" + carnum + "';";
return DaoEntity::exec_once(sql, result);
}
bool DaoCar::insert_car(DataFields& fields)
{
fields.check(DMCar::FID_RANGE, "", "0");
fields.check(DMCar::FID_PRODUCT_DATE, "", "NULL");
fields.check(DMCar::FID_BUY_DATE, "", "NULL");
fields.remove(DMCar::FID_CREATE_TIME);
DaoEntity dao(DMCar::TABLENAME);
return dao.insert_fields(fields);
}
bool DaoCar::update_car(DataFields& fields)
{
fields.check(DMCar::FID_RANGE, "", "0");
fields.check(DMCar::FID_PRODUCT_DATE, "", "NULL");
fields.check(DMCar::FID_BUY_DATE, "", "NULL");
fields.remove(DMCar::FID_CREATE_TIME);
DaoEntity dao(DMCar::TABLENAME);
string id = fields.get_str(DMCar::FID_ID);
fields.remove(DMDevice::ID);
return dao.update_fields(fields, "where id='" + id + "'");
}

41
src/database/dao/DaoCar.h Normal file
View File

@@ -0,0 +1,41 @@
#pragma once
#include "DataFields.h"
namespace DMCar
{
const string TABLENAME = "car";
const string FID_ID = "id";
const string FID_USER_ID = "user_id";
const string FID_FRAME_NUM = "frame_no";
const string FID_CAR_NUM = "car_no";
const string FID_BRAND = "brand";
const string FID_FACTORY = "factory";
const string FID_MODEL = "model";
const string FID_RANGE = "range";
const string FID_PRODUCT_DATE = "product_date";
const string FID_BUY_DATE = "buy_time";
const string FID_BATTERY_MODEL = "battery_model";
const string FID_CREATE_TIME = "create_time";
const string FID_BATT_CODE = "batt_code";
}
class DaoCar
{
public:
// ************************************************************************************************
// 车辆信息管理
static bool insert_car(DataFields& fields);
// 更新车辆信息更新条件id
static bool update_car(DataFields& fields);
/**
* 分页查询设备信息
* @param: pageinfo 分页信息
* @param: result 查询的结果数据集
*/
static bool query_car_page(PageInfo& pageinfo, vector<DataFields>& result);
static bool query_car_by_userid(string userid, vector<DataFields>& result);
static bool query_car_by_carnum(string carnum, vector<DataFields>& result);
};

View File

@@ -0,0 +1,48 @@
#include "DaoCharge.h"
#include "app/Global.h"
#include "common/spdlogger.h"
#include "common/TimeUtils.h"
#include "common/Snowflake.h"
#include "database/DaoEntity.h"
#include "database/dao/DaoDevice.h"
#include "Device.h"
bool DaoCharge::create_charge_record(std::string biz_id, int device_id)
{
DataFields fields;
fields.set(DMChargeRecord::ID, biz_id);
fields.set(DMChargeRecord::DEVICE_ID, device_id);
DaoEntity dao(DMChargeRecord::TABLENAME);
return dao.insert_fields(fields);
}
bool DaoCharge::update_charge_record(std::string biz_id, int device_id, DataFields fields)
{
DaoEntity dao(DMChargeRecord::TABLENAME);
std::vector<DataFields> result;
dao.exec("select * from " + DMChargeRecord::TABLENAME + " WHERE id='" + biz_id + "';", result);
if (result.size() == 0)
{
fields.set(DMChargeRecord::ID, biz_id);
fields.set(DMChargeRecord::DEVICE_ID, device_id);
dao.insert_fields(fields);
}
fields.remove(DMChargeRecord::ID);
fields.remove(DMChargeRecord::DEVICE_ID);
return dao.update_fields(fields, "where " + DMChargeRecord::ID + "='" + biz_id + "'");
}
void DaoCharge::query_charger(vector<DataFields>& result)
{
DaoEntity dao(DMDevice::TABLENAME);
string sql = " where device.type='智能充电设备';";
dao.query_fields("*", sql, result);
}
void DaoCharge::query_charger_attr(vector<DataFields>& result)
{
DaoEntity dao(DMDevice::TABLENAME);
string sql = " left join device_attr on device.id =device_attr.device_id where device.type='智能充电设备';";
dao.query_fields("*", sql, result);
}

View File

@@ -0,0 +1,86 @@
#ifndef _DaoCharge_H_
#define _DaoCharge_H_
#include "DataFields.h"
namespace DMChargerData
{
const string TABLENAME = "charge_status";
const string ID = "id";
const string DEVICE_ID = "device_id";
const string STATUS = "status";
const string VOLTAGE = "voltage";
const string CURRENT = "current";
const string POWER = "power";
const string PEAK = "peak";
const string VALLEY = "valley";
const string SHARP = "sharp";
const string FLAT = "flat";
const string SOC = "soc";
const string CREATE_TIME = "create_time";
}
namespace DMChargeRecord
{
const string TABLENAME = "charge_record";
const string ID = "id";
const string DEVICE_ID = "device_id"; // 设备ID
const string BATTERY_CODE = "battery_code";
const string START_TIME = "start_time";
const string END_TIME = "end_time";
const string DURATION = "duration";
const string ELECTRICITY = "electricity"; // 本次充电电量
const string TOP_ELECT = "top_elect"; // 尖阶段电量
const string TOP_AMOUNT = "top_amount"; // 尖阶段电费
const string PEAK_ELECT = "peak_elect"; // 峰阶段电量
const string PEAK_AMOUNT = "peak_amount"; // 峰阶段电费
const string FLAT_ELECT = "flat_elect"; // 平阶段电量
const string FLAT_AMOUNT = "flat_amount"; // 平阶段电费
const string VALLEY_ELECT = "valley_elect"; // 谷阶段电量
const string VALLEY_AMOUNT = "valley_amount"; // 谷阶段电费
const string PAY_AMOUNT = "pay_amount"; // 本次充电金额
const string METER_VALUE_START = "meter_value_start"; // 电表总起值
const string METER_VALUE_END = "meter_value_end"; // 电表总止值
const string SOC_START = "soc_start"; // 充电前soc
const string SOC_END = "soc_end"; // 充电后soc
const string STATUS = "status"; // 状态
const string CHARGE_STOP_CAUSE = "charge_stop_cause"; // 停止原因
}
namespace DMChargeDataRecord
{
const string TABLENAME = "charge_data_record";
const string DEVICE_ID = "device_id";
const string DEVICE_CODE = "device_code";
const string COLLECT_TIME = "collect_time";
const string VOLTAGE = "voltage";
const string CURRENT = "current";
const string POWER = "power";
}
class DaoCharge
{
public:
/**
* 创建充电业务订单记录
* @param: [std::string biz_id] 充电业务订单ID
* @param: [std::string device_id] 充电业务的充电机设备ID
*/
static bool create_charge_record(std::string biz_id, int device_id);
/**
* 更新充电业务订单记录
* @param: [std::string biz_id] 充电业务订单ID
* @param: [DataFields fields] 需要更新的字段
*/
static bool update_charge_record(std::string biz_id, int device_id, DataFields fields);
static void query_charger(vector<DataFields>& result);
static void query_charger_attr(vector<DataFields>& result);
};
#endif // !_DaoCharge_H_

View File

@@ -0,0 +1,61 @@
#include "DaoDevice.h"
#include "database/DaoEntity.h"
void DaoDevice::insert_device(DataFields& fields)
{
fields.remove("id");
fields.check("open_time", "", "NULL");
fields.check("product_time", "", "NULL");
DaoEntity dao(DMDevice::TABLENAME);
dao.insert_fields(fields);
}
void DaoDevice::query_device_page(PageInfo& pageinfo, vector<DataFields>& result)
{
DaoEntity dao(DMDevice::TABLENAME);
dao.query_fields("*", "", pageinfo, result);
}
void DaoDevice::query_device(string sql_c, vector<DataFields>& result)
{
DaoEntity dao(DMDevice::TABLENAME);
dao.query_fields("*", sql_c, result);
}
void DaoDevice::query_device_attr(string sql_c, vector<DataFields>& result)
{
DaoEntity dao(DMDeviceAttr::TABLENAME);
string c = " left join device on device_attr.device_id=device.id " + sql_c + ";";
dao.query_fields("*", c, result);
}
int DaoDevice::update_device(DataFields& fields)
{
string id = fields.get_str(DMDevice::ID);
string sql_c = "WHERE id='" + id + "'";
fields.remove(DMDevice::ID);
fields.check(DMDevice::PRODUCT_DATE, "", "NULL");
fields.check(DMDevice::OPEN_TIME, "", "NULL");
DaoEntity dao(DMDevice::TABLENAME);
return dao.update_fields(fields, sql_c);
}
void DaoDevice::update_device_attr(vector<DataFields> vec_d)
{
DaoEntity dao(DMDeviceAttr::TABLENAME);
vector<string> v_keys = {DMDeviceAttr::ATTR_VAL};
for (auto& fields : vec_d)
{
dao.duplicate_update(fields, v_keys);
}
}
void DaoDevice::query_attr(int device_id, vector<DataFields>& result)
{
DaoEntity dao(DMDeviceAttr::TABLENAME);
string sql = " where device_id='" + to_string(device_id) + "'";
dao.query_fields("*", sql, result);
}

View File

@@ -0,0 +1,101 @@
#ifndef _DaoDevice_H_
#define _DaoDevice_H_
#include "DataFields.h"
namespace DMDevice
{
const string TABLENAME = "device";
const string ID = "id";
const string NAME = "name";
const string CODE = "code";
const string MODEL = "model";
const string TYPE = "type";
const string FACTORY = "factory";
const string TEL = "factory_tel";
const string PRODUCT_DATE = "product_time";
const string IS_OPEN = "is_open";
const string OPEN_TIME = "open_time";
const string COMM_TYPE = "comm_type";
const string COMM_PROTOCOL = "comm_protocol";
const string COMM_IP = "comm_ip";
const string COMM_PORT = "comm_port";
const string STATUS = "status";
const string CREATE_TIME = "create_time";
const string UPDATE_TIME = "update_time";
}
namespace DMDeviceAttr
{
const string TABLENAME = "device_attr";
const string DEVICE_ID = "device_id";
const string ATTR_ID = "attr_id";
const string ATTR_VAL = "attr_val";
// 属性ID的关键字
// 充电机属性
const string K_STORAGE_ID = "storage_id";
const string K_MODEL = "model";
const string K_MANUFACTOR = "manufactor";
const string K_RATED_POWER = "rated_power";
const string K_VOLTAGE_MIN = "voltage_min";
const string K_VOLTAGE_MAX = "voltage_max";
const string K_CURRENT_MAX = "current_max";
// 存储架属性:仓位电池型号和存储的电池编号
const string K_BATT_MODEL = "battery_model";
const string K_BATT_CODE = "battery_code";
// 电表属性:
const string K_LINK_DEVICE = "link_device";
}
namespace DMDeviceDataRecord
{
const string TABLENAME = "device_data_record";
const string DEVICE_ID = "device_id"; // 设备ID
const string COLLECT_TIME = "collect_time"; // 采集时间
const string VOLTAGE = "voltage"; // 电压
const string CURRENT = "current"; // 电流
const string POWER = "power"; // 功率
const string POWER_Q = "power_q"; // 无功功率
const string POWER_S = "power_s"; // 视在功率
const string FACTOR = "factor"; // 功率因数
}
class DaoDevice
{
public:
/**
* 新增设备信息, DataFields 的 key 见【namespace DaoDevice】中的定义
*/
static void insert_device(DataFields& fields);
/**
* 查询设备信息结果集字段见【namespace DaoDevice】中的定义
* @param: sql_c 查询条件: 例:"where id='1'"
* @param: result 查询的结果数据集
*/
static void query_device(string sql_c, vector<DataFields>& result);
static void query_device_attr(string sql_c, vector<DataFields>& result);
/**
* 分页查询设备信息
* @param: pageinfo 分页信息
* @param: result 查询的结果数据集
*/
static void query_device_page(PageInfo& pageinfo, vector<DataFields>& result);
/**
* 更新设备信息
* @param: fields 更新的字段信息,其中 DaoDevice::FID_ID 作为更新条件
*/
static int update_device(DataFields& fields);
// ************************************************************************************************
// 设备属性管理
static void update_device_attr(vector<DataFields> vec_d);
static void query_attr(int device_id, vector<DataFields>& result);
private:
};
#endif // !!!_DaoDevice_H_

View File

@@ -0,0 +1,84 @@
#include "DaoStat.h"
#include "database/DaoEntity.h"
#include "database/dao/DaoCharge.h"
#include "database/dao/DaoDevice.h"
#include "TimeUtils.h"
#include "database/SQL.h"
bool DaoStat::insert_charge_curve(DataFields& fields)
{
DaoEntity dao(DMChargeDataRecord::TABLENAME);
return dao.insert_fields(fields);
}
bool DaoStat::query_charge_curve_by_time(string start_time, string end_time, std::vector<DataFields>& result)
{
string sql = "select * from " + DMChargeDataRecord::TABLENAME + " where " + DMChargeDataRecord::COLLECT_TIME + ">='" + start_time
+ "' and " + DMChargeDataRecord::COLLECT_TIME + "<='" + end_time + "';";
return DaoEntity::exec_once(sql, result);
}
bool DaoStat::query_station_power_by_time(string start_time, string end_time, std::vector<DataFields>& result)
{
string sql = "select * from " + DMDeviceDataRecord::TABLENAME + " where " + DMDeviceDataRecord::COLLECT_TIME + ">='" + start_time
+ "' and " + DMDeviceDataRecord::COLLECT_TIME + "<='" + end_time + "';";
return DaoEntity::exec_once(sql, result);
}
#include "Device.h"
void DaoStat::insert_charger_data(int t_interval)
{
// 存储时间间隔60
// 记录上一次存储的时间点,用于计算防止重复存储
static uint64_t t_last = 0;
// 存储时间间隔: 从0点开始计算每间隔t_interval存储一次数据
uint64_t t_start = TimeUtils::datetime2ts(TimeUtils::now_date() + " 00:00:00");
uint64_t t_now = TimeUtils::now();
uint64_t a = (t_now - t_start) / t_interval;
uint64_t b = (t_now - t_start) % t_interval;
uint64_t t = t_start + a * t_interval;
if (t != t_last)
{
t_last = t;
std::string t_str = TimeUtils::ts2datetime(t);
DaoEntity dao(DMChargeDataRecord::TABLENAME);
for (int i = 1; i <= 6; i++)
{
std::string device_code = std::to_string(i);
auto charger = Device::get_charger(device_code);
if (charger)
{
float v = charger->bms.voltage + charger->bms.current + charger->bms.power;
if (v != 0.0f)
{
DataFields d;
d.set(DMChargeDataRecord::DEVICE_ID, charger->device_id);
d.set(DMChargeDataRecord::DEVICE_CODE, device_code);
d.set(DMChargeDataRecord::COLLECT_TIME, t_str);
d.set(DMChargeDataRecord::VOLTAGE, charger->bms.voltage);
d.set(DMChargeDataRecord::CURRENT, charger->bms.current);
d.set(DMChargeDataRecord::POWER, charger->bms.power);
dao.insert_fields({d});
}
}
}
}
}
bool DaoStat::query_charge_data(std::string dt, vector<DataFields>& result)
{
// 存储查询结果集
vector<DataFields> vec_result;
// 查询设备数据记录表
std::string sql_c = DMDeviceDataRecord::COLLECT_TIME + ">='" + dt + " 00:00:00"
+ "' AND " + DMDeviceDataRecord::COLLECT_TIME + "<='" + dt + " 23:59:59" + "'";
std::string sql = SQL(SQL::TYPE::select).table(DMDeviceDataRecord::TABLENAME).select("*").where(sql_c).str();
// 执行数据库查询
return DaoEntity::exec_once(sql, vec_result);
}

View File

@@ -0,0 +1,69 @@
#pragma once
#include "DataFields.h"
namespace DMStatSwap
{
const string TABLENAME = "stat_swap";
const string DT = "dt"; // 统计的日期(按天统计)
const string T_TOTAL = "t_total"; // 总换电时长
const string T_AVG = "t_avg"; // 平均换电时长
const string T_MIN = "t_min"; // 最快换电时长
const string T_MAX = "t_max"; // 最慢换电时长
const string ELECTRIC = "electric"; // 总电量
const string FEE_SERVICE = "fee_service"; // 服务费
const string FEE_ELECTRIC = "fee_electric"; // 电费
const string NUM = "num"; // 换电次数
const string NUM_SUCCESS = "num_success"; // 换电成功次数
const string NUM_FAILED = "num_failed"; // 换电失败次数
const string NUM_DF = "num_brand_df"; // 品牌车辆换电次数(东风)
const string NUM_WL = "num_brand_wl"; // 品牌车辆换电次数(蔚来)
const string NUM_BQ = "num_brand_bq"; // 品牌车辆换电次数(北汽)
}
namespace DMStatCharge
{
const string TABLENAME = "stat_charge";
const string DT = "dt";
const string T_TOTAL = "t_total";
const string T_AVG = "t_avg";
const string T_MIN = "t_min";
const string T_MAX = "t_max";
const string T_ONLINE = "t_online";
const string ELECTRIC = "electric";
const string ELECT_AVG = "elect_avg";
const string FEE_ELECTRIC = "fee_electric";
const string FEE_SERVICE = "fee_service";
const string NUM = "num"; // 充电次数
const string NUM_SUCCESS = "num_success"; // 充电成功次数
const string NUM_FAILED = "num_failed"; // 充电失败次数
}
namespace DMStatChargerData
{
const string TABLENAME = "stat_charger_data";
const string TIME = "collect_time";
const string CHARGER_ID = "charger_id";
const string VOLTAGE = "voltage";
const string CURRENT = "current";
const string POWER = "power";
}
class DaoStat
{
public:
// ************************************************************************************************
static bool insert_charge_curve(DataFields& fields);
static bool query_charge_curve_by_time(string start_time, string end_time, std::vector<DataFields>& result);
static bool query_station_power_by_time(string start_time, string end_time, std::vector<DataFields>& result);
static void insert_charger_data(int t_interval);
/**
* 查询当天的充电机电压、电流、功率历史数据
*/
static bool query_charge_data(std::string dt, vector<DataFields>& result);
};

View File

@@ -0,0 +1,63 @@
#include "DaoSwap.h"
#include "app/Constant.h"
#include "app/Global.h"
#include "common/spdlogger.h"
#include "common/TimeUtils.h"
#include "common/Snowflake.h"
#include "database/DaoEntity.h"
#include "Device.h"
std::string DaoSwap::create_swap_record(std::string biz_id, DeviceSwapEntity* swap_entity)
{
auto& appdata = Global::data();
if (!swap_entity)
{
Spdlogger::error("create swap record failed: swap_entity is null, biz_id={}", biz_id);
return "";
}
swap_entity->info.biz_id = biz_id;
Spdlogger::info("[SWAP] create swap biz record: biz_id={}", swap_entity->info.biz_id);
DataFields fields;
fields.set(DMSwapRecord::ID, swap_entity->info.biz_id);
fields.set(DMSwapRecord::SWAP_MODE, (int)swap_entity->work_mode);
fields.set(DMSwapRecord::BATT_MODEL, swap_entity->info.car_battery_model);
fields.set(DMSwapRecord::CAR_NUM, swap_entity->info.car_no);
fields.set(DMSwapRecord::USER_ID, swap_entity->info.user_id);
fields.set(DMSwapRecord::BATT_DOWN_ID, swap_entity->info.car_batt_code);
fields.set(DMSwapRecord::BATT_ON_ID, swap_entity->info.new_batt_code);
fields.set(DMSwapRecord::BATT_ON_SOC, swap_entity->info.soc);
fields.set(DMSwapRecord::STATUS, swap_entity->info.status);
fields.set(DMSwapRecord::CAUSE, PV::NODE_CAR_VERIFY);
fields.set(DMSwapRecord::OPEN_TIME, TimeUtils::ts2datetime(swap_entity->info.open_time));
DaoEntity dao(DMSwapRecord::TABLENAME);
bool res = dao.insert_fields(fields);
if (!res)
{
Spdlogger::error("create swap record failed: database error, biz_id={}, car_no={}.", swap_entity->info.biz_id, swap_entity->info.car_no);
}
return swap_entity->info.biz_id;
}
int DaoSwap::update_swap_record(std::string biz_id, DataFields& fields)
{
auto& appdata = Global::data();
if (biz_id.empty())
{
Spdlogger::error("[SWAP] update swap data record errorbizid is NULL");
return 0;
}
if (fields.size() > 0)
{
fields.remove(DMSwapRecord::ID);
string sql_c = " where " + DMSwapRecord::ID + "='" + biz_id + "'";
DaoEntity dao(DMSwapRecord::TABLENAME);
dao.update_fields(fields, sql_c);
Global::request_stat = true;
return 1;
}
return 0;
}

View File

@@ -0,0 +1,56 @@
#pragma once
#include "DataFields.h"
class DeviceSwapEntity;
namespace DMSwapRecord
{
const string TABLENAME = "swap_record";
const string ID = "id";
const string USER_ID = "user_id";
const string CAR_NUM = "car_no";
const string SWAP_MODE = "swap_mode";
const string BATT_MODEL = "batt_model";
const string BATT_DOWN_ID = "batt_down_id";
const string BATT_DOWN_SOC = "batt_down_soc";
const string BATT_DOWN_POWER = "batt_down_power";
const string BATT_ON_ID = "batt_on_id";
const string BATT_ON_SOC = "batt_on_soc";
const string BATT_ON_POWER = "batt_on_power";
const string OPEN_TIME = "open_time";
const string CLOSE_TIME = "close_time";
const string START_TIME = "start_time";
const string END_TIME = "end_time";
const string DURATION = "duration";
const string TOTAL_DURATION = "total_duration";
const string STATUS = "status";
const string CAUSE = "cause";
const string FEE_ELECTRICE = "fee_electric";
const string FEE_SERVICE = "fee_service";
const string POWER = "power";
const string CREATE_TIME = "create_time";
const string UPDATE_TIME = "create_time";
}
class DaoSwap
{
public:
/**
* 创建换电业务订单
*/
static std::string create_swap_record(std::string biz_id, DeviceSwapEntity* swap_entity);
/**
* 更新换电业务订单
* @param: [std::string biz_id] 订单号
* @param: [DataFields& fields] 要更新的字段
* @return: [int] 0: 更新失败;其它表示更新成功
*/
static int update_swap_record(std::string biz_id, DataFields& fields);
/**
* 写入换电业务节点状态执行记录
*/
static void insert_swap_node_status();
};

239
src/database/dao/DaoSys.cpp Normal file
View File

@@ -0,0 +1,239 @@
#include "DaoSys.h"
#include "common/Utils.h"
#include "common/Snowflake.h"
#include "Admin.h"
#include "Spdlogger.h"
#include "database/DaoEntity.h"
#include "database/dao/DaoDevice.h"
#include "database/dao/DaoCharge.h"
static void LogDaoResult(std::vector<DataFields>& vec_fields)
{
for (int i = 0; i < vec_fields.size(); i++)
{
string s = "{";
vec_fields[i].foreach_item([&](string key, string val)
{
s += (key + ":" + val + ", ");
});
s = s.substr(0, s.size() - 2);
s += "}";
}
}
int DaoSys::insert_price(DataFields& fields)
{
fields.remove(DMPrice::FID_CREATE_TIME);
fields.remove(DMPrice::FID_UPDATE_TIME);
DaoEntity dao(DMPrice::TABLENAME);
return dao.insert_fields(fields);
}
bool DaoSys::query_price(PageInfo& pageinfo, vector<DataFields>& result, string sql_c)
{
DaoEntity dao(DMPrice::TABLENAME);
return dao.query_fields("*", sql_c, pageinfo, result);
}
bool DaoSys::update_price(DataFields& fields, const string& sql_c)
{
fields.remove(DMPrice::FID_ID);
fields.remove(DMPrice::FID_CREATE_TIME);
fields.remove(DMPrice::FID_UPDATE_TIME);
DaoEntity dao(DMPrice::TABLENAME);
return dao.update_fields(fields, sql_c);
}
bool DaoSys::update_price_attr(vector<DataFields>& vec_fields)
{
DaoEntity dao(DMPriceAttr::TABLENAME);
bool ret = true;
std::vector<DataFields> result;
string sql = "";
for (auto& item : vec_fields)
{
item.remove("id");
string price_id = item.get_str(DMPriceAttr::FID_PRICE_ID);
if (!sql.empty())
{
sql += ",";
}
sql += ("'" + price_id + "'");
}
sql = "delete from " + DMPriceAttr::TABLENAME + " where " + DMPriceAttr::FID_PRICE_ID + " in (" + sql + ")";
dao.exec(sql);
dao.insert_fields(vec_fields);
return ret;
}
void DaoSys::insert_sec_warn(DataFields& fields)
{
// 生成告警示例
//DaoSecLog::DataModel d;
//d.id = Snowflake::instance().nextIdString(); // ID
//d.ts; // 告警时间
//d.type; // 告警类型: 1:站控系统类 2:换电设备类 3:充电机类 4:辅助设备类
//d.level = 1; // 告警级别: L1 ~ L4
//d.content; // 告警内容
//d.device_id; // 设备ID
//d.status = 1; // 当前状态
DaoEntity dao(DMSecRecord::TABLENAME);
dao.insert_fields(fields);
}
int DaoSys::update_sec_warn(string id, int status)
{
DataFields fields;
//d.add(DaoSecLog::FID_ID, "");
fields.set(DMSecRecord::DISPOSE_USER, Admin::instance().optor().name);
fields.set(DMSecRecord::DISPOSE_TIME, Utils::time_now_string());
fields.set(DMSecRecord::STATUS, to_string(status)); // 当前状态 0: 已复位 1: 未处理 2: --
DaoEntity dao(DMSecRecord::TABLENAME);
return dao.update_fields(fields, "where id='" + id + "'");
}
int DaoSys::insert_message_log(DataFields& fields)
{
string date;
string time = fields.get_str(DMMessageLog::FID_CREATE_TIME);
if (time.size() < 10)
{
Spdlogger::error("[DB] Message log time error: time={}, set table name date={}", time, date);
date = Utils::time_now_string().substr(0, 10);
}
else
{
date = time.substr(0, 10);
}
string tbname = DMMessageLog::TABLENAME + date;
string dll_sql = "CREATE TABLE IF NOT EXISTS `" + tbname + "` " + DMMessageLog::DDL;
bool ret = DaoEntity::exec_once(dll_sql.c_str());
if (!ret)
{
Spdlogger::error("[DB] Message log create table failed: {}", dll_sql);
return 0;
}
DaoEntity::exec_once(fields.get_insert_sql(tbname).c_str());
return 1;
}
bool DaoSys::query_system_info(std::vector<DataFields>& result)
{
DaoEntity dao(DMSystemInfo::TABLENAME);
return dao.query_fields("*", "", result);
}
bool DaoSys::insert_ammeter_data(DataFields& fields)
{
DaoEntity dao(DMDeviceDataRecord::TABLENAME);
return dao.insert_fields(fields);
}
int DaoSys::insert_sec_policy(DataFields& fields)
{
DaoEntity dao(DMSecPolicy::TABLENAME);
return dao.insert_fields(fields);
}
bool DaoSys::query_sec_policy(PageInfo& pageinfo, vector<DataFields>& result, string sql_c)
{
DaoEntity dao(DMSecPolicy::TABLENAME);
return dao.query_fields("*", sql_c, pageinfo, result);
}
bool DaoSys::update_sec_policy_by_id(DataFields& fields)
{
string id = fields.get_str(DMSecPolicy::FID_ID);
fields.remove(DMSecPolicy::FID_ID);
DaoEntity dao(DMSecPolicy::TABLENAME);
return dao.update_fields(fields, "where " + DMSecPolicy::FID_ID + "='" + id + "'");
}
bool DaoSys::insert_sec_record(DataFields& fields)
{
DaoEntity dao(DMSecRecord::TABLENAME);
return dao.insert_fields(fields);
}
bool DaoSys::query_sec_record(PageInfo& pageinfo, vector<DataFields>& result, string sql_c)
{
DaoEntity dao(DMSecRecord::TABLENAME);
return dao.query_fields("*", sql_c, pageinfo, result);
}
bool DaoSys::update_sec_record(DataFields& fields, const string& sql_c)
{
DaoEntity dao(DMSecRecord::TABLENAME);
return dao.update_fields(fields, sql_c);
}
int DaoSys::insert_service(DataFields& fields)
{
fields.remove(DMService::FID_CREATE_TIME);
fields.remove(DMService::FID_UPDATE_TIME);
DaoEntity dao(DMService::TABLENAME);
return dao.insert_fields(fields);
}
bool DaoSys::query_service(PageInfo& pageinfo, vector<DataFields>& result, string sql_c)
{
DaoEntity dao(DMService::TABLENAME);
return dao.query_fields("*", sql_c, pageinfo, result);
}
bool DaoSys::update_service(DataFields& fields, const string& sql_c)
{
fields.remove(DMService::FID_INTERFACE_NAME);
fields.remove(DMService::FID_CREATE_TIME);
fields.remove(DMService::FID_UPDATE_TIME);
DaoEntity dao(DMService::TABLENAME);
return dao.update_fields(fields, sql_c);
}
int DaoSys::insert_serv_history(DataFields& fields)
{
fields.remove(DMServHistory::FID_CREATE_TIME);
DaoEntity dao(DMServHistory::TABLENAME);
return dao.insert_fields(fields);
}
bool DaoSys::query_serv_history(PageInfo& pageinfo, vector<DataFields>& result, string sql_c)
{
DaoEntity dao(DMServHistory::TABLENAME);
return dao.query_fields("*", sql_c, pageinfo, result);
}
bool DaoSys::update_serv_history(DataFields& fields, const string& sql_c)
{
fields.remove(DMServHistory::FID_ID);
fields.remove(DMServHistory::FID_CREATE_TIME);
DaoEntity dao(DMServHistory::TABLENAME);
return dao.update_fields(fields, sql_c);
}
int DaoSys::insert_syslog(string logtype, string optor, string device_id, string msg)
{
DataFields fields;
fields.set(DMSystemLog::FID_ID, Snowflake::instance().next_id_str());
fields.set(DMSystemLog::FID_TYPE, logtype);
fields.set(DMSystemLog::FID_USER_ID, optor);
fields.set(DMSystemLog::FID_DEVICE_ID, device_id);
fields.set(DMSystemLog::FID_MSG, msg);
DaoEntity dao(DMSystemLog::TABLENAME);
dao.insert_fields(fields);
return 0;
}

192
src/database/dao/DaoSys.h Normal file
View File

@@ -0,0 +1,192 @@
#pragma once
#include <vector>
#include "DataFields.h"
namespace DMPrice
{
const string TABLENAME = "price";
const string FID_ID = "id";
const string FID_NAME = "name";
const string FID_TYPE = "type";
const string FID_EFFECTIVE_TIME = "effective_time";
const string FID_EXPIRE_TIME = "expire_time";
const string FID_IS_OPEN = "is_open";
const string FID_CREATE_TIME = "create_time";
const string FID_UPDATE_TIME = "update_time";
}
namespace DMPriceAttr
{
const string TABLENAME = "price_attr";
const string FID_PRICE_ID = "price_id";
const string FID_TYPE = "type";
const string FID_START_TIME = "start_time";
const string FID_END_TIME = "end_time";
const string FID_VALUE = "value";
}
namespace DMSecPolicy
{
const string TABLENAME = "sec_policy";
const string FID_ID = "id";
const string FID_SEC_TYPE = "sec_type";
const string FID_EVENT_NAME = "event_name";
const string FID_EVENT_CODE = "event_code";
const string FID_LEVEL = "level";
const string FID_IS_OPEN = "is_open";
const string FID_REMARK = "remark";
const string FID_ACTION = "action";
const string FID_TEXT = "text";
const string FID_VOICE = "voice";
}
namespace DMSecRecord
{
const string TABLENAME = "sec_record";
const string ID = "id";
const string TIME = "warn_time";
const string TYPE = "type";
const string LEVEL = "level";
const string CONTENT = "content";
const string POLICY_ID = "policy_id";
const string DEVICE_ID = "device_id";
const string USER = "user";
const string DISPOSE_USER = "dispose_user";
const string DISPOSE_TIME = "dispose_time";
const string PROCESS_MODE = "process_mode";
const string STATUS = "status";
}
namespace DMSystemInfo
{
const string TABLENAME = "system_info";
const string FID_STATION_NAME = "station_name";
const string FID_ACTIVATION_TIME = "activation_time";
const string FID_WORK_MODE = "swap_mode";
}
namespace DMService
{
const string TABLENAME = "service_monitor";
const string FID_INTERFACE_NAME = "interface_name";
const string FID_PROTOCOL_TYPE = "protocol_type";
const string FID_REPORT_TYPE = "report_type";
const string FID_REPORT_CYCLE = "report_cycle";
const string FID_REMARK = "remark";
const string FID_IS_OPEN = "is_open";
const string FID_CREATE_TIME = "create_time";
const string FID_UPDATE_TIME = "update_time";
}
namespace DMServHistory
{
const string TABLENAME = "service_history";
const string FID_ID = "id";
const string FID_SERV_ID = "service_id";
const string FID_DATA_NUM = "data_num";
const string FID_SUCCESS_NUM = "success_num";
const string FID_FAILURE_NUM = "failure_num";
const string FID_REQ_TIME = "req_time";
const string FID_RES_TIME = "res_time";
const string FID_CREATE_TIME = "create_time";
}
namespace DMSystemLog
{
const string TABLENAME = "system_log";
const string FID_ID = "id";
const string FID_TYPE = "type";
const string FID_USER_ID = "user_id";
const string FID_DEVICE_ID = "device_id";
const string FID_MSG = "msg";
const string FID_CREATE_TIME = "create_time";
const string FID_UPDATE_TIME = "update_time";
}
// 报文日志
namespace DMMessageLog
{
// 表名称根据日期改变(日期作为后缀: message_log2023-01-01
const string TABLENAME = "message_log";
const string DDL = R"((
`id` varchar(32) NOT NULL COMMENT 'ID',
`device_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'ID',
`create_time` datetime NOT NULL COMMENT '',
`type` int DEFAULT NULL COMMENT ', 12',
`function` varchar(60) DEFAULT NULL,
`data` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '',
`status` int DEFAULT NULL COMMENT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;)";
const string FID_ID = "id";
const string FID_DEVICE_ID = "device_id";
const string FID_CREATE_TIME = "create_time";
const string FID_TYPE = "type"; // 1: 发送2接收
const string FID_FUNCTION = "function";
const string FID_DATA = "data";
const string FID_STATUS = "status";
}
class DaoSys
{
public:
// ************************************************************************************************
// 计费管理
static int insert_price(DataFields& fields);
static bool query_price(PageInfo& pageinfo, vector<DataFields>& result, string sql_c);
static bool update_price(DataFields& fields, const string& sql_c);
static bool update_price_attr(vector<DataFields>& vec_fields);
static void insert_sec_warn(DataFields& fields);
static int update_sec_warn(string id, int status);
// ************************************************************************************************
// 报文管理
static int insert_message_log(DataFields& fields);
static bool query_system_info(std::vector<DataFields>& result);
// ************************************************************************************************
// 电表采集数据
// 写入电表采集的数据
static bool insert_ammeter_data(DataFields& fields);
// ************************************************************************************************
// 安全策略
static int insert_sec_policy(DataFields& fields);
static bool query_sec_policy(PageInfo& pageinfo, vector<DataFields>& result, string sql_c);
static bool update_sec_policy_by_id(DataFields& fields);
// ************************************************************************************************
// 安全运行记录
static bool insert_sec_record(DataFields& fields);
static bool query_sec_record(PageInfo& pageinfo, vector<DataFields>& result, string sql_c);
static bool update_sec_record(DataFields& fields, const string& sql_c);
// ************************************************************************************************
// 服务管理
static int insert_service(DataFields& fields);
static bool query_service(PageInfo& pageinfo, vector<DataFields>& result, string sql_c);
static bool update_service(DataFields& fields, const string& sql_c);
// ************************************************************************************************
// 服务管理历史记录
static int insert_serv_history(DataFields& fields);
static bool query_serv_history(PageInfo& pageinfo, vector<DataFields>& result, string sql_c);
static bool update_serv_history(DataFields& fields, const string& sql_c);
// ************************************************************************************************
// 日志管理
static int insert_syslog(string logtype, string optor, string device_id, string msg);
};

View File

@@ -0,0 +1,45 @@
#include "DaoUser.h"
#include "database/DaoEntity.h"
#include "common/Snowflake.h"
bool DaoUser::insert_user(DataFields& fields)
{
fields.check(DMAccount::BALANCE, "", "0");
fields.check(DMAccount::STATUS, "", "NULL");
fields.check(DMAccount::TYPE, "", "NULL");
fields.remove(DMAccount::CREATE_TIME);
fields.remove(DMAccount::UPDATE_TIME);
fields.set(DMAccount::USER_ID, "U" + Snowflake::instance().next_id_str());
DaoEntity dao(DMAccount::TABLENAME);
return dao.insert_fields(fields);
}
bool DaoUser::update_user(std::string user_id, DataFields& fields)
{
fields.check(DMAccount::BALANCE, "", "0");
fields.check(DMAccount::STATUS, "", "NULL");
fields.check(DMAccount::TYPE, "", "NULL");
fields.remove(DMAccount::USER_ID);
fields.remove(DMAccount::CREATE_TIME);
fields.remove(DMAccount::UPDATE_TIME);
DaoEntity dao(DMAccount::TABLENAME);
string sql_c = "where " + DMAccount::USER_ID + "='" + user_id + "'";
return dao.update_fields(fields, sql_c);
}
bool DaoUser::query_user(PageInfo& pageinfo, vector<DataFields>& result, string sql_c/*=""*/)
{
// 查询数据库
DaoEntity dao(DMAccount::TABLENAME);
return dao.query_fields("*", sql_c, pageinfo, result);
}
bool DaoUser::query_user_by_car_num(string car_num, vector<DataFields>& result)
{
string sql = "SELECT car.id, car.car_no, car.brand, car.model, car.battery_model, car.batt_code, battery.model batt_model, battery.lock_type,"
"account.user_id, account.name, account.phone, account.balance FROM car "
"LEFT JOIN battery ON battery.code=car.batt_code "
"LEFT JOIN account ON account.user_id=car.user_id "
"where car_no = '" + car_num + "';";
return DaoEntity::exec_once(sql, result);
}

View File

@@ -0,0 +1,68 @@
#pragma once
#include "DataFields.h"
/**
* 用户表结构字段
*/
namespace DMUser
{
const string USER_ID = "user_id";
const string ACCOUNT_ID = "account_id";
const string FID_NAME = "name";
const string FID_PHONE = "phone";
const string FIELD_GENDER = "gender";
const string FIELD_AGE = "age";
const string CREATETIME = "create_time";
const string UPDATETIME = "update_time";
}
/**
* 用户账户表结构字段
*/
namespace DMAccount
{
const string TABLENAME = "account"; // 表名称
const string USER_ID = "user_id"; // 用户ID
const string ACCOUNT = "account"; // 账户名称
const string NAME = "name"; // 用户姓名
const string PHONE = "phone"; // 手机号
const string GENDER = "gender"; // 性别
const string STATUS = "status"; // 状态
const string TYPE = "type"; // 类型
const string BALANCE = "balance"; // 余额
const string CREATE_TIME = "create_time";
const string UPDATE_TIME = "update_time";
}
class DaoUser
{
public:
/**
* 创建新的用户
* @param: [DataFields& fields] 用户信息
*/
static bool insert_user(DataFields& fields);
/**
* 更新用户账户信息更新条件user_id
* @param: [std::string user_id] 用户ID
* @param: [DataFields& fields] 用户信息
*/
static bool update_user(std::string user_id, DataFields& fields);
/**
* 查询用户信息
* @param: [PageInfo& pageinfo] 分页设置
* @param: [vector<DataFields>& result] 查询结果集
* @param: [string sql_c] 查询条件where id='1'
*/
static bool query_user(PageInfo& pageinfo, vector<DataFields>& result, string sql_c = "");
/**
* 根据车牌号码查询用户信息(需要联合用户表和车辆信息表)
* @param: [string car_num] 车牌号
* @param: [vector<DataFields>& result] 查询结果集
*/
static bool query_user_by_car_num(string car_num, vector<DataFields>& result);
};

62
src/main.cpp Normal file
View File

@@ -0,0 +1,62 @@
#include <Windows.h>
#include <QApplication>
#include <QtWebEngineWidgets/QtWebEngineWidgets>
#include <filesystem>
#include "widgets/MainWindow.h"
#include "common/Utils.h"
#include "app/Application.h"
#include "app/Dao.h"
int main(int argc, char** argv)
{
SetConsoleOutputCP(CP_UTF8); // 设置控制台输出为UTF-8
auto& mysqlOptions = DaoEntity::mysqlOptions();
mysqlOptions.host = "localhost";
mysqlOptions.port = 3306;
mysqlOptions.user = "root";
mysqlOptions.password = "123456";
mysqlOptions.dbname = "ees";
std::string filename = "assets/html/data中文.txt";
std::filesystem::path filePath = std::filesystem::u8path("assets/html/data中文.txt");
//std::locale::global(locale(""));//将全局区域设为操作系统默认区域
std::ifstream ifs(filePath, std::ios::binary);
//std::locale::global(locale("C"));//还原全局区域设定
if (ifs.is_open())
{
// 将文件指针移动到末尾获取文件大小
ifs.seekg(0, std::ios::end);
std::streamsize size = ifs.tellg();
ifs.seekg(0, std::ios::beg);
std::string buf(size, '\0');
ifs.read(&buf[0], size);
std::cout << "文件内容: " << buf << std::endl;
}
else
{
std::cout << "error" << std::endl;
}
// 运行后台服务
Application::instance().init();
// 运行QT主窗口
QApplication qapp(argc, argv);
MainWindow mainWin;
mainWin.setWindowTitle("风光储能站控制管理系统");
mainWin.resize(1920, 1080);
mainWin.show();
qapp.exec();
return 0;
}

184
src/widgets/MainWindow.cpp Normal file
View File

@@ -0,0 +1,184 @@
#include "MainWindow.h"
#include <chrono>
#include <sstream>
#include <iomanip>
static std::string DatetimeNow(char c1 = '-', char c2 = ':', char c3 = ' ')
{
std::stringstream ss;
ss << "%Y" << c1 << "%m" << c1 << "%d" << c3 << "%H" << c2 << "%M" << c2 << "%S";
std::string fmt = ss.str();
ss.str("");
auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
ss << std::put_time(std::localtime(&t), fmt.c_str());
return ss.str();
}
static const std::string STY_BTN_MENU =
"QPushButton{background:rgba(50,128,218,200);color:white;border-radius:5px;border:2px solid rgb(10,120,215);font:bold 18px;}"
"QPushButton:hover{background-color:rgb(32,164,128);}"
"QPushButton:pressed{border-width:3px 0 0 3px;background-color:rgb(150,150,150);border-style:inset;}"
"QPushButton:disabled{color:rgb(150,150,150);}";
static const std::string STY_BTN_MENU_ACTIVE =
"QPushButton{background:rgba(32,164,128,200);color:white;border-radius:5px;border:2px solid rgb(10,255,215);font:bold 18px;}"
"QPushButton:hover{background-color:rgb(32,164,128);}"
"QPushButton:pressed{border-width:3px 0 0 3px;background-color:rgb(150,150,150);border-style:inset;}"
"QPushButton:disabled{color:rgb(150,150,150);}";
void Menu::init(
QWidget* parent,
int x, int y,
std::vector<std::string>& vecMenuId,
std::function<void(std::string id)> cb)
{
int num = vecMenuId.size();
x = (1920 - (num*110 - 10))*0.5;
cb_ = cb;
for (int i = 0; i<num; i++)
{
std::string menuName = vecMenuId[i];
auto btn = std::make_shared<QPushButton>(parent);
btn->setGeometry(x+i*110, y, 100, 35);
btn->setText(menuName.c_str());
btn->setFont(QFont("微软雅黑"));
if (menuName == curMenuId_)
{
btn->setStyleSheet(STY_BTN_MENU_ACTIVE.c_str());
activeBtn_ = btn.get();
}
else
{
btn->setStyleSheet(STY_BTN_MENU.c_str());
}
vecBtn_.push_back(btn);
QObject::connect(btn.get(), &QPushButton::clicked, this, &Menu::onMenuBtnClicked);
}
}
void Menu::onMenuBtnClicked()
{
QPushButton* btn = qobject_cast<QPushButton*>(sender());
std::string menuName = btn->text().toStdString();
if (menuName == curMenuId_)
{
return;
}
curMenuId_ = menuName;
if (activeBtn_) { activeBtn_->setStyleSheet(STY_BTN_MENU.c_str()); }
activeBtn_ = btn;
activeBtn_->setStyleSheet(STY_BTN_MENU_ACTIVE.c_str());
if (cb_) { cb_(curMenuId_); }
}
#include "WebHandler.h"
#include <QWebChannel>
MainWindow::MainWindow()
{
webView = std::make_shared<QWebEngineView>(this);
MyWebHandler* myWebHandler = new MyWebHandler();
QWebChannel* webChannel = new QWebChannel();
webChannel->registerObject("cppNative", myWebHandler);
webView->page()->setWebChannel(webChannel);
webView->setGeometry(0, 0, 1920, 1080);
// 默认设置透明, 解决加载时的白屏闪烁
webView->page()->setBackgroundColor(Qt::transparent);
webView->setContextMenuPolicy(Qt::NoContextMenu);
//webView.load(QUrl("https://www.baidu.com"));
webView->load(QUrl("file:///assets/html/main.html"));
//connect(wWebView.get(), &QWebEngineView::loadFinished, this, &MyWidget::slotLoadFinished);
//std::string htmlContent = "HelloWorld";
//webView->setHtml(htmlContent.c_str(), QUrl("file:///assets/html/"));
webView->show();
return;
QUI::label(labBkg_, this, 0, 0, 1920, 1080, "");
labBkg_.setPixmap(QPixmap("assets/ui/bkg01.png"));
// 顶部区域: 显示系统信息、时间、登录用户信息
//QUI::label(labBkgHead_, this, 0, 0, 1920, 114, "");
//labBkgHead_.setPixmap(QPixmap("assets/ui/bkg_head.png"));
// 系统名称
QUI::label(labTitle_, this, 100, 20, 520, 50, "", "font:bold 42px;color:white;");
// 时钟标签
QUI::label(labTime_, this, 50, 25, 320, 40, DatetimeNow().c_str(), "");
labTime_.setFont(QFont("微软雅黑", 16, 1000));
//wPage_ = std::make_shared<WidgetPageHome>(this);
//wPage_->setGeometry(0, 115, 1920, 1080-115);
//wPage_->show();
this->initMenu();
// 登录框
wLogin_.setParent(this);
wLogin_.show();
connect(&wLogin_, &WidgetLogin::signalLoginSuccess, this, &MainWindow::slotLoginSuccess);
QObject::connect(&timer_, &QTimer::timeout, this, &MainWindow::onTimeout);
timer_.start(1000);
}
void MainWindow::initMenu()
{
std::vector<std::string> vecMenuId =
{
"系统总览", "运行监控", "预测监控", "统计分析", "安全管理", "系统管理", "服务管理", "参数管理"
};
menu_ = std::make_shared<Menu>();
menu_->init(this, 740, 1030, vecMenuId, [=](std::string menuId) { this->onMenuClicked(menuId); });
// 考虑处理二级菜单
}
void MainWindow::resizeEvent(QResizeEvent* event)
{
auto& size = event->size();
if (webView)
{
webView->resize(size);
}
}
void MainWindow::slotLoginSuccess()
{
wLogin_.hide();
onMenuClicked("系统总览");
}
void MainWindow::onMenuClicked(std::string menuId)
{
auto w = WidgetPage::create(this, menuId);
if (w)
{
w->setGeometry(0, 90, 1920, 950);
wPage_ = w;
wPage_->show();
//wPage_->updateData();
}
else
{
wPage_ = nullptr;
}
}
void MainWindow::onTimeout()
{
if (wPage_)
{
//wPage_->updateData();
}
labTime_.setText(DatetimeNow().c_str());
}

55
src/widgets/MainWindow.h Normal file
View File

@@ -0,0 +1,55 @@
#include <QMainWindow>
#include <QtWebEngineWidgets/QWebEngineView>
#include <vector>
#include <QTimer>
#include <fstream>
#include <filesystem>
#include "uihelper.h"
#include "WidgetLogin.h"
#include "WidgetPage.h"
class Menu : public QObject
{
Q_OBJECT
public:
std::string curMenuId_;
std::vector<std::shared_ptr<QPushButton>> vecBtn_;
QPushButton* activeBtn_ = NULL;
std::function<void(std::string id)> cb_ = nullptr;
void init(QWidget* parent, int x, int y, std::vector<std::string>& vecMenuId, std::function<void(std::string id)> cb);
void onMenuBtnClicked();
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
void initMenu();
void resizeEvent(QResizeEvent* event);
public slots:
void slotLoginSuccess();
void onMenuClicked(std::string menuId);
void onTimeout();
public:
QLabel labBkg_;
QLabel labBkgHead_;
QLabel labTitle_;
QLabel labTime_;
WidgetLogin wLogin_;
QTimer timer_;
std::shared_ptr<WidgetPage> wPage_ = nullptr;
std::shared_ptr<Menu> menu_ = nullptr;
std::shared_ptr<QWebEngineView> webView;
};

604
src/widgets/WebHandler.cpp Normal file
View File

@@ -0,0 +1,604 @@
#include "WebHandler.h"
#include <fstream>
#include <filesystem>
#include <iostream>
#include "common/Utils.h"
#include "common/Logger.h"
#include "Snowflake.h"
#include "app/Dao.h"
static void JSsetResPaginaion(QVariantMap& result, std::vector<DataFields>& data, int page, int pageSize, int count, int code, string err)
{
result["code"] = code;
result["err"] = "操作成功";
result["count"] = count;
result["page"] = page;
result["pageSize"] = pageSize;
QVariantList listRow;
for (auto& fields: data)
{
QVariantMap row;
for (auto& field: fields.fields())
{
row[field.first.c_str()] = field.second.c_str();
}
listRow << row;
}
result["data"] = listRow;
}
static void JSgetReqParam(QString key, QVariantMap& params, DataFields& fields)
{
if (params.contains(key)) fields.set(key.toStdString(), params[key].toString().toStdString());
}
void MyWebHandler::setNativeText(const QString& text)
{
nativeText_ = text;
emit signalNativeTextChanged(text);
}
void MyWebHandler::log(const QString& text)
{
XLOGD() << "[JS] " << text.toStdString();
}
QString MyWebHandler::readFile(const QString& filename)
{
//std::string filePath = "assets/html/系统管理/index.html"; //filename.toStdString();
std::filesystem::path filePath = std::filesystem::u8path(filename.toStdString());
XLOGD() << "[cppNative] readFile: " << filePath;
std::ifstream ifs(filePath);
if (ifs.is_open())
{
// 获取文件大小
ifs.seekg(0, std::ios::end);
std::streamsize size = ifs.tellg();
XLOGD() << "[cppNative] readFile [" << filePath << "] success, data size=" << size;
// 定位回文件开始,读取文件内容到缓冲区
ifs.seekg(0, std::ios::beg);
std::string buf(size, '\0');
ifs.read(&buf[0], size);
ifs.close();
return buf.c_str();
}
else
{
XLOGD() << "[cppNative] readFile [" << filePath << "] failed.";
}
return "";
}
QVariantMap MyWebHandler::queryUserList(int page, int pageSize)
{
XLOGD() << "[cppNative] queryUserList";
std::vector<DataFields> res;
DAO::queryUser(res);
QVariantMap result;
JSsetResPaginaion(result, res, page, pageSize, res.size(), 0, "操作成功");
return result;
}
int MyWebHandler::insertUser(QVariantMap params)
{
DataFields fields;
JSgetReqParam("account", params, fields);
fields.set("passwd", "123456");
JSgetReqParam("name", params, fields);
JSgetReqParam("gender", params, fields);
JSgetReqParam("age", params, fields);
JSgetReqParam("phone", params, fields);
JSgetReqParam("email", params, fields);
JSgetReqParam("is_open", params, fields);
XLOGD() << "[cppNative] insertUser: params=" << fields.to_str();
bool ret = DAO::insertUser(fields);
// 设置用户角色
std::string user_id = fields.get_str("user_id");
if (params.contains("role_id")) {
int role_id = params["role_id"].toInt();
DataFields fieldsUserRole;
fieldsUserRole.set("user_id", user_id);
fieldsUserRole.set("role_id", role_id);
fieldsUserRole.set("create_time", Utils::timeNowStr());
auto dao = DAO::get("user_role");
ret = dao->insertFields(fieldsUserRole);
}
return ret;
}
int MyWebHandler::deleteUser(const QString& userId) { return 1; }
int MyWebHandler::updateUser(const QString& userId, QVariantMap params)
{
XLOGD() << "[cppNative] updateUser";
int ret = 1;
DataFields fields;
JSgetReqParam("account", params, fields);
JSgetReqParam("name", params, fields);
JSgetReqParam("gender", params, fields);
JSgetReqParam("age", params, fields);
JSgetReqParam("phone", params, fields);
JSgetReqParam("email", params, fields);
JSgetReqParam("is_open", params, fields);
if (params.size() > 0)
{
ret = DAO::updateUserById(userId.toStdString(), fields);
XLOGD() << "updateUser: ret=" << ret;
}
if (params.contains("role_id")) {
int role_id = params["role_id"].toInt();
fields.clear();
fields.set("user_id", userId.toStdString());
fields.set("role_id", role_id);
fields.set("create_time", Utils::timeNowStr());
fields.set("update_time", Utils::timeNowStr());
//fields.set("update_by", "");
auto dao = DAO::get("user_role");
std::vector<std::string> keysUpdate = {"role_id", "update_time"};
bool res = dao->duplicateUpdate(fields, keysUpdate);
ret = ret ? 0 : 1;
XLOGD() << "updateUser, update role, ret=" << ret;
}
return ret;
}
// ================================================================================================================
// 角色管理接口
QVariantMap MyWebHandler::queryRoleList(int page, int pageSize)
{
std::vector<DataFields> res;
auto dao = DAO::get("role");
bool ret = dao->exec("SELECT * FROM role;", res);
QVariantMap result;
JSsetResPaginaion(result, res, page, pageSize, res.size(), 0, "操作成功");
XLOGD() << "[cppNative] queryRoleList " << (ret ? "success." : "failed.");
return result;
}
int MyWebHandler::insertRole(QVariantMap params)
{
DataFields fields;
if (params.contains("name")) fields.set("name", params["name"].toString().toStdString());
if (fields.size() == 0)
{
return 1;
}
if (params.contains("describe")) fields.set("describe", params["describe"].toString().toStdString());
// 数据表 role_id 是自增id
fields.set("create_time", Utils::timeNowStr());
fields.set("update_time", Utils::timeNowStr());
auto dao = DAO::get("role");
bool ret = dao->insertFields(fields);
return ret ? 0: 1;
}
int MyWebHandler::deleteRole(const QString& roleId) { return 1; }
int MyWebHandler::updateRole(const QString& roleId, QVariantMap params)
{
DataFields fields;
JSgetReqParam("name", params, fields);
JSgetReqParam("describe", params, fields);
if (fields.size() <= 0)
{
return 0;
}
fields.set("update_time", Utils::timeNowStr());
std::string sqlC = " WHERE role_id='" + roleId.toStdString() + "'";
auto dao = DAO::get("role");
bool ret = dao->updateFields(fields, sqlC);
return ret ? 0 : 1;
}
QVariantList MyWebHandler::queryRolePermissionList(int roleId)
{
std::vector<DataFields> result;
std::string sql = "SELECT p.permission_id, p.name, rp.role_id, rp.is_open FROM permission p "
"LEFT JOIN role_permission rp ON(rp.permission_id = p.permission_id AND rp.role_id = '" + std::to_string(roleId) +"') WHERE p.is_open='1';";
auto dao = DAO::get("role_permission");
bool ret = dao->exec(sql, result);
QVariantList listRow;
for (auto& fields: result)
{
QVariantMap row;
for (auto& field: fields.fields())
{
row[field.first.c_str()] = field.second.c_str();
}
listRow << row;
}
return listRow;
};
int MyWebHandler::updateRolePermission(int roleId, QVariantList params)
{
auto dao = DAO::get("role_permission");
std::string sql = "DELETE FROM role_permission WHERE role_id='" + std::to_string(roleId) + "';";
bool ret = dao->exec(sql);
std::vector<DataFields> vecFields;
for (QVariant& item: params)
{
if (item.canConvert<QVariantMap>())
{
QVariantMap itemMap = item.toMap();
DataFields fields;
fields.set("role_id", roleId);
JSgetReqParam("permission_id", itemMap, fields);
JSgetReqParam("is_open", itemMap, fields);
vecFields.push_back(fields);
}
}
ret = dao->insertFields(vecFields);
return ret ? 0 : 1;
};
// ================================================================================================================
// 权限管理接口
QVariantMap MyWebHandler::queryPermissionList(int page, int pageSize)
{
std::vector<DataFields> res;
auto dao = DAO::get("permission");
bool ret = dao->exec("SELECT * FROM permission;", res);
QVariantMap result;
JSsetResPaginaion(result, res, page, pageSize, res.size(), 0, "操作成功");
return result;
}
int MyWebHandler::insertPermission(QVariantMap params)
{
DataFields fields;
JSgetReqParam("name", params, fields);
JSgetReqParam("describe", params, fields);
JSgetReqParam("is_open", params, fields);
fields.set("create_time", Utils::timeNowStr());
fields.set("update_time", Utils::timeNowStr());
auto dao = DAO::get("permission");
bool ret = dao->insertFields(fields);
return ret ? 0 : 1;
}
int MyWebHandler::deletePermission(const QString& permissionId) { return 1; }
int MyWebHandler::updatePermission(const QString& permissionId, QVariantMap params)
{
DataFields fields;
JSgetReqParam("name", params, fields);
JSgetReqParam("describe", params, fields);
JSgetReqParam("is_open", params, fields);
if (fields.size() <= 0)
{
return 0;
}
fields.set("update_time", Utils::timeNowStr());
auto dao = DAO::get("permission");
std::string sqlC = " WHERE permission_id='" + permissionId.toStdString() + "'";
bool ret = dao->updateFields(fields, sqlC);
return ret ? 0 : 1;
}
// ================================================================================================================
// 设备管理接口
QVariantMap MyWebHandler::queryDeviceList(int page, int pageSize)
{
XLOGD() << "queryDeviceList:";
std::vector<DataFields> res;
auto dao = DAO::get("device");
bool ret = dao->exec("SELECT * FROM device;", res);
XLOGD() << "queryDeviceList: size=" << res.size();
QVariantMap result;
JSsetResPaginaion(result, res, page, pageSize, res.size(), 0, "操作成功");
return result;
}
int MyWebHandler::insertDevice(QVariantMap params)
{
DataFields fields;
JSgetReqParam("type", params, fields);
JSgetReqParam("name", params, fields);
JSgetReqParam("code", params, fields);
JSgetReqParam("model", params, fields);
JSgetReqParam("factory", params, fields);
JSgetReqParam("is_open", params, fields);
if (fields.size() == 0)
{
return 0;
}
fields.set("create_time", Utils::timeNowStr());
fields.set("update_time", Utils::timeNowStr());
auto dao = DAO::get("device");
bool ret = dao->insertFields(fields);
return ret ? 0 : 1;
}
int MyWebHandler::deleteDevice(const QString& deviceId) { return 1; }
int MyWebHandler::updateDevice(const QString& deviceId, QVariantMap params)
{
DataFields fields;
JSgetReqParam("type", params, fields);
JSgetReqParam("name", params, fields);
JSgetReqParam("code", params, fields);
JSgetReqParam("model", params, fields);
JSgetReqParam("factory", params, fields);
JSgetReqParam("is_open", params, fields);
if (fields.size() == 0)
{
return 0;
}
fields.set("update_time", Utils::timeNowStr());
auto dao = DAO::get("device");
std::string sqlC = "WHERE device_id='" + deviceId.toStdString() + "'";
auto ret = dao->updateFields(fields, sqlC);
return ret ? 0 : 1;
}
QVariantList MyWebHandler::queryDeviceTypeList()
{
const std::vector<std::pair<int, std::string>> vecTypeDef =
{
{1, "光伏设备"},
{2, "储能设备"},
{3, "充电设备"},
{4, "逆变器"},
{5, "汇流箱"},
{6, "电表"},
};
QVariantList result;
for (auto& item: vecTypeDef)
{
QVariantMap row;
row["id"] = item.first;
row["name"] = item.second.c_str();
result << row;
}
return result;
}
// ================================================================================================================
// 计费管理接口
QVariantMap MyWebHandler::queryPriceList(int page, int pageSize)
{
std::vector<DataFields> res;
auto dao = DAO::get("price");
bool ret = dao->exec("SELECT * FROM price;", res);
XLOGD() << "queryPriceList: size=" << res.size();
QVariantMap result;
JSsetResPaginaion(result, res, page, pageSize, res.size(), 0, "操作成功");
return result;
}
int MyWebHandler::insertPrice(QVariantMap params)
{
DataFields fields;
JSgetReqParam("type", params, fields);
JSgetReqParam("describe", params, fields);
JSgetReqParam("is_open", params, fields);
if (fields.size() == 0)
{
return 0;
}
fields.set("create_time", Utils::timeNowStr());
fields.set("update_time", Utils::timeNowStr());
auto dao = DAO::get("price");
bool ret = dao->insertFields(fields);
return ret ? 0 : 1;
}
int MyWebHandler::deletePrice(const QString& priceId) { return 1; }
int MyWebHandler::updatePrice(const QString& priceId, QVariantMap params)
{
DataFields fields;
JSgetReqParam("name", params, fields);
JSgetReqParam("type", params, fields);
JSgetReqParam("describe", params, fields);
JSgetReqParam("is_open", params, fields);
if (fields.size() == 0)
{
return 0;
}
fields.set("update_time", Utils::timeNowStr());
std::string sqlC = "WHERE price_id='" + priceId.toStdString() + "'";
auto dao = DAO::get("price");
auto ret = dao->updateFields(fields, sqlC);
return ret ? 0 : 1;
}
QVariantList MyWebHandler::queryPriceTypeList()
{
const std::vector<std::pair<int, std::string>> vecTypeDef =
{
{1, "充电计费"},
};
QVariantList result;
for (auto& item: vecTypeDef)
{
QVariantMap row;
row["id"] = item.first;
row["name"] = item.second.c_str();
result << row;
}
return result;
}
QVariantMap MyWebHandler::queryPolicyList(int page, int pageSize)
{
std::vector<DataFields> res;
auto dao = DAO::get("policy");
bool ret = dao->exec("SELECT * FROM policy;", res);
XLOGD() << "queryPolicyList: size=" << res.size();
QVariantMap result;
JSsetResPaginaion(result, res, page, pageSize, res.size(), 0, "操作成功");
return result;
}
int MyWebHandler::insertPolicy(QVariantMap params)
{
DataFields fields;
JSgetReqParam("type", params, fields);
JSgetReqParam("name", params, fields);
JSgetReqParam("value", params, fields);
JSgetReqParam("describe", params, fields);
JSgetReqParam("is_open", params, fields);
if (fields.size() == 0)
{
return 0;
}
fields.set("create_time", Utils::timeNowStr());
fields.set("update_time", Utils::timeNowStr());
auto dao = DAO::get("policy");
bool ret = dao->insertFields(fields);
return ret ? 0 : 1;
}
int MyWebHandler::deletePolicy(const QString& policyId) { return 1; }
int MyWebHandler::updatePolicy(const QString& policyId, QVariantMap params)
{
DataFields fields;
JSgetReqParam("type", params, fields);
JSgetReqParam("name", params, fields);
JSgetReqParam("value", params, fields);
JSgetReqParam("describe", params, fields);
JSgetReqParam("is_open", params, fields);
if (fields.size() == 0)
{
return 0;
}
fields.set("update_time", Utils::timeNowStr());
std::string sqlC = "WHERE policy_id='" + policyId.toStdString() + "'";
auto dao = DAO::get("policy");
auto ret = dao->updateFields(fields, sqlC);
return ret ? 0 : 1;
}
QVariantList MyWebHandler::queryPolicyTypeList()
{
const std::vector<std::pair<int, std::string>> vecTypeDef =
{
{1, "发电策略"},
{2, "储能策略"},
{3, "充电策略"},
};
QVariantList result;
for (auto& item: vecTypeDef)
{
QVariantMap row;
row["id"] = item.first;
row["name"] = item.second.c_str();
result << row;
}
return result;
}
QVariantMap MyWebHandler::querySyslogList(int page, int pageSize)
{
std::vector<DataFields> res;
auto dao = DAO::get("system_log");
bool ret = dao->exec("SELECT * FROM system_log;", res);
XLOGD() << "querySyslogList: size=" << res.size();
QVariantMap result;
JSsetResPaginaion(result, res, page, pageSize, res.size(), 0, "操作成功");
return result;
}
QVariantMap MyWebHandler::querySecPolicyList(int page, int pageSize)
{
std::vector<DataFields> res;
auto dao = DAO::get("sec_policy");
bool ret = dao->exec("SELECT * FROM sec_policy;", res);
XLOGD() << "querySecPolicyList: size=" << res.size();
QVariantMap result;
JSsetResPaginaion(result, res, page, pageSize, res.size(), 0, "操作成功");
return result;
}
int MyWebHandler::insertSecPolicy(QVariantMap params)
{
DataFields fields;
JSgetReqParam("name", params, fields);
JSgetReqParam("type", params, fields);
JSgetReqParam("code", params, fields);
JSgetReqParam("level", params, fields);
JSgetReqParam("describe", params, fields);
JSgetReqParam("action", params, fields);
JSgetReqParam("is_open", params, fields);
if (fields.size() == 0)
{
return 0;
}
fields.set("create_time", Utils::timeNowStr());
fields.set("update_time", Utils::timeNowStr());
auto dao = DAO::get("sec_policy");
bool ret = dao->insertFields(fields);
return ret ? 0 : 1;
}
int MyWebHandler::updateSecPolicy(const QString& policyId, QVariantMap params)
{
DataFields fields;
JSgetReqParam("name", params, fields);
JSgetReqParam("type", params, fields);
JSgetReqParam("code", params, fields);
JSgetReqParam("level", params, fields);
JSgetReqParam("describe", params, fields);
JSgetReqParam("action", params, fields);
JSgetReqParam("is_open", params, fields);
if (fields.size() == 0)
{
return 0;
}
fields.set("update_time", Utils::timeNowStr());
std::string sqlC = "WHERE sec_policy_id='" + policyId.toStdString() + "'";
auto dao = DAO::get("sec_policy");
auto ret = dao->updateFields(fields, sqlC);
return ret ? 0 : 1;
}
QVariantMap MyWebHandler::querySecRecordList(int page, int pageSize)
{
std::vector<DataFields> res;
auto dao = DAO::get("sec_record");
bool ret = dao->exec("SELECT * FROM sec_record;", res);
XLOGD() << "querySecRecordList: size=" << res.size();
QVariantMap result;
JSsetResPaginaion(result, res, page, pageSize, res.size(), 0, "操作成功");
return result;
};
int MyWebHandler::insertSecRecord(QVariantMap params) {};
int MyWebHandler::updateSecRecord(const QString& policyId, QVariantMap params) {};

106
src/widgets/WebHandler.h Normal file
View File

@@ -0,0 +1,106 @@
#pragma once
#include <QObject>
#include <QStringList>
#include <QVariantMap>
#include <QVariantList>
class MyWebHandler : public QObject
{
Q_OBJECT
//Q_PROPERTY(QString nativeText READ nativeText MEMBER m_nativeText NOTIFY signalNativeTextChanged FINAL)
public:
explicit MyWebHandler(QObject* parent = nullptr)
{
}
QString nativeText() const { return nativeText_; }
signals:
//在C++中定义的信号可以在JS端监听此信号接收消息
void signalNativeTextChanged(const QString& text);
void singalReadFileFinished(const QString& text);
public slots:
//C++ 端的公共槽函数可以在JS端调用。
void setNativeText(const QString& text);
void log(const QString& text);
QString readFile(const QString& filename);
// ================================================================================================================
// 用户管理接口
QVariantMap queryUserList(int page, int pageSize);
int insertUser(QVariantMap params);
int deleteUser(const QString& userId);
int updateUser(const QString& userId, QVariantMap params);
// ================================================================================================================
// 角色管理接口
/**
* 查询角色列表, pageSize !=0 时分页查询
* @param [int page]: 当前的页码
* @param [int pageSize]: 一页的数据条数0: 不分页; >0: 分页
*/
QVariantMap queryRoleList(int page, int pageSize);
int insertRole(QVariantMap params);
int deleteRole(const QString& roleId);
int updateRole(const QString& roleId, QVariantMap params);
QVariantList queryRolePermissionList(int roleId);
int updateRolePermission(int roleId, QVariantList params);
// ================================================================================================================
// 权限管理接口
QVariantMap queryPermissionList(int page, int pageSize);
int insertPermission(QVariantMap params);
int deletePermission(const QString& permissionId);
int updatePermission(const QString& permissionId, QVariantMap params);
// ================================================================================================================
// 设备管理接口
QVariantMap queryDeviceList(int page, int pageSize);
int insertDevice(QVariantMap params);
int deleteDevice(const QString& deviceId);
int updateDevice(const QString& deviceId, QVariantMap params);
QVariantList queryDeviceTypeList();
// ================================================================================================================
// 计费管理接口
QVariantMap queryPriceList(int page, int pageSize);
int insertPrice(QVariantMap params);
int deletePrice(const QString& priceId);
int updatePrice(const QString& priceId, QVariantMap params);
QVariantList queryPriceTypeList();
// ================================================================================================================
// 策略管理接口
QVariantMap queryPolicyList(int page, int pageSize);
int insertPolicy(QVariantMap params);
int deletePolicy(const QString& policyId);
int updatePolicy(const QString& policyId, QVariantMap params);
QVariantList queryPolicyTypeList();
// ================================================================================================================
// 系统日志接口
QVariantMap querySyslogList(int page, int pageSize);
// ================================================================================================================
// 安全策略
QVariantMap querySecPolicyList(int page, int pageSize);
int insertSecPolicy(QVariantMap params);
int updateSecPolicy(const QString& policyId, QVariantMap params);
// ================================================================================================================
// 安全日志记录
QVariantMap querySecRecordList(int page, int pageSize);
int insertSecRecord(QVariantMap params);
int updateSecRecord(const QString& policyId, QVariantMap params);
public:
QString nativeText_;
};

View File

@@ -0,0 +1,78 @@
#include "WidgetLogin.h"
#include <QPushButton>
#include "app/Application.h"
WidgetLogin::WidgetLogin()
{
this->resize(1920, 1080);
QUI::label(labBkg_, this, 0, 0, 1920, 1080, "");
labBkg_.setPixmap(QPixmap("assets/ui/bkgLogin.png"));
int w = 517;
int h = 534;
int x = (1920 - w) *0.5;
int y = (1080 - h) *0.5;
//QUI::label(labLoginBkg_, this, x, y, w, h, "");
//labLoginBkg_.setPixmap(QPixmap("assets/ui/login.png"));
QUI::lineedit(lineUsername_, this, 870, 447, 300, 36);
QUI::lineedit(linePasswd_, this, 870, 510, 300, 36);
std::string sty = "QLineEdit {"
" background-color: #2859b0;" // 背景颜色
" color: #ffffff;" // 文字颜色
" border: 0px solid #ccc;" // 边框
" border-radius: 5px;" // 圆角
" padding: 5px;" // 内边距
" font-size: 16px;" // 字体大小
" font-weight: bold;" // 字体加粗
"}";
lineUsername_.setStyleSheet(sty.c_str());
linePasswd_.setStyleSheet(sty.c_str());
// 提示信息框
QUI::label(labMsg_, this, 838, 630, 350, 36, "");
// 登录按钮
QUI::button(btnLoigin_, this, 838, 588, 338, 46, "登 入", "background-color:#2a82e4; color:white;font-size: 14px;font-weight:bold;");
QObject::connect(&btnLoigin_, &QPushButton::clicked, this, &WidgetLogin::slotBtnCilckLogin);
}
void WidgetLogin::slotBtnCilckLogin()
{
if (0)
{
std::string account = lineUsername_.text().toStdString();
std::string passwd = linePasswd_.text().toStdString();
std::string err;
if (account.empty())
{
labMsg_.setText(std::string("请输入用户名" + err).c_str());
return;
}
if (passwd.empty())
{
labMsg_.setText(std::string("请输入用密码" + err).c_str());
return;
}
auto& op = Application::instance().getOperator();
bool ret = op.login(account, passwd, err);
if (!ret)
{
labMsg_.setText(std::string("登录失败:" + err).c_str());
return;
}
}
// 检查登录用户名和密码
emit signalLoginSuccess();
}

31
src/widgets/WidgetLogin.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#include <QWidget>
#include "uihelper.h"
class WidgetLogin : public QWidget
{
Q_OBJECT
public:
WidgetLogin();
signals:
void signalLoginSuccess();
public slots:
void slotBtnCilckLogin();
public:
QLabel labBkg_;
QLabel labLoginBkg_;
QLineEdit lineUsername_;
QLineEdit linePasswd_;
QLabel labMsg_;
QPushButton btnLoigin_;
};

View File

@@ -0,0 +1,25 @@
#include "WidgetPage.h"
#include "pages/WidgetPageHome.h"
#include "pages/WidgetPageOverview.h"
#include "pages/WidgetPageRunning.h"
#include "pages/WidgetPageWeb.h"
std::shared_ptr<WidgetPage> WidgetPage::create(QWidget* parent, std::string name)
{
std::shared_ptr<WidgetPage> w = nullptr;
if (name == "系统总览")
{
w = std::make_shared<WidgetPageOverview>(parent);
}
else if (name == "运行监控")
{
w = std::make_shared<WidgetPageRunning>(parent);
}
else
{
w = std::make_shared<WidgetPageWeb>(parent, name);
}
return w;
}

17
src/widgets/WidgetPage.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#include "uihelper.h"
class WidgetPage : public QWidget
{
public:
static std::shared_ptr<WidgetPage> create(QWidget* parent, std::string name);
WidgetPage(QWidget* parent) : QWidget(parent)
{
}
virtual void updateData() {};
};

41
src/widgets/WidgetWeb.cpp Normal file
View File

@@ -0,0 +1,41 @@
#include "WidgetWeb.h"
WebHandler::WebHandler(QObject* parent)
: QObject {parent}
{
webChannel = new QWebChannel();
// 注册C++对象到QWebChannel这样远端的QWebChannel也会生成一个对应的JS对象
// 在JS中引入 qwebchannel.js 使用 channel.objects.webNative 获取注册的“webNative”
webChannel->registerObject("webNative", this);
}
void WebHandler::setNativeText(const QString& text)
{
m_nativeText = text;
qDebug() << QString("setNativeText:") << text;
emit signalNativeTextChanged(text);
}
WidgetWeb::WidgetWeb(QWidget* parent) : QWebEngineView(parent)
{
webHandler_ = new WebHandler();
this->page()->setWebChannel(webHandler_->webChannel);
this->setContextMenuPolicy(Qt::NoContextMenu);
}
void WidgetWeb::loadHtml(std::string url)
{
// "file:///assets/html/echarts//maptest.html"
this->load(QUrl(url.c_str()));
connect(this, &QWebEngineView::loadFinished, this, &WidgetWeb::slotLoadFinished);
}
void WidgetWeb::invikeJS(QString jscode)
{
//QString jscode = QString("showalert('%1')").arg("Hello QtWebEngine!");
this->page()->runJavaScript(jscode, [](const QVariant& v) { qDebug() << v.toString(); });
}
void WidgetWeb::slotLoadFinished(bool ret)
{
}

48
src/widgets/WidgetWeb.h Normal file
View File

@@ -0,0 +1,48 @@
#pragma once
#include <QWebChannel>
#include <QtWebEngineWidgets/QWebEngineView>
#include <string>
class WebHandler : public QObject
{
Q_OBJECT
Q_PROPERTY(QString nativeText READ nativeText MEMBER m_nativeText NOTIFY signalNativeTextChanged FINAL)
public:
explicit WebHandler(QObject* parent = nullptr);
QString nativeText() const { return m_nativeText; }
signals:
//在C++中定义的信号可以在JS端监听此信号接收消息
void signalNativeTextChanged(const QString& text);
public slots:
//C++ 端的公共槽函数可以在JS端调用。
void setNativeText(const QString& text);
public:
QString m_nativeText;
QWebChannel* webChannel;
};
class WidgetWeb : public QWebEngineView
{
public:
WidgetWeb(QWidget* parent);
void loadHtml(std::string url);
void invikeJS(QString jscode);
// slots
void slotLoadFinished(bool ret);
public:
WebHandler* webHandler_;
};

View File

View File

View File

@@ -0,0 +1,203 @@
#include "WidgetPageHome.h"
#include "common/TimeUtils.h"
#include "common/Utils.h"
static std::vector<double> RANDT(int n, int min, int max)
{
std::vector<double> v(n);
for (int i = 0; i<n; i++) { v[i] = Utils::random(min, max); }
return v;
}
class InfoItem : public QWidget
{
public:
QLabel labTitle_;
QLabel labVal_;
QLabel labUnit_;
InfoItem::InfoItem(QWidget* parent, QRect rt, std::string title, std::string unit, std::string v="")
: QWidget(parent)
{
this->setGeometry(rt);
QUI::setBackground(this, "InfoCardItem", QColor(200, 200, 200, 30));
int xHalf = rt.width()/2;
int yHalf = rt.height()/2;
QUI::label(labTitle_, this, 0, 0, rt.width(), yHalf-10, title);
labTitle_.setAlignment(Qt::AlignBottom | Qt::AlignHCenter);
QUI::label(labVal_, this, 0, yHalf, xHalf+20, 30, v, "font:bold 24px;color:rgb(38,220,172);");
labVal_.setAlignment(Qt::AlignRight | Qt::AlignVCenter);
QUI::label(labUnit_, this, xHalf+30, yHalf, 30, 30, unit);
}
void InfoItem::setVal(std::string v)
{
labVal_.setText(v.c_str());
}
};
class EnvItem
{
public:
QLabel labBkg_;
QLabel labIcon_;
QLabel labVal_;
EnvItem(QWidget* parent, int x, int y, std::string icon, std::string v)
{
QUI::label(labBkg_, parent, x, y, 60, 60, "", "background-color:rgb(42, 74, 132);border-radius:30px;");
QUI::label(labIcon_, parent, x+6, y+6, 48, 48, "");
labIcon_.setPixmap(QPixmap(icon.c_str()));
QUI::label(labVal_, parent, x-10, y+65, 80, 40, v, "font:bold 14px;color:white;");
labVal_.setAlignment(Qt::AlignCenter);
}
};
void WidgetPageHome::slotLoadFinished(bool bOK)
{
QString jsCode = QString("showalert('%1')").arg("Hello QtWebEngine!");
wWebView->page()->runJavaScript(jsCode, [](const QVariant& v) { qDebug() << v.toString(); });
}
WidgetPageHome::WidgetPageHome(QWidget* parent) : WidgetPage(parent)
{
const std::string STY_VAL = "font:bold 18px;color:rgb(38,220,172);";
const int H = 300;
// 地图
//QUI::label(labMapBkg_, this, 500, 10, 920, H*3-10, "");
//labMapBkg_.setPixmap(QPixmap("assets/ui/bkg_map.png"));
wWebView = std::make_shared<QWebEngineView>(this);
wWebView->setGeometry(500, 10, 920, H*3-10);
wWebView->setContextMenuPolicy(Qt::NoContextMenu);
//webEngineView.load(QUrl("https://www.baidu.com"));
wWebView->load(QUrl("file:///assets/echarts/HTML/maptest.html"));
connect(wWebView.get(), &QWebEngineView::loadFinished, this, &WidgetPageHome::slotLoadFinished);
//std::string htmlContent = "HelloWorld";
//webEngineView.setHtml(htmlContent.c_str());
wWebView->show();
panelStation_ = std::make_shared<Panel>(this, QRect(10, 10, 480, H-10), "信息概览");
{
QWidget* wParent = panelStation_.get();
infoNum1_ = std::make_shared<InfoItem>(wParent, QRect(20, 50, 210, 100), "风电设备数量", "", "5");
infoNum2_ = std::make_shared<InfoItem>(wParent, QRect(240, 50, 210, 100), "光伏设备数量", "", "27");
infoNum3_ = std::make_shared<InfoItem>(wParent, QRect(20, 160, 210, 100), "储能设备", "", "16");
infoNum4_ = std::make_shared<InfoItem>(wParent, QRect(240, 160, 210, 100), "充电设备", "", "12");
}
panelStat_ = std::make_shared<Panel>(this, QRect(10, 10+H, 480, H-10), "统计信息");
{
int x = 40; int y = 50;
int w = 180;
int h = 60; int h1 = 40;
QWidget* wParent = panelStat_.get();
labSwapCount_ = QUI::labelPairV(wParent, x, y, w, h, h1, "风电今日发电量", "100.000");
labElectCount_ = QUI::labelPairV(wParent, x + 200, y, w, h, h1, "风电累计发电量", "100.000");
labSwapCountDay_ = QUI::labelPairV(wParent, x, y += (h+10), w, h, h1, "光伏今日发电量", "100.000");
labElectCountDay_ = QUI::labelPairV(wParent, x+ 200, y, w, h, h1, "光伏累计发电量", "100.000");
labCarbonCount_ = QUI::labelPairV(wParent, x, y += (h+10), w, h, h1, "信息5", "100.000");
labP1_ = QUI::labelPairV(wParent, x+ 200, y, w, h, h1, "信息4", "100.000");
}
panelEnv_ = std::make_shared<Panel>(this, QRect(10, 10+H*2, 480, H-10), "环境信息");
{
QWidget* wParent = panelEnv_.get();
int x = 40;
int y = 50;
envTemperature_ = std::make_shared<EnvItem>(wParent, x, y, "./assets/ui/temperature.png", "温度\n31℃");
envHumidity_ = std::make_shared<EnvItem>(wParent, x+100, y, "./assets/ui/humidity.png", "湿度\n42%");
envWind_ = std::make_shared<EnvItem>(wParent, x+200, y, "./assets/ui/windsSolid.png", "风速\n1.5m/s");
envSolar_ = std::make_shared<EnvItem>(wParent, x+300, y, "./assets/ui/brightness.png", "辐照度\n120W/m2");
y += 120;
QUI::label(labProgressCpu_, wParent, 40, y, 100, 24, "CPU使用率");
progressCpu_ = std::make_shared<ProgressView>(wParent, 120, y, 24);
progressCpu_->setVal(30);
y += 40;
QUI::label(labProgressMem_, wParent, 40, y, 100, 24, "内存使用率");
progressMem_ = std::make_shared<ProgressView>(wParent, 120, y, 24);
progressMem_->setVal(60);
y += 40;
QUI::label(labProgressDisk_, wParent, 40, y, 100, 24, "磁盘使用率");
progressDisk_ = std::make_shared<ProgressView>(wParent, 120, y, 24);
progressDisk_->setVal(60);
}
int y = 10;
int h = 280;
panelSwap_ = std::make_shared<Panel>(this, QRect(1430, 10+H*0, 480, H-10), "信息1");
{
//chartbar1_ = std::make_shared<ChartBarView>(panelSwap_.get(), QRect(0, 30, 480, h-20), 7);
//chartbar1_->addItem("数据1");
//chartbar1_->addItem("数据2");
//chartbar1_->addItem("数据3");
//chartbar1_->addItem("数据4");
}
y += (h+10);
panel2_ = std::make_shared<Panel>(this, QRect(1430, 10+H*1, 480, H-10), "信息2");
{
//chartbar2_ = std::make_shared<ChartBarView>(panel2_.get(), QRect(0, 30, 480, h-20), 7);
//chartbar2_->addItem("数据1");
//chartbar2_->addItem("数据2");
//chartbar2_->addItem("数据3");
}
y += (h+10);
panel3_ = std::make_shared<Panel>(this, QRect(1430, 10+H*2, 480, H-10), "信息3");
{
chartbar3_ = std::make_shared<ChartBarView>(panel3_.get(), QRect(0, 30, 480, h-20), 7);
chartbar3_->addItem("数据1");
chartbar3_->addItem("数据2");
// 测试数据
//chartbar3_->updateItem(0, RANDT(7, 1, 10));
//chartbar3_->updateItem(1, RANDT(7, 1, 10));
}
//chartbar1_->updateItem(0, RANDT(7, 1, 10));
//chartbar1_->updateItem(1, RANDT(7, 1, 10));
//chartbar1_->updateItem(2, RANDT(7, 1, 10));
//chartbar1_->updateItem(3, RANDT(7, 1, 10));
//chartbar2_->updateItem(0, RANDT(7, 1, 10));
//chartbar2_->updateItem(1, RANDT(7, 1, 10));
//chartbar2_->updateItem(2, RANDT(7, 1, 10));
//panelPower_ = std::make_shared<Panel>(this, QRect(500, 590, 920, 280), "今日负荷曲线");
//{
// QWidget* wParent = panelPower_.get();
// chartline7_ = std::make_shared<ChartLineView>(wParent, QRect(10, 30, 900, 240));
// chartline7_->addItem("数据1");
// chartline7_->addItem("数据2");
// chartline7_->setAxisYLeft(-1, 1, 7);
// //double t0 = TimeUtils::datetime2tms(TimeUtils::now_date() + " 00:00:00");
// //double tx = t0;
// //int n = 360;
// //std::vector<std::pair<double, double>> vd0(n+1);
// //std::vector<std::pair<double, double>> vd1(n+1);
// //for (int i = 0; i<=n; i++)
// //{
// // tx = t0 + i*(86400/n)*1000;
// // vd0[i] = {tx, sin(2*3.1415926*float(i*2)/float(360))};
// // vd1[i] = {tx, cos(2*3.1415926*float(i*2)/float(360))};
// //}
// //chartline7_->setAxisX(t0, tx, 13, "hh:mm");
// //chartline7_->updateItem(0, vd0);
// //chartline7_->updateItem(1, vd1);
//}
};

View File

@@ -0,0 +1,64 @@
#pragma once
#include "WidgetPage.h"
#include <QtWebEngineWidgets/QWebEngineView>
class InfoItem;
class EnvItem;
class WidgetPageHome : public WidgetPage
{
public:
WidgetPageHome(QWidget* parent);
void slotLoadFinished(bool bOK);
QLabel labTitle_;
QLabel labMapBkg_;
std::shared_ptr<Panel> panelStation_;
std::shared_ptr<InfoItem> infoNum2_;
std::shared_ptr<InfoItem> infoNum1_;
std::shared_ptr<InfoItem> infoNum3_;
std::shared_ptr<InfoItem> infoNum4_;
std::shared_ptr<Panel> panelSwap_;
std::shared_ptr<ChartBarView> chartbar1_;
std::shared_ptr<Panel> panel2_;
std::shared_ptr<ChartBarView> chartbar2_;
std::shared_ptr<Panel> panel3_;
std::shared_ptr<ChartBarView> chartbar3_;
std::shared_ptr<Panel> panelStat_;
std::shared_ptr<LabelPairV> labSwapCount_;
std::shared_ptr<LabelPairV> labSwapCountDay_;
std::shared_ptr<LabelPairV> labElectCount_;
std::shared_ptr<LabelPairV> labElectCountDay_;
std::shared_ptr<LabelPairV> labCarbonCount_;
std::shared_ptr<LabelPairV> labP1_;
std::shared_ptr<Panel> panelEnv_;
std::shared_ptr<Panel> panelPower_;
QLabel labProgressCpu_;
std::shared_ptr<ProgressView> progressCpu_;
QLabel labProgressMem_;
std::shared_ptr<ProgressView> progressMem_;
QLabel labProgressDisk_;
std::shared_ptr<ProgressView> progressDisk_;
std::shared_ptr<EnvItem> envTemperature_;
std::shared_ptr<EnvItem> envHumidity_;
std::shared_ptr<EnvItem> envWind_;
std::shared_ptr<EnvItem> envSolar_;
std::shared_ptr<ChartLineView> chartline_;
std::shared_ptr<QWebEngineView> wWebView = nullptr;
};

View File

@@ -0,0 +1,173 @@
#include "WidgetPageOverview.h"
#include "common/TimeUtils.h"
#include "common/Utils.h"
static std::vector<double> RANDT(int n, int min, int max)
{
std::vector<double> v(n);
for (int i = 0; i<n; i++) { v[i] = Utils::random(min, max); }
return v;
}
WidgetPageOverview::WidgetPageOverview(QWidget* parent) : WidgetPage(parent)
{
{
panel1_ = std::make_shared<Panel>(this, QRect(10, 10, 490, 300), "运行状况");
QWidget* wParent = panel1_.get();
labBkg_ = QUI::label(wParent, 10, 40, 150, 250, "", "border:1px solid rgb(27, 88, 105);background-color:rgba(200,200,200,30)");
labDaysK_ = QUI::label(wParent, 10, 180, 150, 30, "安全运行时间", "color:white;font: bold 20px;");
labDaysK_->setAlignment(Qt::AlignCenter);
labDaysV_ = QUI::label(wParent, 10, 100, 105, 50, "223", "color:rgb(77, 215, 240);font: bold 40px;");
labDaysV_->setAlignment(Qt::AlignBottom | Qt::AlignRight);
labDaysT_ = QUI::label(wParent, 120, 105, 40, 40, "", "color:white;font: bold 14px;");
labDaysT_->setAlignment(Qt::AlignBottom);
int x = 170; int y = 40;
int w = 150; int h = 77;
labp1_ = std::make_shared<LabelParam>(wParent, "站内风机设备", "100", "", x, y, w, h);
labp2_ = std::make_shared<LabelParam>(wParent, "站内光伏设备", "100", "", x += (w+10), y, w, h);
labp3_ = std::make_shared<LabelParam>(wParent, "当日入网电量", "31.58", "Kwh", x = 170, y += (h+10), w, h);
labp4_ = std::make_shared<LabelParam>(wParent, "累计入网设备", "54763.01", "Kwh", x += (w+10), y, w, h);
labp5_ = std::make_shared<LabelParam>(wParent, "累计充放电量", "387.13", "", x = 170, y += (h+10), w, h);
labp6_ = std::make_shared<LabelParam>(wParent, "累计碳减排量", "66.72", "", x += (w+10), y, w, h);
}
{
panel2_ = std::make_shared<Panel>(this, QRect(10, 320, 490, 300), "光伏设备");
QWidget* wParent = panel2_.get();
int x = 10; int y = 40;
int w = 150; int h = 50;
labp21_ = std::make_shared<LabelParam>(wParent, "日累计发电量", "223", "Kwh", x, y, w, h);
labp22_ = std::make_shared<LabelParam>(wParent, "日上网电量", "100", "Kwh", x += (w+10), y, w, h);
labp23_ = std::make_shared<LabelParam>(wParent, "日发电时长", "152", "h", x += (w+10), y, w, h);
chartbar2_ = std::make_shared<ChartBarView>(wParent, QRect(10, 95, 470, 210), 5);
chartbar2_->addItem("日累计发电量");
chartbar2_->addItem("日上网电量");
chartbar2_->addItem("日发电时长");
chartbar2_->updateItem(0, RANDT(7, 1, 10));
chartbar2_->updateItem(1, RANDT(7, 1, 10));
chartbar2_->updateItem(2, RANDT(7, 1, 10));
}
{
panel3_ = std::make_shared<Panel>(this, QRect(10, 630, 490, 300), "储能设备");
QWidget* wParent = panel3_.get();
int x = 10; int y = 40;
int w = 225; int h = 50;
labp31_ = std::make_shared<LabelParam>(wParent, "日累计充电电量", "223.23", "Kwh", x, y, w, h);
labp32_ = std::make_shared<LabelParam>(wParent, "日累计放电电量", "123.01", "Kwh", x += (w+20), y, w, h);
chartbar3_ = std::make_shared<ChartBarView>(wParent, QRect(10, 95, 470, 210), 5);
chartbar3_->addItem("日累充电电量");
chartbar3_->addItem("日上放电电量");
chartbar3_->updateItem(0, RANDT(7, 1, 10));
chartbar3_->updateItem(1, RANDT(7, 1, 10));
}
{
panel4_ = std::make_shared<Panel>(this, QRect(1420, 10, 490, 300), "负荷设备");
QWidget* wParent = panel4_.get();
int x = 10; int y = 40;
int w = 150; int h = 50;
labp41_ = std::make_shared<LabelParam>(wParent, "日用电功率", "223.23", "Kw", x, y, w, h);
labp42_ = std::make_shared<LabelParam>(wParent, "日用电次数", "126", "", x += (w+10), y, w, h);
labp43_ = std::make_shared<LabelParam>(wParent, "日用电电量", "53.62", "Kwh", x += (w+10), y, w, h);
chartbar4_ = std::make_shared<ChartBarView>(wParent, QRect(10, 95, 470, 210), 5);
chartbar4_->addItem("日用电功率");
chartbar4_->addItem("日用电次数");
chartbar4_->addItem("日用电电量");
chartbar4_->updateItem(0, RANDT(7, 1, 10));
chartbar4_->updateItem(1, RANDT(7, 1, 10));
chartbar4_->updateItem(2, RANDT(7, 1, 10));
}
{
panel5_ = std::make_shared<Panel>(this, QRect(1420, 320, 490, 300), "充电设备");
QWidget* wParent = panel5_.get();
int x = 10; int y = 40;
int w = 225; int h = 50;
labp51_ = std::make_shared<LabelParam>(wParent, "日时间利用率", "58", "%", x, y, w, h);
labp52_ = std::make_shared<LabelParam>(wParent, "日功率利用率", "61", "%", x += (w+20), y, w, h);
chartbar5_ = std::make_shared<ChartBarView>(wParent, QRect(10, 95, 470, 210), 5);
chartbar5_->addItem("日时间利用率");
chartbar5_->addItem("日功率利用率");
chartbar5_->updateItem(0, RANDT(7, 1, 10));
chartbar5_->updateItem(1, RANDT(7, 1, 10));
}
{
panel6_ = std::make_shared<Panel>(this, QRect(1420, 630, 490, 300), "告警信息");
QWidget* wParent = panel6_.get();
int x = 10; int y = 40;
int w = 150; int h = 50;
labp61_ = std::make_shared<LabelParam>(wParent, "日光伏设备告警", "5", "", x, y, w, h);
labp62_ = std::make_shared<LabelParam>(wParent, "日储能设备告警", "2", "", x += (w+10), y, w, h);
labp63_ = std::make_shared<LabelParam>(wParent, "日负荷设备告警", "3", "", x += (w+10), y, w, h);
chartbar6_ = std::make_shared<ChartBarView>(wParent, QRect(10, 95, 470, 210), 5);
chartbar6_->addItem("光伏设备");
chartbar6_->addItem("储能设备");
chartbar6_->addItem("负荷设备");
chartbar6_->updateItem(0, RANDT(7, 1, 10));
chartbar6_->updateItem(1, RANDT(7, 1, 10));
chartbar6_->updateItem(2, RANDT(7, 1, 10));
}
{
panel7_ = std::make_shared<Panel>(this, QRect(510, 680, 900, 250), "功率与辐照度");
QWidget* wParent = panel7_.get();
chartline7_ = std::make_shared<ChartLineView>(wParent, QRect(10, 50, 880, 200));
chartline7_->addItem("功率");
chartline7_->addItem("辐照度");
chartline7_->setAxisYLeft(-1, 1, 5);
double t0 = TimeUtils::datetime2tms(TimeUtils::now_date() + " 00:00:00");
double tx = t0;
int n = 360;
std::vector<std::pair<double, double>> vd0(n+1);
std::vector<std::pair<double, double>> vd1(n+1);
for (int i = 0; i<=n; i++)
{
tx = t0 + i*(86400/n)*1000;
vd0[i] = {tx, sin(2*3.1415926*float(i*2)/float(360))};
vd1[i] = {tx, cos(2*3.1415926*float(i*2)/float(360))};
}
chartline7_->setAxisX(t0, tx, 13, "hh:mm");
chartline7_->updateItem(0, vd0);
chartline7_->updateItem(1, vd1);
}
{
wWebView = std::make_shared<QWebEngineView>(this);
wWebView->setGeometry(510, 100, 900, 560);
// 默认设置透明, 解决加载时的白屏闪烁
wWebView->page()->setBackgroundColor(Qt::transparent);
wWebView->setContextMenuPolicy(Qt::NoContextMenu);
//webEngineView.load(QUrl("https://www.baidu.com"));
wWebView->load(QUrl("file:///assets/echarts/HTML/maptest.html"));
//connect(wWebView.get(), &QWebEngineView::loadFinished, this, &WidgetPageHome::slotLoadFinished);
//std::string htmlContent = "HelloWorld";
//webEngineView.setHtml(htmlContent.c_str());
wWebView->show();
//lab712_.setPixmap(QPixmap(icon.c_str()));
iconp1_ = std::make_shared<IconParam>(this, "光照", "27.2", "Lux", 600, 40, QColor(246, 155, 82));
iconp2_ = std::make_shared<IconParam>(this, "风速", "1.2", "m/s", 800, 40, QColor(155, 216, 1));
iconp3_ = std::make_shared<IconParam>(this, "环境温度", "27.2", "", 1000, 40, QColor(61, 254, 250));
iconp4_ = std::make_shared<IconParam>(this, "环境湿度", "27.2", "%", 1200, 40, QColor(216, 61, 108));
}
}

View File

@@ -0,0 +1,110 @@
#pragma once
#include "WidgetPage.h"
#include <QtWebEngineWidgets/QWebEngineView>
#include <sstream>
#include <iostream>
class LabelParam
{
public:
std::shared_ptr<QLabel> labBkg_;
std::shared_ptr<QLabel> labKey_;
std::shared_ptr<QLabel> labVal_;
std::shared_ptr<QLabel> labTail_;
LabelParam(QWidget* parent, std::string k, std::string v, std::string t, int x, int y, int w, int h)
{
labBkg_ = QUI::label(parent, x, y, w, h, "", "background-color:rgba(100,100,100,50)");
labKey_ = QUI::label(parent, x, y, w, h*0.5, k, "color:white;font: bold 16px;");
labVal_ = QUI::label(parent, x, y+h*0.5, w*float(2.0/3.0), h*0.5, v, "color:rgb(77, 215, 240);font:bold 16px;");
labTail_ = QUI::label(parent, x+w*float(2.0/3.0)+5, y+h*0.5, w*float(1.0/3.0), h*0.5, t, "color:white;font: bold 12px;");
labKey_->setAlignment(Qt::AlignCenter);
labVal_->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
labTail_->setAlignment(Qt::AlignVCenter);
}
};
class IconParam
{
public:
std::shared_ptr<QLabel> lab711_;
std::shared_ptr<QLabel> lab712_;
std::shared_ptr<QLabel> lab713_;
std::shared_ptr<QLabel> lab714_;
std::string tail;
IconParam(QWidget* parent, std::string k, std::string v, std::string t, int x, int y, QColor color= QColor(61, 254, 250))
{
tail = t;
std::stringstream ss;
ss << color.red() << "," << color.green() << "," << color.blue();
lab711_ = QUI::label(parent, x, y, 5, 50, "", "background-color:rgb(" + ss.str() + ")");
lab712_ = QUI::label(parent, x + 10, y, 50, 50, "", "background-color:rgba(" + ss.str() + ",50)");
lab713_ = QUI::label(parent, x + 10 + 60, y, 100, 25, k, "font: normal 16px; color:white");
lab714_ = QUI::label(parent, x + 10 + 60, y+25, 100, 25, v+tail, "font: normal 16px; color:white");
}
};
class WidgetPageOverview : public WidgetPage
{
public:
WidgetPageOverview(QWidget* parent);
std::shared_ptr<Panel> panel1_;
std::shared_ptr<QLabel> labBkg_;
std::shared_ptr<QLabel> labDaysK_;
std::shared_ptr<QLabel> labDaysV_;
std::shared_ptr<QLabel> labDaysT_;
std::shared_ptr<LabelParam> labp1_;
std::shared_ptr<LabelParam> labp2_;
std::shared_ptr<LabelParam> labp3_;
std::shared_ptr<LabelParam> labp4_;
std::shared_ptr<LabelParam> labp5_;
std::shared_ptr<LabelParam> labp6_;
std::shared_ptr<Panel> panel2_;
std::shared_ptr<LabelParam> labp21_;
std::shared_ptr<LabelParam> labp22_;
std::shared_ptr<LabelParam> labp23_;
std::shared_ptr<ChartBarView> chartbar2_;
std::shared_ptr<Panel> panel3_;
std::shared_ptr<LabelParam> labp31_;
std::shared_ptr<LabelParam> labp32_;
std::shared_ptr<ChartBarView> chartbar3_;
std::shared_ptr<Panel> panel4_;
std::shared_ptr<LabelParam> labp41_;
std::shared_ptr<LabelParam> labp42_;
std::shared_ptr<LabelParam> labp43_;
std::shared_ptr<ChartBarView> chartbar4_;
std::shared_ptr<Panel> panel5_;
std::shared_ptr<LabelParam> labp51_;
std::shared_ptr<LabelParam> labp52_;
std::shared_ptr<ChartBarView> chartbar5_;
std::shared_ptr<Panel> panel6_;
std::shared_ptr<LabelParam> labp61_;
std::shared_ptr<LabelParam> labp62_;
std::shared_ptr<LabelParam> labp63_;
std::shared_ptr<ChartBarView> chartbar6_;
std::shared_ptr<Panel> panel7_;
std::shared_ptr<ChartLineView> chartline7_;
std::shared_ptr<QWebEngineView> wWebView = nullptr;
std::shared_ptr<IconParam> iconp1_;
std::shared_ptr<IconParam> iconp2_;
std::shared_ptr<IconParam> iconp3_;
std::shared_ptr<IconParam> iconp4_;
};

View File

@@ -0,0 +1,359 @@
#include "WidgetPageRunning.h"
#include "common/Logger.h"
static void ReviseQueuePos(int i, int maxCol, int w, int h, int& x, int& y)
{
if (i > 0)
{
if (i%maxCol == 0)
{
x = 0;
y += (h);
}
else
{
x += (w);
}
}
}
class PanelCard : public Panel
{
public:
QLabel labIcon_;
QLabel labName_;
QLabel labTyle_;
QLabel labStatus_;
std::map<std::string, std::pair<std::shared_ptr<QLabel>, std::shared_ptr<QLabel>>> mapLabParams_;
std::string styLabelK_ = "QLabel {font:bold 15px;color:rgb(166, 184, 221);}";
std::string styLabel_ = "QLabel {font:bold 15px;color:white;}";
PanelCard(QWidget* parent, QRect rt, std::string type) : Panel(parent, rt, "")
{
//this->setObjectName("MyPanel");
//std::string sty = "#MyPanel {background-color:rgb(8, 54, 91);border:1px solid rgba(255,255,255,10);border-radius:15px;}";
this->setAutoFillBackground(true);
//this->setStyleSheet(sty.c_str());
this->setBackground(QColor(8, 54, 91), "border:1px solid rgba(255,255,255,10);border-radius:15px;");
QUI::labelImage(labIcon_, this, 10, 20, 64, 64, "assets/ui/solarPanel.png");
QUI::label(labName_, this, 90, 20, 120, 20, "#NAME", styLabel_);
QUI::label(labStatus_, this, 90, 40, 120, 20, "#STATUS", styLabel_);
QUI::label(labTyle_, this, 90, 60, 120, 20, type, "QLabel {font:bold 15px;color:rgb(8, 165, 255);}");
}
void setIcon(std::string icon)
{
labIcon_.setPixmap(QPixmap(icon.c_str()));
}
void setName(std::string name)
{
labName_.setText(name.c_str());
}
void setStatus(int status)
{
std::vector<std::string> VEC_STATUS = {"运行", "空闲", "离线", "故障"};
if (status >=0 && status <=3)
{
labStatus_.setText(VEC_STATUS[status].c_str());
}
else
{
labStatus_.setText("#STATUS");
}
}
void setParam(std::string k, std::string v)
{
std::shared_ptr<QLabel> labK = nullptr;
std::shared_ptr<QLabel> labV = nullptr;
auto iter = mapLabParams_.find(k);
if (iter == mapLabParams_.end())
{
int y = 100 + mapLabParams_.size() * 24;
labK = QUI::label(this, 20, y, 80, 20, k + ":", styLabelK_);
labV = QUI::label(this, 110, y, 120, 20, v, styLabel_);
mapLabParams_[k] = {labK, labV};
}
else
{
labV = iter->second.second;
labV->setText(v.c_str());
}
}
virtual void enterEvent(QEvent* e) override
{
this->setBackground(QColor(30, 100, 100, 120), "border: 1px solid white;border-radius:15px;");
}
virtual void leaveEvent(QEvent* e) override
{
this->setBackground(QColor(8, 54, 91), "border:1px solid rgba(255,255,255,10);border-radius:15px;");
}
};
class PanelDeviceDetail : public Panel
{
public:
PanelDeviceDetail(QWidget* parent, QRect rt) : Panel(parent, rt)
{
}
};
class PanelDeviceWind : public PanelDeviceDetail
{
public:
std::vector<std::shared_ptr<PanelCard>> vecCards_;
PanelDeviceWind(QWidget* parent, QRect rt) : PanelDeviceDetail(parent, rt)
{
int col = 5;
int x = 0;
int y = 0;
int W = 280;
int H = 320;
for (int i = 0; i<col; i++)
{
ReviseQueuePos(i, 5, W+10, H+10, x, y);
auto card = std::make_shared<PanelCard>(this, QRect(x+10, y+10, W, H), "风机");
card->setIcon("assets/ui/icon1.png");
card->setName("风电设备-" + std::to_string(i+1));
card->setStatus(0);
vecCards_.push_back(card);
card->setParam("位置", "能源站xxxx-xxx");
card->setParam("工作状态", "发电/空闲");
card->setParam("在线状态", "在线/离线");
card->setParam("故障状态", "正常/故障");
card->setParam("电压", "220 V");
card->setParam("电流", "50 A");
card->setParam("额定功率", "30 KW");
card->setParam("实时功率", "28 KW");
}
}
};
class PanelDeviceSolar : public PanelDeviceDetail
{
public:
std::vector<std::shared_ptr<PanelCard>> vecCards_;
PanelDeviceSolar(QWidget* parent, QRect rt) : PanelDeviceDetail(parent, rt)
{
int col = 5;
int x = 0;
int y = 0;
int W = 280;
int H = 320;
for (int i = 0; i<col; i++)
{
ReviseQueuePos(i, 5, W+10, H+10, x, y);
std::string type = (i==0) ? "逆变器" : (i==1 ? "汇流箱" : "光伏板");
auto card = std::make_shared<PanelCard>(this, QRect(x+10, y+10, W, H), type);
card->setIcon("assets/ui/solarPanel.png");
card->setName("设备-" + std::to_string(i+1));
card->setStatus(0);
vecCards_.push_back(card);
card->setParam("位置", "能源站xxxx-xxx");
card->setParam("电压", "220V");
card->setParam("电流", "0.5A");
card->setParam("额定功率", "22kw");
card->setParam("实时功率", "6.83kw");
}
}
};
class PanelDeviceEnergyStorage : public PanelDeviceDetail
{
public:
std::vector<std::shared_ptr<PanelCard>> vecCards_;
PanelDeviceEnergyStorage(QWidget* parent, QRect rt) : PanelDeviceDetail(parent, rt)
{
int col = 10;
int x = 0;
int y = 0;
int W = 280;
int H = 320;
for (int i = 0; i<col; i++)
{
ReviseQueuePos(i, 5, W+10, H+10, x, y);
auto card = std::make_shared<PanelCard>(this, QRect(x+10, y+10, W, H), "储能电池");
card->setIcon("assets/ui/energyStorage.png");
card->setName("储能设备-" + std::to_string(i+1));
card->setStatus(0);
vecCards_.push_back(card);
card->setParam("位置", "能源站xxxx-xxx");
card->setParam("电压", "220V");
card->setParam("电流", "0.5A");
card->setParam("额定功率", "22kw");
card->setParam("实时功率", "6.83kw");
}
}
};
class PanelDeviceCharge : public PanelDeviceDetail
{
public:
std::vector<std::shared_ptr<PanelCard>> vecCards_;
PanelDeviceCharge(QWidget* parent, QRect rt) : PanelDeviceDetail(parent, rt)
{
int col = 5;
int x = 0;
int y = 0;
int W = 280;
int H = 320;
for (int i = 0; i<col; i++)
{
ReviseQueuePos(i, 5, W+10, H+10, x, y);
auto card = std::make_shared<PanelCard>(this, QRect(x+10, y+10, W, H), "充电机");
card->setIcon("assets/ui/charger.png");
card->setName("充电设备-" + std::to_string(i+1));
card->setStatus(0);
vecCards_.push_back(card);
card->setParam("位置", "能源站xxxx-xxx");
card->setParam("电压", "220V");
card->setParam("电流", "0.5A");
card->setParam("额定功率", "22kw");
card->setParam("实时功率", "6.83kw");
}
}
};
class PanelCardCamera
{
public:
Panel panel_;
QLabel labName_;
QLabel labVideo_;
PanelCardCamera(QWidget* parent, QRect rt, std::string type) : panel_(parent, rt, "")
{
panel_.setObjectName("MyPanel");
std::string sty = "#MyPanel {background-color:rgb(8, 54, 91);border:1px solid rgba(255,255,255,10);border-radius:15px;}";
panel_.setAutoFillBackground(true);
panel_.setStyleSheet(sty.c_str());
QUI::label(labName_, &panel_, 10, 10, rt.width()-20, 30, "xxx监控点", "font:bold 16px; color:white;");
QUI::labelImage(labVideo_, &panel_, 10, 40, rt.width()-20, rt.height()-50, "assets/ui/camera.png");
}
};
class PanelDeviceSecurity : public PanelDeviceDetail
{
public:
std::vector<std::shared_ptr<PanelCardCamera>> vecCards_;
PanelDeviceSecurity(QWidget* parent, QRect rt) : PanelDeviceDetail(parent, rt)
{
int col = 6;
int x = 0;
int y = 0;
int W = 410;
int H = 308;
for (int i = 0; i<col; i++)
{
ReviseQueuePos(i, 3, W+50, H+50, x, y);
auto card = std::make_shared<PanelCardCamera>(this, QRect(x+50, y+50, W, H), "");
vecCards_.push_back(card);
}
}
};
static PanelDevice* g_activePanel_ = nullptr;
class PanelDevice : public Panel
{
public:
PanelDevice(QWidget* parent, QRect rt, std::string title) : Panel(parent, rt, title)
{
this->setBackground(QColor(29,54,102), "border:0px solid white; border-radius:5px;");
}
void setBackgroundStatus(int flag)
{
if (flag)
{
this->setBackground(QColor(29, 100, 102), "border: 1px solid white;");
}
else
{
this->setBackground(QColor(29, 54, 102), "border:0px solid white; border-radius:5px;");
}
}
void setActive(bool flag)
{
if (flag)
{
g_activePanel_ = this;
}
setBackgroundStatus(flag);
if (panelDetail_)
{
panelDetail_->setVisible(flag);
}
}
virtual void enterEvent(QEvent* e) override
{
setBackgroundStatus(1);
}
virtual void leaveEvent(QEvent* e) override
{
if (g_activePanel_ != this)
{
setBackgroundStatus(0);
}
}
void mousePressEvent(QMouseEvent* e) override
{
if (e->button() == Qt::LeftButton)
{
if (g_activePanel_ != this)
{
if (g_activePanel_) { g_activePanel_->setActive(false); }
this->setActive(true);
}
}
}
void setDetailPanel(std::shared_ptr<PanelDeviceDetail> panelDetail)
{
panelDetail_ = panelDetail;
}
std::shared_ptr<PanelDeviceDetail> panelDetail_ = nullptr;
};
WidgetPageRunning::WidgetPageRunning(QWidget* parent) : WidgetPage(parent)
{
// 设备类型Panel
int H = 180;
int i = 0;
//panel1_ = std::make_shared<PanelDevice>(this, QRect(10, 10+H*0, 380, H-10), "风电设备");
//panel1_->setDetailPanel(std::make_shared<PanelDeviceWind>(this, QRect(400, 10, 1490, 900)));
//panel1_->setActive(true);
panel2_ = std::make_shared<PanelDevice>(this, QRect(10, 10+H*(i++), 380, H-10), "光伏设备");
panel2_->setDetailPanel(std::make_shared<PanelDeviceSolar>(this, QRect(400, 10, 1490, 900)));
panel2_->setActive(false);
panel3_ = std::make_shared<PanelDevice>(this, QRect(10, 10+H*(i++), 380, H-10), "储能设备");
panel3_->setDetailPanel(std::make_shared<PanelDeviceEnergyStorage>(this, QRect(400, 10, 1490, 900)));
panel3_->setActive(false);
panel4_ = std::make_shared<PanelDevice>(this, QRect(10, 10+H*(i++), 380, H-10), "充电设备");
panel4_->setDetailPanel(std::make_shared<PanelDeviceCharge>(this, QRect(400, 10, 1490, 900)));
panel4_->setActive(false);
panel5_ = std::make_shared<PanelDevice>(this, QRect(10, 10+H*(i++), 380, H-10), "安防设备");
panel5_->setDetailPanel(std::make_shared<PanelDeviceSecurity>(this, QRect(400, 10, 1490, 900)));
panel5_->setActive(false);
panel2_->setActive(true);
//panelDevice_ = std::make_shared<Panel>(this, QRect(420, 10, 1490, 900), "");
//{
//}
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include "WidgetPage.h"
class PanelDevice;
class PanelDeviceDetail;
class WidgetPageRunning : public WidgetPage
{
public:
WidgetPageRunning(QWidget* parent);
std::shared_ptr<PanelDevice> panel1_;
std::shared_ptr<PanelDevice> panel2_;
std::shared_ptr<PanelDevice> panel3_;
std::shared_ptr<PanelDevice> panel4_;
std::shared_ptr<PanelDevice> panel5_;
std::shared_ptr<Panel> panelDevice_;
std::shared_ptr<PanelDeviceDetail> panelDeviceDetial_;
};

View File

@@ -0,0 +1,54 @@
#include "WidgetPageWeb.h"
#include <iostream>
WidgetPageWeb::WidgetPageWeb(QWidget* parent, std::string name) : WidgetPage(parent)
{
wWebView = std::make_shared<QWebEngineView>(this);
wWebView->setGeometry(0, 0, 1920, 900);
jsHandler = new JsHandler();
webChannel = new QWebChannel();
// 注册C++对象到QWebChannel这样远端的QWebChannel也会生成一个对应的JS对象
// 在JS中引入 qwebchannel.js 使用 channel.objects.webNative 获取注册的“webNative”
webChannel->registerObject("webNative", jsHandler);
wWebView->page()->setWebChannel(webChannel);
wWebView->setContextMenuPolicy(Qt::NoContextMenu);
//webEngineView.load(QUrl("https://www.baidu.com"));
std::string url = "file:///assets/html/" + name + "/index.html";
std::cout << "===> url=" << url << std::endl;
wWebView->load(QUrl(url.c_str()));
// 默认设置透明,解决加载过程中白屏
wWebView->page()->setBackgroundColor(Qt::transparent);
// 加载进度
connect(wWebView.get(), &QWebEngineView::loadProgress, [=](int progress)
{
//pWebEngineView->page()->setBackgroundColor(Qt::transparent);
});
connect(wWebView.get(), &QWebEngineView::loadFinished, this, &WidgetPageWeb::slotLoadFinished);
connect(jsHandler, &JsHandler::signalShowWebView, this, &WidgetPageWeb::slotShowWebView);
//std::string htmlContent = "HelloWorld";
//webEngineView.setHtml(htmlContent.c_str());
wWebView->hide();
//webView = std::make_shared<WidgetWeb>(this);
}
void WidgetPageWeb::slotLoadFinished(bool isOk)
{
//QString jsCode = QString("showalert('%1')").arg("Hello QtWebEngine!");
//wWebView->page()->runJavaScript(jsCode, [](const QVariant& v) { qDebug() << v.toString(); });
wWebView->show();
}
void WidgetPageWeb::slotShowWebView()
{
wWebView->show();
}

View File

@@ -0,0 +1,57 @@
#pragma once
#include "WidgetPage.h"
#include <QWebChannel>
#include <QtWebEngineWidgets/QWebEngineView>
class JsHandler : public QObject
{
Q_OBJECT
public:
//Q_PROPERTY(QString nativeText READ nativeText MEMBER m_nativeText NOTIFY signalNativeTextChanged FINAL)
explicit JsHandler(QObject* parent = nullptr)
{
}
QString nativeText() const { return m_nativeText; }
signals:
//在C++中定义的信号可以在JS端监听此信号接收消息
void signalNativeTextChanged(const QString& text);
void signalShowWebView();
public slots:
void showWebView()
{
emit signalShowWebView();
}
//C++ 端的公共槽函数可以在JS端调用。
void setNativeText(const QString& text)
{
m_nativeText = text;
qDebug() << QString("run JS call CPP: setNativeText:") << text;
emit signalNativeTextChanged("HelloWorld");
}
private:
QString m_nativeText;
};
class WidgetPageWeb : public WidgetPage
{
Q_OBJECT
public:
WidgetPageWeb(QWidget* parent, std::string name);
void slotLoadFinished(bool isOk);
void slotShowWebView();
public:
std::shared_ptr<QWebEngineView> wWebView = nullptr;
QWebChannel* webChannel = nullptr;
JsHandler* jsHandler = nullptr;
};

845
src/widgets/uihelper.cpp Normal file
View File

@@ -0,0 +1,845 @@
#include "uihelper.h"
static QFont g_font("微软雅黑", 10);
std::string UiStyle::BTN =
"QPushButton{background-color:rgba(150,150,150,80);border-radius:5px;font:bold 16px;color:white;border:2px solid gray;}"
"QPushButton:hover{background-color:rgba(150,150,150,100);border:2px solid white;}"
"QPushButton:pressed{border-width:3px 0 0 3px;border-style:inset;color:white;}";
std::shared_ptr<QLabel> QUI::label(QWidget* parent, int x, int y, int w, int h, std::string text, std::string sty)
{
auto lab = std::make_shared<QLabel>(parent);
lab->setGeometry(x, y, w, h);
lab->setText(text.c_str());
lab->setFont(g_font);
if (!sty.empty())
{
lab->setStyleSheet(sty.c_str());
}
else
{
lab->setStyleSheet("QLabel {color:white;}");
}
return lab;
}
void QUI::label(QLabel& lab, QWidget* parent, int x, int y, int w, int h, std::string text, std::string sty)
{
lab.setParent(parent);
lab.setGeometry(x, y, w, h);
lab.setText(text.c_str());
lab.setFont(g_font);
if (!sty.empty())
{
lab.setStyleSheet(sty.c_str());
}
else
{
lab.setStyleSheet("QLabel {color:white;}");
}
}
void QUI::labelImage(QLabel& lab, QWidget* parent, int x, int y, int w, int h, std::string img)
{
lab.setParent(parent);
lab.setGeometry(x, y, w, h);
lab.setPixmap(QPixmap(img.c_str()));
}
std::shared_ptr<LabelPairH> QUI::labelPair(QWidget* parent, int x, int y, int w, int h, int w1, std::string k, std::string v)
{
return std::make_shared<LabelPairH>(parent, QRect(x, y, w, h), w1, k, v);
}
std::shared_ptr<LabelPairV> QUI::labelPairV(QWidget* parent, int x, int y, int w, int h, int h1, std::string k, std::string v)
{
auto labPair = std::make_shared<LabelPairV>(parent, QRect(x, y, w, h), h1, k, v);
const std::string STY_VAL = "font:bold 18px;color:rgb(38,220,172);";
labPair->setValStyle(STY_VAL);
return labPair;
}
void QUI::button(QPushButton& btn, QWidget* parent, int x, int y, int w, int h, std::string text, std::string sty)
{
btn.setParent(parent);
btn.setGeometry(x, y, w, h);
btn.setText(text.c_str());
btn.setFont(g_font);
if (!sty.empty())
{
btn.setStyleSheet(sty.c_str());
}
}
QPushButton* QUI::button(QWidget* parent, int x, int y, int w, int h, std::string text, std::string sty/* = ""*/)
{
QPushButton* btn = new QPushButton(parent);
btn->setGeometry(x, y, w, h);
btn->setText(text.c_str());
btn->setFont(g_font);
if (!sty.empty())
{
btn->setStyleSheet(sty.c_str());
}
return btn;
}
//std::shared_ptr<QComboBox> QUI::combox(QWidget* parent, int x, int y, int w, int h, std::vector<std::string>& items)
//{
// std::shared_ptr<QComboBox> comb = std::make_shared<QComboBox>(parent);
// comb->setGeometry(x, y, w, h);
// QStringList strlist;
// for (auto& s: items)
// {
// strlist << s.c_str();
// }
// comb->insertItems(0, strlist);
// return comb;
//}
void QUI::combox(QComboBox& comb, QWidget* parent, int x, int y, int w, int h, std::vector<std::string> items, std::string v/* = ""*/)
{
comb.setParent(parent);
comb.setGeometry(x, y, w, h);
QStringList strlist;
for (auto& s: items)
{
strlist << s.c_str();
}
comb.insertItems(0, strlist);
if (!v.empty())
{
comb.setCurrentText(v.c_str());
}
}
void QUI::lineedit(QLineEdit& line, QWidget* parent, int x, int y, int w, int h)
{
line.setParent(parent);
line.setGeometry(x, y, w, h);
}
void QUI::setBackground(QWidget* w, std::string name, QColor color, std::string border)
{
if (!w) { return; }
w->setObjectName(name.c_str());
std::string sty = "#" + name + "{background-color:rgba("
+ std::to_string(color.red())
+ "," + std::to_string(color.green())
+ "," + std::to_string(color.blue())
+ "," + std::to_string(color.alpha())
+ ");" + border + "}";
w->setAutoFillBackground(true);
w->setStyleSheet(sty.c_str());
}
Panel::Panel(QWidget* parent, QRect rt, std::string title) : QWidget(parent)
{
this->setGeometry(rt);
// 设置背景色:方法一
//QPalette palette(this->palette());
//palette.setColor(QPalette::Background, QColor(29, 54, 102)); // 设置背景色
//this->setAutoFillBackground(true);
//this->setPalette(palette);
// 设置背景色:方法二
//this->setObjectName("PanelBase");
//this->setStyleSheet("#PanelBase{background-color:rgb(30,50,100);border-radius:5px;}");
// 设置背景色
QUI::setBackground(this, "PanelBase", QColor(29, 54, 102, 50));
setMouseTracking(true);
if (!title.empty())
{
// 渐变
std::string styBkg = "background-color:qlineargradient(x1:0,y1:0, x2:1,y2:0,stop:0 rgb(3,208,242),stop:0.9 rgba(3,208,242,0));";
// background-color:rgba(3, 208, 242, 200);
QUI::label(labBkg_, this, 10, 30, this->width()-20, 2, "", styBkg);
QUI::label(labIcon_, this, 10, 7, 6, 16, "", "background-color:rgb(33, 255, 210);");
QUI::label(labTitle_, this, 20, 5, this->width(), 20, title.c_str(), "color:rgb(99, 196, 216);font:bold 16px;");
}
this->show();
}
void Panel::setBackground(QColor color, std::string border)
{
QUI::setBackground(this, "PanelBase", color, border);
}
ChartBarView::ChartBarView(QWidget* parent, QRect rt, int xfrag)
: QChartView(parent)
, xfrag_(xfrag)
{
QFont font("微软雅黑", 9);
this->setGeometry(rt);
QColor labColor(255, 255, 255);
QUI::label(labTitle_, this, 0, 0, this->width(), 24, "");
labTitle_.setAlignment(Qt::AlignHCenter);
labTitle_.setFont(QFont("微软雅黑", 12, 100));
this->setFont(QFont("微软雅黑", 8));
chart_ = std::make_shared<QChart>();
chart_->setTitleFont(font);
chart_->setMargins(QMargins(0,0,0,0));
//chart_->setAnimationOptions(QChart::SeriesAnimations); // 动画方式
setChart(chart_.get());
// === 初始化序列 ==============================================================
series_ = std::make_shared<QBarSeries>();
series_->setBarWidth(0.8);
chart_->addSeries(series_.get());
// === 初始化X轴 ==============================================================
// 创建 X 轴并设置其分类标签
QStringList ticksX;
for (int i = 1; i <= xfrag; ++i) {
ticksX << QString::number(i);
}
axisX_ = std::make_shared<QBarCategoryAxis>();
axisX_->setLabelsColor(labColor); // 设置X轴的颜色
axisX_->setGridLineVisible(false);
axisX_->append(ticksX); // 将分类标签添加到 X 轴
chart_->addAxis(axisX_.get(), Qt::AlignBottom); // 将 X 轴添加到图表底部
series_->attachAxis(axisX_.get()); // 将柱状图系列与 X 轴关联
// === 初始化Y轴 ==============================================================
axisYLeft_ = std::make_shared<QValueAxis>();
axisYLeft_->setGridLineColor(QColor(200, 200, 200, 100));
axisYLeft_->setTickCount(6);
axisYLeft_->setRange(0, 10); // 设置 Y 轴的范围为 0 到 100
chart_->addAxis(axisYLeft_.get(), Qt::AlignLeft); // 将 Y 轴添加到图表左侧
series_->attachAxis(axisYLeft_.get()); // 将柱状图系列与 Y 轴关联
axisYLeft_->setLabelsColor(labColor);
// 设置背景色
this->setBackground(QColor(30, 50, 100, 50));
// === 初始化柱体 ==============================================================
//QBarSet* set1 = new QBarSet("10/01");
//for (int i = 1; i <= xfrag; ++i) { *set1 << i; }
//series_->append(set1);
//this->addBar("日换电次数1");
//this->addBar("日换电次数2");
//this->addBar("日换电次数3");
//this->addBar("日换电次数4");
//// === 示例更新bar的数据
//set1->replace(0, 8);
//// === 示例更新X轴
//QStringList ticksX2;
//for (int i = 1; i <= xfrag; ++i) {
// ticksX2 << QString::number(100+i);
//}
//axisX_->setCategories(ticksX2);
chart_->axisX()->setLabelsFont(font);
chart_->axisY()->setLabelsFont(font);
chart_->axisX()->setTitleFont(font);
chart_->axisY()->setTitleFont(font);
// 设置图例在图表中的位置
// 参数1: 水平位置
// 参数2: 垂直位置
// 参数3: 对齐方式
// , Qt::HorizontalAlignment::Right, Qt::VerticalAlignment::Top
// 附着图表
//chart_->legend()->attachToChart();
//// 位于图表上方
//chart_->legend()->setAlignment(Qt::AlignTop);
//// 位于图表下方
//chart_->legend()->setAlignment(Qt::AlignBottom);
//// 位于图表左侧
//chart_->legend()->setAlignment(Qt::AlignLeft);
//// 位于图表右侧
//chart_->legend()->setAlignment(Qt::AlignRight);
//// 不附着图表
//chart_->legend()->detachFromChart();
chart_->legend()->setFont(g_font);
chart_->legend()->setLabelColor(labColor);
chart_->legend()->setAlignment(Qt::AlignTop);
//chart_->legend()->setGeometry(QRectF(50, 0, this->width(), 24));
//chart_->legend()->update();
}
void ChartBarView::setTitle(std::string title)
{
//chart_->setTitle(title.c_str());
labTitle_.setText(title.c_str());
labTitle_.setGeometry(0, 10, this->width(), 24);
QMargins margin;
margin.setTop(40);
chart_->setMargins(margin);
chart_->legend()->setGeometry(QRectF(50, 20, this->width(), 24));
}
std::shared_ptr<QChart> ChartBarView::chart()
{
return chart_;
}
QBarSet& ChartBarView::addItem(std::string name)
{
int index = series_->barSets().size();
QBarSet* barSet = new QBarSet(name.c_str());
//bar初始化数据
for (int i = 1; i <= xfrag_; ++i) { *barSet << 0; }
//// === 示例更新bar的数据
//barSet->replace(0, 8);
series_->append(barSet);
chart_->legend()->setGeometry(QRectF(50, 0, this->width(), 24));
return *barSet;
}
void ChartBarView::updateItem(int index, std::vector<double>& vd)
{
QBarSet* barSet = this->getBar(index);
if (barSet)
{
for (int i = 0; i < xfrag_ && i< vd.size(); ++i)
{
barSet->replace(i, vd[i]);
}
}
}
QBarSet* ChartBarView::getBar(int index)
{
auto lstBarSet = series_->barSets();
if (index < lstBarSet.size())
{
return lstBarSet[index];
}
return nullptr;
}
void ChartBarView::setBackground(QColor& color)
{
//this->setAutoFillBackground(true);
//QPalette palette;
//palette.setColor(QPalette::Window, color); // 设置背景色
//this->setPalette(palette);
QUI::setBackground(this, "ChartBarView", color);
//this->setObjectName("ChartBarView");
//this->setStyleSheet("#ChartBarView{background-color:rgb(29,54,102);border-radius:5px;}");
chart_->setBackgroundBrush(QBrush(QColor(100,100,100,0))); // 设置背景色
chart_->setBackgroundVisible(true);
}
void ChartBarView::setAxisXTick(std::vector<std::string>& vecTick)
{
QStringList ticks;
for (int i = 0; i < xfrag_ && i<vecTick.size(); ++i) {
ticks << vecTick[i].c_str();
}
axisX_->setCategories(ticks);
}
ChartLineView::ChartLineView(QWidget* parent, QRect rt) : QChartView(parent)
{
QColor labColor(255, 255, 255);
QUI::setBackground(this, "ChartLineView1", QColor(30, 50, 100, 50));
this->setGeometry(rt);
// 图表视图
//QChartView* chartView = new QChartView(chart, wParent);
//this->setGeometry(10, 30, 900, 240);
//this->setRenderHint(QPainter::Antialiasing); // 反锯齿绘制
// 图表
chart_ = std::make_shared<QChart>();
chart_->setBackgroundBrush(QBrush(QColor(100, 100, 100, 0))); // 设置背景色
chart_->setBackgroundVisible(true);
//chart_->setAnimationOptions(QChart::SeriesAnimations); // 动画方式
//chart_->setTheme(QtCharts::QChart::ChartThemeBlueNcs); // 设置主题
//chart_->setTitle("方位角数据"); // 设置标题
chart_->setMargins(QMargins(0, 0, 0, 0));
this->setChart(chart_.get());
QDateTime curDateTIme = QDateTime::currentDateTime();
qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
// x轴(时间轴方式)
axisX = std::make_shared<QDateTimeAxis>();
axisX->setLabelsColor(labColor);
//axisX->setTitleText("时间(分:秒)"); // x轴显示标题
axisX->setGridLineVisible(false); // 隐藏背景网格X轴框线
axisX->setFormat("hh:mm"); // x轴格式
axisX->setLabelsAngle(0); // x轴显示的文字倾斜角度
axisX->setTickCount(10); // 轴上点的个数
axisX->setRange(curDateTIme, curDateTIme.addSecs(10)); // 范围
axisX->setLabelsFont(QFont("微软雅黑", 9));
// y轴
axisY = std::make_shared<QValueAxis>();
axisY->setGridLineColor(QColor(200, 200, 200, 100));
axisY->setLabelsColor(labColor);
//AxisY->setTitleText("角度"); // y轴显示标题
axisY->setRange(0, 20); // 范围
axisY->setTickCount(6); // 轴上点的个数
axisY->setGridLineVisible(true); // 背景网格Y轴框线
axisY->setLabelsFont(QFont("微软雅黑", 9));
chart_->addAxis(axisX.get(), Qt::AlignBottom); // 设置x轴位置
chart_->addAxis(axisY.get(), Qt::AlignLeft); // 设置y轴位置
// 图例
//chart_->legend()->detachFromChart();
chart_->legend()->setFont(g_font);
chart_->legend()->setLabelColor(labColor);
chart_->legend()->setVisible(true); // 图例显示
chart_->legend()->setAlignment(Qt::AlignTop); // 图例向下居中
}
void ChartLineView::addItem(std::string name)
{
auto series = std::make_shared< QLineSeries>();
chart_->addSeries(series.get()); // 添加线段
series->attachAxis(axisX.get()); // 线段依附的x轴
series->attachAxis(axisY.get()); // 线段依附的y轴
series->setName(name.c_str()); // 线段名称,在图例会显示
vecSeries_.push_back(series);
//series->setPen(QPen(Qt::red, 0.6, Qt::SolidLine)); // 设置线段pen
}
//#include "common/TimeUtils.h"
void ChartLineView::updateItem(int index, std::vector<std::pair<double, double>>& vd)
{
if (index >= vecSeries_.size()) { return; }
auto& series = vecSeries_[index];
series->clear();
for (int i = 0; i < vd.size(); ++i)
{
series->append(vd[i].first, vd[i].second);
}
//int64_t t0 = TimeUtils::datetime2tms(TimeUtils::now_date() + " 00:00:00");
//int64_t tx = t0;
//for (int i = 0; i<=240; i++)
//{
// tx = t0 + (i*360)*1000;
// series->append(tx, qrand()%18);
//}
//this->setAxisX(t0, tx, 13);
//this->setAxisYLeft(0, 20, 6);
//QDateTime t0 = QDateTime::fromString("2024-11-28 00:00:00", "yyyy-MM-dd hh:mm:ss");
//QDateTime tx;
//for (int i = 0; i<=240; i++)
//{
// tx = t0.addSecs(i*360);
// series->append(tx.toMSecsSinceEpoch(), qrand()%18);
//}
//this->setAxisX(t0.toMSecsSinceEpoch(), tx.toMSecsSinceEpoch(), 13);
//this->setAxisYLeft(0, 20, 6);
}
void ChartLineView::setAxisX(double min, double max, int tickCount, std::string fmt)
{
axisX->setRange(QDateTime::fromMSecsSinceEpoch(min), QDateTime::fromMSecsSinceEpoch(max)); // 范围
axisX->setTickCount(tickCount); // 轴上点的个数
axisX->setFormat(fmt.c_str());
}
void ChartLineView::setAxisYLeft(double min, double max, double tickCount, std::string fmt)
{
axisY->setRange(min, max);
axisY->setTickCount(tickCount);
axisY->setLabelFormat(fmt.c_str());
}
ProgressView::ProgressView(QWidget* parent, int x, int y, int h, int w, int d, int n)
: QWidget(parent)
, num_(n)
{
this->setGeometry(x, y, (w+d)*num_+4+42, h);
this->show();
vecBar_.resize(num_);
const std::string STY_LAB = "font:bold 14px;color:white;";
QUI::label(labBarBkg_, this, 0, 0, width(), height(), "", "border-width:1px;border-style:solid;border-color:rgba(40,169,222,255);");
for (int i = 0; i < num_; i++)
{
vecBar_[i] = QUI::label(this, 2+i*(w+d), 2, w, height() - 4, "", "background-color:rgba(255,255,255,30);");
}
QUI::label(labVal_, this, width()-42, 0, 40, height(), "100%", STY_LAB);
//labVal_.setAlignment(Qt::AlignRight | Qt::AlignVCenter);
}
void ProgressView::setVal(int v)
{
if (v<0) { v = 0; }
if (v>100) { v = 100; }
labVal_.setText(QString::number(v) + "%");
float c = float(v)*0.01;
int index = c*float(num_) - 1;
for (int i = 0; i<num_; i++)
{
int r = 0 + 255.0f*float(i)/float(num_);
int g = 255 - 255.0f*float(i)/float(num_);
std::string strColor = "background-color:rgba(" + std::to_string(r) + "," + std::to_string(g) + ",0,255);";
vecBar_[i]->setStyleSheet(index>=i ? strColor.c_str() : "background-color:rgba(255,255,255,30);");
}
}
LabelPairV::LabelPairV(QWidget* parent, QRect rt, int h, std::string k, std::string v)
{
QUI::label(labV_, parent, rt.x(), rt.y(), rt.width(), h, v);
QUI::label(labK_, parent, rt.x(), rt.y()+h, rt.width(), rt.height()-h, k);
labV_.setAlignment(Qt::AlignCenter);
labK_.setAlignment(Qt::AlignCenter);
}
void LabelPairV::setVal(std::string v, std::string sty/* = ""*/)
{
labV_.setText(v.c_str());
if (!sty.empty()) { labV_.setStyleSheet(sty.c_str()); }
}
void LabelPairV::setValStyle(std::string sty)
{
labV_.setStyleSheet(sty.c_str());
}
void LabelPairV::setKeyStyle(std::string sty)
{
labK_.setStyleSheet(sty.c_str());
}
void LabelPairV::setStyle(std::string styK, std::string styV /*= ""*/)
{
this->setKeyStyle(styK);
this->setValStyle(styV);
}
LabelPairH::LabelPairH(QWidget* parent, QRect rt, int w, std::string k, std::string v)
{
QUI::label(labK_, parent, rt.x(), rt.y(), w, rt.height(), k);
QUI::label(labV_, parent, rt.x()+w, rt.y(), rt.width()-w, rt.height(), v);
}
void LabelPairH::setVal(std::string v, std::string sty/* = ""*/)
{
labV_.setText(v.c_str());
if (!sty.empty()) { labV_.setStyleSheet(sty.c_str()); }
}
void LabelPairH::setValStyle(std::string sty)
{
labV_.setStyleSheet(sty.c_str());
}
void LabelPairH::setKeyStyle(std::string sty)
{
labK_.setStyleSheet(sty.c_str());
}
void LabelPairH::setStyle(std::string styK, std::string styV /*= ""*/)
{
this->setKeyStyle(styK);
this->setValStyle(styV);
}
static const std::string STY_TAB_BTN = R"(
QPushButton { background-color:rgb(240,120,0);border-radius:0px;font:bold 14px;color:white;border:1px solid #20a481; }
QPushButton:hover { background-color:rgba(32,164,128,255);color:white; }
QPushButton:pressed { border-width:3px 0 0 3px;border-style:inset;color:white;}
)";
static const std::string STY_TAB = R"(
QTableWidget
{
background-color:rgb(37, 89, 120);
alternate-background-color:rgb(57, 103, 130);
color:white;
font:bold 13px;
selection-background-color:rgba(53, 125, 203, 100);
}
QTableWidget::item {padding-left:0px;text-align:center;color:rgba(255,255,255,200);}
QTableWidget::item:selected {color:#FFFFFF; background: rgba(53, 125, 203,100);}
)";
//QTableWidget::item:hover
//{
// color:#FFFFFF;
// background: #4B4B4D;
//}
//QHeaderView::section,QTableCornerButton:section
//{
// text-align:center;
// padding:3px;
// margin:0px;
// color:#DCDCDC;
// border:1px solid #242424;
// border-left-width:0px;
// border-right-width:1px;
// border-top-width:0px;
// border-bottom-width:1px;
// background:qlineargradient(spread:pad,x1:0,y1:0,x2:0,y2:1,stop:0 #646464,stop:1 #525252);
// }
//QHeaderView::section:selected
//{
// color:#FFFFFF;
// border:1px solid #242424;
//}
//QScrollBar:vertical{
// width:8px;
// border-style:flat;
// border-radius: 4px;
// border:0px;
// background: #19191A;
//}
//QScrollBar::handle:vertical{
// background: rgba(255,255,255,0.50);
// border-radius: 4px;
// width:8px;
// min-height:91px;
// border-style:flat;
//}
//QScrollBar::handle:vertical::hover{
// background: rgba(255,255,255,0.90);
// border-radius: 4px;
// width:8px;
//}
//QScrollBar::handle:vertical::pressed{
// background: rgba(255,255,255,0.90);
// border-radius:4px;
// width:8px;
//}
//QScrollBar::sub-page:vertical {
// background: #19191A;
//border-style:flat;
//}
//QScrollBar::add-page:vertical {
// background: #19191A;
//border-style:flat;
//}
//QScrollBar::add-line:vertical{
// background: #19191A;
//}
//QScrollBar::sub-line:vertical {
// background: #19191A;
//}
//QScrollBar:horizontal{
// height:8px;
// border-style:flat;
// border-radius: 4px;
// border:0px;
//background: #19191A;
//}
//QScrollBar::handle:horizontal{
// background: rgba(255,255,255,0.50);
// border-radius: 4px;
// height:8px;
// min-width:91px;
// border-style:flat;
//}
//QScrollBar::handle:horizontal::hover{
// background: rgba(255,255,255,0.90);
// border-radius: 4px;
// height:8px;
//}
//QScrollBar::handle:horizontal::pressed{
// background: rgba(255,255,255,0.90);
// border-radius:4px;
// height:8px;
//}
//QScrollBar::sub-page:horizontal {
// background: #19191A;
// border-style:flat;
//}
//QScrollBar::add-page:horizontal {
// background: #19191A;
// border-style:flat;
//}
//QScrollBar::sub-line:horizontal {
// background: #19191A;
//}
//QScrollBar::add-line:horizontal{
// background: #19191A;
//}
static const std::string STY_TAB_HEADER = R"(
QHeaderView {background:rgb(46,53,97); font:bold 15px;}
QHeaderView::section {background:rgb(46,53,97);color:white;border:1px solid gray;}
)";
TableBase::TableBase(QWidget* parent, int rowMax, int colMax)
{
widget_ = std::make_shared<QTableWidget>(rowMax, colMax, parent);
//this->setItemDelegate(new MyTableItemDelegate(this));
// "alternate-background-color:rgb(11,231,255);background-color:rgb(222,191,255);"
widget_->setStyleSheet(STY_TAB.c_str());
// 交替颜色
widget_->setAlternatingRowColors(true);
// 单元格编辑()
widget_->setEditTriggers(QAbstractItemView::NoEditTriggers);
// 选中一行
widget_->setSelectionBehavior(QAbstractItemView::SelectRows);
// === 水平表头
auto horiHeader = widget_->horizontalHeader();
horiHeader->setFixedHeight(40);
horiHeader->setStyleSheet(STY_TAB_HEADER.c_str());
// === 垂直表头
auto vertHeader = widget_->verticalHeader();
// 隐藏垂直表头
vertHeader->setVisible(false);
// 设置默认行高
vertHeader->setDefaultSectionSize(32);
}
TableBase::~TableBase()
{
widget_->clearContents();
}
void TableBase::setGeometry(int x, int y, int w, int h)
{
if (widget_)
{
widget_->setGeometry(x, y, w, h);
}
}
void TableBase::setHeaderH(std::vector<std::string> vecHeader)
{
widget_->setColumnCount(vecHeader.size());
QStringList strList;
for (int i = 0; i<vecHeader.size(); ++i) { strList << vecHeader[i].c_str(); }
widget_->setHorizontalHeaderLabels(strList);
}
void TableBase::setHeaderWidth(std::vector<int> vecWidth)
{
for (int i = 0; i<vecWidth.size(); ++i)
{
if (vecWidth[i] > 0)
{
widget_->setColumnWidth(i, vecWidth[i]);
}
}
}
void TableBase::setOperate(std::vector<std::string> vecOperate, std::function<void(int, std::string)> cb)
{
cbOper_ = cb;
vecOperate_ = vecOperate;
//if (vecOperate_.size() > 0)
{
int colCount = widget_->columnCount();
widget_->setColumnCount(colCount + 1);
widget_->setHorizontalHeaderItem(colCount, new QTableWidgetItem("操作"));
widget_->horizontalHeader()->setSectionResizeMode(colCount, QHeaderView::Stretch);
}
}
void TableBase::setRowData(int row, std::vector<std::string> vd)
{
int rowCount = widget_->rowCount();
if (row >= rowCount)
{
return;
}
int dataColCount = widget_->columnCount();
if (vecOperate_.size() > 0)
{
dataColCount--;
// 创建操作按钮
if (vecWidgetOper_.size() != rowCount)
{
vecWidgetOper_.resize(rowCount, NULL);
}
std::shared_ptr<QWidget> wOpt = vecWidgetOper_[row];
if (!wOpt)
{
wOpt = std::make_shared<QWidget>();
wOpt->setMaximumSize(QSize(400, 40));
vecWidgetOper_[row] = wOpt;
for (int i = 0; i<vecOperate_.size(); i++)
{
std::string operText = vecOperate_[i];
QPushButton* btn = QUI::button(wOpt.get(), 5+85*i, 5, 80, 24, operText, UiStyle::BTN);
QObject::connect(btn, &QPushButton::clicked, widget_.get(), [=]() { this->onOperate(row, operText); });
}
widget_->setCellWidget(row, dataColCount, wOpt.get());
}
}
for (int col = 0; col<dataColCount; col++)
{
if (col < vd.size())
{
QTableWidgetItem* item = widget_->item(row, col);
if (!item)
{
item = new QTableWidgetItem();
widget_->setItem(row, col, item);
}
item->setText(vd[col].c_str());
item->setTextAlignment(Qt::AlignCenter);
}
}
}
void TableBase::clear()
{
if (!widget_) { return; }
widget_->clearContents();
vecWidgetOper_.clear();
}
std::shared_ptr<QTableWidget> TableBase::widget()
{
return widget_;
}
void TableBase::onOperate(int row, std::string oper)
{
auto curItem = widget_->item(row, 0);
widget_->setCurrentItem(curItem);
if (cbOper_) { cbOper_(row, oper); }
//curItem->setFlags(curItem->flags() | Qt::ItemIsEditable);
//QPushButton* btn = qobject_cast<QPushButton*>(sender());
//std::string text = btn->text().toStdString();
}
PageCtrl::PageCtrl(QWidget* parent, QRect rt, int pageSize) : QWidget(parent), pageSize_(pageSize)
{
this->setGeometry(rt);
QUI::setBackground(this, "PageCtrl", QColor(255, 0, 0, 30));
int x = 10;
QUI::label(labTotal_, this, x, 5, 100, 24, "共0条");
QUI::button(btnFirst_, this, x += 110, 5, 60, 24, "首页");
QUI::button(btnPrev_, this, x += 70, 5, 60, 24, "上一页");
QUI::label(labPage_, this, x += 70, 5, 100, 25, "0/0");
QUI::button(btnNext_, this, x += 110, 5, 60, 24, "下一页");
QUI::button(btnLast_, this, x += 70, 5, 60, 24, "尾页");
labPage_.setAlignment(Qt::AlignCenter);
}
void PageCtrl::setPage(int pageId, int total)
{
curPage_ = pageId;
int pageCount = total/pageSize_;
if (total%pageSize_ > 0) { pageCount++; }
std::string s = "" + std::to_string(total) + "";
labTotal_.setText(s.c_str());
s = std::to_string(curPage_) + "/" + std::to_string(pageCount);
labPage_.setText(s.c_str());
}

207
src/widgets/uihelper.h Normal file
View File

@@ -0,0 +1,207 @@
#pragma once
#include <string>
#include <functional>
#include <iostream>
#include <QPushButton>
#include <QLabel>
#include <QtCharts/QChart>
#include <QChartView>
#include <QBarSeries>
#include <QBarSet>
#include <QBarCategoryAxis>
#include <QValueAxis>
#include <QDateTimeAxis>
#include <QDateTime>
#include <QLineSeries>
#include <QSplineSeries>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QHeaderView>
#include <QComboBox>
#include <QLineEdit>
#include <QTextEdit>
using namespace QtCharts;
using MapLabelPair = std::map<std::string, std::pair<std::shared_ptr<QLabel>, std::shared_ptr<QLabel>>>;
class LabelPairH;
class LabelPairV;
class UiStyle
{
public:
static std::string BTN;
};
class QUI
{
public:
static std::shared_ptr<QLabel> label(QWidget* parent, int x, int y, int w, int h, std::string text, std::string sty="");
static void label(QLabel& lab, QWidget* parent, int x, int y, int w, int h, std::string text, std::string sty = "");
static void labelImage(QLabel& lab, QWidget* parent, int x, int y, int w, int h, std::string img);
static std::shared_ptr<LabelPairH> labelPair(QWidget* parent, int x, int y, int w, int h, int w1, std::string k, std::string v="");
static std::shared_ptr<LabelPairV> labelPairV(QWidget* parent, int x, int y, int w, int h, int h1, std::string k, std::string v = "");
static void button(QPushButton& btn, QWidget* parent, int x, int y, int w, int h, std::string text, std::string sty = "");
static QPushButton* button(QWidget* parent, int x, int y, int w, int h, std::string text, std::string sty = "");
//static std::shared_ptr<QComboBox> combox(QWidget* parent, int x, int y, int w, int h, std::vector<std::string>& items);
static void combox(QComboBox& comb, QWidget* parent, int x, int y, int w, int h, std::vector<std::string> items, std::string v="");
static void lineedit(QLineEdit& line, QWidget* parent, int x, int y, int w, int h);
static void setBackground(QWidget* w, std::string name, QColor color=QColor(29, 54, 102), std::string border="border-radius:5px;");
};
class Panel : public QWidget
{
public:
Panel(QWidget* parent, QRect rt, std::string title="");
void setBackground(QColor color, std::string border="border-radius:1px;border:1px solid gray;");
QLabel labBkg_;
QLabel labIcon_;
QLabel labTitle_;
};
class ChartBarView : public QChartView
{
public:
ChartBarView(QWidget* parent, QRect rt, int xfrag=5);
void setTitle(std::string title);
std::shared_ptr<QChart> chart();
QBarSet& addItem(std::string name);
void updateItem(int index, std::vector<double>& vd);
QBarSet* getBar(int index);
void setBackground(QColor& color);
void setAxisXTick(std::vector<std::string>& vecTick);
public:
std::shared_ptr<QChart> chart_;
std::shared_ptr<QBarSeries> series_;
// X轴
std::shared_ptr<QBarCategoryAxis> axisX_;
// Y轴左侧
std::shared_ptr<QValueAxis> axisYLeft_;
int xfrag_;
QLabel labTitle_;
};
class ChartLineView : QChartView
{
public:
ChartLineView(QWidget* parent, QRect rt);
void setAxisX(double min, double max, int tickCount, std::string fmt = "hh:mm");
void setAxisYLeft(double min, double max, double tickCount, std::string fmt = "%0.1f");
void addItem(std::string name);
void updateItem(int index, std::vector<std::pair<double, double>>& vd);
private:
std::shared_ptr<QChart> chart_;
std::shared_ptr<QDateTimeAxis> axisX;
std::shared_ptr<QValueAxis> axisY;
std::vector<std::shared_ptr<QLineSeries>> vecSeries_;
};
class ProgressView : public QWidget
{
public:
ProgressView(QWidget* parent, int x, int y, int h, int w=3, int d=1, int n=50);
void setVal(int v);
int num_;
QLabel labVal_;
QLabel labBarBkg_;
std::vector<std::shared_ptr<QLabel>> vecBar_;
};
class LabelPairV
{
public:
LabelPairV(QWidget* parent, QRect rt, int w, std::string k, std::string v);
void setVal(std::string v, std::string sty = "");
void setValStyle(std::string sty);
void setKeyStyle(std::string sty);
void setStyle(std::string styK, std::string styV = "");
QLabel labK_;
QLabel labV_;
};
class LabelPairH
{
public:
LabelPairH(QWidget* parent, QRect rt, int w, std::string k, std::string v);
void setVal(std::string v, std::string sty="");
void setValStyle(std::string sty);
void setKeyStyle(std::string sty);
void setStyle(std::string styK, std::string styV="");
QLabel labK_;
QLabel labV_;
};
class TableBase : public QObject
{
Q_OBJECT
public:
TableBase(QWidget* parent, int rowMax, int colMax);
~TableBase();
void setGeometry(int x, int y, int w, int h);
void setHeaderH(std::vector<std::string> vecHeader);
void setHeaderWidth(std::vector<int> vecWidth);
void setOperate(std::vector<std::string> vecOperate, std::function<void(int, std::string)> cb);
void setRowData(int row, std::vector<std::string> vd);
void clear();
std::shared_ptr<QTableWidget> widget();
public:
void onOperate(int row, std::string oper);
private:
std::vector<std::string> vecOperate_;
std::vector<std::shared_ptr<QWidget>> vecWidgetOper_;
std::function<void(int, std::string)> cbOper_ = nullptr;
std::shared_ptr<QTableWidget> widget_;
};
class PageCtrl : public QWidget
{
Q_OBJECT
public:
PageCtrl(QWidget* parent, QRect rt, int pageSize=10);
void setPage(int pageId, int total);
int pageSize_ = 0;
int curPage_ = 0;
QLabel labTotal_;
QLabel labPage_;
QPushButton btnPrev_;
QPushButton btnNext_;
QPushButton btnFirst_;
QPushButton btnLast_;
};