This commit is contained in:
HuangHai
2026-01-12 08:09:32 +08:00
parent 22596afaa4
commit ca23ebf606
44 changed files with 60 additions and 877 deletions

61
Tools/Sql/doris_ddl.sql Normal file
View File

@@ -0,0 +1,61 @@
-- 充电站基础信息表 (SCD2)
-- 保存场站的名称、地址等相对稳定的信息
DROP TABLE IF EXISTS t_station_profile_scd;
CREATE TABLE IF NOT EXISTS t_station_profile_scd (
`station_hash` VARCHAR(32) NOT NULL COMMENT '业务主键 (名称的MD5值)',
`valid_start_time` DATETIME NOT NULL COMMENT '记录生效开始时间',
`id` VARCHAR(50) NOT NULL COMMENT '唯一ID (UUID)',
`operator` VARCHAR(50) NOT NULL COMMENT '运营商名称',
`station_name` VARCHAR(255) NOT NULL COMMENT '场站名称',
`address` VARCHAR(500) COMMENT '详细地址',
`coord_x` DOUBLE COMMENT '经度 (高德坐标系)',
`coord_y` DOUBLE COMMENT '纬度 (高德坐标系)',
`valid_end_time` DATETIME NOT NULL DEFAULT '9999-12-31 23:59:59' COMMENT '记录生效结束时间',
`is_current` TINYINT NOT NULL DEFAULT 1 COMMENT '是否为当前最新记录 (1=是, 0=否)'
)
UNIQUE KEY(`station_hash`, `valid_start_time`, `id`)
DISTRIBUTED BY HASH(`station_hash`) BUCKETS 10
PROPERTIES (
"replication_num" = "1"
);
-- 充电站实时状态表 (SCD2 / Log)
-- 保存场站的桩数、空闲数等动态信息
-- 每次抓取如果状态变化则写入新记录
DROP TABLE IF EXISTS t_station_status_scd;
CREATE TABLE IF NOT EXISTS t_station_status_scd (
`station_hash` VARCHAR(32) NOT NULL COMMENT '业务主键 (名称的MD5值)',
`valid_start_time` DATETIME NOT NULL COMMENT '记录生效开始时间',
`id` VARCHAR(50) NOT NULL COMMENT '唯一ID (UUID)',
`total_piles` INT COMMENT '总桩数',
`free_piles` INT COMMENT '空闲桩数',
`piles_detail_json` TEXT COMMENT '详细桩信息 (JSON格式)',
`current_price` DECIMAL(10, 4) COMMENT '当前价格快照',
`pro_price` DECIMAL(10, 4) COMMENT 'PRO会员专享价快照',
`parking_info` VARCHAR(500) COMMENT '停车收费信息',
`distance` VARCHAR(50) COMMENT '距离信息 (例如 5.3km)',
`valid_end_time` DATETIME NOT NULL DEFAULT '9999-12-31 23:59:59' COMMENT '记录生效结束时间',
`is_current` TINYINT NOT NULL DEFAULT 1 COMMENT '是否为当前最新记录'
)
UNIQUE KEY(`station_hash`, `valid_start_time`, `id`)
DISTRIBUTED BY HASH(`station_hash`) BUCKETS 10
PROPERTIES (
"replication_num" = "1"
);
-- 充电站价格时段表 (SCD2)
-- 保存场站的全天价格时段信息
DROP TABLE IF EXISTS t_station_price_schedule_scd;
CREATE TABLE IF NOT EXISTS t_station_price_schedule_scd (
`station_hash` VARCHAR(32) NOT NULL COMMENT '业务主键 (名称的MD5值)',
`valid_start_time` DATETIME NOT NULL COMMENT '记录生效开始时间',
`id` VARCHAR(50) NOT NULL COMMENT '唯一ID (UUID)',
`schedule_json` TEXT COMMENT '价格时段详情 (JSON格式)',
`valid_end_time` DATETIME NOT NULL DEFAULT '9999-12-31 23:59:59' COMMENT '记录生效结束时间',
`is_current` TINYINT NOT NULL DEFAULT 1 COMMENT '是否为当前最新记录'
)
UNIQUE KEY(`station_hash`, `valid_start_time`, `id`)
DISTRIBUTED BY HASH(`station_hash`) BUCKETS 10
PROPERTIES (
"replication_num" = "1"
);

68
Tools/T1_CreateTable.py Normal file
View File

@@ -0,0 +1,68 @@
import asyncio
import os
import sys
import logging
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# 将项目根目录添加到系统路径,以便能够导入 DbKit 和 Config 等模块
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if project_root not in sys.path:
sys.path.append(project_root)
from Util import Win32Patch
# 应用 Windows 平台的异步策略补丁
Win32Patch.patch()
from DbKit.Db import Db
from Config.Config import DB_URL
async def init_tables():
"""
初始化数据库表结构:读取 SQL 文件并逐条执行。
"""
logger.info("正在初始化数据库连接...")
db = Db(db_url=DB_URL)
await db.init_db()
logger.info("正在读取 SQL 文件...")
# SQL 文件路径:相对于当前脚本所在目录 (DbKit/)
sql_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '', 'Sql/doris_ddl.sql')
logger.info(f"使用 SQL 文件: {sql_path}")
with open(sql_path, 'r', encoding='utf-8') as f:
sql_content = f.read()
# 使用分号分割 SQL 语句,并过滤掉空行和空白语句
statements = [s.strip() for s in sql_content.split(';') if s.strip()]
logger.info(f"共找到 {len(statements)} 条 SQL 语句。")
async with await db.get_session() as session:
for i, stmt in enumerate(statements):
logger.info(f"正在执行第 {i + 1} 条语句...")
# 使用 SQLAlchemy 的 text() 函数执行原生 SQL
from sqlalchemy import text
try:
await session.execute(text(stmt))
logger.info(f"{i + 1} 条语句执行成功。")
except Exception as e:
logger.error(f"执行第 {i + 1} 条语句时出错: {e}")
# 虽然大多数数据库的 DDL 语句是自动提交的,但显式提交是一个好习惯
await session.commit()
logger.info("数据库表初始化完成。")
# 优雅地关闭数据库引擎并释放连接
await db.engine.dispose()
if __name__ == "__main__":
# 再次确保补丁已应用
Win32Patch.patch()
# 运行异步初始化函数
asyncio.run(init_tables())

54
Tools/T2_ScreenShot.py Normal file
View File

@@ -0,0 +1,54 @@
# coding=utf-8
import asyncio
import logging
import os
from datetime import datetime
import uiautomator2 as u2
from Config.Config import TEMP_IMAGE_DIR
# 配置日志输出
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("ScreenshotTool")
async def take_screenshot():
"""
打开微信主界面并拍照(截图)
"""
# 连接设备
d = u2.connect()
# 执行截图
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"Screenshot_{timestamp}.jpg"
filepath = os.path.join(TEMP_IMAGE_DIR, filename)
logger.info(f"正在拍照(截图)并保存至: {filepath}")
d.screenshot(filepath)
if os.path.exists(filepath):
logger.info("拍照成功!")
return filepath
else:
logger.error("拍照失败,未找到生成的文件。")
return None
async def main():
filepath = await take_screenshot()
if filepath:
logger.info(f"任务执行完成,截图文件: {filepath}")
else:
logger.error("任务执行失败。")
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
logger.info("程序被用户中断.")
except Exception as e:
logger.exception(f"运行过程中出现异常: {e}")