From b7843917ffbca91ba2fdaa42906012ff75c7e5fb Mon Sep 17 00:00:00 2001 From: dongchangxi <458593490@qq.com> Date: Wed, 10 Dec 2025 17:14:34 +0800 Subject: [PATCH] 111111 --- factory_sliceing/README_BUILD.md | 51 +++++- .../main_begin_sliceing.py | 12 +- .../utils/click_soft_button.py | 10 +- .../utils/exe_operate.py | 16 +- factory_sliceing/build_exe.py | 31 +++- factory_sliceing/config.example.toml | 40 +++++ factory_sliceing/config.toml | 44 +++++ .../main_download_batch_data_and_trans.py | 4 +- factory_sliceing/main.py | 22 ++- factory_sliceing/utils/__init__.py | 2 + factory_sliceing/utils/config.py | 155 ++++++++++++++++++ 11 files changed, 362 insertions(+), 25 deletions(-) create mode 100644 factory_sliceing/config.example.toml create mode 100644 factory_sliceing/config.toml create mode 100644 factory_sliceing/utils/__init__.py create mode 100644 factory_sliceing/utils/config.py diff --git a/factory_sliceing/README_BUILD.md b/factory_sliceing/README_BUILD.md index 800c731..236a570 100644 --- a/factory_sliceing/README_BUILD.md +++ b/factory_sliceing/README_BUILD.md @@ -38,19 +38,58 @@ pyinstaller --name=factory_sliceing --onefile --console --clean main.py 打包完成后,exe 文件位于 `dist/factory_sliceing.exe` -使用方法: +### 配置文件 + +**重要**: 打包后的 exe 需要配置文件 `config.toml` 才能正常运行。 + +- **配置文件位置**: 必须放在 **exe 同级目录**(与 `factory_sliceing.exe` 同一目录) +- **自动复制**: 打包脚本会自动将 `config.toml` 复制到 `dist/` 目录 +- **如果配置文件不存在**: 打包脚本会尝试复制 `config.example.toml` 作为模板,你需要根据实际情况修改 + +配置文件示例: +```toml +[redis] +host = "your-redis-host" +password = "your-redis-password" +port = 6379 +db = 6 + +[oss] +access_key_id = "your-access-key-id" +access_key_secret = "your-access-key-secret" +endpoint = "oss-cn-shanghai.aliyuncs.com" +bucket = "your-bucket-name" + +[api] +base_url = "https://mp.api.suwa3d.com" +env = "prod" + +[work] +default_dir = "C:\\work" # 默认工作目录 +``` + +### 使用方法 + ```bash -factory_sliceing.exe +factory_sliceing.exe [work_dir] ``` 可用命令: -- `batch_dwonload` - 批量下载 +- `batch_download` - 批量下载 - `begin_sliceing` - 开始切片 - `download_zip` - 下载压缩包 +参数说明: +- `command`: 必需,要执行的命令 +- `work_dir`: 可选,工作目录。如果未提供,将从配置文件读取 `work.default_dir`,如果配置文件中也没有,则使用 exe 所在目录 + 示例: ```bash +# 使用命令行参数指定工作目录 factory_sliceing.exe begin_sliceing C:\work\data + +# 使用配置文件中的默认工作目录 +factory_sliceing.exe begin_sliceing ``` ## 注意事项 @@ -92,3 +131,9 @@ factory_sliceing.exe begin_sliceing C:\work\data - 如果仍然提示文件不存在,检查 `build_exe.py` 中的 `--add-data` 参数是否正确 - 文件会被放在 `_MEIPASS/utils/` 和 `_MEIPASS/download_batch_data/utils/` 目录下 +### 问题:配置文件不存在或读取失败 +- **配置文件位置**: 必须放在 exe 同级目录(与 `factory_sliceing.exe` 同一目录) +- 打包脚本会自动复制 `config.toml` 到 `dist/` 目录 +- 如果配置文件不存在,程序会使用默认值或提示错误 +- 可以复制 `config.example.toml` 并重命名为 `config.toml`,然后根据实际情况修改 + diff --git a/factory_sliceing/auto_sliceing_operate/main_begin_sliceing.py b/factory_sliceing/auto_sliceing_operate/main_begin_sliceing.py index e071eae..20736e4 100644 --- a/factory_sliceing/auto_sliceing_operate/main_begin_sliceing.py +++ b/factory_sliceing/auto_sliceing_operate/main_begin_sliceing.py @@ -8,12 +8,12 @@ import os from .utils.request import requestApiToUpdateSliceStatusComplate #"C:/test/10192_small_No4/data" -def BeginSliceing(batchId,machineId, folderPath): +def BeginSliceing(batchId,machineId, folderPath,data): # 打开3d切片软件 - start_exe() - time.sleep(1) + start_exe(data) + time.sleep(5) #点击确认按钮 - click_confirm() + # click_confirm() #先打开导入文件的弹框 clickFileIMportShow() time.sleep(1) @@ -29,7 +29,7 @@ def BeginSliceing(batchId,machineId, folderPath): log("切片结束") time.sleep(5) #切片完成之后,将切片文件打包成zip文件,上传到OSS,并且请求api 更新批次状态为切片完成 - requestApiToUpdateSliceStatusComplate(batchId, 0) + # requestApiToUpdateSliceStatusComplate(batchId, 0) # sadd 插入对应的队列 r = redisClient() r.sadd('pb:begin_print_machine_'+machineId, batchId) @@ -62,6 +62,6 @@ def main(work_dir=None): batchId = data.split('_')[0] #批次ID # machineType = data.split('_')[1] #机型类型 machineId = data.split('_')[2].replace('No', '') #机器ID - BeginSliceing(batchId,machineId,folderPath) + BeginSliceing(batchId,machineId,folderPath,data) time.sleep(10) diff --git a/factory_sliceing/auto_sliceing_operate/utils/click_soft_button.py b/factory_sliceing/auto_sliceing_operate/utils/click_soft_button.py index 0402304..503167b 100644 --- a/factory_sliceing/auto_sliceing_operate/utils/click_soft_button.py +++ b/factory_sliceing/auto_sliceing_operate/utils/click_soft_button.py @@ -1,7 +1,7 @@ import uiautomation as auto +from utils.config import cfg - -softName = "赛纳3D打印控制系统 V1.4.3.2" +softName = cfg('exe.soft_name', None) # 遍历所有控件 找到 def findAndClick(control, depth=0,index=1): @@ -71,12 +71,18 @@ def findAndClick(control, depth=0,index=1): # 点击导入文件按钮 def clickFileIMportShow(): + if softName is None: + print(f"错误:软件名称未配置") + exit(1) control = auto.WindowControl(searchDepth=1, Name=softName) clickRes = findAndClick(control,index=1) return clickRes # 点击开始切片按钮 def clickBegingSlice(): + if softName is None: + print(f"错误:软件名称未配置") + exit(1) control = auto.WindowControl(searchDepth=1, Name=softName) clickRes = findAndClick(control,index=2) return clickRes diff --git a/factory_sliceing/auto_sliceing_operate/utils/exe_operate.py b/factory_sliceing/auto_sliceing_operate/utils/exe_operate.py index 5dcb44a..45c176d 100644 --- a/factory_sliceing/auto_sliceing_operate/utils/exe_operate.py +++ b/factory_sliceing/auto_sliceing_operate/utils/exe_operate.py @@ -3,9 +3,21 @@ import os import subprocess import time import uiautomation as auto -exe_path = r"C:\Users\Administrator\Desktop\排版软件\NormalTek.ThreeDPrinter.UI.exe" +from utils.config import cfg +# exe_path = cfg('exe.small_exe', None) +# if exe_path is None: +# print(f"错误:exe_path 未配置") +# exit(1) -def start_exe(): +def start_exe(data): + exe_path = None + if "small" in data: + exe_path = cfg('exe.small_exe', None) + elif "big" in data: + exe_path = cfg('exe.big_exe', None) + else: + print(f"错误:机型类型未配置") + exit(1) try: # 检查文件是否存在 if not os.path.exists(exe_path): diff --git a/factory_sliceing/build_exe.py b/factory_sliceing/build_exe.py index 8273f12..e632c65 100644 --- a/factory_sliceing/build_exe.py +++ b/factory_sliceing/build_exe.py @@ -134,9 +134,36 @@ def build_exe(): print(f"生成的 exe 文件: {exe_path}") print(f"文件大小: {file_size:.2f} MB") print() + + # 复制配置文件到 dist 目录(如果存在) + config_file = os.path.join(current_dir, 'config.toml') + dist_config = os.path.join(current_dir, 'dist', 'config.toml') + if os.path.exists(config_file): + try: + shutil.copy2(config_file, dist_config) + print(f"配置文件已复制到: {dist_config}") + except Exception as e: + print(f"警告: 复制配置文件失败: {e}") + print(f"请手动将 config.toml 复制到 exe 同级目录: {os.path.dirname(exe_path)}") + else: + # 如果 config.toml 不存在,尝试复制示例文件 + example_config = os.path.join(current_dir, 'config.example.toml') + if os.path.exists(example_config): + try: + shutil.copy2(example_config, dist_config) + print(f"配置文件示例已复制到: {dist_config}") + print("请根据实际情况修改配置文件") + except Exception as e: + print(f"警告: 复制配置文件示例失败: {e}") + else: + print("提示: 请将 config.toml 放在 exe 同级目录") + + print() print("使用方法:") - print(" factory_sliceing.exe ") - print(" 可用命令: batch_dwonload | begin_sliceing | download_zip") + print(" factory_sliceing.exe [work_dir]") + print(" 可用命令: batch_download | begin_sliceing | download_zip") + print() + print("注意: 配置文件 config.toml 需要放在 exe 同级目录") return True else: print("打包失败!") diff --git a/factory_sliceing/config.example.toml b/factory_sliceing/config.example.toml new file mode 100644 index 0000000..8c7d45a --- /dev/null +++ b/factory_sliceing/config.example.toml @@ -0,0 +1,40 @@ +# Factory Sliceing 配置文件示例 +# 复制此文件为 config.toml 并根据实际情况修改配置 + +# Redis 配置 +[redis] +host = "your-redis-host" +password = "your-redis-password" +port = 6379 +db = 6 +socket_timeout = 30 +socket_connect_timeout = 10 +socket_keepalive = true +health_check_interval = 30 + +# Redis 重试配置 +[redis.retry] +retry_interval = 5 +max_retry_interval = 60 + +# OSS 配置 +[oss] +access_key_id = "your-access-key-id" +access_key_secret = "your-access-key-secret" +endpoint = "oss-cn-shanghai.aliyuncs.com" +bucket = "your-bucket-name" + +# API 配置 +[api] +base_url = "https://mp.api.suwa3d.com" +env = "prod" # prod 或 dev +# dev_url = "http://mp.api.dev.com" # 开发环境 URL(可选) + +# 工作目录配置 +[work] +default_dir = "" # 默认工作目录,为空则使用脚本所在目录 + +# 日志配置 +[log] +level = "INFO" # DEBUG, INFO, WARNING, ERROR + diff --git a/factory_sliceing/config.toml b/factory_sliceing/config.toml new file mode 100644 index 0000000..35fcd30 --- /dev/null +++ b/factory_sliceing/config.toml @@ -0,0 +1,44 @@ +# Factory Sliceing 配置文件 + +# Redis 配置 +[redis] +host = "mp.api.suwa3d.com" +password = "kcV2000" +port = 6379 +db = 6 +socket_timeout = 30 +socket_connect_timeout = 10 +socket_keepalive = true +health_check_interval = 30 + +# Redis 重试配置 +[redis.retry] +retry_interval = 5 +max_retry_interval = 60 + +# OSS 配置 +[oss] +access_key_id = "LTAI5tSReWm8hz7dSYxxth8f" +access_key_secret = "8ywTDF9upPAtvgXtLKALY2iMYHIxdS" +endpoint = "oss-cn-shanghai.aliyuncs.com" +bucket = "suwa3d-securedata" + +# API 配置 +[api] +base_url = "https://mp.api.suwa3d.com" +env = "prod" # prod 或 dev + +# 工作目录配置 +[work] +default_dir = "C://work" # 默认工作目录,为空则使用脚本所在目录 + +# 日志配置 +[log] +level = "INFO" # DEBUG, INFO, WARNING, ERROR + +#切片软件的执行路径 +[exe] +soft_name = "" +small_exe = "" +big_exe = "C:\Users\Administrator\print_factory_type_setting\software\小机型 切片软件\切片软件V1.4.3.6_2\切片软件V1.4.3.6_2\NormalTek.ThreeDPrinter.UI.exe" + diff --git a/factory_sliceing/download_batch_data/main_download_batch_data_and_trans.py b/factory_sliceing/download_batch_data/main_download_batch_data_and_trans.py index 4cfc0c9..fc516cb 100644 --- a/factory_sliceing/download_batch_data/main_download_batch_data_and_trans.py +++ b/factory_sliceing/download_batch_data/main_download_batch_data_and_trans.py @@ -47,9 +47,9 @@ def step1(versionId): return False #塞入切片的队列 ,SADD 插入 , {batchId}_{machineType}_No{machineId} machineType = "" - if machineInfo["machine_type"] == '1': + if str(machineInfo["machine_type"]) == '1': machineType = 'small' - elif machineInfo["machine_type"] == '2': + elif str(machineInfo["machine_type"]) == '2': machineType = 'big' keyValue = f'{versionId}_{machineType}_No{machineInfo["id"]}' r = redisClient() diff --git a/factory_sliceing/main.py b/factory_sliceing/main.py index dd224e0..effe4a0 100644 --- a/factory_sliceing/main.py +++ b/factory_sliceing/main.py @@ -1,20 +1,24 @@ -import os,sys +import sys +import os from auto_sliceing_operate import main_begin_sliceing from download_batch_data import main_download_batch_data_and_trans from auto_sliceing_operate import main_download_zip +from utils.config import cfg, get_work_dir + if __name__ == '__main__': # 根据参数决定执行哪个模块 # 命令映射表:命令名 -> 处理函数 command_handlers = { - 'batch_dwonload': main_download_batch_data_and_trans.main, + 'batch_download': main_download_batch_data_and_trans.main, 'begin_sliceing': main_begin_sliceing.main, 'download_zip': main_download_zip.main, } # 检查参数数量 if len(sys.argv) < 2: - print('Usage: python main.py ') + print('Usage: python main.py [work_dir]') print('可用命令:', ' | '.join(command_handlers.keys())) + print('\n注意: work_dir 参数可选,如果未提供将从配置文件读取默认值') sys.exit(1) command = sys.argv[1] @@ -25,12 +29,14 @@ if __name__ == '__main__': print('可用命令:', ' | '.join(command_handlers.keys())) sys.exit(1) - # 检查是否提供了 work_dir 参数 - if len(sys.argv) < 3: - print(f'Usage: python main.py {command} ') - sys.exit(1) - + # 获取工作目录:优先使用命令行参数,其次使用配置文件,最后使用当前目录 work_dir = sys.argv[2] + # 打印配置信息(可选,用于调试) + if cfg('log.level', 'INFO') == 'DEBUG': + print(f'配置信息:') + print(f' - API URL: {cfg("api.base_url", "未配置")}') + print(f' - Redis Host: {cfg("redis.host", "未配置")}') + print(f' - 工作目录: {work_dir}') # 执行对应的处理函数 command_handlers[command](work_dir=work_dir) \ No newline at end of file diff --git a/factory_sliceing/utils/__init__.py b/factory_sliceing/utils/__init__.py new file mode 100644 index 0000000..c556522 --- /dev/null +++ b/factory_sliceing/utils/__init__.py @@ -0,0 +1,2 @@ +# utils 模块 + diff --git a/factory_sliceing/utils/config.py b/factory_sliceing/utils/config.py new file mode 100644 index 0000000..606364d --- /dev/null +++ b/factory_sliceing/utils/config.py @@ -0,0 +1,155 @@ +""" +配置文件读取工具 +支持从 config.toml 文件中读取配置信息 +""" +import toml +import os +import sys + + +def get_config_path(): + """ + 获取配置文件路径 + + 查找顺序: + 1. 如果是打包后的 exe,优先查找 exe 同级目录的 config.toml + 2. 开发环境:查找 factory_sliceing 目录下的 config.toml + 3. 当前目录下的 config.toml + """ + # 判断是否在 PyInstaller 打包后的环境中 + if getattr(sys, 'frozen', False): + # 打包后的 exe 环境 + # sys.executable 是 exe 文件的完整路径 + exe_dir = os.path.dirname(os.path.abspath(sys.executable)) + config_path = os.path.join(exe_dir, 'config.toml') + + # 如果 exe 同级目录存在配置文件,直接返回 + if os.path.exists(config_path): + return config_path + + # 如果不存在,也返回这个路径(让调用者知道应该在哪里创建配置文件) + return config_path + + # 开发环境:查找 factory_sliceing 目录下的 config.toml + current_dir = os.path.dirname(os.path.abspath(__file__)) + # 向上查找 factory_sliceing 目录 + factory_sliceing_dir = os.path.dirname(current_dir) + config_path = os.path.join(factory_sliceing_dir, 'config.toml') + + # 如果文件存在,返回 + if os.path.exists(config_path): + return config_path + + # 如果不存在,尝试当前目录 + config_path = os.path.join(current_dir, 'config.toml') + if os.path.exists(config_path): + return config_path + + # 都不存在,返回 factory_sliceing 目录下的路径(作为默认路径) + return os.path.join(factory_sliceing_dir, 'config.toml') + + +def cfg(key_name, default=None): + """ + 读取配置文件中的值 + + :param key_name: 配置项的键名,支持点号分隔的嵌套键,如 "redis.host" 或 "redis.retry.interval" + :param default: 如果配置项不存在,返回的默认值 + :return: 配置项的值,如果不存在且未提供默认值则返回 None + """ + try: + config_path = get_config_path() + + if not os.path.exists(config_path): + print(f"警告: 配置文件不存在,路径: {config_path}") + return default + + with open(config_path, 'r', encoding='utf-8') as f: + config = toml.load(f) + + # 处理嵌套键名,如 "redis.host" + if "." in key_name: + keys = key_name.split(".") + value = config + for key in keys: + if isinstance(value, dict) and key in value: + value = value[key] + else: + if default is not None: + return default + print(f"配置项 {key_name} 不存在") + return None + return value + else: + # 单层键名 + if key_name in config: + return config[key_name] + else: + if default is not None: + return default + print(f"配置项 {key_name} 不存在") + return None + except FileNotFoundError: + print(f"配置文件不存在,路径: {config_path}") + return default + except Exception as e: + print(f"读取配置文件时发生错误: {e}") + return default + + +def get_redis_config(): + """ + 获取 Redis 配置字典 + :return: Redis 配置字典 + """ + return { + 'host': cfg('redis.host', 'localhost'), + 'password': cfg('redis.password', ''), + 'port': cfg('redis.port', 6379), + 'db': cfg('redis.db', 0), + 'socket_timeout': cfg('redis.socket_timeout', 30), + 'socket_connect_timeout': cfg('redis.socket_connect_timeout', 10), + 'socket_keepalive': cfg('redis.socket_keepalive', True), + 'health_check_interval': cfg('redis.health_check_interval', 30) + } + + +def get_oss_config(): + """ + 获取 OSS 配置字典 + :return: OSS 配置字典 + """ + return { + 'access_key_id': cfg('oss.access_key_id'), + 'access_key_secret': cfg('oss.access_key_secret'), + 'endpoint': cfg('oss.endpoint'), + 'bucket': cfg('oss.bucket') + } + + +def get_api_url(): + """ + 获取 API 基础 URL + :return: API URL 字符串 + """ + env = cfg('api.env', 'prod') + base_url = cfg('api.base_url', 'https://mp.api.suwa3d.com') + + # 如果环境是 dev,可以覆盖 URL + if env == 'dev': + dev_url = cfg('api.dev_url', 'http://mp.api.dev.com') + return dev_url + + return base_url + + +def get_work_dir(): + """ + 获取默认工作目录 + :return: 工作目录路径,如果未配置则返回 None + """ + return cfg('work.default_dir', None) + + +def get_exe_path(typeExe): + return cfg('exe.'+typeExe+'_exe', None) \ No newline at end of file