main.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. # -*- coding: utf-8 -*-
  2. # @Time : 2019/8/24 17:58
  3. # @Author : ricky
  4. # @File : main.py
  5. # @Software: vscode
  6. """主界面"""
  7. import sys
  8. import os
  9. import subprocess
  10. import threading
  11. import zipfile
  12. import datetime
  13. import wx
  14. import wx.adv
  15. import ui
  16. from . import main_frame as frame
  17. from loguru import logger
  18. from constant import constant
  19. from spider import upgradespider
  20. from utils import configini
  21. from utils import path
  22. from core import alterparam
  23. from core import ruoyi
  24. from core import ruoyicloud
  25. from core import ruoyifast
  26. from core import ruoyivue
  27. import platform
  28. class TaskThread(threading.Thread):
  29. def __init__(self, parent, select_file_path, alter_param: alterparam.AlterParam, rbm_index):
  30. """
  31. :param parent: 主线程UI
  32. """
  33. super(TaskThread, self).__init__()
  34. self.parent = parent
  35. self.select_file_path = select_file_path
  36. alter_param.context = self
  37. self.alter_param = alter_param
  38. self.rbm_index = rbm_index
  39. self.setDaemon(True)
  40. def show_operate_log(self, log):
  41. """
  42. 统一显示日志到控件
  43. 参数:
  44. self (object): 当前对象
  45. log (str): 日志内容
  46. """
  47. # 这里要在主线程更新UI,否则会报错
  48. wx.CallAfter(self.parent.receive_call_after, log + '\n')
  49. def run(self):
  50. wx.CallAfter(self.parent.task_start)
  51. self.show_operate_log('正在检测文件...')
  52. select_dir_path = os.path.dirname(self.select_file_path)
  53. # 目标目录
  54. target_dir = os.path.join(
  55. select_dir_path, datetime.datetime.now().strftime('%Y%m%d%H%M%S'))
  56. # 记录输出目录
  57. globals()['output_directory'] = target_dir
  58. # 解压到指定的文件夹
  59. with zipfile.ZipFile(self.select_file_path, 'r') as zip_file:
  60. zip_file.extractall(target_dir)
  61. self.show_operate_log('输出目录:' + target_dir)
  62. self.show_operate_log('解压完成,正在修改文件请稍后...')
  63. # 读取配置文件
  64. config_dict = configini.Config().get_dict()
  65. # 读取模板配置文件
  66. template_config_path = path.resource_path('template_config.ini')
  67. if not os.path.exists(template_config_path):
  68. template_config_path = path.resource_path(
  69. os.path.join('conf', 'template_config.ini'))
  70. template_dict = configini.Config(template_config_path).get_dict()
  71. # 实例化核心修改类
  72. self.alter_param.targetdir = target_dir
  73. if self.rbm_index == 0:
  74. ry = ruoyi.RuoYi(self.alter_param, config_dict, template_dict,
  75. self.show_operate_log)
  76. elif self.rbm_index == 1:
  77. ry = ruoyivue.RuoYiVue(
  78. self.alter_param, config_dict, template_dict, self.show_operate_log)
  79. elif self.rbm_index == 2:
  80. ry = ruoyifast.RuoYiFast(
  81. self.alter_param, config_dict, template_dict, self.show_operate_log)
  82. elif self.rbm_index == 3:
  83. ry = ruoyicloud.RuoYiCloud(
  84. self.alter_param, config_dict, template_dict, self.show_operate_log)
  85. try:
  86. # 开始修改
  87. ry.start()
  88. except Exception as error:
  89. self.show_operate_log('-------------------\n\r')
  90. self.show_operate_log('修改发生异常:\n{}'.format(error))
  91. self.show_operate_log('\r----------------------')
  92. logger.error('修改发生异常:{}', error)
  93. finally:
  94. self.parent.task_finally()
  95. logger.info('修改完成,输出目录:{}', target_dir)
  96. self.show_operate_log('输出目录:' + target_dir)
  97. self.show_operate_log('任务结束!')
  98. class Main(frame.MainFrame):
  99. def __init__(self, parent):
  100. frame.MainFrame.__init__(self, parent)
  101. app_name = wx.GetApp().GetAppName()
  102. if app_name != 'run' and platform.system().lower().startswith('win'):
  103. icon = wx.Icon(f'{app_name}.exe', wx.BITMAP_TYPE_ICO)
  104. self.SetIcon(icon)
  105. self.m_filePicker.GetPickerCtrl().SetLabel('选择文件')
  106. self.m_filePicker.GetTextCtrl().SetHint('请选择从官网下载下来的“.zip”后缀的压缩文件')
  107. self.m_text_ctrl_project_dir_name.SetHint('请输入目录名称')
  108. self.m_text_ctrl_project_name.SetHint('请输入项目名称')
  109. self.m_text_ctrl_package_name.SetHint('请输入包名')
  110. self.m_text_ctrl_artifact_id.SetHint('请输入artifactId')
  111. self.m_text_ctrl_group_id.SetHint('请输入groupId')
  112. self.m_text_ctrl_site_name.SetHint('请输入站点名称')
  113. self.m_statusbar.SetFieldsCount(4) # 状态栏分成4个区域
  114. # self.m_statusbar.SetStatusWidths([-5,-2]) #区域宽度比列,用负数
  115. self.m_statusbar.SetStatusText(' 软件版本:' + constant.APP_VERSION_STRING,
  116. 0)
  117. self.m_statusbar.SetStatusText(
  118. ' Python版本:' + constant.PYTHON_VERSION_STRING, 1)
  119. self.m_statusbar.SetStatusText(
  120. ' WxPython版本:' + constant.WXPYTHON_VERSION_STRING, 2)
  121. self.m_statusbar.SetStatusText(' 联系作者(RICKY):QQ11748854', 3)
  122. self.Centre()
  123. def task_start(self):
  124. """
  125. 任务开始
  126. """
  127. self.m_text_log.Clear()
  128. # 禁用按钮
  129. self.m_btn_start.Disable()
  130. self.m_btn_clear.Disable()
  131. self.m_btn_open_output_directory.Disable()
  132. def task_finally(self):
  133. """
  134. 任务结束
  135. """
  136. self.m_btn_open_output_directory.Enable()
  137. # 启用按钮
  138. self.m_btn_start.Enable()
  139. self.m_btn_clear.Enable()
  140. def show_message(self, message):
  141. """
  142. 统一显示对话框
  143. 参数:
  144. message (str): 对话框内容
  145. """
  146. wx.MessageDialog(self, message, '操作提醒', wx.OK).ShowModal()
  147. def receive_call_after(self, message):
  148. """
  149. 接收子线程传递消息,刷新UI线程
  150. 参数:
  151. self (object): 当前对象
  152. message (str): 日志内容
  153. """
  154. self.m_text_log.AppendText(message)
  155. self.m_text_log.ShowPosition(self.m_text_log.GetLastPosition())
  156. def upgrade_call_after(self, is_new_version, show_no_new_version_tip, title=None, message=None):
  157. """
  158. 接收更新程序线程传递消息,弹窗提示框
  159. 参数:
  160. self (object): 当前对象
  161. is_new_version (bool): 是否是新版本
  162. show_no_new_version_tip (bool): 是否显示提示
  163. title (str): 标题
  164. message (str): 消息
  165. """
  166. if is_new_version:
  167. logger.info('检查更新结果:发现新的版本-{}', title)
  168. dlg = wx.GenericMessageDialog(
  169. self, '新版本:%s\n\n更新日志:\n%s' %
  170. (title, message), '版本更新提醒', wx.OK | wx.CANCEL)
  171. dlg.SetOKCancelLabels('前往升级', '忽略更新')
  172. if dlg.ShowModal() == wx.ID_OK:
  173. wx.LaunchDefaultBrowser(
  174. 'https://gitee.com/lpf_project/RuoYi-MT/releases')
  175. dlg.Destroy()
  176. else:
  177. logger.info('检查更新结果:当前版本是最新版本!')
  178. if show_no_new_version_tip:
  179. wx.MessageDialog(self, '当前版本是最新版本!', '检测更新', wx.OK).ShowModal()
  180. def check_input(self):
  181. """
  182. 校验输入框
  183. 参数:
  184. self (object): 当前对象
  185. Return:
  186. 提示消息,校验通过返回''
  187. """
  188. message = ''
  189. # 验证输入框是否有值
  190. if len(self.m_text_ctrl_project_dir_name.GetValue()) == 0:
  191. message = '请填写目录名称'
  192. if len(self.m_text_ctrl_project_name.GetValue()) == 0:
  193. message = '请填写项目名'
  194. if len(self.m_text_ctrl_package_name.GetValue()) == 0:
  195. message = '请填写包名'
  196. if len(self.m_text_ctrl_artifact_id.GetValue()) == 0:
  197. message = '请填写artifactId'
  198. if len(self.m_text_ctrl_group_id.GetValue()) == 0:
  199. message = '请填写groupId'
  200. if len(self.m_text_ctrl_site_name.GetValue()) == 0:
  201. message = '请填写站点名称'
  202. return message
  203. # 实现开始执行按钮的事件
  204. def OnClickEventStart(self, event):
  205. select_file_path = self.m_filePicker.GetPath()
  206. if len(select_file_path) == 0:
  207. self.show_message('请选择文件')
  208. return
  209. if select_file_path.endswith('.zip') is False:
  210. self.show_message('请选择标准的.zip文件')
  211. return
  212. if os.path.exists(select_file_path) is False:
  213. self.show_message('请选择有效的.zip文件')
  214. return
  215. message = self.check_input()
  216. if len(message) != 0:
  217. self.show_message(message)
  218. return
  219. dlg = wx.MessageDialog(None, '确认开始执行吗?', '操作提醒', wx.YES_NO)
  220. if dlg.ShowModal() == wx.ID_YES:
  221. dlg.Destroy()
  222. # 构造参数
  223. params = alterparam.AlterParam()
  224. params.sitename = self.m_text_ctrl_site_name.GetValue()
  225. params.projectdirname = self.m_text_ctrl_project_dir_name.GetValue()
  226. params.packagename = self.m_text_ctrl_package_name.GetValue()
  227. params.projectname = self.m_text_ctrl_project_name.GetValue()
  228. params.artifactid = self.m_text_ctrl_artifact_id.GetValue()
  229. params.groupid = self.m_text_ctrl_group_id.GetValue()
  230. rbm_index = self.m_radio_box_mode.GetSelection()
  231. t = TaskThread(self, select_file_path, params, rbm_index)
  232. t.start()
  233. # 实现退出菜单事件
  234. def OnMenuClickEventExit(self, event):
  235. dlg = wx.MessageDialog(self, '确认退出程序吗?', '退出提醒', wx.YES_NO)
  236. dlg.SetYesNoLabels('退出', '取消')
  237. if dlg.ShowModal() == wx.ID_YES:
  238. self.Destroy()
  239. dlg.Destroy()
  240. def OnMenuClickEventConfig(self, event):
  241. dlg = ui.config.config.Config(self)
  242. dlg.ShowModal()
  243. dlg.Destroy()
  244. def OnMenuClickEventTemplateConfig(self, event):
  245. dlg = ui.config.templateConfig.TemplateConfig(self)
  246. dlg.ShowModal()
  247. dlg.Destroy()
  248. # 实现清空按钮的事件
  249. def OnClickEventClear(self, event):
  250. self.m_filePicker.SetPath('')
  251. self.m_text_ctrl_project_dir_name.SetValue('')
  252. self.m_text_ctrl_project_name.SetValue('')
  253. self.m_text_ctrl_package_name.SetValue('')
  254. self.m_text_ctrl_artifact_id.SetValue('')
  255. self.m_text_ctrl_group_id.SetValue('')
  256. self.m_text_ctrl_site_name.SetValue('')
  257. self.m_text_log.SetValue('')
  258. self.m_btn_open_output_directory.Disable()
  259. self.m_radio_box_mode.SetSelection(0)
  260. # 实现打开输出目录按钮的事件
  261. def OnClickEventOpenOutputDirectory(self, event):
  262. directory = globals()['output_directory']
  263. try:
  264. os.startfile(directory)
  265. except:
  266. subprocess.Popen(['open', directory])
  267. # 实现打赏作者事件
  268. def OnMenuClickEventReward(self, event):
  269. dlg = ui.reward.Reward(self)
  270. dlg.ShowModal()
  271. dlg.Destroy()
  272. # 实现druid秘钥生成事件
  273. def OnMenuClickEventDruidEncrypt(self, event):
  274. dlg = ui.druidencrypt.DruidEncrypt(self)
  275. dlg.ShowModal()
  276. dlg.Destroy()
  277. # 实现批量删除文件事件
  278. def OnMenuClickEventDeleteFile(self, event):
  279. dlg = ui.filedel.FileDel(self)
  280. dlg.ShowModal()
  281. dlg.Destroy()
  282. # 实现关于事件
  283. def OnAbout(self, event):
  284. dlg = ui.about.About(self)
  285. dlg.ShowModal()
  286. dlg.Destroy()
  287. # 实现检测更新事件
  288. def OnUpgrade(self, event):
  289. t = upgradespider.UpgradeThread(self, True)
  290. t.start()
  291. # 实现使用指南事件
  292. def OnManual(self, event):
  293. dlg = ui.manual.Manual(self)
  294. dlg.ShowModal()
  295. dlg.Destroy()
  296. # 实现打开程序目录事件
  297. def OnOpenAppDir(self, event):
  298. dir = path.resource_path('')
  299. try:
  300. os.startfile(dir)
  301. except:
  302. subprocess.Popen(['open', dir])