Ricky пре 4 година
родитељ
комит
bd6166feb8

+ 10 - 0
.gitignore

@@ -3,3 +3,13 @@
 !.vscode/tasks.json
 !.vscode/launch.json
 !.vscode/extensions.json
+*.pyc
+*.db
+venv
+/.idea
+*.log
+*.spec
+*.ini
+__pycache__
+dist
+build

+ 14 - 0
bin/package.bat

@@ -0,0 +1,14 @@
+@echo off
+echo.
+echo [信息] 打包Python项目,生成exe文件。
+echo.
+
+%~d0
+cd %~dp0
+call pyinstaller --add-data="../img;img" --add-data="../libs;libs" --version-file ../conf/file_version_info.txt -F -w -n 若依框架修改器V2-20210507 -i ../img/favicon.ico  ../run.py
+
+echo.
+echo [信息] 打包完成。
+echo.
+
+pause

+ 41 - 0
conf/file_version_info.txt

@@ -0,0 +1,41 @@
+# UTF-8
+#
+# For more details about fixed file info 'ffi' see:
+# http://msdn.microsoft.com/en-us/library/ms646997.aspx
+VSVersionInfo(
+  ffi=FixedFileInfo(
+    # filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4)
+    # Set not needed items to zero 0.
+    filevers=(4, 6, 1, 20210518),
+    prodvers=(4, 6, 1, 20210518),
+    # Contains a bitmask that specifies the valid bits 'flags'r
+    mask=0x3f,
+    # Contains a bitmask that specifies the Boolean attributes of the file.
+    flags=0x0,
+    # The operating system for which this file was designed.
+    # 0x4 - NT and there is no need to change it.
+    OS=0x40004,
+    # The general type of file.
+    # 0x1 - the file is an application.
+    fileType=0x1,
+    # The function of the file.
+    # 0x0 - the function is not defined for this fileType
+    subtype=0x0,
+    # Creation date and time stamp.
+    date=(0, 0)
+    ),
+  kids=[
+    StringFileInfo(
+      [
+      StringTable(
+        u'080404b0',
+        [StringStruct(u'CompanyName', u'个人'),
+        StringStruct(u'FileDescription', u'若依框架修改器'),
+        StringStruct(u'FileVersion', u'4.6.1.20210518'),
+        StringStruct(u'LegalCopyright', u'Copyright (C) 2020-2021 Ricky. All Rights Reserved'),
+        StringStruct(u'ProductName', u'常用工具'),
+        StringStruct(u'ProductVersion', u'4.6.1')])
+      ]), 
+    VarFileInfo([VarStruct(u'Translation', [2052, 1200])])
+  ]
+)

+ 1 - 0
constant/__init__.py

@@ -0,0 +1 @@
+'''常量模块'''

+ 12 - 0
constant/constant.py

@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/05/18
+# @Author : ricky
+# @File : constant.py
+# @Software: vscode
+"""
+系统常量
+"""
+APP_VERSION_INT = 220210406
+APP_VERSION_STRING = '4.6.0.20210406'
+PYTHON_VERSION_STRING = '3.7.9'
+WXPYTHON_VERSION_STRING = '4.1.0'

+ 78 - 0
constant/ruoyicloudconstant.py

@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/05/18
+# @Author : ricky
+# @File : ruoyicloudconstant.py
+# @Software: vscode
+"""
+若依微服务版本(RuoYi-Cloud)常量
+"""
+import sys
+
+
+class _const:
+    # 自定义异常处理
+    class ConstError(PermissionError):
+        pass
+
+    class ConstCaseError(ConstError):
+        pass
+
+    # 重写 __setattr__() 方法
+    def __setattr__(self, name, value):
+        if name in self.__dict__:
+            # 已包含该常量,不能二次赋值
+            raise self.ConstError("Can't change const {0}".format(name))
+        if not name.isupper():
+            # 所有的字母需要大写
+            raise self.ConstCaseError(
+                "const name {0} is not all uppercase".format(name))
+        self.__dict__[name] = value
+
+
+const = _const()
+# 默认的工程目录名称(顶层目录)
+const.RUOYI_DEFAULT_PROJECT_DIR_NAME = 'RuoYi-Cloud'
+# 默认的artifactId
+const.RUOYI_DEFAULT_ARTIFACTID_PREFIX = 'ruoyi'
+# 默认的groupId
+const.RUOYI_DEFAULT_GROUP_ID = 'com.ruoyi'
+# 默认的包名
+const.RUOYI_DEFAULT_PACKAGE_NAME = 'com.ruoyi'
+# 默认的站点名称
+const.RUOYI_DEFAULT_SITE_NAME = '若依微服务系统'
+# 默认的项目名称
+const.RUOYI_DEFAULT_PROJECT_NAME = 'ruoyi'
+# 默认的nacos配置sql前缀
+const.RUOYI_DEFAULT_NACOS_CONFIG_SQL_PREFIX = 'ry_config_'
+# 需要修改站点名称的资源路径
+const.RUOYI_SITE_RESOURCES_PATH_TUPLE = (
+    'ruoyi-ui#.env.development', 'ruoyi-ui#.env.production',
+    'ruoyi-ui#.env.staging', 'ruoyi-ui#package.json', 'ruoyi-ui#vue.config.js',
+    'ruoyi-ui#src#settings.js',
+    'ruoyi-ui#src#layout#components#Sidebar#Logo.vue',
+    'ruoyi-ui#src#views#login.vue')
+# 默认的模块名
+const.RUOYI_DEFAULT_MODULE_NAME_TUPLE = (
+    'ruoyi-api#ruoyi-api-system',
+    'ruoyi-common#ruoyi-common-core',
+    'ruoyi-common#ruoyi-common-datascope',
+    'ruoyi-common#ruoyi-common-datasource',
+    'ruoyi-common#ruoyi-common-log',
+    'ruoyi-common#ruoyi-common-redis',
+    'ruoyi-common#ruoyi-common-security',
+    'ruoyi-common#ruoyi-common-swagger',
+    'ruoyi-modules#ruoyi-file',
+    'ruoyi-modules#ruoyi-gen',
+    'ruoyi-modules#ruoyi-job',
+    'ruoyi-modules#ruoyi-system',
+    'ruoyi-visual#ruoyi-monitor',
+    'ruoyi-api',
+    'ruoyi-auth',
+    'ruoyi-common',
+    'ruoyi-gateway',
+    'ruoyi-modules',
+    'ruoyi-visual',
+    'ruoyi-ui',
+)
+# 将系统加载的模块列表中的 constant 替换为 _const() 实例
+sys.modules[__name__] = const

+ 59 - 0
constant/ruoyiconstant.py

@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/05/18
+# @Author : ricky
+# @File : ruoyiconstant.py
+# @Software: vscode
+"""
+若依标准版本(RuoYi)常量
+"""
+import sys
+
+
+class _const:
+    # 自定义异常处理
+    class ConstError(PermissionError):
+        pass
+
+    class ConstCaseError(ConstError):
+        pass
+
+    # 重写 __setattr__() 方法
+    def __setattr__(self, name, value):
+        if name in self.__dict__:
+            raise self.ConstError("Can't change const {0}".format(name))
+        if not name.isupper():
+            raise self.ConstCaseError(
+                "const name {0} is not all uppercase".format(name))
+        self.__dict__[name] = value
+
+
+const = _const()
+# 默认的工程目录名称(顶层目录)
+const.RUOYI_DEFAULT_PROJECT_DIR_NAME = 'RuoYi'
+# 默认的artifactId
+const.RUOYI_DEFAULT_ARTIFACTID_PREFIX = 'ruoyi'
+# 默认的groupId
+const.RUOYI_DEFAULT_GROUP_ID = 'com.ruoyi'
+# 默认的包名
+const.RUOYI_DEFAULT_PACKAGE_NAME = 'com.ruoyi'
+# 默认的站点名称
+const.RUOYI_DEFAULT_SITE_NAME = '若依管理系统'
+# 默认的项目名称
+const.RUOYI_DEFAULT_PROJECT_NAME = 'ruoyi'
+# 需要修改站点名称的资源路径
+const.RUOYI_SITE_RESOURCES_PATH_TUPLE = (
+    'ruoyi-admin#src#main#resources#templates#login.html',
+    'ruoyi-admin#src#main#resources#templates#index.html',
+    'ruoyi-admin#src#main#resources#templates#index-topnav.html',
+    'ruoyi-admin#src#main#resources#templates#main_v1.html',
+    'ruoyi-admin#src#main#resources#templates#register.html',
+    'ruoyi-admin#src#main#resources#templates#error#404.html',
+    'ruoyi-admin#src#main#resources#templates#error#500.html',
+    'ruoyi-admin#src#main#resources#templates#error#business.html',
+    'ruoyi-admin#src#main#resources#templates#error#unauth.html')
+# 默认的模块名
+const.RUOYI_DEFAULT_MODULE_NAME_TUPLE = ('ruoyi-admin', 'ruoyi-common',
+                                         'ruoyi-framework', 'ruoyi-generator',
+                                         'ruoyi-quartz', 'ruoyi-system')
+# 将系统加载的模块列表中的 constant 替换为 _const() 实例
+sys.modules[__name__] = const

+ 55 - 0
constant/ruoyifastconstant.py

@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/05/18
+# @Author : ricky
+# @File : ruoyifastconstant.py
+# @Software: vscode
+"""
+若依单体应用版本(RuoYi-fast)常量
+"""
+import sys
+
+
+class _const:
+    # 自定义异常处理
+    class ConstError(PermissionError):
+        pass
+
+    class ConstCaseError(ConstError):
+        pass
+
+    # 重写 __setattr__() 方法
+    def __setattr__(self, name, value):
+        if name in self.__dict__:
+            raise self.ConstError("Can't change const {0}".format(name))
+        if not name.isupper():
+            raise self.ConstCaseError(
+                "const name {0} is not all uppercase".format(name))
+        self.__dict__[name] = value
+
+
+const = _const()
+# 默认的工程目录名称(顶层目录)
+const.RUOYI_DEFAULT_PROJECT_DIR_NAME = 'RuoYi-fast'
+# 默认的artifactId
+const.RUOYI_DEFAULT_ARTIFACTID_PREFIX = 'ruoyi'
+# 默认的groupId
+const.RUOYI_DEFAULT_GROUP_ID = 'com.ruoyi'
+# 默认的包名
+const.RUOYI_DEFAULT_PACKAGE_NAME = 'com.ruoyi'
+# 默认的站点名称
+const.RUOYI_DEFAULT_SITE_NAME = '若依管理系统'
+# 默认的项目名称
+const.RUOYI_DEFAULT_PROJECT_NAME = 'ruoyi'
+# 需要修改站点名称的资源路径
+const.RUOYI_SITE_RESOURCES_PATH_TUPLE = (
+    'src#main#resources#templates#login.html',
+    'src#main#resources#templates#index.html',
+    'src#main#resources#templates#index-topnav.html',
+    'src#main#resources#templates#main_v1.html',
+    'src#main#resources#templates#register.html',
+    'src#main#resources#templates#error#404.html',
+    'src#main#resources#templates#error#500.html',
+    'src#main#resources#templates#error#business.html',
+    'src#main#resources#templates#error#unauth.html')
+# 将系统加载的模块列表中的 constant 替换为 _const() 实例
+sys.modules[__name__] = const

+ 56 - 0
constant/ruoyivueconstant.py

@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/05/18
+# @Author : ricky
+# @File : ruoyivueconstant.py
+# @Software: vscode
+"""
+若依前后端分离版本(RuoYi-Vue)常量
+"""
+import sys
+
+
+class _const:
+    # 自定义异常处理
+    class ConstError(PermissionError):
+        pass
+
+    class ConstCaseError(ConstError):
+        pass
+
+    # 重写 __setattr__() 方法
+    def __setattr__(self, name, value):
+        if name in self.__dict__:
+            raise self.ConstError("Can't change const {0}".format(name))
+        if not name.isupper():
+            raise self.ConstCaseError(
+                "const name {0} is not all uppercase".format(name))
+        self.__dict__[name] = value
+
+
+const = _const()
+# 默认的工程目录名称(顶层目录)
+const.RUOYI_DEFAULT_PROJECT_DIR_NAME = 'RuoYi-Vue'
+# 默认的artifactId
+const.RUOYI_DEFAULT_ARTIFACTID_PREFIX = 'ruoyi'
+# 默认的groupId
+const.RUOYI_DEFAULT_GROUP_ID = 'com.ruoyi'
+# 默认的包名
+const.RUOYI_DEFAULT_PACKAGE_NAME = 'com.ruoyi'
+# 默认的站点名称
+const.RUOYI_DEFAULT_SITE_NAME = '若依管理系统'
+# 默认的项目名称
+const.RUOYI_DEFAULT_PROJECT_NAME = 'ruoyi'
+# 需要修改站点名称的资源路径
+const.RUOYI_SITE_RESOURCES_PATH_TUPLE = (
+    'ruoyi-ui#.env.development', 'ruoyi-ui#.env.production',
+    'ruoyi-ui#.env.staging', 'ruoyi-ui#package.json', 'ruoyi-ui#vue.config.js',
+    'ruoyi-ui#src#settings.js',
+    'ruoyi-ui#src#layout#components#Sidebar#Logo.vue',
+    'ruoyi-ui#src#views#login.vue')
+# 默认的模块名
+const.RUOYI_DEFAULT_MODULE_NAME_TUPLE = ('ruoyi-admin', 'ruoyi-common',
+                                         'ruoyi-framework', 'ruoyi-generator',
+                                         'ruoyi-quartz', 'ruoyi-system',
+                                         'ruoyi-ui')
+# 将系统加载的模块列表中的 constant 替换为 _const() 实例
+sys.modules[__name__] = const

+ 84 - 0
core/base.py

@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/05/17/
+# @Author : ricky
+# @File : base.py
+# @Software: vscode
+"""
+关键字修改类基类
+"""
+import os
+from shutil import move
+from loguru import logger
+
+
+class BaseCore:
+    """
+    初始化参数:
+        context (object): 上下文对象
+        targetdir (str): 目标路径
+        sitename (str): 新站点名称,
+        projectdirname (str): 新目录名称
+        packagename (str): 新包名
+        projectname (str): 新项目名
+        artifactid (str): 新artifactId
+        groupid (str): 新groupId
+        configdict (dict): 配置字典
+        callback (function): 回调方法
+
+    """
+    def __init__(self, context, targetdir, sitename, projectdirname,
+                 packagename, projectname, artifactid, groupid, configdict,
+                 callback):
+
+        self.context = context
+        self.targetdir = targetdir
+        self.sitename = sitename
+        self.packagename = packagename
+        self.projectdirname = projectdirname
+        self.projectname = projectname
+        self.artifactid = artifactid
+        self.groupid = groupid
+        self.configdict = configdict
+        self.callback = callback
+        self.exceptions = []
+
+    def start(self):
+        """开始方法"""
+        pass
+
+    def messagehandle(self, message):
+        """
+        消息处理
+
+        参数:
+            message (str): 消息
+        """
+        if hasattr(self.callback, '__call__'):
+            self.callback(self.context, message)
+
+    def exceptionhandle(self, message):
+        """
+        异常处理
+
+        参数:
+            message (str): 消息
+        """
+        self.exceptions.append(str(len(self.exceptions) + 1) + "." + message)
+        logger.error(message)
+
+    def move_dir(self, old_dir, new_dir):
+        """
+        移动目录
+        
+        参数:
+            old_dir (str): 旧目录
+            new_dir (str): 新目录
+        """
+        for temp_path in os.listdir(old_dir):
+            filepath = new_dir + os.path.sep + temp_path
+            oldpath = old_dir + os.path.sep + temp_path
+            if os.path.isdir(oldpath):
+                os.mkdir(filepath)
+                self.move_dir(oldpath, filepath)
+            if os.path.isfile(oldpath):
+                move(oldpath, filepath)

