From c62dbec7328a8b44e6ec61758e7b8463f2e502dd Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期五, 12 九月 2025 11:58:15 +0800
Subject: [PATCH] Merge branch 'liuyang'
---
SourceCode/Bond/Servo/GlassLogDb.h | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 170 insertions(+), 0 deletions(-)
diff --git a/SourceCode/Bond/Servo/GlassLogDb.h b/SourceCode/Bond/Servo/GlassLogDb.h
new file mode 100644
index 0000000..2bdf9bc
--- /dev/null
+++ b/SourceCode/Bond/Servo/GlassLogDb.h
@@ -0,0 +1,170 @@
+#pragma once
+// GlassLogDb.h - 单例封装:SQLite 写入/查询/分页/统计/CSV 导出(已对接 SERVO::CGlass)
+
+#include <string>
+#include <vector>
+#include <mutex>
+#include <optional>
+#include <chrono>
+#include <cstdint>
+#include <memory> // std::unique_ptr
+
+#include "CGlass.h" // 需要 SERVO::CGlass
+
+// 可在编译命令或本头文件前自定义表名:#define GLASS_LOG_TABLE "your_table_name"
+#ifndef GLASS_LOG_TABLE
+#define GLASS_LOG_TABLE "glass_log"
+#endif
+
+// 前置声明,避免头文件依赖 sqlite3.h
+struct sqlite3;
+struct sqlite3_stmt;
+
+class GlassLogDb {
+public:
+ // ====== 单例接口 ======
+ // 初始化(或切换)数据库文件路径;第一次调用会创建实例
+ static void Init(const std::string& dbPath);
+ // 获取全局实例;若未初始化会抛异常
+ static GlassLogDb& Instance();
+ // 是否已初始化
+ static bool IsInitialized() noexcept;
+ // 运行中切换到另一份数据库文件(等同 Init,不存在则创建)
+ static void Reopen(const std::string& dbPath);
+ // 当前数据库文件路径(未初始化返回空串)
+ static std::string CurrentPath();
+
+ // ====== 事务控制 ======
+ void beginTransaction();
+ void commit();
+ void rollback();
+
+ // ====== 写入 ======
+ // 直接从 SERVO::CGlass 写入(注意:参数为 非 const 引用,因为你的若干 getter 非 const)
+ long long insertFromCGlass(SERVO::CGlass& g);
+
+ // 显式参数插入(tStart/tEnd 可空;均写入 UTC ISO8601 文本或 NULL)
+ long long insertExplicit(
+ int cassetteSeqNo,
+ int jobSeqNo,
+ const std::string& classId,
+ int materialType,
+ int state,
+ std::optional<std::chrono::system_clock::time_point> tStart,
+ std::optional<std::chrono::system_clock::time_point> tEnd,
+ const std::string& buddyId,
+ int aoiResult,
+ const std::string& pathDesc,
+ const std::string& paramsDesc,
+ const std::string& prettyString);
+
+ // ====== 查询返回结构 ======
+ struct Row {
+ long long id = 0;
+ int cassetteSeqNo = 0;
+ int jobSeqNo = 0;
+ std::string classId;
+ int materialType = 0;
+ int state = 0;
+ std::string tStart; // ISO8601(库中为 NULL 则为空串)
+ std::string tEnd; // ISO8601(库中为 NULL 则为空串)
+ std::string buddyId;
+ int aoiResult = 0;
+ std::string path;
+ std::string params;
+ std::string pretty;
+ };
+
+ // ====== 过滤条件 ======
+ struct Filters {
+ std::optional<std::string> classId; // 精确匹配 class_id
+ std::optional<int> cassetteSeqNo;
+ std::optional<int> jobSeqNo;
+
+ // 关键字模糊:对 class_id / buddy_id / path / params / pretty 做 OR LIKE
+ std::optional<std::string> keyword;
+
+ // 时间范围:对 t_start 过滤,含边界(ISO8601 文本比较)
+ std::optional<std::chrono::system_clock::time_point> tStartFrom;
+ std::optional<std::chrono::system_clock::time_point> tStartTo;
+ };
+
+ // ====== 查询 / 统计 / 分页 ======
+ // 分页查询(limit/offset),按 id DESC
+ std::vector<Row> query(
+ const Filters& filters = {},
+ int limit = 50,
+ int offset = 0);
+
+ // 统计与 filters 相同条件的总数
+ long long count(const Filters& filters = {});
+
+ struct Page {
+ std::vector<Row> items; // 当前页数据
+ long long total = 0; // 符合条件的总记录数
+ int limit = 0; // 本次查询的页容量
+ int offset = 0; // 本次查询的起始偏移
+ };
+ // 一次取回列表 + 总数
+ Page queryPaged(
+ const Filters& filters = {},
+ int limit = 50,
+ int offset = 0);
+
+ // ====== 导出 ======
+ // 导出满足 filters 的“全部记录”(不受分页限制)为 CSV(UTF-8)
+ // 返回写出的数据行数(不含表头)
+ long long exportCsv(const std::string& csvPath, const Filters& filters = {});
+
+ // ====== 析构 / 拷贝控制 ======
+ ~GlassLogDb();
+ GlassLogDb(const GlassLogDb&) = delete;
+ GlassLogDb& operator=(const GlassLogDb&) = delete;
+
+private:
+ // 仅允许通过单例接口构造
+ explicit GlassLogDb(const std::string& dbPath);
+
+ // 内部打开/关闭/重开
+ void openDb(const std::string& dbPath);
+ void closeDb() noexcept;
+ void reopenInternal(const std::string& dbPath);
+
+ // 建表 / 预编译 / 释放
+ void ensureSchema();
+ void prepareStatements();
+ void finalizeStatements() noexcept;
+
+ // 工具:time_point -> "YYYY-MM-DDTHH:MM:SSZ"(UTC)
+ static std::string toIso8601Utc(std::chrono::system_clock::time_point tp);
+
+ // 实际插入执行(支持可空时间)
+ long long doInsert(
+ int cassetteSeqNo,
+ int jobSeqNo,
+ const std::string& classId,
+ int materialType,
+ int state,
+ std::optional<std::chrono::system_clock::time_point> tStart,
+ std::optional<std::chrono::system_clock::time_point> tEnd,
+ const std::string& buddyId,
+ int aoiResult,
+ const std::string& pathDesc,
+ const std::string& paramsDesc,
+ const std::string& prettyString);
+
+private:
+ // SQLite 句柄
+ sqlite3* db_ = nullptr;
+ sqlite3_stmt* stmtInsert_ = nullptr;
+
+ // 实例内并发保护(同一连接上的写/读串行化)
+ std::mutex mtx_;
+
+ // 当前数据库文件路径
+ std::string dbPath_;
+
+ // 单例静态对象与其互斥
+ static std::unique_ptr<GlassLogDb> s_inst;
+ static std::mutex s_instMtx;
+};
--
Gitblit v1.9.3