275 lines
12 KiB
Python
275 lines
12 KiB
Python
import os
|
||
import time
|
||
import json
|
||
|
||
import shutil
|
||
import base64
|
||
from PyQt6.QtGui import QCloseEvent
|
||
import win32gui
|
||
import win32con
|
||
import win32api
|
||
from PyQt6 import *
|
||
from PyQt6.QtCore import *
|
||
from PyQt6.QtGui import *
|
||
from PyQt6.QtWidgets import *
|
||
from ui.Ui_dataSyncForm import Ui_dataSyncForm
|
||
from common import common
|
||
from taskModel.taskManager import taskManager
|
||
from dmGroupModel.dmGroupManager import dmGroupManager
|
||
from deviceModel.deviceManager import deviceManager
|
||
from devGroupModel.devGroupManager import devGroupManager
|
||
from devmodelModel.devModelManager import devModelManager
|
||
from taskGroupModel.taskGroupManager import taskGroupManager
|
||
from instructionModel.instructionManager import instructionManager
|
||
from taskInstructionModel.taskInstructionManager import taskInstructionManager
|
||
from config import config
|
||
from models import Session
|
||
from logs import log
|
||
class DataSyncForm(QWidget):
|
||
|
||
def __init__(self, parent=None):
|
||
super().__init__(parent)
|
||
self.ui = Ui_dataSyncForm()
|
||
self.ui.setupUi(self)
|
||
# 创建一个文本编辑器来显示 Git 命令的输出
|
||
self.outputTextEdit = QTextEdit()
|
||
self.outputTextEdit.setReadOnly(True)
|
||
self.gitProcess = QProcess(self)
|
||
self.hwnd = None
|
||
self.topWidget = None
|
||
self.fileSystemModel1 = QFileSystemModel()
|
||
self.fileSystemModel2 = QFileSystemModel()
|
||
self.git_path = config.data["project"]["git_path"]
|
||
self.platform_path1 = config.data["project"]["platform_path1"]
|
||
self.platform_path2 = config.data["project"]["platform_path2"]
|
||
self.fileSystemModel1.setRootPath(self.platform_path1)
|
||
self.ui.treeView1.setModel(self.fileSystemModel1)
|
||
self.fileSystemModel2.setRootPath(self.platform_path2)
|
||
self.ui.treeView2.setModel(self.fileSystemModel2)
|
||
self.ui.treeView1.setRootIndex(self.fileSystemModel1.index(self.platform_path1))
|
||
self.ui.treeView2.setModel(self.fileSystemModel2)
|
||
self.ui.treeView2.setRootIndex(self.fileSystemModel2.index(self.platform_path2))
|
||
self.ui.pbGitManager1.clicked.connect(self.startGitGui1)
|
||
self.ui.pbGitManager2.clicked.connect(self.startGitGui2)
|
||
self.ui.pbImport.clicked.connect(self.importData)
|
||
self.ui.pbGitSync.clicked.connect(self.gitSync)
|
||
self.ui.pbDataSync.clicked.connect(self.dataSync)
|
||
self.ui.treeView1.resizeEvent = self.onResize
|
||
self.ui.treeView2.resizeEvent = self.onResize
|
||
self.destroyed.connect(self.cleanup)
|
||
def startGitGui1(self):
|
||
# 假设 git.exe 位于系统路径中
|
||
self.gitProcess.setWorkingDirectory(self.platform_path1)
|
||
self.gitProcess.start(self.git_path, ["gui"])
|
||
# if self.gitProcess.waitForStarted():
|
||
# time.sleep(2)
|
||
# self.find_windows_with_title_prefix("Git Gui")
|
||
def startGitGui2(self):
|
||
# 假设 git.exe 位于系统路径中
|
||
self.gitProcess.setWorkingDirectory(self.platform_path2)
|
||
self.gitProcess.start(self.git_path, ["gui"])
|
||
|
||
def merge_directories(self, src_dir, dst_dir):
|
||
"""
|
||
将src_dir中的文件复制到dst_dir中,如果文件重名则覆盖,保留dst_dir中独有的文件。
|
||
|
||
:param src_dir: 源目录路径
|
||
:param dst_dir: 目标目录路径
|
||
"""
|
||
# 确保目标目录存在
|
||
if not os.path.exists(dst_dir):
|
||
os.makedirs(dst_dir)
|
||
|
||
# 遍历源目录中的所有文件(包括子目录中的文件)
|
||
for root, dirs, files in os.walk(src_dir):
|
||
for file in files:
|
||
src_path = os.path.join(root, file)
|
||
rel_path = os.path.relpath(src_path, src_dir) # 获取相对于源目录的路径
|
||
dst_path = os.path.join(dst_dir, rel_path)
|
||
|
||
# 确保目标路径的目录存在
|
||
dst_dir_path = os.path.dirname(dst_path)
|
||
if not os.path.exists(dst_dir_path):
|
||
os.makedirs(dst_dir_path)
|
||
shutil.copy2(src_path, dst_path) # 使用shutil.copy2来保留文件的元数据
|
||
|
||
def importData(self):
|
||
#打开文件选择对话框,选择zip文件
|
||
filePath, _ = QFileDialog.getOpenFileName(self, "选择文件", "", "Zip Files (*.zip)")
|
||
if filePath:
|
||
exportPath = os.path.join(os.path.dirname(__file__),"export")
|
||
#清空exportPath目录
|
||
common.clearDir(exportPath)
|
||
#创建exportPath目录
|
||
common.createDir(exportPath)
|
||
shutil.unpack_archive(filePath, exportPath, "zip")
|
||
#遍历exportPath目录子目录名
|
||
for root, dirs, files in os.walk(exportPath):
|
||
for dir in dirs:
|
||
if dir == "dev_model" or dir == "instruction":
|
||
#将dev_model目录下的文件强制复制到self.platform_path1目录下
|
||
self.merge_directories(os.path.join(root, dir), os.path.join(self.platform_path1, dir))
|
||
else:
|
||
#将device目录下的文件复制到self.platform_path2目录下
|
||
self.merge_directories(os.path.join(root, dir), os.path.join(self.platform_path2, dir))
|
||
def gitSync(self):
|
||
if self.topWidget == None:
|
||
self.topWidget = self.findTopLevelParent(self)
|
||
if self.topWidget != None: #必须这样写,不能写else
|
||
if self.topWidget.askDialog("同步数据","是否同步?"):
|
||
# 删除self.platform_path目录下的所有文件 除了 .git 目录和.git目录下的所有文件
|
||
for root, dirs, files in os.walk(self.platform_path1):
|
||
if ".git" not in root:
|
||
for name in files:
|
||
os.remove(os.path.join(root, name))
|
||
for root, dirs, files in os.walk(self.platform_path2):
|
||
if ".git" not in root:
|
||
for name in files:
|
||
os.remove(os.path.join(root, name))
|
||
# 删除所有表
|
||
self.ui.lbState.setText("正在同步数据...")
|
||
self.ui.pbImport.setEnabled(False)
|
||
self.ui.pbGitSync.setEnabled(False)
|
||
self.ui.pbDataSync.setEnabled(False)
|
||
self.writeJson("dev_model")
|
||
self.writeJson("instruction")
|
||
self.writeJson("device")
|
||
self.writeJson("device_group")
|
||
self.writeJson("task_group")
|
||
self.writeJson("task")
|
||
self.writeJson("task_instruction")
|
||
self.writeJson("device_model_group")
|
||
self.ui.lbState.setText("数据同步完成")
|
||
self.ui.pbImport.setEnabled(True)
|
||
self.ui.pbGitSync.setEnabled(True)
|
||
self.ui.pbDataSync.setEnabled(True)
|
||
|
||
def writeJson(self, table_name):
|
||
manager = None
|
||
if table_name == "dev_model":
|
||
manager = devModelManager
|
||
elif table_name == "instruction":
|
||
manager = instructionManager
|
||
elif table_name == "device":
|
||
manager = deviceManager
|
||
elif table_name == "device_group":
|
||
manager = devGroupManager
|
||
elif table_name == "task_group":
|
||
manager = taskGroupManager
|
||
elif table_name == "task":
|
||
manager = taskManager
|
||
elif table_name == "task_instruction":
|
||
manager = taskInstructionManager
|
||
elif table_name == "device_model_group":
|
||
manager = dmGroupManager
|
||
if manager:
|
||
infos = manager.getInfo('all')
|
||
for info in infos:
|
||
QCoreApplication.processEvents()
|
||
Session.writeJson(table_name, common.ensure_serializable(info))
|
||
def onResize(self, event):
|
||
self.setAllColumnWidth()
|
||
|
||
def dataSync(self):
|
||
if self.topWidget == None:
|
||
self.topWidget = self.findTopLevelParent(self)
|
||
if self.topWidget != None: #必须这样写,不能写else
|
||
if self.topWidget.askDialog("同步数据","是否同步?"):
|
||
self.ui.lbState.setText("正在同步数据...")
|
||
self.ui.pbImport.setEnabled(False)
|
||
self.ui.pbGitSync.setEnabled(False)
|
||
self.ui.pbDataSync.setEnabled(False)
|
||
Session.deleteAllTable()
|
||
self.dataSync1()
|
||
self.dataSync2()
|
||
self.ui.lbState.setText("数据同步完成")
|
||
self.ui.pbImport.setEnabled(True)
|
||
self.ui.pbGitSync.setEnabled(True)
|
||
self.ui.pbDataSync.setEnabled(True)
|
||
# 批量设置列宽
|
||
def setAllColumnWidth(self):
|
||
try:
|
||
if self.fileSystemModel1.rowCount() > 0:
|
||
# 对水平表头的所有行设置为自动调整大小以适应内容
|
||
self.ui.treeView1.header().setSectionResizeMode(0,QHeaderView.ResizeMode.Stretch)
|
||
if self.fileSystemModel2.rowCount() > 0:
|
||
self.ui.treeView2.header().setSectionResizeMode(0,QHeaderView.ResizeMode.Stretch)
|
||
except Exception as e:
|
||
print(e)
|
||
|
||
def dataSync1(self):
|
||
|
||
#遍历目录,查找所有json文件,并读取内容
|
||
for root, dirs, files in os.walk(self.platform_path1):
|
||
#表名为二级目录名
|
||
table_name = os.path.basename(root)
|
||
manager = None
|
||
if table_name == "dev_model":
|
||
manager = devModelManager
|
||
elif table_name == "instruction":
|
||
manager = instructionManager
|
||
elif table_name == "device_model_group":
|
||
manager = dmGroupManager
|
||
if manager:
|
||
for file in files:
|
||
QCoreApplication.processEvents()
|
||
try:
|
||
if file.endswith(".json"):
|
||
file_path = os.path.join(root, file)
|
||
with open(file_path, "r", encoding="utf-8") as f:
|
||
data = json.load(f)
|
||
manager.create_from_git_json(data)
|
||
except Exception as e:
|
||
log.error("dataSync1", e)
|
||
|
||
def dataSync2(self):
|
||
#遍历目录,查找所有json文件,并读取内容
|
||
for root, dirs, files in os.walk(self.platform_path2):
|
||
#表名为二级目录名
|
||
table_name = os.path.basename(root)
|
||
manager = None
|
||
if table_name == "task":
|
||
manager = taskManager
|
||
elif table_name == "device":
|
||
manager = deviceManager
|
||
elif table_name == "device_group":
|
||
manager = devGroupManager
|
||
elif table_name == "task_group":
|
||
manager = taskGroupManager
|
||
elif table_name == "task_instruction":
|
||
manager = taskInstructionManager
|
||
if manager:
|
||
for file in files:
|
||
QCoreApplication.processEvents()
|
||
try:
|
||
if file.endswith(".json"):
|
||
file_path = os.path.join(root, file)
|
||
with open(file_path, "r", encoding="utf-8") as f:
|
||
data = json.load(f)
|
||
manager.create_from_git_json(data)
|
||
except Exception as e:
|
||
log.error("dataSync2", e)
|
||
|
||
def findTopLevelParent(self, widget):
|
||
parent = widget.parent()
|
||
while parent and not isinstance(parent, QMainWindow): # 假设顶层窗口是 QMainWindow
|
||
widget = parent
|
||
parent = widget.parent()
|
||
return parent
|
||
|
||
def cleanup(self):
|
||
self.gitProcess.terminate()
|
||
self.close_windows_with_title_prefix("Git Gui")
|
||
|
||
def close_windows_with_title_prefix(self, prefix):
|
||
def callback(hwnd, extra):
|
||
if win32gui.IsWindowVisible(hwnd) and win32gui.GetWindowText(hwnd).startswith(prefix):
|
||
# win32gui.SetParent(hwnd, self.ui.widget.winId())
|
||
# win32gui.CloseWindow(hwnd)#self.hwnd = hwnd
|
||
win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
|
||
# win32gui.MoveWindow(hwnd, 0, 0, self.ui.widget.width(), self.ui.widget.height(), True)
|
||
# #全屏显示并隐藏标题栏
|
||
# win32gui.SetWindowLong(hwnd, win32con.GWL_STYLE, win32con.WS_POPUP | win32con.WS_VISIBLE)
|
||
# print(f"Found window: {win32gui.GetWindowText(hwnd)} with handle: {hwnd}")
|
||
win32gui.EnumWindows(callback, None)
|