+ 258 - 0
core/ruoyi.py

@@ -0,0 +1,258 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/05/18
+# @Author : ricky
+# @File : ruoyi.py
+# @Software: vscode
+"""
+核心修改类 RuoYi(标准版)
+"""
+import os
+from core import base
+from constant import ruoyiconstant as const
+
+
+class RuoYi(base.BaseCore):
+    def start(self):
+        # 拼接根路径
+        self.rootpath = os.path.join(self.targetdir,
+                                     const.RUOYI_DEFAULT_PROJECT_DIR_NAME)
+        # 1.修改站点名称
+        self.messagehandle('正在修改标题和修站点名称...')
+        self.__alter_site_name_and_title()
+        self.messagehandle('站点名称和标题修改完成!')
+        # 2.修改包名和项目名
+        self.messagehandle('正在修改包名和项目名...')
+        self.__alter_package_name_and_project_name(self.rootpath)
+        self.messagehandle('包名和项目名修改完成!')
+        # 3.修改pom.xml文件
+        self.messagehandle('正在修改pom.xml...')
+        self.__alter_pom_xml()
+        self.messagehandle('pom.xml修改完成!')
+        # 4.修改目录结构
+        self.messagehandle('正在修改目录结构...')
+        self.__alter_project_dir()
+        self.messagehandle('目录结构修改完成!')
+
+        if len(self.exceptions) > 0:
+            self.messagehandle('\r发现有异常信息')
+            self.messagehandle('-------------------\n\r')
+            for e in self.exceptions:
+                self.messagehandle(e)
+            self.messagehandle('\r----------------------')
+
+    def __alter_site_name_and_title(self):
+        """修改站点名称和网站标题"""
+        ntuple = const.RUOYI_SITE_RESOURCES_PATH_TUPLE
+        for item in ntuple:
+            filepath = os.path.join(self.rootpath,
+                                    item.replace('#', os.path.sep))
+            if os.path.exists(filepath):
+                try:
+                    with open(filepath, 'r',
+                              encoding='utf-8') as srcfile, open(
+                                  '%s.bak' % filepath, 'w',
+                                  encoding='utf-8') as desfile:
+                        for line in srcfile:
+                            if const.RUOYI_DEFAULT_SITE_NAME in line:
+                                line = line.replace(
+                                    const.RUOYI_DEFAULT_SITE_NAME,
+                                    self.sitename)
+                            if '若依后台管理系统' in line:
+                                line = line.replace('若依后台管理系统', self.sitename)
+                            if '若依 后台管理系统' in line:
+                                line = line.replace('若依 后台管理系统', self.sitename)
+                            if '登录若依系统' in line:
+                                line = line.replace('登录若依系统',
+                                                    '登录' + self.sitename)
+                            if '若依系统' in line:
+                                line = line.replace('若依系统', self.sitename)
+                            if '若依介绍' in line:
+                                line = line.replace('若依介绍',
+                                                    self.sitename + '介绍')
+                            if 'RuoYi -' in line:
+                                line = line.replace('RuoYi -', self.sitename)
+                            desfile.write(line)
+                    # 移除旧文件
+                    os.remove(filepath)
+                    # 重命名备份文件为新文件
+                    os.rename('%s.bak' % filepath, filepath)
+                except Exception as err:
+                    self.exceptionhandle(
+                        '修改站点名称和网站标题异常\n修改文件:{}\n异常信息:{}'.format(
+                            filepath, err))
+
+    def __alter_package_name_and_project_name(self, rootpath):
+        """
+        修改包名和项目名称
+
+        参数:
+            rootpath (str): 根路径
+        """
+        files = os.listdir(rootpath)
+        for filename in files:
+            filepath = os.path.join(rootpath, filename)
+            if os.path.isdir(filepath):
+                self.__alter_package_name_and_project_name(filepath)
+            else:
+                if filename.endswith('.java') or filename.endswith(
+                        '.yml'
+                ) or filename.endswith('Mapper.xml') or filename.endswith(
+                        'logback.xml') or filename.endswith(
+                            '.factories') or filename.endswith(
+                                '.vm') or filename.endswith(
+                                    '.bat') or filename.endswith('.sh'):
+                    try:
+                        with open(filepath, 'r',
+                                  encoding='utf-8') as srcfile, open(
+                                      '%s.bak' % filepath,
+                                      'w',
+                                      encoding='utf-8') as desfile:
+                            self.messagehandle('正在修改:' + filename)
+                            for line in srcfile:
+                                if const.RUOYI_DEFAULT_PACKAGE_NAME in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_PACKAGE_NAME,
+                                        self.packagename)
+                                if const.RUOYI_DEFAULT_PROJECT_NAME + '-' in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_PROJECT_NAME + '-',
+                                        self.projectname + '-')
+                                if self.configdict['config.enable'] == 'True':
+                                    if filename.endswith('.yml'):
+                                        line = self.__check_yml_config(
+                                            line, filename)
+                                desfile.write(line)
+                        # 移除旧文件
+                        os.remove(filepath)
+                        # 重命名备份文件为新文件
+                        os.rename('%s.bak' % filepath, filepath)
+                    except Exception as err:
+                        self.exceptionhandle(
+                            '修改包名和项目名称异常\n修改文件:{}\n异常信息:{}'.format(
+                                filepath, err))
+
+    def __check_yml_config(self, line, filename):
+        """
+        检测yml配置文件
+
+        参数:
+            line (str): 行
+            filename (str): 文件名
+        """
+        if 'localhost:3306/ry' in line and filename == 'application-druid.yml':
+            line = self.__alert_yml_config(line, 'mysql_ip_port_name')
+        if 'username: root' in line and filename == 'application-druid.yml':
+            line = self.__alert_yml_config(line, 'mysql_username')
+        if 'password: password' in line and filename == 'application-druid.yml':
+            line = self.__alert_yml_config(line, 'mysql_password')
+        return line
+
+    def __alert_yml_config(self, line, type_):
+        """
+        修改yml配置文件
+
+        参数:
+            line (str): 行
+            type_ (str): 修改类型
+        """
+        if type_ == 'mysql_ip_port_name':
+            mysql_ip = self.configdict['database.ip']
+            mysql_port = self.configdict['database.port']
+            mysql_name = self.configdict['database.name']
+            return line.replace('localhost:3306/ry',
+                                mysql_ip + ':' + mysql_port + '/' + mysql_name)
+        if type_ == 'mysql_username':
+            mysql_username = self.configdict['database.username']
+            return line.replace('username: root',
+                                'username: ' + mysql_username)
+        if type_ == 'mysql_password':
+            mysql_password = self.configdict['database.password']
+            return line.replace('password: password',
+                                'password: ' + mysql_password)
+        return line
+
+    def __alter_pom_xml(self):
+        """修改项目pom.xml文件"""
+        # 将最外层的文件夹添加到新的元组中
+        ttuple = (const.RUOYI_DEFAULT_PROJECT_DIR_NAME, )
+        ntuple = ttuple + const.RUOYI_DEFAULT_MODULE_NAME_TUPLE
+        for module_name in ntuple:
+            pom_xml_file = ''
+            # 如果元组内元素是项目名,文件路径需要特殊处理
+            if module_name == const.RUOYI_DEFAULT_PROJECT_DIR_NAME:
+                pom_xml_file = os.path.join(self.rootpath, 'pom.xml')
+            else:
+                pom_xml_file = os.path.join(self.rootpath, module_name,
+                                            'pom.xml')
+            if not os.path.exists(pom_xml_file):
+                continue
+            try:
+                with open(pom_xml_file, 'r',
+                          encoding='utf-8') as xml_file, open(
+                              '%s.bak' % pom_xml_file, 'w',
+                              encoding='utf-8') as target_file:
+                    self.messagehandle('正在修改:' + module_name + '/pom.xml')
+                    for line in xml_file:
+                        if const.RUOYI_DEFAULT_GROUP_ID in line and '<groupId>' in line:
+                            line = line.replace(const.RUOYI_DEFAULT_GROUP_ID,
+                                                self.groupid)
+                        if const.RUOYI_DEFAULT_ARTIFACTID_PREFIX in line and '<artifactId>' in line:
+                            line = line.replace(
+                                const.RUOYI_DEFAULT_ARTIFACTID_PREFIX,
+                                self.artifactid)
+                        if module_name == const.RUOYI_DEFAULT_PROJECT_DIR_NAME:
+                            if '<name>' in line or '<module>' in line:
+                                line = line.replace(
+                                    const.RUOYI_DEFAULT_PROJECT_NAME,
+                                    self.projectname)
+                            if 'version>' in line:
+                                line = line.replace(
+                                    const.RUOYI_DEFAULT_ARTIFACTID_PREFIX,
+                                    self.artifactid)
+                            if 'description>' in line:
+                                line = line.replace(
+                                    const.RUOYI_DEFAULT_SITE_NAME,
+                                    self.sitename)
+                        target_file.write(line)
+                # 移除旧文件
+                os.remove(pom_xml_file)
+                # 重命名备份文件为新文件
+                os.rename('%s.bak' % pom_xml_file, pom_xml_file)
+            except Exception as err:
+                self.exceptionhandle(
+                    '修改项目pom.xml文件异常\n修改文件:{}\n异常信息:{}'.format(
+                        pom_xml_file, err))
+
+    def __alter_project_dir(self):
+        """修改目录名"""
+        for module_name in const.RUOYI_DEFAULT_MODULE_NAME_TUPLE:
+            src_main_java_dir = os.path.join(self.rootpath, module_name,
+                                             'src/main/java')
+            # 如果没有找到源代码路径,结束本次循环
+            if not os.path.exists(src_main_java_dir):
+                continue
+            source_dir = os.path.join(
+                src_main_java_dir, self.packagename.replace('.', os.path.sep))
+            if not os.path.exists(source_dir):
+                os.makedirs(source_dir)
+            self.move_dir(os.path.join(src_main_java_dir, 'com/ruoyi'),
+                          source_dir)
+
+            # 拷贝完目录后会删除掉之前的文件,但是目录没有删除,再次删除目录
+            for root, dirs, files in os.walk(os.path.join(
+                    src_main_java_dir, 'com/ruoyi'),
+                                             topdown=False):
+                if not os.listdir(root):
+                    os.rmdir(root)
+            # 删除com目录
+            if not os.listdir(os.path.join(src_main_java_dir, 'com')):
+                os.rmdir(os.path.join(src_main_java_dir, 'com'))
+            os.rename(
+                os.path.join(self.rootpath, module_name),
+                os.path.join(
+                    self.rootpath,
+                    self.projectname + '-' + module_name.split('-')[1]))
+            self.messagehandle('正在修改:' + module_name)
+        os.rename(self.rootpath,
+                  os.path.join(self.targetdir, self.projectdirname))
+        self.messagehandle('正在修改:' + const.RUOYI_DEFAULT_PROJECT_DIR_NAME)

+ 380 - 0
core/ruoyicloud.py

@@ -0,0 +1,380 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/05/18
+# @Author : ricky
+# @File : ruoyicloud.py
+# @Software: vscode
+"""
+核心修改类 RuoYi-Cloud版本
+"""
+import os
+from core import base
+from constant import ruoyicloudconstant as const
+
+
+class RuoYiCloud(base.BaseCore):
+    def start(self):
+        # 拼接根路径
+        self.rootpath = os.path.join(self.targetdir,
+                                     const.RUOYI_DEFAULT_PROJECT_DIR_NAME)
+        # 1.修改站点名称
+        self.messagehandle('正在修改标题和修站点名称...')
+        self.__alter_site_name_and_title()
+        self.messagehandle('站点名称和标题修改完成!')
+        # 2.修改包名和项目名
+        self.messagehandle('正在修改包名和项目名...')
+        self.__alter_package_name_and_project_name(self.rootpath)
+        self.messagehandle('包名和项目名修改完成!')
+        # 3.修改项目配置和日志配置
+        self.messagehandle('正在修改项目配置和日志配置...')
+        self.__alter_bootstrapyml_and_logbackxml(self.rootpath)
+        self.messagehandle('项目配置和日志配置修改完成!')
+        # 4.修改Nacos配置
+        self.messagehandle('正在修改Nacos配置...')
+        self.__alter_nacos_config(os.path.join(self.rootpath, 'sql'))
+        self.messagehandle('Nacos配置修改完成!')
+        # 5.修改pom.xml文件
+        self.messagehandle('正在修改pom.xml...')
+        self.__alter_pom_xml(self.rootpath)
+        self.messagehandle('pom.xml修改完成!')
+        # 6.修改目录结构
+        self.messagehandle('正在修改目录结构...')
+        self.__alter_project_dir()
+        self.messagehandle('目录结构修改完成!')
+
+        if len(self.exceptions) > 0:
+            self.messagehandle('\r发现有异常信息')
+            self.messagehandle('-------------------\n\r')
+            for e in self.exceptions:
+                self.messagehandle(e)
+            self.messagehandle('\r----------------------')
+
+    def __alter_site_name_and_title(self):
+        """修改站点名称和网站标题"""
+        ntuple = const.RUOYI_SITE_RESOURCES_PATH_TUPLE
+        for item in ntuple:
+            filepath = os.path.join(self.rootpath,
+                                    item.replace('#', os.path.sep))
+            if not os.path.exists(filepath):
+                continue
+            try:
+                with open(filepath, 'r', encoding='utf-8') as srcfile, open(
+                        '%s.bak' % filepath, 'w', encoding='utf-8') as desfile:
+                    for line in srcfile:
+                        if const.RUOYI_DEFAULT_SITE_NAME in line:
+                            line = line.replace(const.RUOYI_DEFAULT_SITE_NAME,
+                                                self.sitename)
+                        if '若依后台管理系统' in line:
+                            line = line.replace('若依后台管理系统', self.sitename)
+                        if '若依 后台管理系统' in line:
+                            line = line.replace('若依 后台管理系统', self.sitename)
+                        if '登录若依系统' in line:
+                            line = line.replace('登录若依系统', '登录' + self.sitename)
+                        if '若依系统' in line:
+                            line = line.replace('若依系统', self.sitename)
+                        if '若依介绍' in line:
+                            line = line.replace('若依介绍', self.sitename + '介绍')
+                        if 'RuoYi -' in line:
+                            line = line.replace('RuoYi -', self.sitename)
+                        desfile.write(line)
+                # 移除旧文件
+                os.remove(filepath)
+                # 重命名备份文件为新文件
+                os.rename('%s.bak' % filepath, filepath)
+            except Exception as err:
+                self.exceptionhandle('修改站点名称和网站标题异常\n修改文件:{}\n异常信息:{}'.format(
+                    filepath, err))
+
+    def __alter_package_name_and_project_name(self, rootpath):
+        """修改包名和项目名称"""
+        files = os.listdir(rootpath)
+        for filename in files:
+            filepath = os.path.join(rootpath, filename)
+            if os.path.isdir(filepath):
+                self.__alter_package_name_and_project_name(filepath)
+            else:
+                if filename.endswith('.java') or filename.endswith(
+                        '.yml'
+                ) or filename.endswith('Mapper.xml') or filename.endswith(
+                        'logback.xml') or filename.endswith(
+                            '.factories') or filename.endswith(
+                                '.vm') or filename.endswith(
+                                    '.bat') or filename.endswith('.sh'):
+                    try:
+                        with open(filepath, 'r',
+                                  encoding='utf-8') as srcfile, open(
+                                      '%s.bak' % filepath,
+                                      'w',
+                                      encoding='utf-8') as desfile:
+                            self.messagehandle('正在修改:' + filename)
+                            for line in srcfile:
+                                if const.RUOYI_DEFAULT_PACKAGE_NAME in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_PACKAGE_NAME,
+                                        self.packagename)
+                                if const.RUOYI_DEFAULT_PROJECT_NAME + '-' in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_PROJECT_NAME + '-',
+                                        self.projectname + '-')
+                                if self.configdict['config.enable'] == 'True':
+                                    if filename.endswith('.yml'):
+                                        line = self.__check_yml_or_sql_config(
+                                            line, filename)
+                                desfile.write(line)
+                        # 移除旧文件
+                        os.remove(filepath)
+                        # 重命名备份文件为新文件
+                        os.rename('%s.bak' % filepath, filepath)
+                    except Exception as err:
+                        self.exceptionhandle(
+                            '修改包名和项目名称异常\n修改文件:{}\n异常信息:{}'.format(
+                                filepath, err))
+
+    def __alter_bootstrapyml_and_logbackxml(self, rootpath):
+        """
+        修改项目bootstrap.yml和logback.xml中的模块名
+
+        参数:
+            rootpath (str): 根路径
+        """
+        # 循环修改指定后缀名的文件内容
+        files = os.listdir(rootpath)
+        for filename in files:
+            filepath = os.path.join(rootpath, filename)
+            # 如果是目录继续递归
+            if os.path.isdir(filepath):
+                self.__alter_bootstrapyml_and_logbackxml(filepath)
+            else:
+                try:
+                    # 如果是文件才进行修改
+                    if filename.endswith('.yml') or filename.endswith(
+                            'logback.xml'):
+                        with open(filepath, 'r',
+                                  encoding='utf-8') as srcfile, open(
+                                      '%s.bak' % filepath,
+                                      'w',
+                                      encoding='utf-8') as desfile:
+                            self.messagehandle('正在修改:' + filename)
+                            for line in srcfile:
+                                if const.RUOYI_DEFAULT_PROJECT_NAME in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_PROJECT_NAME,
+                                        self.projectname)
+                                desfile.write(line)
+                        # 移除旧文件
+                        os.remove(filepath)
+                        # 重命名备份文件为新文件
+                        os.rename('%s.bak' % filepath, filepath)
+                except Exception as err:
+                    self.exceptionhandle(
+                        '修改项目bootstrap.yml和logback.xml中的模块名异常\n修改文件:{}\n异常信息:{}'
+                        .format(filepath, err))
+
+    def __alter_nacos_config(self, sqldir):
+        """
+        修改项目Nacos配置
+
+        参数:
+            sqldir (str): sql目录
+        """
+        files = os.listdir(sqldir)
+        for filename in files:
+            filepath = os.path.join(sqldir, filename)
+            # 如果是目录继续递归
+            if os.path.isdir(filepath):
+                self.__alter_nacos_config(filepath)
+            else:
+                try:
+                    # 如果是文件才进行修改
+                    if filename.startswith(
+                            const.RUOYI_DEFAULT_NACOS_CONFIG_SQL_PREFIX):
+                        with open(filepath, 'r',
+                                  encoding='utf-8') as srcfile, open(
+                                      '%s.bak' % filepath,
+                                      'w',
+                                      encoding='utf-8') as desfile:
+                            self.messagehandle('正在修改:' + filename)
+                            for line in srcfile:
+                                if const.RUOYI_DEFAULT_PACKAGE_NAME in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_PACKAGE_NAME,
+                                        self.packagename)
+                                if const.RUOYI_DEFAULT_PROJECT_NAME + '-' in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_PROJECT_NAME + '-',
+                                        self.projectname + '-')
+                                if self.configdict['config.enable'] == 'True':
+                                    line = self.__check_yml_or_sql_config(
+                                        line, filename)
+                                desfile.write(line)
+                        # 移除旧文件
+                        os.remove(filepath)
+                        # 重命名备份文件为新文件
+                        os.rename('%s.bak' % filepath, filepath)
+                except Exception as err:
+                    self.exceptionhandle(
+                        '修改项目Nacos配置异常\n修改文件:{}\n异常信息:{}'.format(
+                            filepath, err))
+
+    def __check_yml_or_sql_config(self, line, filename):
+        """
+        检测yml配置文件
+
+        参数:
+            line (str): 行
+            filename (str): 文件名
+        """
+        if 'localhost:3306/ry-cloud' in line and filename.endswith('.sql'):
+            line = self.__alert_yml_or_sql_config(line, 'mysql_ip_port_name')
+        if 'username: root' in line and filename.endswith('.sql'):
+            line = self.__alert_yml_or_sql_config(line, 'mysql_username')
+        if 'password: password' in line and filename.endswith('.sql'):
+            line = self.__alert_yml_or_sql_config(line, 'mysql_password')
+        if 'host: localhost' in line and filename.endswith('.sql'):
+            line = self.__alert_yml_or_sql_config(line, 'redis_host')
+        if 'port: 6379' in line and filename.endswith('.sql'):
+            line = self.__alert_yml_or_sql_config(line, 'redis_port')
+        if 'password: \\r\\n' in line and filename.endswith('.sql'):
+            line = self.__alert_yml_or_sql_config(line, 'redis_password')
+
+        return line
+
+    def __alert_yml_or_sql_config(self, line, type_):
+        """
+        修改yml配置文件
+
+        参数:
+            line (str): 行
+            type_ (str): 修改类型
+        """
+        if type_ == 'mysql_ip_port_name':
+            mysql_ip = self.configdict['database.ip']
+            mysql_port = self.configdict['database.port']
+            mysql_name = self.configdict['database.name']
+            return line.replace('localhost:3306/ry-cloud',
+                                mysql_ip + ':' + mysql_port + '/' + mysql_name)
+        if type_ == 'mysql_username':
+            mysql_username = self.configdict['database.username']
+            return line.replace('username: root',
+                                'username: ' + mysql_username)
+        if type_ == 'mysql_password':
+            mysql_password = self.configdict['database.password']
+            return line.replace('password: password',
+                                'password: ' + mysql_password)
+        if type_ == 'redis_host':
+            redis_ip = self.configdict['redis.ip']
+            return line.replace('host: localhost', 'host: ' + redis_ip)
+        if type_ == 'redis_port':
+            redis_port = self.configdict['redis.port']
+            return line.replace('port: 6379', 'port: ' + redis_port)
+        if type_ == 'redis_password':
+            redis_password = self.configdict['redis.password']
+            return line.replace('password: \\r\\n',
+                                'password: ' + redis_password + '\\r\\n')
+        return line
+
+    def __alter_pom_xml(self, rootpath):
+        """
+        修改项目pom.xml文件
+
+        参数:
+            rootpath (str): 根目录
+        """
+        files = os.listdir(rootpath)
+        for filename in files:
+            filepath = os.path.join(rootpath, filename)
+            # 如果是目录继续递归
+            if os.path.isdir(filepath):
+                self.__alter_pom_xml(filepath)
+            else:
+                try:
+                    # 如果是文件才进行修改
+                    if filename.endswith('pom.xml'):
+                        with open(filepath, 'r',
+                                  encoding='utf-8') as srcfile, open(
+                                      '%s.bak' % filepath,
+                                      'w',
+                                      encoding='utf-8') as desfile:
+                            self.messagehandle('正在修改:' + filename)
+                            for line in srcfile:
+                                if const.RUOYI_DEFAULT_GROUP_ID in line and '<groupId>' in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_GROUP_ID,
+                                        self.groupid)
+                                if const.RUOYI_DEFAULT_ARTIFACTID_PREFIX in line and '<artifactId>' in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_ARTIFACTID_PREFIX,
+                                        self.artifactid)
+                                if '<name>' in line or '<module>' in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_PROJECT_NAME,
+                                        self.projectname)
+                                if 'version>' in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_ARTIFACTID_PREFIX,
+                                        self.artifactid)
+                                if const.RUOYI_DEFAULT_SITE_NAME in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_SITE_NAME,
+                                        self.sitename)
+                                line = line.replace(
+                                    const.RUOYI_DEFAULT_ARTIFACTID_PREFIX,
+                                    self.projectname)
+                                desfile.write(line)
+                        # 移除旧文件
+                        os.remove(filepath)
+                        # 重命名备份文件为新文件
+                        os.rename('%s.bak' % filepath, filepath)
+                except Exception as err:
+                    self.exceptionhandle(
+                        '修改项目pom.xml文件异常\n修改文件:{}\n异常信息:{}'.format(
+                            filepath, err))
+
+    def __alter_project_dir(self):
+        """修改目录名"""
+        for module_name in const.RUOYI_DEFAULT_MODULE_NAME_TUPLE:
+            replace_module_name = module_name.replace('#', os.path.sep)
+            src_main_java_dir = os.path.join(self.rootpath,
+                                             replace_module_name,
+                                             'src/main/java')
+            if os.path.exists(src_main_java_dir):
+                source_dir = os.path.join(
+                    src_main_java_dir,
+                    self.packagename.replace('.', os.path.sep))
+                if not os.path.exists(source_dir):
+                    print(source_dir)
+                    os.makedirs(source_dir)
+                self.move_dir(os.path.join(src_main_java_dir, 'com/ruoyi'),
+                              source_dir)
+                # 拷贝完目录后会删除掉之前的文件,但是目录没有删除,再次删除目录
+                for root, dirs, files in os.walk(os.path.join(
+                        src_main_java_dir, 'com/ruoyi'),
+                                                 topdown=False):
+                    if not os.listdir(root):
+                        os.rmdir(root)
+                # 删除com目录
+                if not os.listdir(os.path.join(src_main_java_dir, 'com')):
+                    os.rmdir(os.path.join(src_main_java_dir, 'com'))
+                if module_name.find('#') == -1:
+                    os.rename(
+                        os.path.join(self.rootpath, module_name),
+                        os.path.join(
+                            self.rootpath, self.projectname + '-' +
+                            module_name.split('-')[1]))
+                else:
+                    tarpath = os.path.join(
+                        self.rootpath,
+                        module_name.split('#')[0], self.projectname + '-' +
+                        module_name.split('#')[1].replace('-', '$',
+                                                          1).split('$')[1])
+                    os.rename(os.path.join(self.rootpath, replace_module_name),
+                              tarpath)
+            else:
+                os.rename(
+                    os.path.join(self.rootpath, module_name),
+                    os.path.join(
+                        self.rootpath,
+                        self.projectname + '-' + module_name.split('-')[1]))
+            self.messagehandle('正在修改:' + replace_module_name)
+        os.rename(self.rootpath,
+                  os.path.join(self.targetdir, self.projectdirname))
+        self.messagehandle('正在修改:' + const.RUOYI_DEFAULT_PROJECT_DIR_NAME)

+ 234 - 0
core/ruoyifast.py

@@ -0,0 +1,234 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/05/18
+# @Author : ricky
+# @File : ruoyifast.py
+# @Software: vscode
+"""
+核心修改类 RuoYi-fast版本
+"""
+import os
+from core import base
+from constant import ruoyifastconstant as const
+
+
+class RuoYiFast(base.BaseCore):
+    def start(self):
+        # 拼接根路径
+        self.rootpath = os.path.join(self.targetdir,
+                                     const.RUOYI_DEFAULT_PROJECT_DIR_NAME)
+        # 1.修改站点名称
+        self.messagehandle("正在修改标题和修站点名称...")
+        self.__alter_site_name_and_title()
+        self.messagehandle("站点名称和标题修改完成!")
+        # 2.修改包名和项目名
+        self.messagehandle("正在修改包名和项目名...")
+        self.__alter_package_name_and_project_name(self.rootpath)
+        self.messagehandle("包名和项目名修改完成!")
+        # 3.修改pom.xml文件
+        self.messagehandle("正在修改pom.xml...")
+        self.__alter_pom_xml()
+        self.messagehandle("pom.xml修改完成!")
+        # 4.修改目录结构
+        self.messagehandle("正在修改目录结构...")
+        self.__alter_project_dir()
+        self.messagehandle("目录结构修改完成!")
+
+        if len(self.exceptions) > 0:
+            self.messagehandle("\r发现有异常信息")
+            self.messagehandle("-------------------\n\r")
+            for e in self.exceptions:
+                self.messagehandle(e)
+            self.messagehandle("\r----------------------")
+
+    def __alter_site_name_and_title(self):
+        """修改站点名称和网站标题"""
+        ntuple = const.RUOYI_SITE_RESOURCES_PATH_TUPLE
+        for item in ntuple:
+            filepath = os.path.join(self.rootpath,
+                                    item.replace('#', os.path.sep))
+            if os.path.exists(filepath):
+                try:
+                    with open(filepath, "r",
+                              encoding="utf-8") as srcfile, open(
+                                  "%s.bak" % filepath, "w",
+                                  encoding="utf-8") as desfile:
+                        for line in srcfile:
+                            if const.RUOYI_DEFAULT_SITE_NAME in line:
+                                line = line.replace(
+                                    const.RUOYI_DEFAULT_SITE_NAME,
+                                    self.sitename)
+                            if '若依后台管理系统' in line:
+                                line = line.replace('若依后台管理系统', self.sitename)
+                            if '若依 后台管理系统' in line:
+                                line = line.replace('若依 后台管理系统', self.sitename)
+                            if '登录若依系统' in line:
+                                line = line.replace('登录若依系统',
+                                                    '登录' + self.sitename)
+                            if '若依系统' in line:
+                                line = line.replace('若依系统', self.sitename)
+                            if '若依介绍' in line:
+                                line = line.replace('若依介绍',
+                                                    self.sitename + '介绍')
+                            if 'RuoYi -' in line:
+                                line = line.replace('RuoYi -', self.sitename)
+                            desfile.write(line)
+                    # 移除旧文件
+                    os.remove(filepath)
+                    # 重命名备份文件为新文件
+                    os.rename("%s.bak" % filepath, filepath)
+                except Exception as err:
+                    self.exceptionhandle(
+                        "修改站点名称和网站标题异常\n修改文件:{}\n异常信息:{}".format(
+                            filepath, err))
+
+    def __alter_package_name_and_project_name(self, rootpath):
+        """
+        修改包名和项目名称
+
+        参数:
+            rootpath (str): 文件路径
+        """
+        files = os.listdir(rootpath)
+        for filename in files:
+            filepath = os.path.join(rootpath, filename)
+            if os.path.isdir(filepath):
+                self.__alter_package_name_and_project_name(filepath)
+            else:
+                if filename.endswith('.java') or filename.endswith(
+                        '.yml') or filename.endswith(
+                            'Mapper.xml') or filename.endswith(
+                                'logback.xml') or filename.endswith(
+                                    '.vm') or filename.endswith(
+                                        '.bat') or filename.endswith('.sh'):
+                    try:
+                        with open(filepath, "r",
+                                  encoding="utf-8") as srcfile, open(
+                                      "%s.bak" % filepath,
+                                      "w",
+                                      encoding="utf-8") as desfile:
+                            self.messagehandle("正在修改:" + filename)
+                            for line in srcfile:
+                                if const.RUOYI_DEFAULT_PACKAGE_NAME in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_PACKAGE_NAME,
+                                        self.packagename)
+                                if const.RUOYI_DEFAULT_PROJECT_NAME + '-' in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_PROJECT_NAME + '-',
+                                        self.projectname + '-')
+                                if self.configdict['config.enable'] == 'True':
+                                    if filename.endswith('.yml'):
+                                        line = self.__check_yml_config(
+                                            line, filename)
+                                desfile.write(line)
+                        # 移除旧文件
+                        os.remove(filepath)
+                        # 重命名备份文件为新文件
+                        os.rename("%s.bak" % filepath, filepath)
+                    except Exception as err:
+                        self.exceptionhandle(
+                            "修改包名和项目名称异常\n修改文件:{}\n异常信息:{}".format(
+                                filepath, err))
+
+    def __check_yml_config(self, line, filename):
+        """
+        检测yml配置文件
+
+        参数:
+            line (str): 行
+            filename (str): 文件名
+        """
+        if 'localhost:3306/ry' in line and filename == 'application-druid.yml':
+            line = self.__alert_yml_config(line, 'mysql_ip_port_name')
+        if 'username: root' in line and filename == 'application-druid.yml':
+            line = self.__alert_yml_config(line, 'mysql_username')
+        if 'password: password' in line and filename == 'application-druid.yml':
+            line = self.__alert_yml_config(line, 'mysql_password')
+        return line
+
+    def __alert_yml_config(self, line, type_):
+        """
+        修改yml配置文件
+
+        参数:
+            line (str): 行
+            type_ (str): 修改类型
+        """
+        if type_ == 'mysql_ip_port_name':
+            mysql_ip = self.configdict['database.ip']
+            mysql_port = self.configdict['database.port']
+            mysql_name = self.configdict['database.name']
+            return line.replace('localhost:3306/ry',
+                                mysql_ip + ":" + mysql_port + "/" + mysql_name)
+        if type_ == 'mysql_username':
+            mysql_username = self.configdict['database.username']
+            return line.replace('username: root',
+                                'username: ' + mysql_username)
+        if type_ == 'mysql_password':
+            mysql_password = self.configdict['database.password']
+            return line.replace('password: password',
+                                'password: ' + mysql_password)
+        return line
+
+    def __alter_pom_xml(self):
+        """修改项目pom.xml文件"""
+        pom_xml_file = os.path.join(self.rootpath, 'pom.xml')
+        if not os.path.exists(pom_xml_file):
+            return
+        try:
+            with open(pom_xml_file, "r", encoding="utf-8") as xml_file, open(
+                    "%s.bak" % pom_xml_file, "w",
+                    encoding="utf-8") as target_file:
+                self.messagehandle("正在修改:" +
+                                   const.RUOYI_DEFAULT_PROJECT_DIR_NAME +
+                                   "/pom.xml")
+                for line in xml_file:
+                    if const.RUOYI_DEFAULT_GROUP_ID in line and '<groupId>' in line:
+                        line = line.replace(const.RUOYI_DEFAULT_GROUP_ID,
+                                            self.groupid)
+                    if const.RUOYI_DEFAULT_ARTIFACTID_PREFIX in line and '<artifactId>' in line:
+                        line = line.replace(
+                            const.RUOYI_DEFAULT_ARTIFACTID_PREFIX,
+                            self.artifactid)
+                    if '<name>' in line or '<module>' in line:
+                        line = line.replace(const.RUOYI_DEFAULT_PROJECT_NAME,
+                                            self.projectname)
+                    if 'version>' in line:
+                        line = line.replace(
+                            const.RUOYI_DEFAULT_ARTIFACTID_PREFIX,
+                            self.artifactid)
+                    if 'description>' in line:
+                        line = line.replace(const.RUOYI_DEFAULT_SITE_NAME,
+                                            self.sitename)
+                    target_file.write(line)
+            # 移除旧文件
+            os.remove(pom_xml_file)
+            # 重命名备份文件为新文件
+            os.rename("%s.bak" % pom_xml_file, pom_xml_file)
+        except Exception as err:
+            self.exceptionhandle("修改项目pom.xml文件异常\n修改文件:{}\n异常信息:{}".format(
+                pom_xml_file, err))
+
+    def __alter_project_dir(self):
+        """修改目录名"""
+        src_main_java_dir = os.path.join(self.rootpath, 'src/main/java')
+        if not os.path.exists(src_main_java_dir):
+            return
+        source_dir = os.path.join(src_main_java_dir,
+                                  self.packagename.replace('.', os.path.sep))
+        if not os.path.exists(source_dir):
+            os.makedirs(source_dir)
+        self.move_dir(os.path.join(src_main_java_dir, 'com/ruoyi'), source_dir)
+
+        # 拷贝完目录后会删除掉之前的文件,但是目录没有删除,再次删除目录
+        for root, dirs, files in os.walk(os.path.join(src_main_java_dir,
+                                                      'com/ruoyi'),
+                                         topdown=False):
+            if not os.listdir(root):
+                os.rmdir(root)
+        # 删除com目录
+        if not os.listdir(os.path.join(src_main_java_dir, 'com')):
+            os.rmdir(os.path.join(src_main_java_dir, 'com'))
+        os.rename(self.rootpath,
+                  os.path.join(self.targetdir, self.projectdirname))
+        self.messagehandle("正在修改:" + const.RUOYI_DEFAULT_PROJECT_DIR_NAME)

+ 275 - 0
core/ruoyivue.py

@@ -0,0 +1,275 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/05/18
+# @Author : ricky
+# @File : ruoyivue.py
+# @Software: vscode
+"""
+核心修改类 RuoYi-Vue版本
+"""
+import os
+from core import base
+from constant import ruoyivueconstant as const
+
+
+class RuoYiVue(base.BaseCore):
+    def start(self):
+        # 拼接根路径
+        self.rootpath = os.path.join(self.targetdir,
+                                     const.RUOYI_DEFAULT_PROJECT_DIR_NAME)
+        # 1.修改站点名称
+        self.messagehandle('正在修改标题和修站点名称...')
+        self.__alter_site_name_and_title()
+        self.messagehandle('站点名称和标题修改完成!')
+        # 2.修改包名和项目名
+        self.messagehandle('正在修改包名和项目名...')
+        self.__alter_package_name_and_project_name(self.rootpath)
+        self.messagehandle('包名和项目名修改完成!')
+        # 3.修改pom.xml文件
+        self.messagehandle('正在修改pom.xml...')
+        self.__alter_pom_xml()
+        self.messagehandle('pom.xml修改完成!')
+        # 4.修改目录结构
+        self.messagehandle('正在修改目录结构...')
+        self.__alter_project_dir()
+        self.messagehandle('目录结构修改完成!')
+
+        if len(self.exceptions) > 0:
+            self.messagehandle('\r发现有异常信息')
+            self.messagehandle('-------------------\n\r')
+            for e in self.exceptions:
+                self.messagehandle(e)
+            self.messagehandle('\r----------------------')
+
+    def __alter_site_name_and_title(self):
+        """修改站点名称和网站标题"""
+        ntuple = const.RUOYI_SITE_RESOURCES_PATH_TUPLE
+        for item in ntuple:
+            filepath = os.path.join(self.rootpath,
+                                    item.replace('#', os.path.sep))
+            if os.path.exists(filepath):
+                try:
+                    with open(filepath, 'r',
+                              encoding='utf-8') as srcfile, open(
+                                  '%s.bak' % filepath, 'w',
+                                  encoding='utf-8') as desfile:
+                        for line in srcfile:
+                            if const.RUOYI_DEFAULT_SITE_NAME in line:
+                                line = line.replace(
+                                    const.RUOYI_DEFAULT_SITE_NAME,
+                                    self.sitename)
+                            if '若依后台管理系统' in line:
+                                line = line.replace('若依后台管理系统', self.sitename)
+                            if '若依 后台管理系统' in line:
+                                line = line.replace('若依 后台管理系统', self.sitename)
+                            if '登录若依系统' in line:
+                                line = line.replace('登录若依系统',
+                                                    '登录' + self.sitename)
+                            if '若依系统' in line:
+                                line = line.replace('若依系统', self.sitename)
+                            if '若依介绍' in line:
+                                line = line.replace('若依介绍',
+                                                    self.sitename + '介绍')
+                            if 'RuoYi -' in line:
+                                line = line.replace('RuoYi -', self.sitename)
+                            desfile.write(line)
+                    # 移除旧文件
+                    os.remove(filepath)
+                    # 重命名备份文件为新文件
+                    os.rename('%s.bak' % filepath, filepath)
+                except Exception as err:
+                    self.exceptionhandle(
+                        '修改站点名称和网站标题异常\n修改文件:{}\n异常信息:{}'.format(
+                            filepath, err))
+
+    def __alter_package_name_and_project_name(self, rootpath):
+        """修改包名和项目名称"""
+        files = os.listdir(rootpath)
+        for filename in files:
+            filepath = os.path.join(rootpath, filename)
+            if os.path.isdir(filepath):
+                self.__alter_package_name_and_project_name(filepath)
+            else:
+                if filename.endswith('.java') or filename.endswith(
+                        '.yml'
+                ) or filename.endswith('Mapper.xml') or filename.endswith(
+                        'logback.xml') or filename.endswith(
+                            '.factories') or filename.endswith(
+                                '.vm') or filename.endswith(
+                                    '.bat') or filename.endswith('.sh'):
+                    try:
+                        with open(filepath, 'r',
+                                  encoding='utf-8') as srcfile, open(
+                                      '%s.bak' % filepath,
+                                      'w',
+                                      encoding='utf-8') as desfile:
+                            self.messagehandle('正在修改:' + filename)
+                            for line in srcfile:
+                                if const.RUOYI_DEFAULT_PACKAGE_NAME in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_PACKAGE_NAME,
+                                        self.packagename)
+                                if const.RUOYI_DEFAULT_PROJECT_NAME + '-' in line:
+                                    line = line.replace(
+                                        const.RUOYI_DEFAULT_PROJECT_NAME + '-',
+                                        self.projectname + '-')
+                                if self.configdict['config.enable'] == 'True':
+                                    if filename.endswith('.yml'):
+                                        line = self.__check_yml_config(
+                                            line, filename)
+                                desfile.write(line)
+                        # 移除旧文件
+                        os.remove(filepath)
+                        # 重命名备份文件为新文件
+                        os.rename('%s.bak' % filepath, filepath)
+                    except Exception as err:
+                        self.exceptionhandle(
+                            '修改包名和项目名称异常\n修改文件:{}\n异常信息:{}'.format(
+                                filepath, err))
+
+    def __check_yml_config(self, line, filename):
+        """
+        检测yml配置文件
+
+        参数:
+            line (str): 行
+            filename (str): 文件名
+        """
+        if 'localhost:3306/ry-vue' in line and filename == 'application-druid.yml':
+            line = self.__alert_yml_config(line, 'mysql_ip_port_name')
+        if 'username: root' in line and filename == 'application-druid.yml':
+            line = self.__alert_yml_config(line, 'mysql_username')
+        if 'password: password' in line and filename == 'application-druid.yml':
+            line = self.__alert_yml_config(line, 'mysql_password')
+        if 'host: localhost' in line and filename == 'application.yml':
+            line = self.__alert_yml_config(line, 'redis_host')
+        if 'port: 6379' in line and filename == 'application.yml':
+            line = self.__alert_yml_config(line, 'redis_port')
+        if 'password: \n' in line and filename == 'application.yml':
+            line = self.__alert_yml_config(line, 'redis_password')
+        return line
+
+    def __alert_yml_config(self, line, type_):
+        """
+        修改yml配置文件
+
+        参数:
+            line (str): 行
+            type_ (str): 修改类型
+        """
+        if type_ == 'mysql_ip_port_name':
+            mysql_ip = self.configdict['database.ip']
+            mysql_port = self.configdict['database.port']
+            mysql_name = self.configdict['database.name']
+            return line.replace('localhost:3306/ry-vue',
+                                mysql_ip + ':' + mysql_port + '/' + mysql_name)
+        if type_ == 'mysql_username':
+            mysql_username = self.configdict['database.username']
+            return line.replace('username: root',
+                                'username: ' + mysql_username)
+        if type_ == 'mysql_password':
+            mysql_password = self.configdict['database.password']
+            return line.replace('password: password',
+                                'password: ' + mysql_password)
+        if type_ == 'redis_host':
+            redis_ip = self.configdict['redis.ip']
+            return line.replace('host: localhost', 'host: ' + redis_ip)
+        if type_ == 'redis_port':
+            redis_port = self.configdict['redis.port']
+            return line.replace('port: 6379', 'port: ' + redis_port)
+        if type_ == 'redis_password':
+            redis_password = self.configdict['redis.password']
+            return line.replace('password: \n',
+                                'password: ' + redis_password + '\n')
+        return line
+
+    def __alter_pom_xml(self):
+        """修改项目pom.xml文件"""
+        # 将最外层的文件夹添加到新的元组中
+        ttuple = (const.RUOYI_DEFAULT_PROJECT_DIR_NAME, )
+        ntuple = ttuple + const.RUOYI_DEFAULT_MODULE_NAME_TUPLE
+        for module_name in ntuple:
+            pom_xml_file = ''
+            # 如果元组内元素是项目名,文件路径需要特殊处理
+            if module_name == const.RUOYI_DEFAULT_PROJECT_DIR_NAME:
+                pom_xml_file = os.path.join(self.rootpath, 'pom.xml')
+            else:
+                pom_xml_file = os.path.join(self.rootpath, module_name,
+                                            'pom.xml')
+            if not os.path.exists(pom_xml_file):
+                continue
+            try:
+                with open(pom_xml_file, 'r',
+                          encoding='utf-8') as xml_file, open(
+                              '%s.bak' % pom_xml_file, 'w',
+                              encoding='utf-8') as target_file:
+                    self.messagehandle('正在修改:' + module_name + '/pom.xml')
+                    for line in xml_file:
+                        if const.RUOYI_DEFAULT_GROUP_ID in line and '<groupId>' in line:
+                            line = line.replace(const.RUOYI_DEFAULT_GROUP_ID,
+                                                self.groupid)
+                        if const.RUOYI_DEFAULT_ARTIFACTID_PREFIX in line and '<artifactId>' in line:
+                            line = line.replace(
+                                const.RUOYI_DEFAULT_ARTIFACTID_PREFIX,
+                                self.artifactid)
+                        if module_name == const.RUOYI_DEFAULT_PROJECT_DIR_NAME:
+                            if '<name>' in line or '<module>' in line:
+                                line = line.replace(
+                                    const.RUOYI_DEFAULT_PROJECT_NAME,
+                                    self.projectname)
+                            if 'version>' in line:
+                                line = line.replace(
+                                    const.RUOYI_DEFAULT_ARTIFACTID_PREFIX,
+                                    self.artifactid)
+                            if 'description>' in line:
+                                line = line.replace(
+                                    const.RUOYI_DEFAULT_SITE_NAME,
+                                    self.sitename)
+                        target_file.write(line)
+                # 移除旧文件
+                os.remove(pom_xml_file)
+                # 重命名备份文件为新文件
+                os.rename('%s.bak' % pom_xml_file, pom_xml_file)
+            except Exception as err:
+                self.exceptionhandle(
+                    '修改项目pom.xml文件异常\n修改文件:{}\n异常信息:{}'.format(
+                        pom_xml_file, err))
+
+    def __alter_project_dir(self):
+        """修改目录名"""
+        for module_name in const.RUOYI_DEFAULT_MODULE_NAME_TUPLE:
+            src_main_java_dir = os.path.join(self.rootpath, module_name,
+                                             'src/main/java')
+            # 如果没有找到源代码路径,结束本次循环
+            if os.path.exists(src_main_java_dir):
+                source_dir = os.path.join(
+                    src_main_java_dir,
+                    self.packagename.replace('.', os.path.sep))
+                if not os.path.exists(source_dir):
+                    os.makedirs(source_dir)
+                self.move_dir(os.path.join(src_main_java_dir, 'com/ruoyi'),
+                              source_dir)
+
+                # 拷贝完目录后会删除掉之前的文件,但是目录没有删除,再次删除目录
+                for root, dirs, files in os.walk(os.path.join(
+                        src_main_java_dir, 'com/ruoyi'),
+                                                 topdown=False):
+                    if not os.listdir(root):
+                        os.rmdir(root)
+                # 删除com目录
+                if not os.listdir(os.path.join(src_main_java_dir, 'com')):
+                    os.rmdir(os.path.join(src_main_java_dir, 'com'))
+                os.rename(
+                    os.path.join(self.rootpath, module_name),
+                    os.path.join(
+                        self.rootpath,
+                        self.projectname + '-' + module_name.split('-')[1]))
+            else:
+                os.rename(
+                    os.path.join(self.rootpath, module_name),
+                    os.path.join(
+                        self.rootpath,
+                        self.projectname + '-' + module_name.split('-')[1]))
+            self.messagehandle('正在修改:' + module_name)
+        os.rename(self.rootpath,
+                  os.path.join(self.targetdir, self.projectdirname))
+        self.messagehandle('正在修改:' + const.RUOYI_DEFAULT_PROJECT_DIR_NAME)


BIN
img/wx_reward.png


BIN
libs/jar/druid-1.2.4.jar


+ 1 - 0
requirements.txt

@@ -0,0 +1 @@
+pyperclip==1.8.2

+ 29 - 0
run.py

@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/05/18
+# @Author : ricky
+# @File : run.py
+# @Software: vscode
+"""
+启动类
+"""
+import wx
+from ui import main
+from spider import upgradespider
+from loguru import logger
+
+if __name__ == '__main__':
+    """
+    程序入口
+    """
+    logger.add('out.log')
+    app = wx.App(False)
+    frame = main.Main(None)
+    frame.Show(True)
+    try:
+        # 检测更新
+        upgradespider.check()
+        app.MainLoop()
+
+    except Exception as err:
+        logger.error('程序发生异常: {}', err)
+        raise

+ 4 - 0
spider/__init__.py

@@ -0,0 +1,4 @@
+'''
+爬虫模块
+'''
+import spider.upgradespider as upgradespider

+ 52 - 0
spider/upgradespider.py

@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/02/23
+# @Author : ricky
+# @File : upgradespider.py
+# @Software: vscode
+"""
+爬取gitee,检测更新
+"""
+import threading
+import requests
+import wx
+from bs4 import BeautifulSoup
+from constant import constant
+from loguru import logger
+
+
+def _get(show_no_new_version_tip=False):
+    """
+    异步解析
+
+    参数:
+        show_no_new_version_tip (bool): 是否显示没有新版本提示,默认为False
+    """
+    url = 'https://gitee.com/lpf_project/common-tools/tags'
+    wb_data = requests.get(url)
+    soup = BeautifulSoup(wb_data.text, 'html.parser')
+    tags = soup.select('div.tag-item-action.tag-name>a')
+    is_has_new_version = False
+    for tag in tags:
+        version = ''.join(list(filter(str.isdigit, tag['title'])))
+        if int(version) > constant.APP_VERSION_INT:
+            is_has_new_version = True
+            logger.info('检查更新结果:发现新的版本-{}', tag['title'])
+            wx.MessageDialog(
+                None, '发现新的版本【%s】,请前往gitee下载,\ngitee地址可以查看“关于我们”中的“软件官网”' %
+                tag['title'], '版本升级提醒', wx.OK).ShowModal()
+            break
+    if not is_has_new_version:
+        logger.info('检查更新结果:当前版本是最新版本!')
+        if show_no_new_version_tip:
+            wx.MessageDialog(None, '当前版本是最新版本!', '检测更新', wx.OK).ShowModal()
+
+
+def check(show_no_new_version_tip=False):
+    """
+    检测更新
+
+    参数:
+        show_no_new_version_tip (bool): 是否显示没有新版本提示,默认为False
+    """
+    thread = threading.Thread(target=_get, args=(show_no_new_version_tip, ))
+    thread.start()

+ 8 - 0
ui/__init__.py

@@ -0,0 +1,8 @@
+"""
+ui模块
+"""
+import ui.main.main as main
+import ui.config.config as config
+import ui.reward.reward as reward
+import ui.about.about as about
+import ui.druid.druidencrypt as druidencrypt

+ 1 - 0
ui/about/__init__.py

@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-

+ 18 - 0
ui/about/about.py

@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/02/23
+# @Author : ricky
+# @File : about.py
+# @Software: vscode
+"""
+关于我们界面
+"""
+from constant import constant
+import ui.about.about_dialog as dialog
+
+
+class About(dialog.AboutDialog):
+    def __init__(self, parent):
+        dialog.AboutDialog.__init__(self, parent)
+        self.m_static_text_version.SetLabelText('当前版本号:' +
+                                                constant.APP_VERSION_STRING)
+        self.Centre()

+ 120 - 0
ui/about/about_dialog.py

@@ -0,0 +1,120 @@
+# -*- coding: utf-8 -*-
+
+###########################################################################
+## Python code generated with wxFormBuilder (version Oct 26 2018)
+## http://www.wxformbuilder.org/
+##
+## PLEASE DO *NOT* EDIT THIS FILE!
+###########################################################################
+
+import wx
+import wx.xrc
+import wx.adv
+
+###########################################################################
+## Class AboutDialog
+###########################################################################
+
+class AboutDialog ( wx.Dialog ):
+
+	def __init__( self, parent ):
+		wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"关于我们", pos = wx.DefaultPosition, size = wx.Size( 330,459 ), style = wx.DEFAULT_DIALOG_STYLE )
+
+		self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
+		self.SetBackgroundColour( wx.Colour( 255, 255, 255 ) )
+
+		bSizer = wx.BoxSizer( wx.VERTICAL )
+
+		bSizer2 = wx.BoxSizer( wx.VERTICAL )
+
+		self.m_static_text_version = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_static_text_version.Wrap( -1 )
+
+		bSizer2.Add( self.m_static_text_version, 0, wx.ALL|wx.EXPAND, 5 )
+
+		self.m_scrolled_window = wx.ScrolledWindow( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.VSCROLL )
+		self.m_scrolled_window.SetScrollRate( 5, 5 )
+		bSizer17 = wx.BoxSizer( wx.VERTICAL )
+
+		self.m_staticText21 = wx.StaticText( self.m_scrolled_window, wx.ID_ANY, u"[介绍]", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_staticText21.Wrap( -1 )
+
+		bSizer17.Add( self.m_staticText21, 0, wx.ALL, 5 )
+
+		self.m_staticText22 = wx.StaticText( self.m_scrolled_window, wx.ID_ANY, u"本软件是为了方便大家修改若依框架的包名、项目名\n等制作的,如同若依框架一样免费使用,功能如下:", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_staticText22.Wrap( -1 )
+
+		bSizer17.Add( self.m_staticText22, 0, wx.ALL, 5 )
+
+		self.m_staticText23 = wx.StaticText( self.m_scrolled_window, wx.ID_ANY, u"1、修改包名、目录名、项目名等", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_staticText23.Wrap( -1 )
+
+		bSizer17.Add( self.m_staticText23, 0, wx.ALL, 5 )
+
+		self.m_staticText24 = wx.StaticText( self.m_scrolled_window, wx.ID_ANY, u"2、修改前可以配置其他的修改参数,例如配置数据\n库地址、名称、账号、密码等,在修改时会将配置文\n件中的对应参数一起修改掉", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_staticText24.Wrap( -1 )
+
+		bSizer17.Add( self.m_staticText24, 0, wx.ALL, 5 )
+
+		self.m_staticText25 = wx.StaticText( self.m_scrolled_window, wx.ID_ANY, u"3、未来可能会加入更多的一键操作功能,敬请期待", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_staticText25.Wrap( -1 )
+
+		bSizer17.Add( self.m_staticText25, 0, wx.ALL, 5 )
+
+		self.m_staticText27 = wx.StaticText( self.m_scrolled_window, wx.ID_ANY, u"[说明]", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_staticText27.Wrap( -1 )
+
+		bSizer17.Add( self.m_staticText27, 0, wx.ALL, 5 )
+
+		self.m_staticText28 = wx.StaticText( self.m_scrolled_window, wx.ID_ANY, u"1、在使用过程中如果遇到问题,请联系作者进行反\n馈", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_staticText28.Wrap( -1 )
+
+		bSizer17.Add( self.m_staticText28, 0, wx.ALL, 5 )
+
+		self.m_staticText29 = wx.StaticText( self.m_scrolled_window, wx.ID_ANY, u"2、本软件只有一个地方是网络请求,就是检测更新\n,检测更新是爬取的gitee页面来实现的,所以可以\n放心使用", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_staticText29.Wrap( -1 )
+
+		bSizer17.Add( self.m_staticText29, 0, wx.ALL, 5 )
+
+
+		self.m_scrolled_window.SetSizer( bSizer17 )
+		self.m_scrolled_window.Layout()
+		bSizer17.Fit( self.m_scrolled_window )
+		bSizer2.Add( self.m_scrolled_window, 1, wx.EXPAND, 5 )
+
+		bSizer4 = wx.BoxSizer( wx.HORIZONTAL )
+
+		self.m_hyperlink1 = wx.adv.HyperlinkCtrl( self, wx.ID_ANY, u"软件官网", u"https://gitee.com/lpf_project/common-tools", wx.DefaultPosition, wx.Size( -1,-1 ), wx.adv.HL_DEFAULT_STYLE )
+		self.m_hyperlink1.SetMinSize( wx.Size( -1,30 ) )
+
+		bSizer4.Add( self.m_hyperlink1, 0, wx.ALL, 5 )
+
+		self.m_hyperlink2 = wx.adv.HyperlinkCtrl( self, wx.ID_ANY, u"若依官网", u"http://ruoyi.vip/", wx.DefaultPosition, wx.Size( -1,-1 ), wx.adv.HL_DEFAULT_STYLE )
+		self.m_hyperlink2.SetMinSize( wx.Size( -1,30 ) )
+
+		bSizer4.Add( self.m_hyperlink2, 0, wx.ALL, 5 )
+
+
+		bSizer2.Add( bSizer4, 0, wx.EXPAND, 5 )
+
+
+		bSizer.Add( bSizer2, 1, wx.ALL|wx.EXPAND, 5 )
+
+		bSizer3 = wx.BoxSizer( wx.VERTICAL )
+
+		self.m_button_close = wx.Button( self, wx.ID_CANCEL, u"关闭", wx.DefaultPosition, wx.DefaultSize, 0 )
+		bSizer3.Add( self.m_button_close, 0, wx.ALL, 5 )
+
+
+		bSizer.Add( bSizer3, 0, wx.ALIGN_RIGHT|wx.ALL, 5 )
+
+
+		self.SetSizer( bSizer )
+		self.Layout()
+
+		self.Centre( wx.BOTH )
+
+	def __del__( self ):
+		pass
+
+

+ 1 - 0
ui/config/__init__.py

@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-

+ 54 - 0
ui/config/config.py

@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/02/20
+# @Author : ricky
+# @File : config.py
+# @Software: vscode
+"""
+参数配置界面
+"""
+import wx
+import ui.config.config_dialog as config_dialog
+from utils import configini
+
+
+class Config(config_dialog.ConfigDialog):
+    """
+    主类
+    """
+    def __init__(self, parent):
+        config_dialog.ConfigDialog.__init__(self, parent)
+        self.configini = configini.Config()
+        config_enable = self.configini.get_value('config', 'enable')
+        database_ip = self.configini.get_value('database', 'ip')
+        database_port = self.configini.get_value('database', 'port')
+        database_name = self.configini.get_value('database', 'name')
+        database_username = self.configini.get_value('database', 'username')
+        database_password = self.configini.get_value('database', 'password')
+
+        redis_ip = self.configini.get_value('redis', 'ip')
+        redis_port = self.configini.get_value('redis', 'port')
+        redis_password = self.configini.get_value('redis', 'password')
+
+        self.m_property_item_enable.SetValue(config_enable)
+
+        self.m_property_item_database_ip.SetValue(database_ip)
+        if len(database_port) > 0:
+            self.m_property_item_database_port.SetValue(int(database_port))
+        self.m_property_item_database_name.SetValue(database_name)
+        self.m_property_item_database_username.SetValue(database_username)
+        self.m_property_item_database_password.SetValue(database_password)
+
+        self.m_property_item_redis_ip.SetValue(redis_ip)
+        if len(redis_port) > 0:
+            self.m_property_item_redis_port.SetValue(int(redis_port))
+        self.m_property_item_redis_password.SetValue(redis_password)
+        self.Centre()
+
+    def OnClickEventSave(self, event):
+        values = self.m_property_page.GetPropertyValues()
+        for key in values:
+            key_array = key.split('_', 1)
+            value = str(values[key])
+            self.configini.set_value(key_array[0], key_array[1], value)
+        self.configini.write()
+        self.EndModal(wx.ID_OK)

+ 84 - 0
ui/config/config_dialog.py

@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+
+###########################################################################
+## Python code generated with wxFormBuilder (version Oct 26 2018)
+## http://www.wxformbuilder.org/
+##
+## PLEASE DO *NOT* EDIT THIS FILE!
+###########################################################################
+
+import wx
+import wx.xrc
+import wx.propgrid as pg
+
+###########################################################################
+## Class ConfigDialog
+###########################################################################
+
+class ConfigDialog ( wx.Dialog ):
+
+	def __init__( self, parent ):
+		wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"配置参数", pos = wx.DefaultPosition, size = wx.Size( 318,450 ), style = wx.DEFAULT_DIALOG_STYLE )
+
+		self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
+
+		b_sizer = wx.BoxSizer( wx.VERTICAL )
+
+		self.m_property_manager = pg.PropertyGridManager(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.propgrid.PGMAN_DEFAULT_STYLE|wx.propgrid.PG_BOLD_MODIFIED|wx.propgrid.PG_DESCRIPTION|wx.propgrid.PG_SPLITTER_AUTO_CENTER)
+
+		self.m_property_page = self.m_property_manager.AddPage( u"基础设置", wx.NullBitmap )
+		self.m_property_item_enable = self.m_property_page.Append( pg.BoolProperty( u"是否启用配置", u"config_enable" ) )
+		self.m_property_page.SetPropertyHelpString(self.m_property_item_enable, u"选择为True时参数生效,在修改框架时会使用配置的参数,否则不使用" )
+		self.m_property_item_mysql_category = self.m_property_page.Append( pg.PropertyCategory( u"数据库配置", u"mysql_config" ) )
+		self.m_property_item_database_ip = self.m_property_page.Append( pg.LongStringProperty( u"IP地址", u"database_ip" ) )
+		self.m_property_page.SetPropertyHelpString(self.m_property_item_database_ip, u"mysql数据库的ip地址,本地也可以填写localhost\n或者127.0.0.1" )
+		self.m_property_item_database_port = self.m_property_page.Append( pg.IntProperty( u"端口号", u"database_port", 3306) )
+		self.m_property_page.SetPropertyHelpString(self.m_property_item_database_port, u"mysql数据库的端口号,mysql默认3306" )
+		self.m_property_item_database_name = self.m_property_page.Append( pg.LongStringProperty( u"名称", u"database_name" ) )
+		self.m_property_page.SetPropertyHelpString(self.m_property_item_database_name, u"mysql数据库名称" )
+		self.m_property_item_database_username = self.m_property_page.Append( pg.LongStringProperty( u"账号", u"database_username" ) )
+		self.m_property_page.SetPropertyHelpString(self.m_property_item_database_username, u"mysql数据库登录账号(存储时会加密,放心填写)" )
+		self.m_property_item_database_password = self.m_property_page.Append( pg.LongStringProperty( u"密码", u"database_password" ) )
+		self.m_property_page.SetPropertyHelpString(self.m_property_item_database_password, u"mysql数据库登录密码(存储时会加密,放心填写)" )
+		self.m_property_item_redis_category = self.m_property_page.Append( pg.PropertyCategory( u"Redis配置", u"redis_config" ) )
+		self.m_property_item_redis_ip = self.m_property_page.Append( pg.LongStringProperty( u"IP地址", u"redis_ip" ) )
+		self.m_property_page.SetPropertyHelpString(self.m_property_item_redis_ip, u"redis数据库的ip地址,本地也可以填写localhost\n或者127.0.0.1" )
+		self.m_property_item_redis_port = self.m_property_page.Append( pg.IntProperty( u"端口号", u"redis_port", 6379 ) )
+		self.m_property_page.SetPropertyHelpString(self.m_property_item_redis_port, u"redis数据库端口号,默认6379" )
+		self.m_property_item_redis_password = self.m_property_page.Append( pg.LongStringProperty( u"密码", u"redis_password" ) )
+		self.m_property_page.SetPropertyHelpString(self.m_property_item_redis_password, u"redis数据库登录密码(存储时会加密,放心填写)" )
+		b_sizer.Add( self.m_property_manager, 1, wx.ALL|wx.EXPAND, 5 )
+
+		self.m_static_text = wx.StaticText( self, wx.ID_ANY, u"注:设置一次后下次修改不需要再次设置", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_static_text.Wrap( -1 )
+
+		b_sizer.Add( self.m_static_text, 0, wx.ALL, 5 )
+
+		b_sizer2 = wx.BoxSizer( wx.HORIZONTAL )
+
+		self.m_button_save = wx.Button( self, wx.ID_ANY, u"保存", wx.DefaultPosition, wx.DefaultSize, 0 )
+		b_sizer2.Add( self.m_button_save, 0, wx.ALL, 5 )
+
+		self.m_button_close = wx.Button( self, wx.ID_CANCEL, u"关闭", wx.DefaultPosition, wx.DefaultSize, 0 )
+		b_sizer2.Add( self.m_button_close, 0, wx.ALL, 5 )
+
+
+		b_sizer.Add( b_sizer2, 0, wx.ALIGN_RIGHT, 5 )
+
+		self.SetSizer( b_sizer )
+		self.Layout()
+
+		self.Centre( wx.BOTH )
+
+		# Connect Events
+		self.m_button_save.Bind( wx.EVT_BUTTON, self.OnClickEventSave )
+
+	def __del__( self ):
+		pass
+
+
+	# Virtual event handlers, overide them in your derived class
+	def OnClickEventSave( self, event ):
+		event.Skip()
+
+

+ 1 - 0
ui/druid/__init__.py

@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-

+ 126 - 0
ui/druid/druid_encrypt_dialog.py

@@ -0,0 +1,126 @@
+# -*- coding: utf-8 -*-
+
+###########################################################################
+## Python code generated with wxFormBuilder (version Oct 26 2018)
+## http://www.wxformbuilder.org/
+##
+## PLEASE DO *NOT* EDIT THIS FILE!
+###########################################################################
+
+import wx
+import wx.xrc
+
+###########################################################################
+## Class DruidEncryptDialog
+###########################################################################
+
+class DruidEncryptDialog ( wx.Dialog ):
+
+	def __init__( self, parent ):
+		wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"druid秘钥生成工具", pos = wx.DefaultPosition, size = wx.Size( 600,460 ), style = wx.DEFAULT_DIALOG_STYLE )
+
+		self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
+
+		b_sizer_main = wx.BoxSizer( wx.VERTICAL )
+
+		self.m_scrolled_window = wx.ScrolledWindow( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.VSCROLL )
+		self.m_scrolled_window.SetScrollRate( 0, 20 )
+		b_sizer_scrolled = wx.BoxSizer( wx.VERTICAL )
+
+		sb_sizer_original_password = wx.StaticBoxSizer( wx.StaticBox( self.m_scrolled_window, wx.ID_ANY, u"原始密码" ), wx.VERTICAL )
+
+		b_sizer_original_password = wx.BoxSizer( wx.HORIZONTAL )
+
+		self.m_text_ctrl_original_password = wx.TextCtrl( sb_sizer_original_password.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_text_ctrl_original_password.SetMaxLength( 32 )
+		b_sizer_original_password.Add( self.m_text_ctrl_original_password, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
+
+		self.m_button_generate = wx.Button( sb_sizer_original_password.GetStaticBox(), wx.ID_ANY, u"生成", wx.DefaultPosition, wx.DefaultSize, 0 )
+		b_sizer_original_password.Add( self.m_button_generate, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
+
+		self.m_button_clear = wx.Button( sb_sizer_original_password.GetStaticBox(), wx.ID_ANY, u"清空", wx.DefaultPosition, wx.DefaultSize, 0 )
+		b_sizer_original_password.Add( self.m_button_clear, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
+
+
+		sb_sizer_original_password.Add( b_sizer_original_password, 0, wx.EXPAND, 5 )
+
+
+		b_sizer_scrolled.Add( sb_sizer_original_password, 0, wx.ALL|wx.EXPAND, 5 )
+
+		sb_sizer_private_key = wx.StaticBoxSizer( wx.StaticBox( self.m_scrolled_window, wx.ID_ANY, u"私钥" ), wx.VERTICAL )
+
+		self.m_text_ctrl_private_key = wx.TextCtrl( sb_sizer_private_key.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_WORDWRAP )
+		self.m_text_ctrl_private_key.SetMinSize( wx.Size( -1,120 ) )
+
+		sb_sizer_private_key.Add( self.m_text_ctrl_private_key, 0, wx.ALL|wx.EXPAND, 5 )
+
+		self.m_button_copy_private_key = wx.Button( sb_sizer_private_key.GetStaticBox(), wx.ID_ANY, u"点击复制", wx.DefaultPosition, wx.DefaultSize, 0 )
+		sb_sizer_private_key.Add( self.m_button_copy_private_key, 0, wx.ALL, 5 )
+
+
+		b_sizer_scrolled.Add( sb_sizer_private_key, 0, wx.ALL|wx.EXPAND, 5 )
+
+		sb_sizer_public_key = wx.StaticBoxSizer( wx.StaticBox( self.m_scrolled_window, wx.ID_ANY, u"公钥" ), wx.VERTICAL )
+
+		self.m_text_ctrl_public_key = wx.TextCtrl( sb_sizer_public_key.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_WORDWRAP )
+		self.m_text_ctrl_public_key.SetMinSize( wx.Size( -1,60 ) )
+
+		sb_sizer_public_key.Add( self.m_text_ctrl_public_key, 0, wx.ALL|wx.EXPAND, 5 )
+
+		self.m_button_copy_public_key = wx.Button( sb_sizer_public_key.GetStaticBox(), wx.ID_ANY, u"点击复制", wx.DefaultPosition, wx.DefaultSize, 0 )
+		sb_sizer_public_key.Add( self.m_button_copy_public_key, 0, wx.ALL, 5 )
+
+
+		b_sizer_scrolled.Add( sb_sizer_public_key, 0, wx.ALL|wx.EXPAND, 5 )
+
+		sb_sizer_encrypt_password = wx.StaticBoxSizer( wx.StaticBox( self.m_scrolled_window, wx.ID_ANY, u"密码" ), wx.VERTICAL )
+
+		self.m_text_ctrl_encrypt_password = wx.TextCtrl( sb_sizer_encrypt_password.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_WORDWRAP )
+		self.m_text_ctrl_encrypt_password.SetMinSize( wx.Size( -1,60 ) )
+
+		sb_sizer_encrypt_password.Add( self.m_text_ctrl_encrypt_password, 0, wx.ALL|wx.EXPAND, 5 )
+
+		self.m_button_copy_encrypt_password = wx.Button( sb_sizer_encrypt_password.GetStaticBox(), wx.ID_ANY, u"点击复制", wx.DefaultPosition, wx.DefaultSize, 0 )
+		sb_sizer_encrypt_password.Add( self.m_button_copy_encrypt_password, 0, wx.ALL, 5 )
+
+
+		b_sizer_scrolled.Add( sb_sizer_encrypt_password, 0, wx.ALL|wx.EXPAND, 5 )
+
+
+		self.m_scrolled_window.SetSizer( b_sizer_scrolled )
+		self.m_scrolled_window.Layout()
+		b_sizer_scrolled.Fit( self.m_scrolled_window )
+		b_sizer_main.Add( self.m_scrolled_window, 1, wx.EXPAND |wx.ALL, 5 )
+
+
+		self.SetSizer( b_sizer_main )
+		self.Layout()
+
+		self.Centre( wx.BOTH )
+
+		# Connect Events
+		self.m_button_generate.Bind( wx.EVT_BUTTON, self.OnClickEventGenerate )
+		self.m_button_clear.Bind( wx.EVT_BUTTON, self.OnClickEventClear )
+		self.m_button_copy_private_key.Bind( wx.EVT_BUTTON, self.OnClickEventPrivateKeyCopy )
+		self.m_button_copy_public_key.Bind( wx.EVT_BUTTON, self.OnClickEventPublicKeyCopy )
+		self.m_button_copy_encrypt_password.Bind( wx.EVT_BUTTON, self.OnClickEventEncryptPasswordCopy )
+
+	def __del__( self ):
+		pass
+
+
+	# Virtual event handlers, overide them in your derived class
+	def OnClickEventGenerate( self, event ):
+		event.Skip()
+
+	def OnClickEventClear( self, event ):
+		event.Skip()
+
+	def OnClickEventPrivateKeyCopy( self, event ):
+		event.Skip()
+
+	def OnClickEventPublicKeyCopy( self, event ):
+		event.Skip()
+
+	def OnClickEventEncryptPasswordCopy( self, event ):
+		event.Skip()

+ 107 - 0
ui/druid/druidencrypt.py

@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/05/06
+# @Author : ricky
+# @File : druidencrypt.py
+# @Software: vscode
+"""druid秘钥生成界面
+这里是执行jar命令生成的
+"""
+import wx
+import subprocess
+import pyperclip
+import ui.druid.druid_encrypt_dialog as dialog
+from utils import pathutil
+
+
+def show_message(message):
+    """统一显示对话框
+
+    根据传入对话框内容显示对话框
+
+    参数:
+        message (str): 对话框内容
+    """
+    wx.MessageDialog(None, message, '操作提醒', wx.OK).ShowModal()
+
+
+class DruidEncrypt(dialog.DruidEncryptDialog):
+    def __init__(self, parent):
+        dialog.DruidEncryptDialog.__init__(self, parent)
+        self.m_text_ctrl_original_password.SetHint('请输入原始密码(最长不超过32位)')
+        self.Centre()
+
+    def OnClickEventGenerate(self, event):
+        """生成按钮事件"""
+        # 校验原始密码是否输入
+        original_password = self.m_text_ctrl_original_password.GetValue()
+        if len(original_password) == 0:
+            show_message('请输入原始密码')
+            self.m_text_ctrl_original_password.SetFocus()
+            return
+        # 测试是否安装java环境
+        subp = subprocess.Popen('java -version',
+                                shell=True,
+                                stdin=subprocess.PIPE,
+                                stdout=subprocess.PIPE,
+                                stderr=subprocess.STDOUT)
+        out = subp.stdout.readlines()
+        if (str(out[0]).find('java version') == -1):
+            show_message('检查到您电脑上没有安装jdk,请安装jdk并且配置环境变量')
+            return
+        # 执行秘钥生成的命令
+        jar_file = pathutil.resource_path('libs/jar/druid-1.2.4.jar')
+        original_password = self.m_text_ctrl_original_password.GetValue()
+        cmd = 'java -cp ' + jar_file + ' com.alibaba.druid.filter.config.ConfigTools ' + original_password
+        subp = subprocess.Popen(cmd,
+                                shell=True,
+                                stdin=subprocess.PIPE,
+                                stdout=subprocess.PIPE,
+                                stderr=subprocess.STDOUT,
+                                encoding='gbk')
+        out = subp.stdout.readlines()
+        if (out[0].find('错误') > -1):
+            show_message(','.join(out))
+            return
+
+        # 绑定值
+        self.m_text_ctrl_private_key.SetValue(out[0].replace(
+            '\n', '').split('privateKey:')[1])
+        self.m_text_ctrl_public_key.SetValue(out[1].replace(
+            '\n', '').split('publicKey:')[1])
+        self.m_text_ctrl_encrypt_password.SetValue(out[2].replace(
+            '\n', '').split('password:')[1])
+
+    def OnClickEventPrivateKeyCopy(self, event):
+        """复制私钥按钮事件"""
+        text = self.m_text_ctrl_private_key.GetValue()
+        if len(text) > 0:
+            pyperclip.copy(text)
+            show_message('私钥已复制到剪切板')
+        else:
+            show_message('请生成秘钥')
+
+    def OnClickEventPublicKeyCopy(self, event):
+        """复制公钥按钮事件"""
+        text = self.m_text_ctrl_public_key.GetValue()
+        if len(text) > 0:
+            pyperclip.copy(text)
+            show_message('公钥已复制到剪切板')
+        else:
+            show_message('请生成秘钥')
+
+    def OnClickEventEncryptPasswordCopy(self, event):
+        """复制密码按钮事件"""
+        text = self.m_text_ctrl_encrypt_password.GetValue()
+        if len(text) > 0:
+            pyperclip.copy(text)
+            show_message('密码已复制到剪切板')
+        else:
+            show_message('请生成密码')
+
+    def OnClickEventClear(self, event):
+        """清空按钮事件"""
+        self.m_text_ctrl_original_password.SetValue('')
+        self.m_text_ctrl_original_password.SetFocus()
+        self.m_text_ctrl_private_key.SetValue('')
+        self.m_text_ctrl_public_key.SetValue('')
+        self.m_text_ctrl_encrypt_password.SetValue('')

+ 302 - 0
ui/main/main.py

@@ -0,0 +1,302 @@
+# -*- coding: utf-8 -*-
+# @Time : 2019/8/24 17:58
+# @Author : ricky
+# @File : main.py
+# @Software: vscode
+"""主界面"""
+import os
+import subprocess
+import threading
+import zipfile
+import datetime
+import wx
+import wx.adv
+import ui.main.main_frame as main_frame
+import ui.config.config as config
+import ui.reward.reward as reward
+import ui.about.about as about
+import ui.druid.druidencrypt as druidencrypt
+from loguru import logger
+from constant import constant
+from spider import upgradespider
+from utils import configini
+from utils import pathutil
+from core import ruoyi
+from core import ruoyicloud
+from core import ruoyifast
+from core import ruoyivue
+
+
+def show_message(message):
+    """
+    统一显示对话框
+
+    参数:
+        message (str): 对话框内容
+    """
+    wx.MessageDialog(None, message, '操作提醒', wx.OK).ShowModal()
+
+
+def show_operate_log(self, log):
+    """
+    统一显示日志到控件
+
+    参数:
+        self (object): 当前对象
+        log (str): 日志内容
+    """
+    # 这里要在主线程更新UI,否则会报错
+    wx.CallAfter(self.m_text_log.AppendText, log + '\n')
+    self.m_text_log.ShowPosition(self.m_text_log.GetLastPosition())
+
+
+def alter_callback(self, message):
+    """
+    修改回调处理
+
+    参数:
+        self (object): 上下文对象
+        message (str): 消息
+    """
+    show_operate_log(self, message)
+
+
+def check_input(self):
+    """
+    校验输入框
+
+    参数:
+        self (object): 当前对象
+    Return:
+        提示消息,校验通过返回''
+    """
+    message = ''
+    # 验证输入框是否有值
+    if len(self.m_text_ctrl_project_dir_name.GetValue()) == 0:
+        message = '请填写目录名称'
+    if len(self.m_text_ctrl_project_name.GetValue()) == 0:
+        message = '请填写项目名'
+    if len(self.m_text_ctrl_package_name.GetValue()) == 0:
+        message = '请填写包名'
+    if len(self.m_text_ctrl_artifact_id.GetValue()) == 0:
+        message = '请填写artifactId'
+    if len(self.m_text_ctrl_group_id.GetValue()) == 0:
+        message = '请填写groupId'
+    if len(self.m_text_ctrl_site_name.GetValue()) == 0:
+        message = '请填写站点名称'
+    return message
+
+
+def start_task(self, select_path):
+    """
+    开始任务
+
+    参数:
+        self (object): 当前对象
+        select_path (str): 选择的文件路径
+    """
+    self.m_text_log.Clear()
+    show_operate_log(self, '任务开始!')
+    #禁用按钮
+    self.m_btn_start.Disable()
+    self.m_btn_clear.Disable()
+    self.m_btn_open_output_directory.Disable()
+    show_operate_log(self, '正在检测文件...')
+    file_path, file_name = os.path.split(select_path)
+    os.chdir(file_path)
+    # 检测文件是否通过
+    flag = False
+    with zipfile.ZipFile(file_name, 'r') as zip_file:
+        for item in zip_file.namelist():
+            if 'RuoYi' in item:
+                flag = True
+                show_operate_log(self, '文件检测完毕符合要求,正在解压请稍后...')
+                break
+    if flag is False:
+        #启用按钮
+        self.m_btn_start.Enable()
+        self.m_btn_clear.Enable()
+        show_operate_log(self, '压缩包不符合框架标准,请到官网下载框架后重试')
+        return
+    # 目标目录
+    target_dir = os.getcwd() + os.path.sep + datetime.datetime.now().strftime(
+        '%Y%m%d%H%M%S')
+    # 如果目标目录不存在,创建目录
+    if not os.path.exists(target_dir):
+        os.makedirs(target_dir)
+    # 解压到指定的文件夹
+    with zipfile.ZipFile(file_name, 'r') as zip_file:
+        zip_file.extractall(target_dir)
+
+    show_operate_log(self, '输出目录:' + target_dir)
+    show_operate_log(self, '解压完成,正在修改文件请稍后...')
+    # 读取配置文件
+    configdict = configini.Config().get_dict()
+    try:
+        rbm_index = self.m_radio_box_mode.GetSelection()
+        if rbm_index == 0:
+            ry = ruoyi.RuoYi(self, target_dir,
+                             self.m_text_ctrl_site_name.GetValue(),
+                             self.m_text_ctrl_project_dir_name.GetValue(),
+                             self.m_text_ctrl_package_name.GetValue(),
+                             self.m_text_ctrl_project_name.GetValue(),
+                             self.m_text_ctrl_artifact_id.GetValue(),
+                             self.m_text_ctrl_group_id.GetValue(), configdict,
+                             alter_callback)
+        elif rbm_index == 1:
+            ry = ruoyivue.RuoYiVue(
+                self, target_dir, self.m_text_ctrl_site_name.GetValue(),
+                self.m_text_ctrl_project_dir_name.GetValue(),
+                self.m_text_ctrl_package_name.GetValue(),
+                self.m_text_ctrl_project_name.GetValue(),
+                self.m_text_ctrl_artifact_id.GetValue(),
+                self.m_text_ctrl_group_id.GetValue(), configdict,
+                alter_callback)
+        elif rbm_index == 2:
+            ry = ruoyifast.RuoYiFast(
+                self, target_dir, self.m_text_ctrl_site_name.GetValue(),
+                self.m_text_ctrl_project_dir_name.GetValue(),
+                self.m_text_ctrl_package_name.GetValue(),
+                self.m_text_ctrl_project_name.GetValue(),
+                self.m_text_ctrl_artifact_id.GetValue(),
+                self.m_text_ctrl_group_id.GetValue(), configdict,
+                alter_callback)
+        elif rbm_index == 3:
+            ry = ruoyicloud.RuoYiCloud(
+                self, target_dir, self.m_text_ctrl_site_name.GetValue(),
+                self.m_text_ctrl_project_dir_name.GetValue(),
+                self.m_text_ctrl_package_name.GetValue(),
+                self.m_text_ctrl_project_name.GetValue(),
+                self.m_text_ctrl_artifact_id.GetValue(),
+                self.m_text_ctrl_group_id.GetValue(), configdict,
+                alter_callback)
+        else:
+            show_operate_log(self, '框架版本不支持,请到官网下载框架后重试')
+            return
+        #禁用按钮
+        self.m_btn_start.Disable()
+        self.m_btn_clear.Disable()
+
+        # 开始修改
+        ry.start()
+        logger.info('修改完成,输出目录:{}', target_dir)
+        globals()['output_directory'] = target_dir
+        self.m_btn_open_output_directory.Enable()
+    except Exception as err:
+        show_operate_log(self, '程序发生异常,请查看根目录下的日志文件(out.log)')
+        logger.error('任务发生异常:{}', err)
+    finally:
+        #启用按钮
+        self.m_btn_start.Enable()
+        self.m_btn_clear.Enable()
+        show_operate_log(self, '输出目录:' + target_dir)
+        show_operate_log(self, '任务结束!')
+
+
+class Main(main_frame.MainFrame):
+    def __init__(self, parent):
+        main_frame.MainFrame.__init__(self, parent)
+        self.icon = wx.Icon(pathutil.resource_path('img/favicon.ico'),
+                            wx.BITMAP_TYPE_ICO)
+        self.SetIcon(self.icon)
+
+        self.m_filePicker.GetPickerCtrl().SetLabel('选择文件')
+        self.m_filePicker.GetTextCtrl().SetHint('请选择从官网下载下来的“.zip”后缀的压缩文件')
+
+        self.m_text_ctrl_project_dir_name.SetHint('请输入目录名称')
+        self.m_text_ctrl_project_name.SetHint('请输入项目名称')
+        self.m_text_ctrl_package_name.SetHint('请输入包名')
+        self.m_text_ctrl_artifact_id.SetHint('请输入artifactId')
+        self.m_text_ctrl_group_id.SetHint('请输入groupId')
+        self.m_text_ctrl_site_name.SetHint('请输入站点名称')
+
+        self.m_statusbar.SetFieldsCount(4)  # 状态栏分成4个区域
+        #self.m_statusbar.SetStatusWidths([-5,-2]) #区域宽度比列,用负数
+        self.m_statusbar.SetStatusText('  软件版本:' + constant.APP_VERSION_STRING,
+                                       0)
+        self.m_statusbar.SetStatusText(
+            '  Python版本:' + constant.PYTHON_VERSION_STRING, 1)
+        self.m_statusbar.SetStatusText(
+            '  WxPython版本:' + constant.WXPYTHON_VERSION_STRING, 2)
+        self.m_statusbar.SetStatusText('  联系作者(RICKY):QQ11748854', 3)
+        self.Centre()
+
+    # 实现开始执行按钮的事件
+    def OnClickEventStart(self, event):
+        selectpath = self.m_filePicker.GetPath()
+        if len(selectpath) == 0:
+            show_message('请选择文件')
+            return
+        if selectpath.endswith('.zip') is False:
+            show_message('请选择标准的.zip文件')
+            return
+        if os.path.exists(selectpath) is False:
+            show_message('请选择有效的.zip文件')
+            return
+        message = check_input(self)
+        if len(message) != 0:
+            show_message(message)
+            return
+        dlg = wx.MessageDialog(None, '确认开始执行吗?', '操作提醒', wx.YES_NO)
+        if dlg.ShowModal() == wx.ID_YES:
+            dlg.Destroy()
+            t = threading.Thread(target=start_task, args=(
+                self,
+                selectpath,
+            ))
+            t.start()
+
+    # 实现退出菜单事件
+    def OnMenuClickEventExit(self, event):
+        dlg = wx.MessageDialog(None, '确认退出程序吗?', '退出提醒', wx.YES_NO)
+        if dlg.ShowModal() == wx.ID_YES:
+            self.Destroy()
+        dlg.Destroy()
+
+    def OnMenuClickEventConfig(self, event):
+        dlg = config.Config(self)
+        dlg.ShowModal()
+        dlg.Destroy()
+
+    # 实现清空按钮的事件
+    def OnClickEventClear(self, event):
+        self.m_filePicker.SetPath('')
+        self.m_text_ctrl_project_dir_name.SetValue('')
+        self.m_text_ctrl_project_name.SetValue('')
+        self.m_text_ctrl_package_name.SetValue('')
+        self.m_text_ctrl_artifact_id.SetValue('')
+        self.m_text_ctrl_group_id.SetValue('')
+        self.m_text_ctrl_site_name.SetValue('')
+        self.m_text_log.SetValue('')
+        self.m_btn_open_output_directory.Disable()
+        self.m_radio_box_mode.SetSelection(0)
+
+    # 实现打开输出目录按钮的事件
+    def OnClickEventOpenOutputDirectory(self, event):
+        directory = globals()['output_directory']
+        try:
+            os.startfile(directory)
+        except:
+            subprocess.Popen(['open', directory])
+
+    # 实现打赏作者事件
+    def OnMenuClickEventReward(self, event):
+        dlg = reward.Reward(self)
+        dlg.ShowModal()
+        dlg.Destroy()
+
+    # 实现druid秘钥生成事件
+    def OnMenuClickEventDruidEncrypt(self, event):
+        dlg = druidencrypt.DruidEncrypt(self)
+        dlg.ShowModal()
+        dlg.Destroy()
+
+    # 实现关于事件
+    def OnAbout(self, event):
+        dlg = about.About(self)
+        dlg.ShowModal()
+        dlg.Destroy()
+
+    # 实现检测更新事件
+    def OnUpgrade(self, event):
+        upgradespider.check(True)

+ 222 - 0
ui/main/main_frame.py

@@ -0,0 +1,222 @@
+# -*- coding: utf-8 -*-
+
+###########################################################################
+## Python code generated with wxFormBuilder (version Oct 26 2018)
+## http://www.wxformbuilder.org/
+##
+## PLEASE DO *NOT* EDIT THIS FILE!
+###########################################################################
+
+import wx
+import wx.xrc
+
+###########################################################################
+## Class MainFrame
+###########################################################################
+
+class MainFrame ( wx.Frame ):
+
+	def __init__( self, parent ):
+		wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"若依框架修改器", pos = wx.DefaultPosition, size = wx.Size( 800,550 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
+
+		self.SetSizeHints( wx.Size( 800,550 ), wx.Size( -1,-1 ) )
+		self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOW ) )
+
+		bSizer = wx.BoxSizer( wx.HORIZONTAL )
+
+		sbSizer2 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, wx.EmptyString ), wx.VERTICAL )
+
+		self.m_filePicker = wx.FilePickerCtrl( sbSizer2.GetStaticBox(), wx.ID_ANY, wx.EmptyString, u"请选择.zip文件", u"*.zip", wx.DefaultPosition, wx.Size( -1,-1 ), wx.FLP_DEFAULT_STYLE )
+		self.m_filePicker.SetToolTip( u"请选择.zip文件" )
+
+		sbSizer2.Add( self.m_filePicker, 0, wx.ALL|wx.EXPAND, 5 )
+
+		m_radio_box_modeChoices = [ u"RuoYi标准版", u"RuoYi-Vue", u"RuoYi-fast", u"RuoYi-Cloud" ]
+		self.m_radio_box_mode = wx.RadioBox( sbSizer2.GetStaticBox(), wx.ID_ANY, u"框架版本", wx.DefaultPosition, wx.Size( -1,-1 ), m_radio_box_modeChoices, 1, wx.RA_SPECIFY_ROWS )
+		self.m_radio_box_mode.SetSelection( 0 )
+		sbSizer2.Add( self.m_radio_box_mode, 0, wx.ALL|wx.EXPAND, 5 )
+
+		sbSizer4 = wx.StaticBoxSizer( wx.StaticBox( sbSizer2.GetStaticBox(), wx.ID_ANY, u"修改内容" ), wx.VERTICAL )
+
+		gSizer1 = wx.GridSizer( 6, 2, 0, 0 )
+
+		self.m_static_text_project_dir_name = wx.StaticText( sbSizer4.GetStaticBox(), wx.ID_ANY, u"目录名称(示例:RuoYi)", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_static_text_project_dir_name.Wrap( -1 )
+
+		gSizer1.Add( self.m_static_text_project_dir_name, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
+
+		self.m_text_ctrl_project_dir_name = wx.TextCtrl( sbSizer4.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+		gSizer1.Add( self.m_text_ctrl_project_dir_name, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND, 5 )
+
+		self.m_static_text_project_name = wx.StaticText( sbSizer4.GetStaticBox(), wx.ID_ANY, u"项目名(示例:ruoyi)", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_static_text_project_name.Wrap( -1 )
+
+		gSizer1.Add( self.m_static_text_project_name, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
+
+		self.m_text_ctrl_project_name = wx.TextCtrl( sbSizer4.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+		gSizer1.Add( self.m_text_ctrl_project_name, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND, 5 )
+
+		self.m_static_text_package_name = wx.StaticText( sbSizer4.GetStaticBox(), wx.ID_ANY, u"包名(示例:com.ruoyi)", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_static_text_package_name.Wrap( -1 )
+
+		gSizer1.Add( self.m_static_text_package_name, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
+
+		self.m_text_ctrl_package_name = wx.TextCtrl( sbSizer4.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_text_ctrl_package_name.SetToolTip( u"不限制级数" )
+
+		gSizer1.Add( self.m_text_ctrl_package_name, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND, 5 )
+
+		self.m_static_text_artifact_id = wx.StaticText( sbSizer4.GetStaticBox(), wx.ID_ANY, u"artifactId(示例:ruoyi)", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_static_text_artifact_id.Wrap( -1 )
+
+		gSizer1.Add( self.m_static_text_artifact_id, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
+
+		self.m_text_ctrl_artifact_id = wx.TextCtrl( sbSizer4.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+		gSizer1.Add( self.m_text_ctrl_artifact_id, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND, 5 )
+
+		self.m_static_text_group_id = wx.StaticText( sbSizer4.GetStaticBox(), wx.ID_ANY, u"groupId(示例:com.ruoyi)", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_static_text_group_id.Wrap( -1 )
+
+		gSizer1.Add( self.m_static_text_group_id, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
+
+		self.m_text_ctrl_group_id = wx.TextCtrl( sbSizer4.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_text_ctrl_group_id.SetToolTip( u"不限制级数" )
+
+		gSizer1.Add( self.m_text_ctrl_group_id, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND, 5 )
+
+		self.m_static_text_site_name = wx.StaticText( sbSizer4.GetStaticBox(), wx.ID_ANY, u"站点名称(示例:若依管理系统)", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_static_text_site_name.Wrap( -1 )
+
+		gSizer1.Add( self.m_static_text_site_name, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
+
+		self.m_text_ctrl_site_name = wx.TextCtrl( sbSizer4.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
+		gSizer1.Add( self.m_text_ctrl_site_name, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND, 5 )
+
+
+		sbSizer4.Add( gSizer1, 1, wx.EXPAND, 5 )
+
+
+		sbSizer2.Add( sbSizer4, 0, wx.ALL|wx.EXPAND, 5 )
+
+		bSizer6 = wx.BoxSizer( wx.VERTICAL )
+
+		bSizer3 = wx.BoxSizer( wx.HORIZONTAL )
+
+		self.m_btn_start = wx.Button( sbSizer2.GetStaticBox(), wx.ID_ANY, u"开始执行", wx.DefaultPosition, wx.Size( -1,-1 ), 0 )
+		bSizer3.Add( self.m_btn_start, 0, wx.ALL, 5 )
+
+		self.m_btn_clear = wx.Button( sbSizer2.GetStaticBox(), wx.ID_ANY, u"清空", wx.DefaultPosition, wx.DefaultSize, 0 )
+		bSizer3.Add( self.m_btn_clear, 0, wx.ALL, 5 )
+
+		self.m_btn_open_output_directory = wx.Button( sbSizer2.GetStaticBox(), wx.ID_ANY, u"打开输出目录", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_btn_open_output_directory.Enable( False )
+
+		bSizer3.Add( self.m_btn_open_output_directory, 0, wx.ALL, 5 )
+
+		self.m_btn_reward = wx.Button( sbSizer2.GetStaticBox(), wx.ID_ANY, u"朕要赏(F8)", wx.DefaultPosition, wx.DefaultSize, 0 )
+		bSizer3.Add( self.m_btn_reward, 0, wx.ALL, 5 )
+
+		bSizer6.Add( bSizer3, 1, wx.EXPAND, 5 )
+
+		self.m_static_text_tip1 = wx.StaticText( sbSizer2.GetStaticBox(), wx.ID_ANY, u"注:需要修改其他参数可以打开\"文件\">\"配置参数\"(F6)进行设置", wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_static_text_tip1.Wrap( -1 )
+
+		bSizer6.Add( self.m_static_text_tip1, 0, wx.ALL, 5 )
+
+
+		sbSizer2.Add( bSizer6, 0, wx.EXPAND, 5 )
+
+
+		bSizer.Add( sbSizer2, 0, wx.ALL|wx.EXPAND, 5 )
+
+		sbSizer3 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"操作记录" ), wx.VERTICAL )
+
+		self.m_text_log = wx.TextCtrl( sbSizer3.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE|wx.TE_READONLY )
+		sbSizer3.Add( self.m_text_log, 1, wx.ALL|wx.EXPAND, 5 )
+
+
+		bSizer.Add( sbSizer3, 1, wx.ALL|wx.EXPAND, 5 )
+
+
+		self.SetSizer( bSizer )
+		self.Layout()
+		self.m_menubar = wx.MenuBar( 0 )
+		self.m_file = wx.Menu()
+		self.m_menu_item_config = wx.MenuItem( self.m_file, wx.ID_ANY, u"配置参数"+ u"\t" + u"F6", wx.EmptyString, wx.ITEM_NORMAL )
+		self.m_file.Append( self.m_menu_item_config )
+
+		self.m_menu_item_exit = wx.MenuItem( self.m_file, wx.ID_ANY, u"退出程序"+ u"\t" + u"Alt+F4", wx.EmptyString, wx.ITEM_NORMAL )
+		self.m_file.Append( self.m_menu_item_exit )
+
+		self.m_menubar.Append( self.m_file, u"文件" )
+
+		self.m_menu_other = wx.Menu()
+		self.m_menu_item_druid_encrypt = wx.MenuItem( self.m_menu_other, wx.ID_ANY, u"druid秘钥生成", wx.EmptyString, wx.ITEM_NORMAL )
+		self.m_menu_other.Append( self.m_menu_item_druid_encrypt )
+
+		self.m_menubar.Append( self.m_menu_other, u"工具" )
+
+		self.m_menu_help = wx.Menu()
+		self.m_menu_item_reward = wx.MenuItem( self.m_menu_help, wx.ID_ANY, u"打赏作者"+ u"\t" + u"F8", wx.EmptyString, wx.ITEM_NORMAL )
+		self.m_menu_help.Append( self.m_menu_item_reward )
+		self.m_menu_item_about = wx.MenuItem( self.m_menu_help, wx.ID_ANY, u"关于我们"+ u"\t" + u"F1", wx.EmptyString, wx.ITEM_NORMAL )
+		self.m_menu_help.Append( self.m_menu_item_about )
+
+		self.m_menu_item_upgrade = wx.MenuItem( self.m_menu_help, wx.ID_ANY, u"检测更新", wx.EmptyString, wx.ITEM_NORMAL )
+		self.m_menu_help.Append( self.m_menu_item_upgrade )
+
+		self.m_menubar.Append( self.m_menu_help, u"帮助" )
+
+		self.SetMenuBar( self.m_menubar )
+
+		self.m_statusbar = self.CreateStatusBar( 1, wx.STB_SIZEGRIP, wx.ID_ANY )
+
+		self.Centre( wx.HORIZONTAL )
+
+		# Connect Events
+		self.Bind( wx.EVT_CLOSE, self.OnMenuClickEventExit )
+		self.m_btn_start.Bind( wx.EVT_BUTTON, self.OnClickEventStart )
+		self.m_btn_clear.Bind( wx.EVT_BUTTON, self.OnClickEventClear )
+		self.m_btn_open_output_directory.Bind( wx.EVT_BUTTON, self.OnClickEventOpenOutputDirectory )
+		self.m_btn_reward.Bind( wx.EVT_BUTTON, self.OnMenuClickEventReward )
+		self.Bind( wx.EVT_MENU, self.OnMenuClickEventExit, id = self.m_menu_item_exit.GetId() )
+		self.Bind( wx.EVT_MENU, self.OnMenuClickEventConfig, id = self.m_menu_item_config.GetId() )
+		self.Bind( wx.EVT_MENU, self.OnMenuClickEventReward, id = self.m_menu_item_reward.GetId() )
+		self.Bind( wx.EVT_MENU, self.OnMenuClickEventDruidEncrypt, id = self.m_menu_item_druid_encrypt.GetId() )
+		self.Bind( wx.EVT_MENU, self.OnAbout, id = self.m_menu_item_about.GetId() )
+		self.Bind( wx.EVT_MENU, self.OnUpgrade, id = self.m_menu_item_upgrade.GetId() )
+
+	def __del__( self ):
+		pass
+
+
+	# Virtual event handlers, overide them in your derived class
+	def OnMenuClickEventExit( self, event ):
+		event.Skip()
+
+	def OnMenuClickEventConfig( self, event ):
+		event.Skip()
+
+	def OnClickEventStart( self, event ):
+		event.Skip()
+
+	def OnClickEventClear( self, event ):
+		event.Skip()
+
+	def OnClickEventOpenOutputDirectory( self, event ):
+		event.Skip()
+	
+	def OnMenuClickEventReward( self, event ):
+		event.Skip()
+
+	def OnMenuClickEventDruidEncrypt( self, event ):
+		event.Skip()
+
+	def OnAbout( self, event ):
+		event.Skip()
+
+	def OnUpgrade( self, event ):
+		event.Skip()
+		
+
+

+ 1 - 0
ui/reward/__init__.py

@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-

+ 32 - 0
ui/reward/reward.py

@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/02/23
+# @Author : ricky
+# @File : reward.py
+# @Software: vscode
+"""
+打赏页面
+"""
+import wx
+import ui.reward.reward_dialog as dialog
+from utils import pathutil
+
+
+class Reward(dialog.RewardDialog):
+    def __init__(self, parent):
+        dialog.RewardDialog.__init__(self, parent)
+        image_file = pathutil.resource_path('img/wx_reward.png')
+        image = wx.Image(image_file, wx.BITMAP_TYPE_ANY)
+        image.Rescale(300, 300, wx.IMAGE_QUALITY_HIGH)
+        bitmap = image.ConvertToBitmap()
+        self.m_bitmap_wx.SetBitmap(bitmap)
+        self.Centre()
+
+    def OnOk(self, event):
+        self.EndModal(wx.ID_OK)
+        wx.MessageDialog(None, '谢谢您的打赏!保佑您的代码永无BUG!', '亲爱的帅哥美女大老板:',
+                         wx.OK).ShowModal()
+
+    def OnCancel(self, event):
+        self.EndModal(wx.ID_CANCEL)
+        wx.MessageDialog(None, '加油努力挣大钱!全面小康,就靠您赏!', '亲爱的帅哥美女大老板:',
+                         wx.OK).ShowModal()

+ 65 - 0
ui/reward/reward_dialog.py

@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+
+###########################################################################
+## Python code generated with wxFormBuilder (version Oct 26 2018)
+## http://www.wxformbuilder.org/
+##
+## PLEASE DO *NOT* EDIT THIS FILE!
+###########################################################################
+
+import wx
+import wx.xrc
+
+###########################################################################
+## Class RewardDialog
+###########################################################################
+
+class RewardDialog ( wx.Dialog ):
+
+	def __init__( self, parent ):
+		wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"打赏作者", pos = wx.DefaultPosition, size = wx.Size( 389,381 ), style = wx.DEFAULT_DIALOG_STYLE )
+
+		self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
+		self.SetBackgroundColour( wx.Colour( 255, 255, 255 ) )
+
+		bSizer = wx.BoxSizer( wx.VERTICAL )
+
+		self.m_bitmap_wx = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 )
+		self.m_bitmap_wx.SetBackgroundColour( wx.Colour( 255, 255, 255 ) )
+		bSizer.Add( self.m_bitmap_wx, 1, wx.ALL|wx.EXPAND, 0 )
+
+		self.m_static_line2 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
+		bSizer.Add( self.m_static_line2, 0, wx.EXPAND |wx.ALL, 0 )
+
+		bSizer3 = wx.BoxSizer( wx.HORIZONTAL )
+
+		self.m_button_ok = wx.Button( self, wx.ID_ANY, u"赏你了!", wx.DefaultPosition, wx.DefaultSize, 0 )
+		bSizer3.Add( self.m_button_ok, 0, wx.ALL, 5 )
+
+		self.m_button_no = wx.Button( self, wx.ID_ANY, u"不富裕,不打赏了", wx.DefaultPosition, wx.DefaultSize, 0 )
+		bSizer3.Add( self.m_button_no, 0, wx.ALL, 5 )
+
+
+		bSizer.Add( bSizer3, 0, wx.ALIGN_RIGHT, 5 )
+
+
+		self.SetSizer( bSizer )
+		self.Layout()
+
+		self.Centre( wx.BOTH )
+
+		# Connect Events
+		self.Bind( wx.EVT_CLOSE, self.OnCancel )
+		self.m_button_ok.Bind( wx.EVT_BUTTON, self.OnOk )
+		self.m_button_no.Bind( wx.EVT_BUTTON, self.OnCancel )
+
+	def __del__( self ):
+		pass
+
+	# Virtual event handlers, overide them in your derived class
+	def OnOk( self, event ):
+		event.Skip()
+	
+	def OnCancel( self, event ):
+		event.Skip()
+

+ 8 - 0
utils/__init__.py

@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+"""
+工具类模块
+"""
+import utils.aescrypt as aescrypt
+import utils.configini as configini
+import utils.pathutil as pathutil
+import utils.globalvalues as globalvalues

+ 49 - 0
utils/aescrypt.py

@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/02/20
+# @Author : ricky
+# @File : aescrypt.py
+# @Software: vscode
+"""
+AES加解密
+"""
+from Crypto.Cipher import AES
+import base64
+
+AES_LENGTH = 16
+
+
+class AesCrypt():
+    def __init__(self, key='ngf8t58XzWMYSMLK'):
+        self.key = self.add_16(key)
+        self.mode = AES.MODE_ECB
+        self.aes = AES.new(self.key, self.mode)
+
+    def add_16(self, par):
+        if type(par) == str:
+            par = par.encode()
+        while len(par) % 16 != 0:
+            par += b'\x00'
+        return par
+
+    def encrypt(self, text):
+        """
+        加密
+
+        参数:
+            text:明文
+        """
+        text = self.add_16(text)
+        self.encrypt_text = self.aes.encrypt(text)
+        return str(base64.encodebytes(self.encrypt_text),
+                   encoding='utf-8').strip('\0')
+
+    def decrypt(self, text):
+        """
+        解密
+
+        参数:
+            text:密文
+        """
+        text = base64.decodebytes(text.encode(encoding='utf-8'))
+        self.decrypt_text = self.aes.decrypt(text).strip(b"\x00")
+        return str(self.decrypt_text, encoding='utf-8')

+ 92 - 0
utils/configini.py

@@ -0,0 +1,92 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/02/22
+# @Author : ricky
+# @File : configini.py
+# @Software: vscode
+"""
+系统配置类
+"""
+import configparser
+import os
+
+from utils import globalvalues
+from utils import aescrypt
+
+
+class Config:
+    """
+    系统配置类
+    """
+    
+    # 敏感属性
+    __SENSITIVE_TUPLE = ('password', 'pass', 'pwd')
+    
+    def __init__(self, filepath=None):
+        if filepath:
+            config_path = filepath
+        else:
+            config_path = os.path.join(os.path.abspath('.'), 'config.ini')
+        if len(globalvalues.CONFIG_INI_PATH) == 0:
+            globalvalues.CONFIG_INI_PATH = config_path
+        self.config_parser = configparser.ConfigParser()
+        if not os.path.exists(globalvalues.CONFIG_INI_PATH):
+            self.config_parser['config'] = {'enable': False}
+            self.write()
+        self.config_parser.read(globalvalues.CONFIG_INI_PATH)
+        self.crypt = aescrypt.AesCrypt()
+
+    def get_value(self, section, key):
+        """
+        根据section和key获取value
+
+        参数:
+            section: 节点
+            key: 键
+        返回:
+            value: 值
+        """
+        if not self.config_parser.has_section(section):
+            return ''
+        value = self.config_parser.get(section, key)
+        if key in self.__SENSITIVE_TUPLE:
+            value = self.crypt.decrypt(value)
+        return value
+
+    def get_dict(self):
+        """
+        获取配置字典
+        
+        返回:
+            字典类型数据
+        """
+        d = {}
+        sections = self.config_parser.sections()
+        for s in sections:
+            items = self.config_parser.items(s)
+            for item in items:
+                k = item[0]
+                v = item[1]
+                if k in self.__SENSITIVE_TUPLE:
+                    v = self.crypt.decrypt(v)
+                d[s + '.' + k] = v
+        return d
+
+    def set_value(self, section, key, value):
+        """
+        根据section和key设置value
+
+        参数:
+            section: 节点
+            key: 键
+            value: 值
+        """
+        if not self.config_parser.has_section(section):
+            self.config_parser.add_section(section)
+        if key in self.__SENSITIVE_TUPLE:
+            value = self.crypt.encrypt(value).replace('\n','') 
+        self.config_parser.set(section, key, value)
+
+    def write(self):
+        """写入配置文件"""
+        with open(globalvalues.CONFIG_INI_PATH, 'w+') as config_file:
+            self.config_parser.write(config_file)

+ 10 - 0
utils/globalvalues.py

@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/02/22
+# @Author : ricky
+# @File : globalvalues.py
+# @Software: vscode
+"""
+全局变量
+"""
+CONFIG_INI_PATH = ''
+EXE_PATH = ''

+ 34 - 0
utils/pathutil.py

@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# @Time : 2021/02/20
+# @Author : ricky
+# @File : pathutil.py
+# @Software: vscode
+"""
+路径工具类
+"""
+import os
+import sys
+from utils import globalvalues
+
+
+def resource_path(relative_path):
+    """
+    返回资源绝对路径
+    
+    参数:
+        relative_path (str): 相对路径或者资源名称
+    返回:
+        绝对路径(带临时目录的)
+    """
+    if hasattr(sys, '_MEIPASS'):
+        # PyInstaller会创建临时文件夹temp
+        # 并把路径存储在_MEIPASS中
+        exepath = sys._MEIPASS
+    else:
+        exepath = os.path.abspath('.')
+        if len(globalvalues.EXE_PATH) > 0:
+            exepath = globalvalues.EXE_PATH
+        else:
+            globalvalues.EXE_PATH = exepath
+
+    return os.path.join(exepath, relative_path)