yue 7 月之前
父节点
当前提交
22b81a185c
共有 33 个文件被更改,包括 844 次插入538 次删除
  1. 5 5
      SourceCode/IntelligentRailwayCosting/app/config.yml
  2. 5 5
      SourceCode/IntelligentRailwayCosting/app/core/api/response.py
  3. 11 11
      SourceCode/IntelligentRailwayCosting/app/executor/task_processor.py
  4. 14 6
      SourceCode/IntelligentRailwayCosting/app/executor/task_runner.py
  5. 23 13
      SourceCode/IntelligentRailwayCosting/app/flask_app/__init__.py
  6. 2 1
      SourceCode/IntelligentRailwayCosting/app/routes/__init__.py
  7. 28 20
      SourceCode/IntelligentRailwayCosting/app/routes/auth.py
  8. 24 15
      SourceCode/IntelligentRailwayCosting/app/routes/log.py
  9. 1 1
      SourceCode/IntelligentRailwayCosting/app/routes/project_quota.py
  10. 74 61
      SourceCode/IntelligentRailwayCosting/app/routes/project_task.py
  11. 0 1
      SourceCode/IntelligentRailwayCosting/app/services/__init__.py
  12. 53 18
      SourceCode/IntelligentRailwayCosting/app/services/log.py
  13. 102 38
      SourceCode/IntelligentRailwayCosting/app/services/project.py
  14. 6 5
      SourceCode/IntelligentRailwayCosting/app/services/user.py
  15. 5 2
      SourceCode/IntelligentRailwayCosting/app/stores/__init__.py
  16. 2 2
      SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_mysql/__init__.py
  17. 31 31
      SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_mysql/log.py
  18. 81 54
      SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_mysql/project_quota.py
  19. 44 40
      SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_mysql/project_task.py
  20. 2 2
      SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_sqlserver/__init__.py
  21. 32 32
      SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_sqlserver/log.py
  22. 44 40
      SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_sqlserver/project_task.py
  23. 65 49
      SourceCode/IntelligentRailwayCosting/app/tools/db_helper/mysql_helper.py
  24. 53 34
      SourceCode/IntelligentRailwayCosting/app/tools/db_helper/sqlserver_helper.py
  25. 20 1
      SourceCode/IntelligentRailwayCosting/app/tools/utils/__init__.py
  26. 51 18
      SourceCode/IntelligentRailwayCosting/app/tools/utils/ai_helper.py
  27. 3 1
      SourceCode/IntelligentRailwayCosting/app/tools/utils/config_helper.py
  28. 13 6
      SourceCode/IntelligentRailwayCosting/app/tools/utils/file_helper.py
  29. 10 4
      SourceCode/IntelligentRailwayCosting/app/tools/utils/string_helper.py
  30. 2 1
      SourceCode/IntelligentRailwayCosting/app/views/__init__.py
  31. 11 9
      SourceCode/IntelligentRailwayCosting/app/views/log.py
  32. 4 3
      SourceCode/IntelligentRailwayCosting/app/views/login.py
  33. 23 9
      SourceCode/IntelligentRailwayCosting/app/views/project.py

+ 5 - 5
SourceCode/IntelligentRailwayCosting/app/config.yml

@@ -26,7 +26,7 @@ db:
   sqlserver_mian_2020:
   sqlserver_mian_2020:
     driver: '{ODBC Driver 17 for SQL Server}'
     driver: '{ODBC Driver 17 for SQL Server}'
     server: 192.168.0.81,1433
     server: 192.168.0.81,1433
-#    server: shvber.com,5030
+    #    server: shvber.com,5030
     username: iwb
     username: iwb
     password: 123456Qsc
     password: 123456Qsc
     database: Iwb_RecoData2020
     database: Iwb_RecoData2020
@@ -34,7 +34,7 @@ db:
   Iwb_RailwayCosting:
   Iwb_RailwayCosting:
     driver: '{ODBC Driver 17 for SQL Server}'
     driver: '{ODBC Driver 17 for SQL Server}'
     server: 192.168.0.81,1433
     server: 192.168.0.81,1433
-#    server: shvber.com,5030
+    #    server: shvber.com,5030
     username: iwb
     username: iwb
     password: 123456Qsc
     password: 123456Qsc
     database: iwb_railway_costing_v1
     database: iwb_railway_costing_v1
@@ -44,9 +44,9 @@ db:
     server: 192.168.0.81,1433
     server: 192.168.0.81,1433
     username: iwb
     username: iwb
     password: 123456Qsc
     password: 123456Qsc
-#    server: shvber.com,50535
-#    username: sa
-#    password: Iwb2017
+    #    server: shvber.com,50535
+    #    username: sa
+    #    password: Iwb2017
     database: Iwb_RecoData2024
     database: Iwb_RecoData2024
     trusted_connection: false
     trusted_connection: false
   Iwb_RecoData2020:
   Iwb_RecoData2020:

+ 5 - 5
SourceCode/IntelligentRailwayCosting/app/core/api/response.py

@@ -33,7 +33,7 @@ class ResponseBase:
 
 
     @staticmethod
     @staticmethod
     def error(
     def error(
-            message: str = "操作失败", code: int = 400, data: Optional[Any] = None
+        message: str = "操作失败", code: int = 400, data: Optional[Any] = None
     ) -> Response:
     ) -> Response:
         """错误响应
         """错误响应
         Args:
         Args:
@@ -51,10 +51,10 @@ class ResponseBase:
 
 
     @staticmethod
     @staticmethod
     def json_response(
     def json_response(
-            success: bool = True,
-            code: int = 200,
-            message: str = "",
-            data: Optional[Any] = None,
+        success: bool = True,
+        code: int = 200,
+        message: str = "",
+        data: Optional[Any] = None,
     ) -> Response:
     ) -> Response:
         """自定义响应
         """自定义响应
         Args:
         Args:

+ 11 - 11
SourceCode/IntelligentRailwayCosting/app/executor/task_processor.py

@@ -172,13 +172,13 @@ class TaskProcessor:
             return None, msg
             return None, msg
 
 
     def _build_api_body(
     def _build_api_body(
-            self,
-            task: ProjectTaskDto,
-            project: ProjectDto,
-            budgets: list[TotalBudgetInfoDto],
-            parents: list[ChapterDto],
-            children: list[ChapterDto],
-            files: list[ExcelParseFileDto],
+        self,
+        task: ProjectTaskDto,
+        project: ProjectDto,
+        budgets: list[TotalBudgetInfoDto],
+        parents: list[ChapterDto],
+        children: list[ChapterDto],
+        files: list[ExcelParseFileDto],
     ):
     ):
         try:
         try:
             budgets_data = [ExcelParseZgsDto.from_dto(budget) for budget in budgets]
             budgets_data = [ExcelParseZgsDto.from_dto(budget) for budget in budgets]
@@ -226,10 +226,10 @@ class TaskProcessor:
             raise Exception(msg)
             raise Exception(msg)
 
 
     def _insert_data(
     def _insert_data(
-            self,
-            task: ProjectTaskDto,
-            project: ProjectDto,
-            data: list[ExcelParseResultDataDto],
+        self,
+        task: ProjectTaskDto,
+        project: ProjectDto,
+        data: list[ExcelParseResultDataDto],
     ):
     ):
         try:
         try:
             self._logger.debug(f"开始插入数据:{task.task_name}")
             self._logger.debug(f"开始插入数据:{task.task_name}")

+ 14 - 6
SourceCode/IntelligentRailwayCosting/app/executor/task_runner.py

@@ -20,6 +20,8 @@ class TaskRunner:
     _task_store = ProjectTaskStore()
     _task_store = ProjectTaskStore()
     _lock = threading.Lock()
     _lock = threading.Lock()
     _task_processor = None
     _task_processor = None
+    _task_empty_wait_count = 0
+    _task_empty_wait_max_count = 20
 
 
     @classmethod
     @classmethod
     def run_task(cls, task: ProjectTaskDto):
     def run_task(cls, task: ProjectTaskDto):
@@ -263,18 +265,24 @@ class TaskRunner:
             if total_tasks > 0:
             if total_tasks > 0:
                 if len(cls._running_projects) < cls._max_concurrent_projects:
                 if len(cls._running_projects) < cls._max_concurrent_projects:
                     cls._logger.debug(f"同步待运行队列,同步{total_tasks}条数据,运行")
                     cls._logger.debug(f"同步待运行队列,同步{total_tasks}条数据,运行")
+                    cls._task_empty_wait_count = 0
                     cls._run()
                     cls._run()
                 else:
                 else:
                     cls._logger.debug(
                     cls._logger.debug(
                         f"同步待运行队列,同步{total_tasks}条数据。暂无空闲线程,稍后运行"
                         f"同步待运行队列,同步{total_tasks}条数据。暂无空闲线程,稍后运行"
                     )
                     )
             else:
             else:
-                cls._logger.info(
-                    f"同步待运行队列,无新增数据,等待{cls._task_sleep_interval}秒后同步数据运行"
-                )
-                sleep(cls._task_sleep_interval)
-                cls._sync_wait_list()
-
+                cls._task_empty_wait_count += 1
+                if cls._task_empty_wait_count < cls._task_empty_wait_max_count:
+                    cls._logger.info(
+                        f"同步待运行队列,无新增数据,等待{cls._task_sleep_interval}秒后同步数据运行,已连续 {cls._task_empty_wait_count} 次无新增数据"
+                    )
+                    sleep(cls._task_sleep_interval)
+                    cls._sync_wait_list()
+                else:
+                    cls._logger.info(
+                        f"同步待运行队列,无新增数据,等待{cls._task_sleep_interval}秒后同步数据运行,已连续 {cls._task_empty_wait_count} 次无新增数据,已超过最大等待次数,停止运行"
+                    )
             return total_tasks
             return total_tasks
         except Exception as e:
         except Exception as e:
             msg = f"同步待运行队列失败,原因:{e}"
             msg = f"同步待运行队列失败,原因:{e}"

+ 23 - 13
SourceCode/IntelligentRailwayCosting/app/flask_app/__init__.py

@@ -13,18 +13,26 @@ class CustomJSONProvider(JSONProvider):
             return str(obj)
             return str(obj)
 
 
     def encode(self, obj):
     def encode(self, obj):
-        return super().encode(obj).encode('utf-8').decode('unicode_escape')
+        return super().encode(obj).encode("utf-8").decode("unicode_escape")
 
 
 
 
 def create_app():
 def create_app():
-    app = Flask(__name__, static_folder='../views/static')
+    app = Flask(__name__, static_folder="../views/static")
     app.secret_key = "1qwe2iwb3vber"
     app.secret_key = "1qwe2iwb3vber"
-    app.config['JSON_AS_ASCII'] = False
-    app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 限制上传文件大小为16MB
-    app.config['UPLOAD_EXTENSIONS'] = ['.jpg', '.png', '.pdf', '.doc', '.docx', '.xls', '.xlsx']  # 允许的文件类型
-    app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
-    app.config['PRESERVE_CONTEXT_ON_EXCEPTION'] = False
-    app.config['REQUEST_BODY_LIMIT'] = '16MB'
+    app.config["JSON_AS_ASCII"] = False
+    app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024  # 限制上传文件大小为16MB
+    app.config["UPLOAD_EXTENSIONS"] = [
+        ".jpg",
+        ".png",
+        ".pdf",
+        ".doc",
+        ".docx",
+        ".xls",
+        ".xlsx",
+    ]  # 允许的文件类型
+    app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024
+    app.config["PRESERVE_CONTEXT_ON_EXCEPTION"] = False
+    app.config["REQUEST_BODY_LIMIT"] = "16MB"
     app.json_provider_class = CustomJSONProvider
     app.json_provider_class = CustomJSONProvider
 
 
     login_manager.init_app(app)
     login_manager.init_app(app)
@@ -36,12 +44,14 @@ def create_app():
     # 注册自定义过滤器
     # 注册自定义过滤器
     for rule in app.url_map.iter_rules():
     for rule in app.url_map.iter_rules():
         route = {
         route = {
-            'endpoint': rule.endpoint,
-            'methods': sorted(rule.methods),
-            'path': str(rule)
+            "endpoint": rule.endpoint,
+            "methods": sorted(rule.methods),
+            "path": str(rule),
         }
         }
-        print(f"URL [{str(rule)}] ==> endpoint: {rule.endpoint}, methods: {sorted(rule.methods)}")
+        print(
+            f"URL [{str(rule)}] ==> endpoint: {rule.endpoint}, methods: {sorted(rule.methods)}"
+        )
     return app
     return app
 
 
 
 
-__all__ = ['create_app']
+__all__ = ["create_app"]

+ 2 - 1
SourceCode/IntelligentRailwayCosting/app/routes/__init__.py

@@ -5,8 +5,9 @@ from routes.project import project_api
 from routes.project_task import project_task_api
 from routes.project_task import project_task_api
 from routes.project_quota import project_quota_api
 from routes.project_quota import project_quota_api
 
 
+
 def register_api(app):
 def register_api(app):
-    url_prefix = '/api'
+    url_prefix = "/api"
     # API蓝图注册
     # API蓝图注册
     app.register_blueprint(auth_api, url_prefix=f"{url_prefix}/auth")
     app.register_blueprint(auth_api, url_prefix=f"{url_prefix}/auth")
     app.register_blueprint(log_api, url_prefix=f"{url_prefix}/log")
     app.register_blueprint(log_api, url_prefix=f"{url_prefix}/log")

+ 28 - 20
SourceCode/IntelligentRailwayCosting/app/routes/auth.py

@@ -1,18 +1,19 @@
 from flask import Blueprint, request, jsonify, session
 from flask import Blueprint, request, jsonify, session
 from flask_login import LoginManager, login_user, logout_user
 from flask_login import LoginManager, login_user, logout_user
 
 
-from core.log import  LogRecordHelper
-from core.enum import OperationType,OperationModule
-from core.api import  ResponseBase
-from core.user_session import  UserSession,CurrentUser
-from services import  UserService
+from core.log import LogRecordHelper
+from core.enum import OperationType, OperationModule
+from core.api import ResponseBase
+from core.user_session import UserSession, CurrentUser
+from services import UserService
 
 
-auth_api = Blueprint('auth_api', __name__)
+auth_api = Blueprint("auth_api", __name__)
 user_service = UserService()
 user_service = UserService()
 
 
 login_manager = LoginManager()
 login_manager = LoginManager()
-login_manager.login_view = 'auth_api.login'
-login_manager.login_message = '请先登录'
+login_manager.login_view = "auth_api.login"
+login_manager.login_message = "请先登录"
+
 
 
 @login_manager.user_loader
 @login_manager.user_loader
 def load_user(user_id):
 def load_user(user_id):
@@ -23,10 +24,10 @@ def load_user(user_id):
     return None
     return None
 
 
 
 
-@auth_api.route('/login', methods=['POST'])
+@auth_api.route("/login", methods=["POST"])
 def login():
 def login():
-    username = request.json.get('username')
-    password = request.json.get('password')
+    username = request.json.get("username")
+    password = request.json.get("password")
 
 
     # 调用UserService进行用户验证
     # 调用UserService进行用户验证
     user, msg = user_service.authenticate_user(username, password)
     user, msg = user_service.authenticate_user(username, password)
@@ -36,23 +37,30 @@ def login():
         login_user(current_user)
         login_user(current_user)
         UserSession.set_user(user)
         UserSession.set_user(user)
         # 记录日志
         # 记录日志
-        LogRecordHelper.log_success(OperationType.LOGIN, OperationModule.ACCOUNT, '用户登录成功', username=user.username)
+        LogRecordHelper.log_success(
+            OperationType.LOGIN,
+            OperationModule.ACCOUNT,
+            "用户登录成功",
+            username=user.username,
+        )
 
 
-        return ResponseBase.success({
-            'user_id': user.id,
-            'username': user.username
-        })
+        return ResponseBase.success({"user_id": user.id, "username": user.username})
     else:
     else:
         # 登录失败,返回错误信息
         # 登录失败,返回错误信息
         return ResponseBase.error(msg)
         return ResponseBase.error(msg)
 
 
 
 
-@auth_api.route('/logout', methods=['POST'])
+@auth_api.route("/logout", methods=["POST"])
 def logout():
 def logout():
-    username = session.get('username')
+    username = session.get("username")
     if username:
     if username:
         logout_user()
         logout_user()
         UserSession.clear_user()
         UserSession.clear_user()
-        LogRecordHelper.log_success(OperationType.LOGIN, OperationModule.ACCOUNT, '用户退出登录', username=username)
+        LogRecordHelper.log_success(
+            OperationType.LOGIN,
+            OperationModule.ACCOUNT,
+            "用户退出登录",
+            username=username,
+        )
         return jsonify(ResponseBase.success())
         return jsonify(ResponseBase.success())
-    return jsonify(ResponseBase.error('用户未登录'))
+    return jsonify(ResponseBase.error("用户未登录"))

+ 24 - 15
SourceCode/IntelligentRailwayCosting/app/routes/log.py

@@ -1,33 +1,42 @@
 from flask import Blueprint, request
 from flask import Blueprint, request
 from core.user_session import Permission
 from core.user_session import Permission
-from core.api import  ResponseBase,TableResponse
-from services import  LogService
+from core.api import ResponseBase, TableResponse
+from services import LogService
 
 
-log_api = Blueprint('log_api', __name__)
+log_api = Blueprint("log_api", __name__)
 log_service = LogService()
 log_service = LogService()
 
 
-@log_api.route('/list', methods=['POST'])
+
+@log_api.route("/list", methods=["POST"])
 @Permission.authorize
 @Permission.authorize
 def get_page_list():
 def get_page_list():
     try:
     try:
         data = request.get_json()
         data = request.get_json()
-        page = int(data.get('pageNum', 1))
-        per_page = int(data.get('pageSize', 10))
-        username = data.get('username')
-        operation_type = data.get('operationType')
-        operation_module = data.get('operationModule')
-        operation_result = data.get('operationResult')
+        page = int(data.get("pageNum", 1))
+        per_page = int(data.get("pageSize", 10))
+        username = data.get("username")
+        operation_type = data.get("operationType")
+        operation_module = data.get("operationModule")
+        operation_result = data.get("operationResult")
         operation_result = int(operation_result) if operation_result else None
         operation_result = int(operation_result) if operation_result else None
         start_date = None
         start_date = None
         end_date = None
         end_date = None
-        date = data.get('date')
+        date = data.get("date")
         if date:
         if date:
-            date = date.split(' - ')
+            date = date.split(" - ")
             start_date = date[0]
             start_date = date[0]
             end_date = date[1]
             end_date = date[1]
 
 
-        logs, total_count = log_service.get_logs_paginated(page, per_page, username, operation_type, operation_module, operation_result,
-                                                           start_date, end_date)
+        logs, total_count = log_service.get_logs_paginated(
+            page,
+            per_page,
+            username,
+            operation_type,
+            operation_module,
+            operation_result,
+            start_date,
+            end_date,
+        )
         return TableResponse.success(logs, total_count)
         return TableResponse.success(logs, total_count)
     except Exception as e:
     except Exception as e:
-        return ResponseBase.error(f'获取日志失败:{str(e)}')
+        return ResponseBase.error(f"获取日志失败:{str(e)}")

+ 1 - 1
SourceCode/IntelligentRailwayCosting/app/routes/project_quota.py

@@ -34,7 +34,7 @@ def get_page_list(budget_id: int, project_id: str, item_code: str):
 )
 )
 @Permission.authorize
 @Permission.authorize
 def get_quotas_by_task_paginated(
 def get_quotas_by_task_paginated(
-        task_id: int, budget_id: int, project_id: str, item_code: str
+    task_id: int, budget_id: int, project_id: str, item_code: str
 ):
 ):
     try:
     try:
         data = request.get_json()
         data = request.get_json()

+ 74 - 61
SourceCode/IntelligentRailwayCosting/app/routes/project_task.py

@@ -1,58 +1,64 @@
-from flask import Blueprint, request,send_from_directory
+from flask import Blueprint, request, send_from_directory
 import os
 import os
 from core.dtos import ProjectTaskDto
 from core.dtos import ProjectTaskDto
 from core.user_session import Permission
 from core.user_session import Permission
-from core.api import  ResponseBase,TableResponse
-from services import  ProjectTaskService
+from core.api import ResponseBase, TableResponse
+from services import ProjectTaskService
 
 
-project_task_api = Blueprint('project_task_api', __name__)
+project_task_api = Blueprint("project_task_api", __name__)
 task_service = ProjectTaskService()
 task_service = ProjectTaskService()
 
 
-@project_task_api.route('/list/<project_id>/<item_code>', methods=['POST'])
+
+@project_task_api.route("/list/<project_id>/<item_code>", methods=["POST"])
 @Permission.authorize
 @Permission.authorize
-def get_page_list(project_id:str,item_code:str):
+def get_page_list(project_id: str, item_code: str):
     try:
     try:
         data = request.get_json()
         data = request.get_json()
-        page = int(data.get('pageNum', 1))
-        per_page = int(data.get('pageSize', 10))
-        keyword = data.get('keyword')
-        process_status = int(data.get('process_status')) if data.get('process_status') else None
-        send_status = int(data.get('send_status')) if data.get('send_status') else None
-        task, total_count = task_service.get_tasks_paginated( project_id, item_code, page, per_page, keyword, process_status, send_status)
+        page = int(data.get("pageNum", 1))
+        per_page = int(data.get("pageSize", 10))
+        keyword = data.get("keyword")
+        process_status = (
+            int(data.get("process_status")) if data.get("process_status") else None
+        )
+        send_status = int(data.get("send_status")) if data.get("send_status") else None
+        task, total_count = task_service.get_tasks_paginated(
+            project_id, item_code, page, per_page, keyword, process_status, send_status
+        )
         return TableResponse.success(task, total_count)
         return TableResponse.success(task, total_count)
     except Exception as e:
     except Exception as e:
-        return ResponseBase.error(f'获取任务列表失败:{str(e)}')
+        return ResponseBase.error(f"获取任务列表失败:{str(e)}")
 
 
 
 
-@project_task_api.route('/get/<int:task_id>', methods=['POST'])
+@project_task_api.route("/get/<int:task_id>", methods=["POST"])
 @Permission.authorize
 @Permission.authorize
-def get_task(task_id:int):
+def get_task(task_id: int):
     try:
     try:
         task = task_service.get_task_dto(task_id)
         task = task_service.get_task_dto(task_id)
         return ResponseBase.success(task.to_dict())
         return ResponseBase.success(task.to_dict())
     except Exception as e:
     except Exception as e:
-        return ResponseBase.error(f'获取项目失败:{str(e)}')
+        return ResponseBase.error(f"获取项目失败:{str(e)}")
 
 
-@project_task_api.route('/save/<int:task_id>', methods=['POST'])
+
+@project_task_api.route("/save/<int:task_id>", methods=["POST"])
 @Permission.authorize
 @Permission.authorize
-def save_task(task_id:int):
+def save_task(task_id: int):
     try:
     try:
         # 从请求中获取表单数据
         # 从请求中获取表单数据
         form_data = request.form.to_dict()
         form_data = request.form.to_dict()
-        budget_id = int(form_data.get('budget_id')) if form_data.get('budget_id') else 0
-        item_id = int(form_data.get('item_id')) if form_data.get('item_id') else None
-        project_id = form_data.get('project_id')
-        item_code = form_data.get('item_code')
-        task_name = form_data.get('task_name')
-        task_desc = form_data.get('task_desc')
-        task_sort = int(form_data.get('task_sort')) if form_data.get('task_sort') else 0
-        run_now = form_data.get('run_now')=='true'
+        budget_id = int(form_data.get("budget_id")) if form_data.get("budget_id") else 0
+        item_id = int(form_data.get("item_id")) if form_data.get("item_id") else None
+        project_id = form_data.get("project_id")
+        item_code = form_data.get("item_code")
+        task_name = form_data.get("task_name")
+        task_desc = form_data.get("task_desc")
+        task_sort = int(form_data.get("task_sort")) if form_data.get("task_sort") else 0
+        run_now = form_data.get("run_now") == "true"
         # delete_old = form_data.get('delete_old', 'false').lower() == 'true'
         # delete_old = form_data.get('delete_old', 'false').lower() == 'true'
         # 获取上传的文件
         # 获取上传的文件
-        files = request.files.getlist('files')
+        files = request.files.getlist("files")
         # 验证必要参数
         # 验证必要参数
-        if not all([ project_id, task_name]):
-            return ResponseBase.error('缺少必要参数:project_id、task_name')
+        if not all([project_id, task_name]):
+            return ResponseBase.error("缺少必要参数:project_id、task_name")
         # 构建任务DTO
         # 构建任务DTO
         task_dto = ProjectTaskDto(
         task_dto = ProjectTaskDto(
             item_id=item_id,
             item_id=item_id,
@@ -62,53 +68,58 @@ def save_task(task_id:int):
             task_name=task_name,
             task_name=task_name,
             task_desc=task_desc,
             task_desc=task_desc,
             task_sort=task_sort,
             task_sort=task_sort,
-            file_path=None
+            file_path=None,
         )
         )
-        
+
         # 保存任务
         # 保存任务
         task = task_service.save_task(task_id, task_dto, files)
         task = task_service.save_task(task_id, task_dto, files)
-        msg =""
+        msg = ""
         if run_now:
         if run_now:
             msg = task_service.start_run_task(task.id)
             msg = task_service.start_run_task(task.id)
-            if msg == '0':
-                msg = '项目有正在运行的任务,已加入等待列表中'
+            if msg == "0":
+                msg = "项目有正在运行的任务,已加入等待列表中"
             elif msg:
             elif msg:
                 return ResponseBase.error(msg)
                 return ResponseBase.error(msg)
         return ResponseBase.success(task.to_dict(), msg)
         return ResponseBase.success(task.to_dict(), msg)
     except ValueError as ve:
     except ValueError as ve:
-        return ResponseBase.error(f'参数格式错误:{str(ve)}')
+        return ResponseBase.error(f"参数格式错误:{str(ve)}")
     except Exception as e:
     except Exception as e:
-        return ResponseBase.error(f'保存任务失败:{str(e)}')
+        return ResponseBase.error(f"保存任务失败:{str(e)}")
 
 
-@project_task_api.route('/delete/<int:task_id>', methods=['POST'])
+
+@project_task_api.route("/delete/<int:task_id>", methods=["POST"])
 @Permission.authorize
 @Permission.authorize
-def delete_task(task_id:int):
+def delete_task(task_id: int):
     try:
     try:
         task = task_service.delete_task(task_id)
         task = task_service.delete_task(task_id)
         return ResponseBase.success(task)
         return ResponseBase.success(task)
     except Exception as e:
     except Exception as e:
-        return ResponseBase.error(f'删除任务失败:{str(e)}')
+        return ResponseBase.error(f"删除任务失败:{str(e)}")
+
 
 
-@project_task_api.route('/download', methods=['POST'])
+@project_task_api.route("/download", methods=["POST"])
 @Permission.authorize
 @Permission.authorize
 def download_file():
 def download_file():
-    filename = request.args.get('filename', type=str)
+    filename = request.args.get("filename", type=str)
     if not filename:
     if not filename:
-        return ResponseBase.error('文件名不能为空')
+        return ResponseBase.error("文件名不能为空")
     try:
     try:
         # 安全处理文件名
         # 安全处理文件名
         pure_filename = os.path.basename(filename)
         pure_filename = os.path.basename(filename)
         safe_filename = os.path.basename(pure_filename)
         safe_filename = os.path.basename(pure_filename)
-        path = filename.replace(safe_filename, '')
+        path = filename.replace(safe_filename, "")
         upload_folder = os.path.abspath(os.path.join(os.getcwd(), path))
         upload_folder = os.path.abspath(os.path.join(os.getcwd(), path))
         if not os.path.exists(upload_folder):
         if not os.path.exists(upload_folder):
-            return ResponseBase.error('项目目录不存在')
+            return ResponseBase.error("项目目录不存在")
         full_path = os.path.join(upload_folder, safe_filename)
         full_path = os.path.join(upload_folder, safe_filename)
         if not os.path.exists(full_path):
         if not os.path.exists(full_path):
-            return ResponseBase.error('文件不存在')
+            return ResponseBase.error("文件不存在")
     except Exception as e:
     except Exception as e:
-        return ResponseBase.error(f'非法文件路径{str(e)}')
-    return send_from_directory(upload_folder.replace('\\', '/'), safe_filename, as_attachment=True)
+        return ResponseBase.error(f"非法文件路径{str(e)}")
+    return send_from_directory(
+        upload_folder.replace("\\", "/"), safe_filename, as_attachment=True
+    )
+
 
 
 # @project_task_api.route('/start_collect/<int:task_id>', methods=['POST'])
 # @project_task_api.route('/start_collect/<int:task_id>', methods=['POST'])
 # @Permission.authorize
 # @Permission.authorize
@@ -132,40 +143,42 @@ def download_file():
 #     except Exception as e:
 #     except Exception as e:
 #         return ResponseBase.error(f'启动处理失败:{str(e)}')
 #         return ResponseBase.error(f'启动处理失败:{str(e)}')
 
 
-@project_task_api.route('/start_task/<int:task_id>', methods=['POST'])
+
+@project_task_api.route("/start_task/<int:task_id>", methods=["POST"])
 @Permission.authorize
 @Permission.authorize
-def start_task(task_id:int):
+def start_task(task_id: int):
     try:
     try:
         msg = task_service.start_run_task(task_id)
         msg = task_service.start_run_task(task_id)
-        if msg == '0':
-            msg = '项目有正在运行的任务,已加入等待列表中'
+        if msg == "0":
+            msg = "项目有正在运行的任务,已加入等待列表中"
         elif msg:
         elif msg:
             return ResponseBase.error(msg)
             return ResponseBase.error(msg)
         else:
         else:
-            msg = '运行成功'
+            msg = "运行成功"
         return ResponseBase.success(message=msg)
         return ResponseBase.success(message=msg)
     except Exception as e:
     except Exception as e:
-        return ResponseBase.error(f'运行失败:{str(e)}')
+        return ResponseBase.error(f"运行失败:{str(e)}")
+
 
 
-@project_task_api.route('/cancel_task/<int:task_id>', methods=['POST'])
+@project_task_api.route("/cancel_task/<int:task_id>", methods=["POST"])
 @Permission.authorize
 @Permission.authorize
-def cancel_task(task_id:int):
+def cancel_task(task_id: int):
     try:
     try:
         msg = task_service.cancel_run_task(task_id)
         msg = task_service.cancel_run_task(task_id)
         if msg:
         if msg:
             return ResponseBase.error(msg)
             return ResponseBase.error(msg)
-        return ResponseBase.success(message='启动采集成功')
+        return ResponseBase.success(message="启动采集成功")
     except Exception as e:
     except Exception as e:
-        return ResponseBase.error(f'启动采集失败:{str(e)}')
+        return ResponseBase.error(f"启动采集失败:{str(e)}")
 
 
 
 
-@project_task_api.route('/start_send/<int:task_id>', methods=['POST'])
+@project_task_api.route("/start_send/<int:task_id>", methods=["POST"])
 @Permission.authorize
 @Permission.authorize
-def start_send(task_id:int):
+def start_send(task_id: int):
     try:
     try:
         msg = task_service.start_send_task(task_id)
         msg = task_service.start_send_task(task_id)
         if msg:
         if msg:
             return ResponseBase.error(msg)
             return ResponseBase.error(msg)
-        return ResponseBase.success(message='启动发送成功')
+        return ResponseBase.success(message="启动发送成功")
     except Exception as e:
     except Exception as e:
-        return ResponseBase.error(f'启动发送失败:{str(e)}')
+        return ResponseBase.error(f"启动发送失败:{str(e)}")

+ 0 - 1
SourceCode/IntelligentRailwayCosting/app/services/__init__.py

@@ -3,4 +3,3 @@ from .log import LogService
 from .project import ProjectService
 from .project import ProjectService
 from .project_quota import ProjectQuotaService
 from .project_quota import ProjectQuotaService
 from .project_task import ProjectTaskService
 from .project_task import ProjectTaskService
-

+ 53 - 18
SourceCode/IntelligentRailwayCosting/app/services/log.py

@@ -1,37 +1,72 @@
-from datetime import datetime,timedelta
+from datetime import datetime, timedelta
 from core.dtos import LogDto
 from core.dtos import LogDto
 from stores import LogStore
 from stores import LogStore
 
 
+
 class LogService:
 class LogService:
     def __init__(self):
     def __init__(self):
         self.log_store = LogStore()
         self.log_store = LogStore()
         pass
         pass
 
 
-    def get_logs_paginated(self, page:int, page_size:int, username:str, operation_type:str, operation_module:str, operation_result:int, start_time:str, end_time:str):
+    def get_logs_paginated(
+            self,
+            page: int,
+            page_size: int,
+            username: str,
+            operation_type: str,
+            operation_module: str,
+            operation_result: int,
+            start_time: str,
+            end_time: str,
+    ):
         # 处理开始时间和结束时间
         # 处理开始时间和结束时间
         start_datetime = None
         start_datetime = None
         end_datetime = None
         end_datetime = None
         try:
         try:
             if start_time:
             if start_time:
-                start_datetime = datetime.strptime(start_time, '%Y-%m-%d').replace(hour=0, minute=0, second=0)
+                start_datetime = datetime.strptime(start_time, "%Y-%m-%d").replace(
+                    hour=0, minute=0, second=0
+                )
             if end_time:
             if end_time:
-                end_datetime = datetime.strptime(end_time, '%Y-%m-%d').replace(hour=0, minute=0, second=0)
+                end_datetime = datetime.strptime(end_time, "%Y-%m-%d").replace(
+                    hour=0, minute=0, second=0
+                )
                 # 使用timedelta来处理结束时间加一天
                 # 使用timedelta来处理结束时间加一天
                 end_datetime = end_datetime + timedelta(days=1)
                 end_datetime = end_datetime + timedelta(days=1)
         except ValueError as e:
         except ValueError as e:
             raise ValueError(f"日期格式错误,请使用YYYY-MM-DD格式: {str(e)}")
             raise ValueError(f"日期格式错误,请使用YYYY-MM-DD格式: {str(e)}")
-        data =  self.log_store.query_logs_paginated(page, page_size, username, operation_type, operation_module, operation_result, start_datetime, end_datetime)
-        return [LogDto.from_model(item).to_dict() for  item in data.get('data',[])], data.get('total',0)
-
+        data = self.log_store.query_logs_paginated(
+            page,
+            page_size,
+            username,
+            operation_type,
+            operation_module,
+            operation_result,
+            start_datetime,
+            end_datetime,
+        )
+        return [
+            LogDto.from_model(item).to_dict() for item in data.get("data", [])
+        ], data.get("total", 0)
 
 
-    def add_operation_log(self,
-                          username:str,
-                          operation_type:str,
-                          operation_module:str,
-                          operation_desc:str,
-                          operation_result:int,
-                          operation_data:str = None,
-                          data_changes:str = None,
-                          operation_ip:str = None,
-                          ):
-        self.log_store.insert_log(username,operation_type,operation_desc,operation_result,operation_module,operation_data,data_changes,operation_ip)
+    def add_operation_log(
+            self,
+            username: str,
+            operation_type: str,
+            operation_module: str,
+            operation_desc: str,
+            operation_result: int,
+            operation_data: str = None,
+            data_changes: str = None,
+            operation_ip: str = None,
+    ):
+        self.log_store.insert_log(
+            username,
+            operation_type,
+            operation_desc,
+            operation_result,
+            operation_module,
+            operation_data,
+            data_changes,
+            operation_ip,
+        )

+ 102 - 38
SourceCode/IntelligentRailwayCosting/app/services/project.py

@@ -5,7 +5,7 @@ from core.dtos import TotalBudgetInfoDto, TotalBudgetItemDto
 from core.dtos.project import ProjectDto
 from core.dtos.project import ProjectDto
 from core.dtos.tree import TreeDto
 from core.dtos.tree import TreeDto
 from core.user_session import UserSession
 from core.user_session import UserSession
-from stores import ProjectStore,BudgetStore,ChapterStore
+from stores import ProjectStore, BudgetStore, ChapterStore
 
 
 
 
 class ProjectService:
 class ProjectService:
@@ -15,41 +15,55 @@ class ProjectService:
         self._budget_store = BudgetStore()
         self._budget_store = BudgetStore()
         self._chapter_store = ChapterStore()
         self._chapter_store = ChapterStore()
 
 
-    def get_projects_paginated(self, page: int, page_size: int, keyword: Optional[str] = None,
-        start_time: Optional[str] = None,
-        end_time: Optional[str] = None, can_edit:Optional[int]=0,):
-        
+    def get_projects_paginated(
+            self,
+            page: int,
+            page_size: int,
+            keyword: Optional[str] = None,
+            start_time: Optional[str] = None,
+            end_time: Optional[str] = None,
+            can_edit: Optional[int] = 0,
+    ):
+
         # 处理开始时间和结束时间
         # 处理开始时间和结束时间
         start_datetime = None
         start_datetime = None
         end_datetime = None
         end_datetime = None
         try:
         try:
             if start_time:
             if start_time:
-                start_datetime = datetime.strptime(start_time, '%Y-%m-%d').replace(hour=0, minute=0, second=0)
+                start_datetime = datetime.strptime(start_time, "%Y-%m-%d").replace(
+                    hour=0, minute=0, second=0
+                )
             if end_time:
             if end_time:
-                end_datetime = datetime.strptime(end_time, '%Y-%m-%d').replace(hour=0, minute=0, second=0)
+                end_datetime = datetime.strptime(end_time, "%Y-%m-%d").replace(
+                    hour=0, minute=0, second=0
+                )
                 # 使用timedelta来处理结束时间加一天
                 # 使用timedelta来处理结束时间加一天
                 end_datetime = end_datetime + timedelta(days=1)
                 end_datetime = end_datetime + timedelta(days=1)
         except ValueError as e:
         except ValueError as e:
             raise ValueError(f"日期格式错误,请使用YYYY-MM-DD格式: {str(e)}")
             raise ValueError(f"日期格式错误,请使用YYYY-MM-DD格式: {str(e)}")
 
 
-        data =  self._project_store.get_user_projects_paginated(page, page_size, keyword, start_datetime, end_datetime, can_edit)
-        return [ProjectDto.from_model(item).to_dict() for item in data.get('data',[])],data.get('total',0)
+        data = self._project_store.get_user_projects_paginated(
+            page, page_size, keyword, start_datetime, end_datetime, can_edit
+        )
+        return [
+            ProjectDto.from_model(item).to_dict() for item in data.get("data", [])
+        ], data.get("total", 0)
 
 
     def get_budget_info(self, project_id: str):
     def get_budget_info(self, project_id: str):
         msg = self._check_project_db_exit(project_id)
         msg = self._check_project_db_exit(project_id)
         if msg:
         if msg:
             return None, msg
             return None, msg
-        data =  self._budget_store.get_budget_info(project_id)
-        return [TotalBudgetInfoDto.from_model(item).to_dict() for item in data],""
+        data = self._budget_store.get_budget_info(project_id)
+        return [TotalBudgetInfoDto.from_model(item).to_dict() for item in data], ""
 
 
     def get_top_budget_items(self, budget_id: int, project_id: str):
     def get_top_budget_items(self, budget_id: int, project_id: str):
         msg = self._check_project_db_exit(project_id)
         msg = self._check_project_db_exit(project_id)
         if msg:
         if msg:
             return None, msg
             return None, msg
-        items = self._budget_store.get_top_budget_items(project_id,budget_id)
-        return [TotalBudgetItemDto.from_model(item).to_dict() for item in items],""
+        items = self._budget_store.get_top_budget_items(project_id, budget_id)
+        return [TotalBudgetItemDto.from_model(item).to_dict() for item in items], ""
 
 
-    def get_chapter_items(self, project_id: str, item_code:str):
+    def get_chapter_items(self, project_id: str, item_code: str):
         msg = self._check_project_db_exit(project_id)
         msg = self._check_project_db_exit(project_id)
         if msg:
         if msg:
             return None, msg
             return None, msg
@@ -58,24 +72,48 @@ class ProjectService:
             team_item_code = None
             team_item_code = None
             current_user = UserSession.get_current_user()
             current_user = UserSession.get_current_user()
             if not current_user.is_admin:
             if not current_user.is_admin:
-                team_item_code_str = self._project_store.get_team_project_item_code(project_id,current_user.username)
+                team_item_code_str = self._project_store.get_team_project_item_code(
+                    project_id, current_user.username
+                )
                 if team_item_code_str:
                 if team_item_code_str:
-                    team_item_code = None if team_item_code_str == 'None' or team_item_code_str == '0' or team_item_code_str == ''  else team_item_code_str.split(',')
-            items =  self._chapter_store.get_top_chapter_items(project_id,team_item_code)
+                    team_item_code = (
+                        None
+                        if team_item_code_str == "None"
+                           or team_item_code_str == "0"
+                           or team_item_code_str == ""
+                        else team_item_code_str.split(",")
+                    )
+            items = self._chapter_store.get_top_chapter_items(
+                project_id, team_item_code
+            )
         else:
         else:
-            items = self._chapter_store.get_child_chapter_items(project_id,item_code)
+            items = self._chapter_store.get_child_chapter_items(project_id, item_code)
         parent = "#"
         parent = "#"
         if item_code:
         if item_code:
-            item = self._chapter_store.get_chapter_item_by_item_code(project_id,item_code)
+            item = self._chapter_store.get_chapter_item_by_item_code(
+                project_id, item_code
+            )
             parent = item.item_id
             parent = item.item_id
         for item in items:
         for item in items:
-            text = f"第{item.chapter}章、{item.project_name}" if item.chapter else ( f"{item.section}  {item.project_name}" if item.section else item.project_name)
-            data_list.append(TreeDto(item.item_id,parent,text,item.children_count>0,item).to_dict())
-        return data_list,""
+            text = (
+                f"第{item.chapter}章、{item.project_name}"
+                if item.chapter
+                else (
+                    f"{item.section}  {item.project_name}"
+                    if item.section
+                    else item.project_name
+                )
+            )
+            data_list.append(
+                TreeDto(
+                    item.item_id, parent, text, item.children_count > 0, item
+                ).to_dict()
+            )
+        return data_list, ""
 
 
-    def get_budget_items(self, budget_id: int, project_id: str, item_code:str):
+    def get_budget_items(self, budget_id: int, project_id: str, item_code: str):
         if not budget_id:
         if not budget_id:
-            return None,'budget_id不能为空'
+            return None, "budget_id不能为空"
         msg = self._check_project_db_exit(project_id)
         msg = self._check_project_db_exit(project_id)
         if msg:
         if msg:
             return None, msg
             return None, msg
@@ -84,26 +122,52 @@ class ProjectService:
             team_item_code = None
             team_item_code = None
             current_user = UserSession.get_current_user()
             current_user = UserSession.get_current_user()
             if not current_user.is_admin:
             if not current_user.is_admin:
-                team_item_code_str = self._project_store.get_team_project_item_code(project_id,current_user.username)
+                team_item_code_str = self._project_store.get_team_project_item_code(
+                    project_id, current_user.username
+                )
                 if team_item_code_str:
                 if team_item_code_str:
-                    team_item_code = None if team_item_code_str == 'None' or team_item_code_str == '0' or team_item_code_str == ''  else team_item_code_str.split(',')
-            items =  self._budget_store.get_top_budget_items(project_id,budget_id,team_item_code)
+                    team_item_code = (
+                        None
+                        if team_item_code_str == "None"
+                           or team_item_code_str == "0"
+                           or team_item_code_str == ""
+                        else team_item_code_str.split(",")
+                    )
+            items = self._budget_store.get_top_budget_items(
+                project_id, budget_id, team_item_code
+            )
         else:
         else:
-            items = self._budget_store.get_child_budget_items(project_id,budget_id,item_code)
+            items = self._budget_store.get_child_budget_items(
+                project_id, budget_id, item_code
+            )
         parent = "#"
         parent = "#"
         if item_code:
         if item_code:
-            item = self._budget_store.get_budget_item_by_item_code(project_id,budget_id,item_code)
+            item = self._budget_store.get_budget_item_by_item_code(
+                project_id, budget_id, item_code
+            )
             parent = item.item_id
             parent = item.item_id
         for item in items:
         for item in items:
-            text = f"第{item.chapter}章、{item.project_name}" if item.chapter else ( f"{item.section}  {item.project_name}" if item.section else item.project_name)
-            data_list.append(TreeDto(item.item_id,parent,text,item.children_count>0,item).to_dict())
-        return data_list,""
+            text = (
+                f"第{item.chapter}章、{item.project_name}"
+                if item.chapter
+                else (
+                    f"{item.section}  {item.project_name}"
+                    if item.section
+                    else item.project_name
+                )
+            )
+            data_list.append(
+                TreeDto(
+                    item.item_id, parent, text, item.children_count > 0, item
+                ).to_dict()
+            )
+        return data_list, ""
 
 
-    def _check_project_db_exit(self, project_id:str):
+    def _check_project_db_exit(self, project_id: str):
         if not project_id:
         if not project_id:
-            return 'project_id不能为空'
+            return "project_id不能为空"
         if not self._project_store.get(project_id):
         if not self._project_store.get(project_id):
-            return '项目不存在'
-        if not project_id.startswith('Reco'):
-            return '项目id格式错误'
-        return None
+            return "项目不存在"
+        if not project_id.startswith("Reco"):
+            return "项目id格式错误"
+        return None

+ 6 - 5
SourceCode/IntelligentRailwayCosting/app/services/user.py

@@ -1,5 +1,7 @@
 from stores import UserStore
 from stores import UserStore
 from core.dtos import UserDto
 from core.dtos import UserDto
+
+
 class UserService:
 class UserService:
     def __init__(self):
     def __init__(self):
         self.user_store = UserStore()
         self.user_store = UserStore()
@@ -19,14 +21,13 @@ class UserService:
     def authenticate_user(self, username: str, password: str):
     def authenticate_user(self, username: str, password: str):
         user = self.user_store.get_user_by_username(username)
         user = self.user_store.get_user_by_username(username)
         if not user:
         if not user:
-            return None,"用户不存在"
+            return None, "用户不存在"
         user = self.user_store.authenticate_user(username, password)
         user = self.user_store.authenticate_user(username, password)
         if user:
         if user:
-            return UserDto.from_model(user),""
-        return None,"密码错误"
+            return UserDto.from_model(user), ""
+        return None, "密码错误"
 
 
     def get_all_users(self) -> list[UserDto]:
     def get_all_users(self) -> list[UserDto]:
         users = self.user_store.get_all_users()
         users = self.user_store.get_all_users()
-        user_list = [UserDto.from_model(user) for  user in users]
+        user_list = [UserDto.from_model(user) for user in users]
         return user_list
         return user_list
-

+ 5 - 2
SourceCode/IntelligentRailwayCosting/app/stores/__init__.py

@@ -1,9 +1,12 @@
 # from stores.railway_costing_mysql import LogStore,ProjectQuotaStore,ProjectTaskStore
 # from stores.railway_costing_mysql import LogStore,ProjectQuotaStore,ProjectTaskStore
-from stores.railway_costing_sqlserver import LogStore,ProjectQuotaStore,ProjectTaskStore
+from stores.railway_costing_sqlserver import (
+    LogStore,
+    ProjectQuotaStore,
+    ProjectTaskStore,
+)
 
 
 from .user import UserStore
 from .user import UserStore
 from .project import ProjectStore
 from .project import ProjectStore
 from .budget import BudgetStore
 from .budget import BudgetStore
 from .chapter import ChapterStore
 from .chapter import ChapterStore
 from .quota_input import QuotaInputStore
 from .quota_input import QuotaInputStore
-

+ 2 - 2
SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_mysql/__init__.py

@@ -1,3 +1,3 @@
-from .project_task import  ProjectTaskStore
+from .project_task import ProjectTaskStore
 from .project_quota import ProjectQuotaStore
 from .project_quota import ProjectQuotaStore
-from .log import LogStore
+from .log import LogStore

+ 31 - 31
SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_mysql/log.py

@@ -5,21 +5,22 @@ import tools.db_helper as db_helper
 
 
 from core.models import LogModel
 from core.models import LogModel
 
 
+
 class LogStore:
 class LogStore:
     def __init__(self):
     def __init__(self):
         # self._database= None
         # self._database= None
-        self._database= 'Iwb_RailwayCosting'
+        self._database = "Iwb_RailwayCosting"
 
 
     def query_logs_paginated(
     def query_logs_paginated(
-        self,
-        page: int = 1,
-        page_size: int = 10,
-        username: Optional[str] = None,
-        operation_type: Optional[str] = None,
-        operation_module: Optional[str] = None,
-        operation_result: Optional[int] = None,
-        start_time: Optional[datetime] = None,
-        end_time: Optional[datetime] = None
+            self,
+            page: int = 1,
+            page_size: int = 10,
+            username: Optional[str] = None,
+            operation_type: Optional[str] = None,
+            operation_module: Optional[str] = None,
+            operation_result: Optional[int] = None,
+            start_time: Optional[datetime] = None,
+            end_time: Optional[datetime] = None,
     ) -> Dict[str, Any]:
     ) -> Dict[str, Any]:
         """
         """
         分页查询日志记录
         分页查询日志记录
@@ -39,7 +40,7 @@ class LogStore:
             # 构建查询条件
             # 构建查询条件
             conditions = []
             conditions = []
             if username:
             if username:
-                conditions.append(LogModel.username.like(f'%{username}%'))
+                conditions.append(LogModel.username.like(f"%{username}%"))
             if operation_type:
             if operation_type:
                 conditions.append(LogModel.operation_type == operation_type)
                 conditions.append(LogModel.operation_type == operation_type)
             if operation_module:
             if operation_module:
@@ -58,26 +59,25 @@ class LogStore:
             total = query.count()
             total = query.count()
 
 
             # 分页并按创建时间倒序排序
             # 分页并按创建时间倒序排序
-            logs = query.order_by(LogModel.created_at.desc())\
-                .offset((page - 1) * page_size)\
-                .limit(page_size)\
+            logs = (
+                query.order_by(LogModel.created_at.desc())
+                .offset((page - 1) * page_size)
+                .limit(page_size)
                 .all()
                 .all()
+            )
+
+            return {"total": total, "data": logs}
 
 
-            return {
-                'total': total,
-                'data': logs
-            }
-    
     def insert_log(
     def insert_log(
-        self,
-        username: str,
-        operation_type: str,
-        operation_desc: Optional[str] = None,
-        operation_result: Optional[int] = None,
-        operation_module: Optional[str] = None,
-        operation_data: Optional[str] = None,
-        data_changes: Optional[str] = None,
-        operation_ip: Optional[str] = None
+            self,
+            username: str,
+            operation_type: str,
+            operation_desc: Optional[str] = None,
+            operation_result: Optional[int] = None,
+            operation_module: Optional[str] = None,
+            operation_data: Optional[str] = None,
+            data_changes: Optional[str] = None,
+            operation_ip: Optional[str] = None,
     ) -> LogModel:
     ) -> LogModel:
         """
         """
         插入单条日志记录
         插入单条日志记录
@@ -99,12 +99,12 @@ class LogStore:
             operation_module=operation_module,
             operation_module=operation_module,
             operation_data=operation_data,
             operation_data=operation_data,
             data_changes=data_changes,
             data_changes=data_changes,
-            operation_ip=operation_ip
+            operation_ip=operation_ip,
         )
         )
         with db_helper.mysql_session(self._database) as db_session:
         with db_helper.mysql_session(self._database) as db_session:
             db_session.add(log)
             db_session.add(log)
             return log
             return log
-    
+
     def batch_insert_logs(self, logs: List[Dict[str, Any]]) -> List[LogModel]:
     def batch_insert_logs(self, logs: List[Dict[str, Any]]) -> List[LogModel]:
         """
         """
         批量插入日志记录
         批量插入日志记录
@@ -114,4 +114,4 @@ class LogStore:
         log_models = [LogModel(**log) for log in logs]
         log_models = [LogModel(**log) for log in logs]
         with db_helper.mysql_session(self._database) as db_session:
         with db_helper.mysql_session(self._database) as db_session:
             db_session.add_all(log_models)
             db_session.add_all(log_models)
-            return log_models
+            return log_models

+ 81 - 54
SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_mysql/project_quota.py

@@ -8,10 +8,11 @@ from core.enum import SendStatusEnum
 from core.models import ProjectQuotaModel
 from core.models import ProjectQuotaModel
 from core.user_session import UserSession
 from core.user_session import UserSession
 
 
+
 class ProjectQuotaStore:
 class ProjectQuotaStore:
     def __init__(self):
     def __init__(self):
         # self._database= None
         # self._database= None
-        self._database = 'Iwb_RailwayCosting'
+        self._database = "Iwb_RailwayCosting"
         self._current_user = None
         self._current_user = None
 
 
     @property
     @property
@@ -21,14 +22,14 @@ class ProjectQuotaStore:
         return self._current_user
         return self._current_user
 
 
     def get_quotas_paginated(
     def get_quotas_paginated(
-        self,
-        budget_id: int,
-        project_id: str,
-        item_code: str,
-        page: int = 1,
-        page_size: int = 10,
-        keyword: Optional[str] = None,
-        send_status: Optional[int] = None,
+            self,
+            budget_id: int,
+            project_id: str,
+            item_code: str,
+            page: int = 1,
+            page_size: int = 10,
+            keyword: Optional[str] = None,
+            send_status: Optional[int] = None,
     ):
     ):
         """分页查询定额列表
         """分页查询定额列表
 
 
@@ -51,32 +52,45 @@ class ProjectQuotaStore:
                 ProjectQuotaModel.is_del == 0,
                 ProjectQuotaModel.is_del == 0,
                 ProjectQuotaModel.project_id == project_id,
                 ProjectQuotaModel.project_id == project_id,
                 ProjectQuotaModel.budget_id == budget_id,
                 ProjectQuotaModel.budget_id == budget_id,
-                ProjectQuotaModel.item_code.like(f"{item_code}%")
+                ProjectQuotaModel.item_code.like(f"{item_code}%"),
             ]
             ]
 
 
             if send_status is not None:
             if send_status is not None:
                 conditions.append(ProjectQuotaModel.send_status == send_status)
                 conditions.append(ProjectQuotaModel.send_status == send_status)
             if keyword:
             if keyword:
-                conditions.append(or_(
-                    ProjectQuotaModel.quota_code.like(f"%{keyword}%"),
-                    ProjectQuotaModel.entry_name.like(f"%{keyword}%"),
-                ))
+                conditions.append(
+                    or_(
+                        ProjectQuotaModel.quota_code.like(f"%{keyword}%"),
+                        ProjectQuotaModel.entry_name.like(f"%{keyword}%"),
+                    )
+                )
             query = query.filter(and_(*conditions))
             query = query.filter(and_(*conditions))
 
 
             # 计算总数
             # 计算总数
             total_count = query.count()
             total_count = query.count()
 
 
             # 分页
             # 分页
-            query = query.order_by(ProjectQuotaModel.created_at.desc()).offset((page - 1) * page_size).limit(page_size)
+            query = (
+                query.order_by(ProjectQuotaModel.created_at.desc())
+                .offset((page - 1) * page_size)
+                .limit(page_size)
+            )
 
 
             quotas = query.all()
             quotas = query.all()
 
 
-            return {
-                'total': total_count,
-                'data': quotas
-            }
-
-    def get_quotas_by_task_paginated(self, task_id: int, budget_id, project_id, item_code, page: int = 1, page_size: int = 10,keyword: Optional[str]=None,send_status: Optional[int] = None):
+            return {"total": total_count, "data": quotas}
+
+    def get_quotas_by_task_paginated(
+            self,
+            task_id: int,
+            budget_id,
+            project_id,
+            item_code,
+            page: int = 1,
+            page_size: int = 10,
+            keyword: Optional[str] = None,
+            send_status: Optional[int] = None,
+    ):
         with db_helper.mysql_query_session(self._database) as db_session:
         with db_helper.mysql_query_session(self._database) as db_session:
             query = db_session.query(ProjectQuotaModel).filter(
             query = db_session.query(ProjectQuotaModel).filter(
                 and_(
                 and_(
@@ -84,46 +98,49 @@ class ProjectQuotaStore:
                     ProjectQuotaModel.budget_id == budget_id,
                     ProjectQuotaModel.budget_id == budget_id,
                     ProjectQuotaModel.project_id == project_id,
                     ProjectQuotaModel.project_id == project_id,
                     ProjectQuotaModel.item_code.like(f"{item_code}%"),
                     ProjectQuotaModel.item_code.like(f"{item_code}%"),
-                    ProjectQuotaModel.is_del == 0
+                    ProjectQuotaModel.is_del == 0,
                 )
                 )
             )
             )
             if keyword:
             if keyword:
-                query = query.filter(or_(
-                    ProjectQuotaModel.quota_code.like(f"%{keyword}%"),
-                    ProjectQuotaModel.entry_name.like(f"%{keyword}%"),
-                ))
+                query = query.filter(
+                    or_(
+                        ProjectQuotaModel.quota_code.like(f"%{keyword}%"),
+                        ProjectQuotaModel.entry_name.like(f"%{keyword}%"),
+                    )
+                )
             if send_status is not None:
             if send_status is not None:
                 query = query.filter(ProjectQuotaModel.send_status == send_status)
                 query = query.filter(ProjectQuotaModel.send_status == send_status)
             # 计算总数
             # 计算总数
             total_count = query.count()
             total_count = query.count()
 
 
             # 分页
             # 分页
-            query = query.order_by(ProjectQuotaModel.created_at.desc()).offset((page - 1) * page_size).limit(
-                page_size)
+            query = (
+                query.order_by(ProjectQuotaModel.created_at.desc())
+                .offset((page - 1) * page_size)
+                .limit(page_size)
+            )
 
 
             quotas = query.all()
             quotas = query.all()
 
 
-            return {
-                'total': total_count,
-                'data': quotas
-            }
-
+            return {"total": total_count, "data": quotas}
 
 
-    def get_quotas_by_task_id(self,task_id:int, with_quota_code:bool=False):
+    def get_quotas_by_task_id(self, task_id: int, with_quota_code: bool = False):
         with db_helper.mysql_query_session(self._database) as db_session:
         with db_helper.mysql_query_session(self._database) as db_session:
             query = db_session.query(ProjectQuotaModel).filter(
             query = db_session.query(ProjectQuotaModel).filter(
                 and_(
                 and_(
-                    ProjectQuotaModel.task_id == task_id,
-                    ProjectQuotaModel.is_del == 0
+                    ProjectQuotaModel.task_id == task_id, ProjectQuotaModel.is_del == 0
                 )
                 )
             )
             )
             if with_quota_code:
             if with_quota_code:
-                query = query.filter(and_(ProjectQuotaModel.quota_code!=None,ProjectQuotaModel.quota_code!='') )
+                query = query.filter(
+                    and_(
+                        ProjectQuotaModel.quota_code != None,
+                        ProjectQuotaModel.quota_code != "",
+                    )
+                )
             quotas = query.all()
             quotas = query.all()
             return quotas
             return quotas
 
 
-
-
     def get_quota(self, quota_id: int) -> Optional[ProjectQuotaModel]:
     def get_quota(self, quota_id: int) -> Optional[ProjectQuotaModel]:
         """根据ID查询定额
         """根据ID查询定额
 
 
@@ -134,13 +151,17 @@ class ProjectQuotaStore:
             Optional[ProjectQuotaDto]
             Optional[ProjectQuotaDto]
         """
         """
         with db_helper.mysql_query_session(self._database) as db_session:
         with db_helper.mysql_query_session(self._database) as db_session:
-            quota = db_session.query(ProjectQuotaModel).filter(
-                and_(
-                    ProjectQuotaModel.id == quota_id,
-                    ProjectQuotaModel.is_del == 0
+            quota = (
+                db_session.query(ProjectQuotaModel)
+                .filter(
+                    and_(
+                        ProjectQuotaModel.id == quota_id, ProjectQuotaModel.is_del == 0
+                    )
                 )
                 )
-            ).first()
+                .first()
+            )
             return quota
             return quota
+
     def get_quota_dto(self, quota_id: int) -> Optional[ProjectQuotaDto]:
     def get_quota_dto(self, quota_id: int) -> Optional[ProjectQuotaDto]:
         """根据ID查询定额
         """根据ID查询定额
 
 
@@ -154,16 +175,22 @@ class ProjectQuotaStore:
 
 
         return ProjectQuotaDto.from_model(quota) if quota else None
         return ProjectQuotaDto.from_model(quota) if quota else None
 
 
-    def get_quota_by_quota_input(self, project_id:str, budget_id:int,quota_input_id:int):
+    def get_quota_by_quota_input(
+            self, project_id: str, budget_id: int, quota_input_id: int
+    ):
         with db_helper.mysql_query_session(self._database) as db_session:
         with db_helper.mysql_query_session(self._database) as db_session:
-            quota = db_session.query(ProjectQuotaModel).filter(
-                and_(
-                    ProjectQuotaModel.project_id == project_id,
-                    ProjectQuotaModel.budget_id == budget_id,
-                    ProjectQuotaModel.quota_id == quota_input_id,
-                    ProjectQuotaModel.is_del == 0
+            quota = (
+                db_session.query(ProjectQuotaModel)
+                .filter(
+                    and_(
+                        ProjectQuotaModel.project_id == project_id,
+                        ProjectQuotaModel.budget_id == budget_id,
+                        ProjectQuotaModel.quota_id == quota_input_id,
+                        ProjectQuotaModel.is_del == 0,
+                    )
                 )
                 )
-            ).first()
+                .first()
+            )
             return ProjectQuotaDto.from_model(quota) if quota else None
             return ProjectQuotaDto.from_model(quota) if quota else None
 
 
     def create_quota(self, quota_dto: ProjectQuotaDto) -> ProjectQuotaDto:
     def create_quota(self, quota_dto: ProjectQuotaDto) -> ProjectQuotaDto:
@@ -255,7 +282,7 @@ class ProjectQuotaStore:
             db_session.merge(quota)
             db_session.merge(quota)
             return True
             return True
 
 
-    def update_send_status(self,quota_id:int, status:int, err:str = None) -> bool:
+    def update_send_status(self, quota_id: int, status: int, err: str = None) -> bool:
         """
         """
         更新发送状态
         更新发送状态
         Args:
         Args:
@@ -293,4 +320,4 @@ class ProjectQuotaStore:
             quota.updated_by = self.current_user.username
             quota.updated_by = self.current_user.username
             quota.updated_at = datetime.now()
             quota.updated_at = datetime.now()
             db_session.merge(quota)
             db_session.merge(quota)
-            return True
+            return True

+ 44 - 40
SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_mysql/project_task.py

@@ -12,7 +12,7 @@ from core.user_session import UserSession
 class ProjectTaskStore:
 class ProjectTaskStore:
     def __init__(self):
     def __init__(self):
         # self._database= None
         # self._database= None
-        self._database = 'Iwb_RailwayCosting'
+        self._database = "Iwb_RailwayCosting"
         self._current_user = None
         self._current_user = None
 
 
     @property
     @property
@@ -20,16 +20,17 @@ class ProjectTaskStore:
         if self._current_user is None:
         if self._current_user is None:
             self._current_user = UserSession.get_current_user()
             self._current_user = UserSession.get_current_user()
         return self._current_user
         return self._current_user
+
     def get_tasks_paginated(
     def get_tasks_paginated(
-        self,
-        project_id: str,
-        item_code: str,
-        page: int = 1,
-        page_size: int = 10,
-        keyword: Optional[str] = None,
-        process_status: Optional[int] = None,
-        send_status: Optional[int] = None,
-    ) :
+            self,
+            project_id: str,
+            item_code: str,
+            page: int = 1,
+            page_size: int = 10,
+            keyword: Optional[str] = None,
+            process_status: Optional[int] = None,
+            send_status: Optional[int] = None,
+    ):
         """分页查询任务列表
         """分页查询任务列表
 
 
         Args:
         Args:
@@ -44,7 +45,7 @@ class ProjectTaskStore:
         Returns:
         Returns:
 
 
         """
         """
-        with (db_helper.mysql_query_session(self._database) as db_session):
+        with db_helper.mysql_query_session(self._database) as db_session:
             query = db_session.query(ProjectTaskModel)
             query = db_session.query(ProjectTaskModel)
 
 
             # 构建查询条件
             # 构建查询条件
@@ -52,10 +53,10 @@ class ProjectTaskStore:
                 ProjectTaskModel.is_del == 0,
                 ProjectTaskModel.is_del == 0,
                 ProjectTaskModel.project_id == project_id,
                 ProjectTaskModel.project_id == project_id,
                 # ProjectTaskModel.budget_id == budget_id,
                 # ProjectTaskModel.budget_id == budget_id,
-                ProjectTaskModel.item_code.like(f"{item_code}%")
+                ProjectTaskModel.item_code.like(f"{item_code}%"),
             ]
             ]
             if keyword:
             if keyword:
-                conditions.append(ProjectTaskModel.task_name.like(f'%{keyword}%'))
+                conditions.append(ProjectTaskModel.task_name.like(f"%{keyword}%"))
             if process_status is not None:
             if process_status is not None:
                 conditions.append(ProjectTaskModel.process_status == process_status)
                 conditions.append(ProjectTaskModel.process_status == process_status)
             if send_status is not None:
             if send_status is not None:
@@ -67,24 +68,26 @@ class ProjectTaskStore:
             total_count = query.count()
             total_count = query.count()
 
 
             # 分页
             # 分页
-            query = query.order_by(ProjectTaskModel.task_sort.desc())\
-                .order_by(ProjectTaskModel.created_at.desc())\
-                .offset((page - 1) * page_size).limit(page_size)
+            query = (
+                query.order_by(ProjectTaskModel.task_sort.desc())
+                .order_by(ProjectTaskModel.created_at.desc())
+                .offset((page - 1) * page_size)
+                .limit(page_size)
+            )
 
 
             tasks = query.all()
             tasks = query.all()
 
 
-            return {
-                'total': total_count,
-                'data': tasks
-            }
+            return {"total": total_count, "data": tasks}
 
 
     def get_task(self, task_id: int) -> Optional[ProjectTaskModel]:
     def get_task(self, task_id: int) -> Optional[ProjectTaskModel]:
         with db_helper.mysql_query_session(self._database) as db_session:
         with db_helper.mysql_query_session(self._database) as db_session:
-            task = db_session.query(ProjectTaskModel).filter(
-                and_(
-                    ProjectTaskModel.id == task_id,
-                    ProjectTaskModel.is_del == 0
-                )).first()
+            task = (
+                db_session.query(ProjectTaskModel)
+                .filter(
+                    and_(ProjectTaskModel.id == task_id, ProjectTaskModel.is_del == 0)
+                )
+                .first()
+            )
             return task
             return task
 
 
     def get_task_dto(self, task_id: int) -> Optional[ProjectTaskDto]:
     def get_task_dto(self, task_id: int) -> Optional[ProjectTaskDto]:
@@ -99,7 +102,7 @@ class ProjectTaskStore:
         task_dto = self.get_task(task_id)
         task_dto = self.get_task(task_id)
         return ProjectTaskDto.from_model(task_dto) if task_dto else None
         return ProjectTaskDto.from_model(task_dto) if task_dto else None
 
 
-    def get_wait_tasks(self,project_id:str=None):
+    def get_wait_tasks(self, project_id: str = None):
         """查询待处理的任务
         """查询待处理的任务
 
 
         Args:
         Args:
@@ -113,14 +116,15 @@ class ProjectTaskStore:
             query = query.filter(
             query = query.filter(
                 and_(
                 and_(
                     ProjectTaskModel.is_del == 0,
                     ProjectTaskModel.is_del == 0,
-                    ProjectTaskModel.process_status == TaskStatusEnum.WAIT.value))
+                    ProjectTaskModel.process_status == TaskStatusEnum.WAIT.value,
+                )
+            )
             if project_id:
             if project_id:
                 query = query.filter(ProjectTaskModel.project_id == project_id)
                 query = query.filter(ProjectTaskModel.project_id == project_id)
             query.order_by(ProjectTaskModel.task_sort.desc())
             query.order_by(ProjectTaskModel.task_sort.desc())
             tasks = query.all()
             tasks = query.all()
             return [ProjectTaskDto.from_model(task) for task in tasks]
             return [ProjectTaskDto.from_model(task) for task in tasks]
 
 
-
     def get_tasks_by_status(self, status: int):
     def get_tasks_by_status(self, status: int):
         """查询指定状态的任务"""
         """查询指定状态的任务"""
         with db_helper.mysql_query_session(self._database) as db_session:
         with db_helper.mysql_query_session(self._database) as db_session:
@@ -128,7 +132,9 @@ class ProjectTaskStore:
             query = query.filter(
             query = query.filter(
                 and_(
                 and_(
                     ProjectTaskModel.is_del == 0,
                     ProjectTaskModel.is_del == 0,
-                    ProjectTaskModel.process_status == status))
+                    ProjectTaskModel.process_status == status,
+                )
+            )
             query.order_by(ProjectTaskModel.task_sort.desc())
             query.order_by(ProjectTaskModel.task_sort.desc())
             tasks = query.all()
             tasks = query.all()
             return [ProjectTaskDto.from_model(task) for task in tasks]
             return [ProjectTaskDto.from_model(task) for task in tasks]
@@ -182,12 +188,12 @@ class ProjectTaskStore:
             # task.item_id = task_dto.item_id
             # task.item_id = task_dto.item_id
             # task.item_code = task_dto.item_code
             # task.item_code = task_dto.item_code
             # task.file_path = task_dto.file_path
             # task.file_path = task_dto.file_path
-            task.updated_by=self.current_user.username
-            task.updated_at=datetime.now()
+            task.updated_by = self.current_user.username
+            task.updated_at = datetime.now()
             task = db_session.merge(task)
             task = db_session.merge(task)
             return ProjectTaskDto.from_model(task)
             return ProjectTaskDto.from_model(task)
 
 
-    def update_task_files(self, task_id: int,files: str):
+    def update_task_files(self, task_id: int, files: str):
         task = self.get_task(task_id)
         task = self.get_task(task_id)
         if not task:
         if not task:
             return None
             return None
@@ -197,8 +203,8 @@ class ProjectTaskStore:
                 task.process_status = 4
                 task.process_status = 4
             if task.send_status != 0:
             if task.send_status != 0:
                 task.send_status = 4
                 task.send_status = 4
-            task.updated_by=self.current_user.username
-            task.updated_at=datetime.now()
+            task.updated_by = self.current_user.username
+            task.updated_at = datetime.now()
             task = db_session.merge(task)
             task = db_session.merge(task)
             return ProjectTaskDto.from_model(task)
             return ProjectTaskDto.from_model(task)
 
 
@@ -221,7 +227,8 @@ class ProjectTaskStore:
             task.deleted_at = datetime.now()
             task.deleted_at = datetime.now()
             db_session.merge(task)
             db_session.merge(task)
             return True
             return True
-    def update_task_status(self,task_id:int, status:int, err:str = None):
+
+    def update_task_status(self, task_id: int, status: int, err: str = None):
         task = self.get_task(task_id)
         task = self.get_task(task_id)
         if not task:
         if not task:
             return False
             return False
@@ -233,9 +240,7 @@ class ProjectTaskStore:
             db_session.merge(task)
             db_session.merge(task)
             return True
             return True
 
 
-
-
-    def update_process_status(self,task_id:int, status:int, err:str = None):
+    def update_process_status(self, task_id: int, status: int, err: str = None):
         task = self.get_task(task_id)
         task = self.get_task(task_id)
         if not task:
         if not task:
             return False
             return False
@@ -247,7 +252,7 @@ class ProjectTaskStore:
             db_session.merge(task)
             db_session.merge(task)
             return True
             return True
 
 
-    def update_send_status(self,task_id:int, status:int, err:str = None):
+    def update_send_status(self, task_id: int, status: int, err: str = None):
         task = self.get_task(task_id)
         task = self.get_task(task_id)
         if not task:
         if not task:
             return False
             return False
@@ -258,4 +263,3 @@ class ProjectTaskStore:
             task.send_time = datetime.now()
             task.send_time = datetime.now()
             db_session.merge(task)
             db_session.merge(task)
             return True
             return True
-

+ 2 - 2
SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_sqlserver/__init__.py

@@ -1,3 +1,3 @@
-from .project_task import  ProjectTaskStore
+from .project_task import ProjectTaskStore
 from .project_quota import ProjectQuotaStore
 from .project_quota import ProjectQuotaStore
-from .log import LogStore
+from .log import LogStore

+ 32 - 32
SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_sqlserver/log.py

@@ -1,25 +1,26 @@
 from typing import List, Optional, Dict, Any
 from typing import List, Optional, Dict, Any
 from datetime import datetime
 from datetime import datetime
-from sqlalchemy import and_,  desc
+from sqlalchemy import and_, desc
 import tools.db_helper as db_helper
 import tools.db_helper as db_helper
 
 
 from core.models import LogModel
 from core.models import LogModel
 
 
+
 class LogStore:
 class LogStore:
     def __init__(self):
     def __init__(self):
         # self._database= None
         # self._database= None
-        self._database= 'Iwb_RailwayCosting'
+        self._database = "Iwb_RailwayCosting"
 
 
     def query_logs_paginated(
     def query_logs_paginated(
-        self,
-        page: int = 1,
-        page_size: int = 10,
-        username: Optional[str] = None,
-        operation_type: Optional[str] = None,
-        operation_module: Optional[str] = None,
-        operation_result: Optional[int] = None,
-        start_time: Optional[datetime] = None,
-        end_time: Optional[datetime] = None
+            self,
+            page: int = 1,
+            page_size: int = 10,
+            username: Optional[str] = None,
+            operation_type: Optional[str] = None,
+            operation_module: Optional[str] = None,
+            operation_result: Optional[int] = None,
+            start_time: Optional[datetime] = None,
+            end_time: Optional[datetime] = None,
     ) -> Dict[str, Any]:
     ) -> Dict[str, Any]:
         """
         """
         分页查询日志记录
         分页查询日志记录
@@ -38,7 +39,7 @@ class LogStore:
             # 构建查询条件
             # 构建查询条件
             conditions = []
             conditions = []
             if username:
             if username:
-                conditions.append(LogModel.username.like(f'%{username}%'))
+                conditions.append(LogModel.username.like(f"%{username}%"))
             if operation_type:
             if operation_type:
                 conditions.append(LogModel.operation_type == operation_type)
                 conditions.append(LogModel.operation_type == operation_type)
             if operation_module:
             if operation_module:
@@ -57,26 +58,25 @@ class LogStore:
             total = query.count()
             total = query.count()
 
 
             # 分页并按创建时间倒序排序
             # 分页并按创建时间倒序排序
-            logs = query.order_by(LogModel.created_at.desc())\
-                .offset((page - 1) * page_size)\
-                .limit(page_size)\
+            logs = (
+                query.order_by(LogModel.created_at.desc())
+                .offset((page - 1) * page_size)
+                .limit(page_size)
                 .all()
                 .all()
+            )
+
+            return {"total": total, "data": logs}
 
 
-            return {
-                'total': total,
-                'data': logs
-            }
-    
     def insert_log(
     def insert_log(
-        self,
-        username: str,
-        operation_type: str,
-        operation_desc: Optional[str] = None,
-        operation_result: Optional[int] = None,
-        operation_module: Optional[str] = None,
-        operation_data: Optional[str] = None,
-        data_changes: Optional[str] = None,
-        operation_ip: Optional[str] = None
+            self,
+            username: str,
+            operation_type: str,
+            operation_desc: Optional[str] = None,
+            operation_result: Optional[int] = None,
+            operation_module: Optional[str] = None,
+            operation_data: Optional[str] = None,
+            data_changes: Optional[str] = None,
+            operation_ip: Optional[str] = None,
     ) -> LogModel:
     ) -> LogModel:
         """
         """
         插入单条日志记录
         插入单条日志记录
@@ -98,12 +98,12 @@ class LogStore:
             operation_module=operation_module,
             operation_module=operation_module,
             operation_data=operation_data,
             operation_data=operation_data,
             data_changes=data_changes,
             data_changes=data_changes,
-            operation_ip=operation_ip
+            operation_ip=operation_ip,
         )
         )
         with db_helper.sqlserver_session(self._database) as db_session:
         with db_helper.sqlserver_session(self._database) as db_session:
             db_session.add(log)
             db_session.add(log)
             return log
             return log
-    
+
     def batch_insert_logs(self, logs: List[Dict[str, Any]]) -> List[LogModel]:
     def batch_insert_logs(self, logs: List[Dict[str, Any]]) -> List[LogModel]:
         """
         """
         批量插入日志记录
         批量插入日志记录
@@ -113,4 +113,4 @@ class LogStore:
         log_models = [LogModel(**log) for log in logs]
         log_models = [LogModel(**log) for log in logs]
         with db_helper.sqlserver_session(self._database) as db_session:
         with db_helper.sqlserver_session(self._database) as db_session:
             db_session.add_all(log_models)
             db_session.add_all(log_models)
-            return log_models
+            return log_models

+ 44 - 40
SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_sqlserver/project_task.py

@@ -12,7 +12,7 @@ from core.user_session import UserSession
 class ProjectTaskStore:
 class ProjectTaskStore:
     def __init__(self):
     def __init__(self):
         # self._database= None
         # self._database= None
-        self._database = 'Iwb_RailwayCosting'
+        self._database = "Iwb_RailwayCosting"
         self._current_user = None
         self._current_user = None
 
 
     @property
     @property
@@ -20,16 +20,17 @@ class ProjectTaskStore:
         if self._current_user is None:
         if self._current_user is None:
             self._current_user = UserSession.get_current_user()
             self._current_user = UserSession.get_current_user()
         return self._current_user
         return self._current_user
+
     def get_tasks_paginated(
     def get_tasks_paginated(
-        self,
-        project_id: str,
-        item_code: str,
-        page: int = 1,
-        page_size: int = 10,
-        keyword: Optional[str] = None,
-        process_status: Optional[int] = None,
-        send_status: Optional[int] = None,
-    ) :
+            self,
+            project_id: str,
+            item_code: str,
+            page: int = 1,
+            page_size: int = 10,
+            keyword: Optional[str] = None,
+            process_status: Optional[int] = None,
+            send_status: Optional[int] = None,
+    ):
         """分页查询任务列表
         """分页查询任务列表
 
 
         Args:
         Args:
@@ -44,7 +45,7 @@ class ProjectTaskStore:
         Returns:
         Returns:
 
 
         """
         """
-        with (db_helper.sqlserver_query_session(self._database) as db_session):
+        with db_helper.sqlserver_query_session(self._database) as db_session:
             query = db_session.query(ProjectTaskModel)
             query = db_session.query(ProjectTaskModel)
 
 
             # 构建查询条件
             # 构建查询条件
@@ -52,10 +53,10 @@ class ProjectTaskStore:
                 ProjectTaskModel.is_del == 0,
                 ProjectTaskModel.is_del == 0,
                 ProjectTaskModel.project_id == project_id,
                 ProjectTaskModel.project_id == project_id,
                 # ProjectTaskModel.budget_id == budget_id,
                 # ProjectTaskModel.budget_id == budget_id,
-                ProjectTaskModel.item_code.like(f"{item_code}%")
+                ProjectTaskModel.item_code.like(f"{item_code}%"),
             ]
             ]
             if keyword:
             if keyword:
-                conditions.append(ProjectTaskModel.task_name.like(f'%{keyword}%'))
+                conditions.append(ProjectTaskModel.task_name.like(f"%{keyword}%"))
             if process_status is not None:
             if process_status is not None:
                 conditions.append(ProjectTaskModel.process_status == process_status)
                 conditions.append(ProjectTaskModel.process_status == process_status)
             if send_status is not None:
             if send_status is not None:
@@ -67,24 +68,26 @@ class ProjectTaskStore:
             total_count = query.count()
             total_count = query.count()
 
 
             # 分页
             # 分页
-            query = query.order_by(ProjectTaskModel.task_sort.desc())\
-                .order_by(ProjectTaskModel.created_at.desc())\
-                .offset((page - 1) * page_size).limit(page_size)
+            query = (
+                query.order_by(ProjectTaskModel.task_sort.desc())
+                .order_by(ProjectTaskModel.created_at.desc())
+                .offset((page - 1) * page_size)
+                .limit(page_size)
+            )
 
 
             tasks = query.all()
             tasks = query.all()
 
 
-            return {
-                'total': total_count,
-                'data': tasks
-            }
+            return {"total": total_count, "data": tasks}
 
 
     def get_task(self, task_id: int) -> Optional[ProjectTaskModel]:
     def get_task(self, task_id: int) -> Optional[ProjectTaskModel]:
         with db_helper.sqlserver_query_session(self._database) as db_session:
         with db_helper.sqlserver_query_session(self._database) as db_session:
-            task = db_session.query(ProjectTaskModel).filter(
-                and_(
-                    ProjectTaskModel.id == task_id,
-                    ProjectTaskModel.is_del == 0
-                )).first()
+            task = (
+                db_session.query(ProjectTaskModel)
+                .filter(
+                    and_(ProjectTaskModel.id == task_id, ProjectTaskModel.is_del == 0)
+                )
+                .first()
+            )
             return task
             return task
 
 
     def get_task_dto(self, task_id: int) -> Optional[ProjectTaskDto]:
     def get_task_dto(self, task_id: int) -> Optional[ProjectTaskDto]:
@@ -99,7 +102,7 @@ class ProjectTaskStore:
         task_dto = self.get_task(task_id)
         task_dto = self.get_task(task_id)
         return ProjectTaskDto.from_model(task_dto) if task_dto else None
         return ProjectTaskDto.from_model(task_dto) if task_dto else None
 
 
-    def get_wait_tasks(self,project_id:str=None):
+    def get_wait_tasks(self, project_id: str = None):
         """查询待处理的任务
         """查询待处理的任务
 
 
         Args:
         Args:
@@ -113,7 +116,9 @@ class ProjectTaskStore:
             query = query.filter(
             query = query.filter(
                 and_(
                 and_(
                     ProjectTaskModel.is_del == 0,
                     ProjectTaskModel.is_del == 0,
-                    ProjectTaskModel.process_status == TaskStatusEnum.WAIT.value))
+                    ProjectTaskModel.process_status == TaskStatusEnum.WAIT.value,
+                )
+            )
             if project_id:
             if project_id:
                 query = query.filter(ProjectTaskModel.project_id == project_id)
                 query = query.filter(ProjectTaskModel.project_id == project_id)
             query.order_by(ProjectTaskModel.task_sort.desc())
             query.order_by(ProjectTaskModel.task_sort.desc())
@@ -127,12 +132,13 @@ class ProjectTaskStore:
             query = query.filter(
             query = query.filter(
                 and_(
                 and_(
                     ProjectTaskModel.is_del == 0,
                     ProjectTaskModel.is_del == 0,
-                    ProjectTaskModel.process_status == status))
+                    ProjectTaskModel.process_status == status,
+                )
+            )
             query.order_by(ProjectTaskModel.task_sort.desc())
             query.order_by(ProjectTaskModel.task_sort.desc())
             tasks = query.all()
             tasks = query.all()
             return [ProjectTaskDto.from_model(task) for task in tasks]
             return [ProjectTaskDto.from_model(task) for task in tasks]
 
 
-
     def create_task(self, task_dto: ProjectTaskDto) -> ProjectTaskDto:
     def create_task(self, task_dto: ProjectTaskDto) -> ProjectTaskDto:
         """创建任务
         """创建任务
 
 
@@ -182,12 +188,12 @@ class ProjectTaskStore:
             # task.item_id = task_dto.item_id
             # task.item_id = task_dto.item_id
             # task.item_code = task_dto.item_code
             # task.item_code = task_dto.item_code
             # task.file_path = task_dto.file_path
             # task.file_path = task_dto.file_path
-            task.updated_by=self.current_user.username
-            task.updated_at=datetime.now()
+            task.updated_by = self.current_user.username
+            task.updated_at = datetime.now()
             task = db_session.merge(task)
             task = db_session.merge(task)
             return ProjectTaskDto.from_model(task)
             return ProjectTaskDto.from_model(task)
 
 
-    def update_task_files(self, task_id: int,files: str):
+    def update_task_files(self, task_id: int, files: str):
         task = self.get_task(task_id)
         task = self.get_task(task_id)
         if not task:
         if not task:
             return None
             return None
@@ -197,8 +203,8 @@ class ProjectTaskStore:
                 task.process_status = 4
                 task.process_status = 4
             if task.send_status != 0:
             if task.send_status != 0:
                 task.send_status = 4
                 task.send_status = 4
-            task.updated_by=self.current_user.username
-            task.updated_at=datetime.now()
+            task.updated_by = self.current_user.username
+            task.updated_at = datetime.now()
             task = db_session.merge(task)
             task = db_session.merge(task)
             return ProjectTaskDto.from_model(task)
             return ProjectTaskDto.from_model(task)
 
 
@@ -221,7 +227,8 @@ class ProjectTaskStore:
             task.deleted_at = datetime.now()
             task.deleted_at = datetime.now()
             db_session.merge(task)
             db_session.merge(task)
             return True
             return True
-    def update_task_status(self,task_id:int, status:int, err:str = None):
+
+    def update_task_status(self, task_id: int, status: int, err: str = None):
         task = self.get_task(task_id)
         task = self.get_task(task_id)
         if not task:
         if not task:
             return False
             return False
@@ -233,9 +240,7 @@ class ProjectTaskStore:
             db_session.merge(task)
             db_session.merge(task)
             return True
             return True
 
 
-
-
-    def update_process_status(self,task_id:int, status:int, err:str = None):
+    def update_process_status(self, task_id: int, status: int, err: str = None):
         task = self.get_task(task_id)
         task = self.get_task(task_id)
         if not task:
         if not task:
             return False
             return False
@@ -247,7 +252,7 @@ class ProjectTaskStore:
             db_session.merge(task)
             db_session.merge(task)
             return True
             return True
 
 
-    def update_send_status(self,task_id:int, status:int, err:str = None):
+    def update_send_status(self, task_id: int, status: int, err: str = None):
         task = self.get_task(task_id)
         task = self.get_task(task_id)
         if not task:
         if not task:
             return False
             return False
@@ -258,4 +263,3 @@ class ProjectTaskStore:
             task.send_time = datetime.now()
             task.send_time = datetime.now()
             db_session.merge(task)
             db_session.merge(task)
             return True
             return True
-

+ 65 - 49
SourceCode/IntelligentRailwayCosting/app/tools/db_helper/mysql_helper.py

@@ -6,31 +6,34 @@ from sqlalchemy.engine import Engine
 from .base import DBHelper
 from .base import DBHelper
 from pymysql import Error
 from pymysql import Error
 
 
+
 class MySQLHelper(DBHelper):
 class MySQLHelper(DBHelper):
     def __init__(self):
     def __init__(self):
         super().__init__()
         super().__init__()
         self._connections: Dict[str, pymysql.Connection] = {}
         self._connections: Dict[str, pymysql.Connection] = {}
         self._default_config = {
         self._default_config = {
-            'db': '',
-            'host': 'localhost',
-            'port': 3306,
-            'user': '',
-            'password': '',
-            'charset': 'utf8mb4',
-            'pool_size': 5,
-            'max_overflow': 10,
-            'pool_timeout': 30,
-            'pool_recycle': 3600
+            "db": "",
+            "host": "localhost",
+            "port": 3306,
+            "user": "",
+            "password": "",
+            "charset": "utf8mb4",
+            "pool_size": 5,
+            "max_overflow": 10,
+            "pool_timeout": 30,
+            "pool_recycle": 3600,
         }
         }
         self.main_database_name = "mysql_main"
         self.main_database_name = "mysql_main"
 
 
-    def get_engine(self, database: str, config: Optional[Dict[str, Any]] = None) -> Engine:
+    def get_engine(
+            self, database: str, config: Optional[Dict[str, Any]] = None
+    ) -> Engine:
         """获取或创建数据库引擎
         """获取或创建数据库引擎
-        
+
         Args:
         Args:
             database: 数据库名称
             database: 数据库名称
             config: 可选的连接配置
             config: 可选的连接配置
-            
+
         Returns:
         Returns:
             SQLAlchemy引擎实例
             SQLAlchemy引擎实例
         """
         """
@@ -39,10 +42,10 @@ class MySQLHelper(DBHelper):
         conn_config.update(db_config)
         conn_config.update(db_config)
         if config:
         if config:
             conn_config.update(config)
             conn_config.update(config)
-        
-        if 'db' not in conn_config or not conn_config['db']:
-            conn_config['db'] = database
-        
+
+        if "db" not in conn_config or not conn_config["db"]:
+            conn_config["db"] = database
+
         url = f"mysql+pymysql://{conn_config['user']}:{conn_config['password']}@{conn_config['host']}:{conn_config['port']}/{conn_config['db']}"
         url = f"mysql+pymysql://{conn_config['user']}:{conn_config['password']}@{conn_config['host']}:{conn_config['port']}/{conn_config['db']}"
         engine = create_engine(
         engine = create_engine(
             url,
             url,
@@ -50,17 +53,19 @@ class MySQLHelper(DBHelper):
             max_overflow=5,  # 减小最大溢出连接数
             max_overflow=5,  # 减小最大溢出连接数
             pool_timeout=30,
             pool_timeout=30,
             pool_recycle=1800,  # 缩短连接回收时间为30分钟
             pool_recycle=1800,  # 缩短连接回收时间为30分钟
-            pool_pre_ping=True  # 启用连接健康检查
+            pool_pre_ping=True,  # 启用连接健康检查
         )
         )
         return engine
         return engine
-    
-    def connect(self, database: str, config: Optional[Dict[str, str]] = None) -> pymysql.Connection:
+
+    def connect(
+            self, database: str, config: Optional[Dict[str, str]] = None
+    ) -> pymysql.Connection:
         """连接到指定数据库
         """连接到指定数据库
-        
+
         Args:
         Args:
             database: 数据库名称
             database: 数据库名称
             config: 可选的连接配置,如果不提供则使用默认配置
             config: 可选的连接配置,如果不提供则使用默认配置
-            
+
         Returns:
         Returns:
             数据库连接对象
             数据库连接对象
         """
         """
@@ -74,27 +79,27 @@ class MySQLHelper(DBHelper):
                 except Error:
                 except Error:
                     pass
                     pass
                 del self._connections[database]
                 del self._connections[database]
-        
+
         conn_config = self._default_config.copy()
         conn_config = self._default_config.copy()
         db_config = self.get_config_for_database(database)
         db_config = self.get_config_for_database(database)
         conn_config.update(db_config)
         conn_config.update(db_config)
         if config:
         if config:
             conn_config.update(config)
             conn_config.update(config)
-        
-        if 'db' not in conn_config or not conn_config['db']:
-            conn_config['db'] = database
-        
+
+        if "db" not in conn_config or not conn_config["db"]:
+            conn_config["db"] = database
+
         connection = pymysql.connect(**conn_config)
         connection = pymysql.connect(**conn_config)
         self._connections[database] = connection
         self._connections[database] = connection
         return connection
         return connection
-    
+
     @contextmanager
     @contextmanager
     def connection(self, database: str):
     def connection(self, database: str):
         """获取数据库连接的上下文管理器
         """获取数据库连接的上下文管理器
-        
+
         Args:
         Args:
             database: 数据库名称
             database: 数据库名称
-            
+
         Yields:
         Yields:
             数据库连接对象
             数据库连接对象
         """
         """
@@ -103,56 +108,67 @@ class MySQLHelper(DBHelper):
             yield connection
             yield connection
         finally:
         finally:
             pass
             pass
-    
-    def execute_query(self, database: str, query: str, params: Optional[Tuple] = None) -> List[Tuple]:
+
+    def execute_query(
+            self, database: str, query: str, params: Optional[Tuple] = None
+    ) -> List[Tuple]:
         connection = self.connect(database)
         connection = self.connect(database)
         cursor = connection.cursor()
         cursor = connection.cursor()
-        
+
         try:
         try:
             if params:
             if params:
                 cursor.execute(query, params)
                 cursor.execute(query, params)
             else:
             else:
                 cursor.execute(query)
                 cursor.execute(query)
-            
+
             results = cursor.fetchall()
             results = cursor.fetchall()
             return [tuple(row) for row in results]
             return [tuple(row) for row in results]
         finally:
         finally:
             cursor.close()
             cursor.close()
-    
-    def execute_non_query(self, database: str, query: str, params: Optional[Tuple] = None) -> int:
+
+    def execute_non_query(
+            self, database: str, query: str, params: Optional[Tuple] = None
+    ) -> int:
         connection = self.connect(database)
         connection = self.connect(database)
         cursor = connection.cursor()
         cursor = connection.cursor()
-        
+
         try:
         try:
             if params:
             if params:
                 cursor.execute(query, params)
                 cursor.execute(query, params)
             else:
             else:
                 cursor.execute(query)
                 cursor.execute(query)
-            
+
             connection.commit()
             connection.commit()
             return cursor.rowcount
             return cursor.rowcount
         finally:
         finally:
             cursor.close()
             cursor.close()
-    
-    def execute_scalar(self, database: str, query: str, params: Optional[Tuple] = None) -> Any:
+
+    def execute_scalar(
+            self, database: str, query: str, params: Optional[Tuple] = None
+    ) -> Any:
         connection = self.connect(database)
         connection = self.connect(database)
         cursor = connection.cursor()
         cursor = connection.cursor()
-        
+
         try:
         try:
             if params:
             if params:
                 cursor.execute(query, params)
                 cursor.execute(query, params)
             else:
             else:
                 cursor.execute(query)
                 cursor.execute(query)
-            
+
             row = cursor.fetchone()
             row = cursor.fetchone()
             return row[0] if row else None
             return row[0] if row else None
         finally:
         finally:
             cursor.close()
             cursor.close()
-    
-    def execute_procedure(self, database: str, procedure_name: str, params: Optional[Dict[str, Any]] = None) -> List[Tuple]:
+
+    def execute_procedure(
+            self,
+            database: str,
+            procedure_name: str,
+            params: Optional[Dict[str, Any]] = None,
+    ) -> List[Tuple]:
         connection = self.connect(database)
         connection = self.connect(database)
         cursor = connection.cursor()
         cursor = connection.cursor()
-        
+
         try:
         try:
             if params:
             if params:
                 param_placeholders = ", ".join([f"%s" for _ in params.keys()])
                 param_placeholders = ", ".join([f"%s" for _ in params.keys()])
@@ -160,12 +176,12 @@ class MySQLHelper(DBHelper):
                 cursor.execute(query, list(params.values()))
                 cursor.execute(query, list(params.values()))
             else:
             else:
                 cursor.execute(f"CALL {procedure_name}()")
                 cursor.execute(f"CALL {procedure_name}()")
-            
+
             results = cursor.fetchall()
             results = cursor.fetchall()
             return [tuple(row) for row in results]
             return [tuple(row) for row in results]
         finally:
         finally:
             cursor.close()
             cursor.close()
-    
+
     def dispose_all(self) -> None:
     def dispose_all(self) -> None:
         """释放所有数据库连接"""
         """释放所有数据库连接"""
         for conn in self._connections.values():
         for conn in self._connections.values():
@@ -174,7 +190,7 @@ class MySQLHelper(DBHelper):
             except Error:
             except Error:
                 pass
                 pass
         self._connections.clear()
         self._connections.clear()
-    
+
     def __del__(self):
     def __del__(self):
         """析构函数,确保所有连接被关闭"""
         """析构函数,确保所有连接被关闭"""
-        self.dispose_all()
+        self.dispose_all()

+ 53 - 34
SourceCode/IntelligentRailwayCosting/app/tools/db_helper/sqlserver_helper.py

@@ -12,30 +12,37 @@ class SQLServerHelper(DBHelper):
         super().__init__()
         super().__init__()
         self._session_makers: Dict[str, sessionmaker] = {}
         self._session_makers: Dict[str, sessionmaker] = {}
         self._default_config = {
         self._default_config = {
-            'driver': 'ODBC Driver 17 for SQL Server',
-            'server': 'localhost',
-            'username': '',
-            'password': '',
-            'trusted_connection': 'yes'
+            "driver": "ODBC Driver 17 for SQL Server",
+            "server": "localhost",
+            "username": "",
+            "password": "",
+            "trusted_connection": "yes",
         }
         }
         self._pool_config = {
         self._pool_config = {
-            'pool_size': 5,  # 减少初始连接数以降低资源占用
-            'max_overflow': 10,  # 适当减少最大溢出连接数
-            'pool_timeout': 60,  # 增加池等待超时时间
-            'pool_recycle': 1800,  # 每30分钟回收连接
-            'pool_pre_ping': True,  # 启用连接健康检查
-            'connect_args': {
-                'timeout': 60,  # 连接超时时间
-                'driver_connects_timeout': 60,  # 驱动连接超时
-                'connect_timeout': 60,  # ODBC连接超时
-                'connect_retries': 3,  # 连接重试次数
-                'connect_retry_interval': 10,  # 重试间隔增加到10秒
-                'connection_timeout': 60  # 额外的连接超时设置
-            }
+            "pool_size": 5,  # 减少初始连接数以降低资源占用
+            "max_overflow": 10,  # 适当减少最大溢出连接数
+            "pool_timeout": 60,  # 增加池等待超时时间
+            "pool_recycle": 1800,  # 每30分钟回收连接
+            "pool_pre_ping": True,  # 启用连接健康检查
+            "connect_args": {
+                "timeout": 60,  # 连接超时时间
+                "driver_connects_timeout": 60,  # 驱动连接超时
+                "connect_timeout": 60,  # ODBC连接超时
+                "connect_retries": 3,  # 连接重试次数
+                "connect_retry_interval": 10,  # 重试间隔增加到10秒
+                "connection_timeout": 60,  # 额外的连接超时设置
+            },
         }
         }
 
 
-        self.main_database_name = f"sqlserver_mian_{configs.app.version}" if configs.app.use_version else "sqlserver_mian"
-    def _build_connection_string(self, database: str, config: Optional[Dict[str, str]] = None) -> str:
+        self.main_database_name = (
+            f"sqlserver_mian_{configs.app.version}"
+            if configs.app.use_version
+            else "sqlserver_mian"
+        )
+
+    def _build_connection_string(
+            self, database: str, config: Optional[Dict[str, str]] = None
+    ) -> str:
         """构建连接字符串"""
         """构建连接字符串"""
         conn_config = self._default_config.copy()
         conn_config = self._default_config.copy()
         db_config = self.get_config_for_database(database)
         db_config = self.get_config_for_database(database)
@@ -45,30 +52,31 @@ class SQLServerHelper(DBHelper):
 
 
         # 构建认证字符串
         # 构建认证字符串
         auth_params = []
         auth_params = []
-        if conn_config.get('trusted_connection', True):
+        if conn_config.get("trusted_connection", True):
             auth_params.append("Trusted_Connection=yes")
             auth_params.append("Trusted_Connection=yes")
         else:
         else:
-            auth_params.extend([
-                f"UID={conn_config['username']}",
-                f"PWD={conn_config['password']}"
-            ])
+            auth_params.extend(
+                [f"UID={conn_config['username']}", f"PWD={conn_config['password']}"]
+            )
 
 
         # 构建ODBC连接字符串
         # 构建ODBC连接字符串
         conn_parts = [
         conn_parts = [
             f"DRIVER={conn_config['driver']}",
             f"DRIVER={conn_config['driver']}",
             f"SERVER={conn_config['server']}",
             f"SERVER={conn_config['server']}",
             f"DATABASE={conn_config['database'] if 'database' in conn_config else database}",
             f"DATABASE={conn_config['database'] if 'database' in conn_config else database}",
-            "CHARSET=UTF-8"
+            "CHARSET=UTF-8",
         ]
         ]
         conn_parts.extend(auth_params)
         conn_parts.extend(auth_params)
-        
+
         # 构建SQLAlchemy连接URL
         # 构建SQLAlchemy连接URL
         conn_str = ";".join(conn_parts)
         conn_str = ";".join(conn_parts)
         conn_url = f"mssql+pyodbc:///?odbc_connect={conn_str}"
         conn_url = f"mssql+pyodbc:///?odbc_connect={conn_str}"
 
 
         return conn_url
         return conn_url
 
 
-    def get_engine(self, database: str, config: Optional[Dict[str, str]] = None) -> Engine:
+    def get_engine(
+            self, database: str, config: Optional[Dict[str, str]] = None
+    ) -> Engine:
         """获取或创建数据库引擎"""
         """获取或创建数据库引擎"""
         conn_str = self._build_connection_string(database, config)
         conn_str = self._build_connection_string(database, config)
         engine = create_engine(conn_str, **self._pool_config)
         engine = create_engine(conn_str, **self._pool_config)
@@ -77,31 +85,42 @@ class SQLServerHelper(DBHelper):
             conn.execute(text("SELECT 1"))
             conn.execute(text("SELECT 1"))
         return engine
         return engine
 
 
-    def execute_query(self, database: str, query: str, params: Optional[Dict[str, Any]] = None) -> List[Tuple]:
+    def execute_query(
+            self, database: str, query: str, params: Optional[Dict[str, Any]] = None
+    ) -> List[Tuple]:
         """执行查询并返回结果"""
         """执行查询并返回结果"""
         with self.session_scope(database) as session:
         with self.session_scope(database) as session:
             result = session.execute(text(query), params or {})
             result = session.execute(text(query), params or {})
             return [tuple(row) for row in result.fetchall()]
             return [tuple(row) for row in result.fetchall()]
 
 
-    def execute_non_query(self, database: str, query: str, params: Optional[Dict[str, Any]] = None) -> int:
+    def execute_non_query(
+            self, database: str, query: str, params: Optional[Dict[str, Any]] = None
+    ) -> int:
         """执行非查询操作(如INSERT, UPDATE, DELETE)"""
         """执行非查询操作(如INSERT, UPDATE, DELETE)"""
         with self.session_scope(database) as session:
         with self.session_scope(database) as session:
             result = session.execute(text(query), params or {})
             result = session.execute(text(query), params or {})
             return result.rowcount
             return result.rowcount
 
 
-    def execute_scalar(self, database: str, query: str, params: Optional[Dict[str, Any]] = None) -> Any:
+    def execute_scalar(
+            self, database: str, query: str, params: Optional[Dict[str, Any]] = None
+    ) -> Any:
         """执行查询并返回第一行第一列的值"""
         """执行查询并返回第一行第一列的值"""
         with self.session_scope(database) as session:
         with self.session_scope(database) as session:
             result = session.execute(text(query), params or {})
             result = session.execute(text(query), params or {})
             row = result.fetchone()
             row = result.fetchone()
             return row[0] if row else None
             return row[0] if row else None
 
 
-    def execute_procedure(self, database: str, procedure_name: str, params: Optional[Dict[str, Any]] = None) -> List[Tuple]:
+    def execute_procedure(
+            self,
+            database: str,
+            procedure_name: str,
+            params: Optional[Dict[str, Any]] = None,
+    ) -> List[Tuple]:
         """执行存储过程"""
         """执行存储过程"""
         params = params or {}
         params = params or {}
         param_str = ", ".join([f"@{key}=:{key}" for key in params.keys()])
         param_str = ", ".join([f"@{key}=:{key}" for key in params.keys()])
         query = f"EXEC {procedure_name} {param_str}"
         query = f"EXEC {procedure_name} {param_str}"
-        
+
         with self.session_scope(database) as session:
         with self.session_scope(database) as session:
             result = session.execute(text(query), params)
             result = session.execute(text(query), params)
             return [tuple(row) for row in result.fetchall()]
             return [tuple(row) for row in result.fetchall()]
@@ -112,4 +131,4 @@ class SQLServerHelper(DBHelper):
 
 
     def __del__(self):
     def __del__(self):
         """析构函数,确保所有引擎资源被释放"""
         """析构函数,确保所有引擎资源被释放"""
-        self.dispose_all()
+        self.dispose_all()

+ 20 - 1
SourceCode/IntelligentRailwayCosting/app/tools/utils/__init__.py

@@ -6,6 +6,7 @@ from tools.utils.file_helper import FileHelper
 from tools.utils.logger_helper import LoggerHelper
 from tools.utils.logger_helper import LoggerHelper
 from tools.utils.string_helper import StringHelper
 from tools.utils.string_helper import StringHelper
 
 
+
 def get_logger():
 def get_logger():
     """
     """
     获取日志记录器实例。
     获取日志记录器实例。
@@ -18,6 +19,7 @@ def get_logger():
     """
     """
     return LoggerHelper.get_logger()
     return LoggerHelper.get_logger()
 
 
+
 def clean_log_file(day: int):
 def clean_log_file(day: int):
     """
     """
     清理指定天数之前的日志文件。
     清理指定天数之前的日志文件。
@@ -26,6 +28,7 @@ def clean_log_file(day: int):
     """
     """
     LoggerHelper.clean_log_file(day)
     LoggerHelper.clean_log_file(day)
 
 
+
 def get_config():
 def get_config():
     """
     """
     获取配置管理器实例。
     获取配置管理器实例。
@@ -36,6 +39,7 @@ def get_config():
     """
     """
     return ConfigHelper()
     return ConfigHelper()
 
 
+
 def reload_config():
 def reload_config():
     """
     """
     重新加载配置文件。
     重新加载配置文件。
@@ -44,6 +48,7 @@ def reload_config():
     """
     """
     get_config().load_config()
     get_config().load_config()
 
 
+
 def get_config_value(key: str, default: str = None):
 def get_config_value(key: str, default: str = None):
     """
     """
     获取配置项的值。
     获取配置项的值。
@@ -54,6 +59,7 @@ def get_config_value(key: str, default: str = None):
     """
     """
     return get_config().get(key, default)
     return get_config().get(key, default)
 
 
+
 def get_config_int(key: str, default: int = None):
 def get_config_int(key: str, default: int = None):
     """
     """
     获取配置项的整数值。
     获取配置项的整数值。
@@ -64,6 +70,7 @@ def get_config_int(key: str, default: int = None):
     """
     """
     return get_config().get_int(key, default)
     return get_config().get_int(key, default)
 
 
+
 def get_config_object(key: str, default: dict = None):
 def get_config_object(key: str, default: dict = None):
     """
     """
     获取配置项的JSON对象。
     获取配置项的JSON对象。
@@ -73,6 +80,8 @@ def get_config_object(key: str, default: dict = None):
     :return: 字典,配置项的JSON对象。
     :return: 字典,配置项的JSON对象。
     """
     """
     return get_config().get_object(key, default)
     return get_config().get_object(key, default)
+
+
 def get_config_bool(key: str):
 def get_config_bool(key: str):
     """
     """
     获取配置项的布尔值。
     获取配置项的布尔值。
@@ -82,6 +91,7 @@ def get_config_bool(key: str):
     """
     """
     return get_config().get_bool(key)
     return get_config().get_bool(key)
 
 
+
 def download_remote_file(file_url: str, file_name: str) -> str:
 def download_remote_file(file_url: str, file_name: str) -> str:
     """
     """
     下载远程文件并保存到本地。
     下载远程文件并保存到本地。
@@ -92,6 +102,7 @@ def download_remote_file(file_url: str, file_name: str) -> str:
     """
     """
     return FileHelper().download_remote_file(file_url, file_name)
     return FileHelper().download_remote_file(file_url, file_name)
 
 
+
 def clean_attach_file(day: int):
 def clean_attach_file(day: int):
     """
     """
     清理指定天数之前的附件文件。
     清理指定天数之前的附件文件。
@@ -100,6 +111,7 @@ def clean_attach_file(day: int):
     """
     """
     FileHelper().clean_attach_file(day)
     FileHelper().clean_attach_file(day)
 
 
+
 def save_report_excel(data, file_name: str = None) -> str:
 def save_report_excel(data, file_name: str = None) -> str:
     """
     """
     保存报表数据到Excel文件。
     保存报表数据到Excel文件。
@@ -110,6 +122,7 @@ def save_report_excel(data, file_name: str = None) -> str:
     """
     """
     return FileHelper().save_report_excel(data, file_name)
     return FileHelper().save_report_excel(data, file_name)
 
 
+
 def clean_report_file(day: int):
 def clean_report_file(day: int):
     """
     """
     清理指定天数之前的报表文件。
     清理指定天数之前的报表文件。
@@ -118,9 +131,11 @@ def clean_report_file(day: int):
     """
     """
     FileHelper().clean_report_file(day)
     FileHelper().clean_report_file(day)
 
 
+
 def encode_file(path: str):
 def encode_file(path: str):
     return FileHelper.encode_file(path)
     return FileHelper.encode_file(path)
 
 
+
 def to_array(s: str, split: str = ",") -> list[str]:
 def to_array(s: str, split: str = ",") -> list[str]:
     """
     """
     将字符串按指定分隔符拆分为数组。
     将字符串按指定分隔符拆分为数组。
@@ -131,7 +146,8 @@ def to_array(s: str, split: str = ",") -> list[str]:
     """
     """
     return StringHelper.to_array(s, split)
     return StringHelper.to_array(s, split)
 
 
-def to_str(data:dict|list|tuple):
+
+def to_str(data: dict | list | tuple):
     """
     """
     将对象转成字符串
     将对象转成字符串
     :param data:
     :param data:
@@ -139,6 +155,7 @@ def to_str(data:dict|list|tuple):
     """
     """
     return StringHelper.to_str(data)
     return StringHelper.to_str(data)
 
 
+
 def is_email(email: str) -> bool:
 def is_email(email: str) -> bool:
     """
     """
     判断字符串是否为有效的电子邮件地址。
     判断字符串是否为有效的电子邮件地址。
@@ -148,6 +165,7 @@ def is_email(email: str) -> bool:
     """
     """
     return StringHelper.is_email(email)
     return StringHelper.is_email(email)
 
 
+
 def is_phone(phone: str) -> bool:
 def is_phone(phone: str) -> bool:
     """
     """
     判断字符串是否为有效的手机号码。
     判断字符串是否为有效的手机号码。
@@ -157,6 +175,7 @@ def is_phone(phone: str) -> bool:
     """
     """
     return StringHelper.is_phone(phone)
     return StringHelper.is_phone(phone)
 
 
+
 def call_openai(system_prompt: str, user_prompt: str) -> json:
 def call_openai(system_prompt: str, user_prompt: str) -> json:
     """
     """
     调用OpenAI API进行对话。
     调用OpenAI API进行对话。

+ 51 - 18
SourceCode/IntelligentRailwayCosting/app/tools/utils/ai_helper.py

@@ -1,16 +1,16 @@
 import json, re
 import json, re
 
 
-import tools.utils as  utils
+import tools.utils as utils
 from openai import OpenAI
 from openai import OpenAI
 from pathlib import Path
 from pathlib import Path
 
 
-class AiHelper:
 
 
+class AiHelper:
     _ai_api_key = None
     _ai_api_key = None
     _ai_api_url = None
     _ai_api_url = None
     _ai_max_tokens = 150
     _ai_max_tokens = 150
 
 
-    def __init__(self, api_url: str=None, api_key: str=None, api_model: str=None):
+    def __init__(self, api_url: str = None, api_key: str = None, api_model: str = None):
         self._ai_api_url = api_url if api_url else utils.get_config_value("ai.url")
         self._ai_api_url = api_url if api_url else utils.get_config_value("ai.url")
         self._ai_api_key = api_key if api_key else utils.get_config_value("ai.key")
         self._ai_api_key = api_key if api_key else utils.get_config_value("ai.key")
         self._api_model = api_model if api_model else utils.get_config_value("ai.model")
         self._api_model = api_model if api_model else utils.get_config_value("ai.model")
@@ -18,9 +18,18 @@ class AiHelper:
         if max_tokens:
         if max_tokens:
             self._ai_max_tokens = int(max_tokens)
             self._ai_max_tokens = int(max_tokens)
 
 
-    def call_openai(self, system_prompt: str, user_prompt: str,api_url: str=None,api_key: str=None,api_model: str=None) -> json:
+    def call_openai(
+            self,
+            system_prompt: str,
+            user_prompt: str,
+            api_url: str = None,
+            api_key: str = None,
+            api_model: str = None,
+    ) -> json:
         self.check_api(api_key, api_model, api_url)
         self.check_api(api_key, api_model, api_url)
-        utils.get_logger().info(f"调用AI API ==> Url:{self._ai_api_url},Model:{self._api_model}")
+        utils.get_logger().info(
+            f"调用AI API ==> Url:{self._ai_api_url},Model:{self._api_model}"
+        )
 
 
         client = OpenAI(api_key=self._ai_api_key, base_url=self._ai_api_url)
         client = OpenAI(api_key=self._ai_api_key, base_url=self._ai_api_url)
         completion = client.chat.completions.create(
         completion = client.chat.completions.create(
@@ -85,18 +94,19 @@ class AiHelper:
             raise Exception("AI 响应中未找到有效的 choices 或 message 数据")
             raise Exception("AI 响应中未找到有效的 choices 或 message 数据")
 
 
         # 移除多余的 ```json 和 ```
         # 移除多余的 ```json 和 ```
-        if message_content.startswith("```json") and message_content.endswith(
-                "```"):
+        if message_content.startswith("```json") and message_content.endswith("```"):
             message_content = message_content[6:-3]
             message_content = message_content[6:-3]
 
 
         # 去除开头的 'n' 字符
         # 去除开头的 'n' 字符
         if message_content.startswith("n"):
         if message_content.startswith("n"):
             message_content = message_content[1:]
             message_content = message_content[1:]
         # 移除无效的转义字符和时间戳前缀
         # 移除无效的转义字符和时间戳前缀
-        message_content = re.sub(r"\\[0-9]{2}", "",
-                                 message_content)  # 移除 \32 等无效转义字符
-        message_content = re.sub(r"\d{4}-\d{2}-\dT\d{2}:\d{2}:\d{2}\.\d+Z", "",
-                                 message_content)  # 移除时间戳
+        message_content = re.sub(
+            r"\\[0-9]{2}", "", message_content
+        )  # 移除 \32 等无效转义字符
+        message_content = re.sub(
+            r"\d{4}-\d{2}-\dT\d{2}:\d{2}:\d{2}\.\d+Z", "", message_content
+        )  # 移除时间戳
         message_content = message_content.strip()  # 去除首尾空白字符
         message_content = message_content.strip()  # 去除首尾空白字符
 
 
         # 替换所有的反斜杠
         # 替换所有的反斜杠
@@ -112,7 +122,9 @@ class AiHelper:
 
 
         except json.JSONDecodeError as e:
         except json.JSONDecodeError as e:
             if first:
             if first:
-                utils.get_logger().error(f"JSON 解析错误,去除部分特殊字符重新解析一次: {e}")
+                utils.get_logger().error(
+                    f"JSON 解析错误,去除部分特殊字符重新解析一次: {e}"
+                )
                 # 替换中文引号为空
                 # 替换中文引号为空
                 message_content = re.sub(r"[“”]", "", response)  # 替换双引号
                 message_content = re.sub(r"[“”]", "", response)  # 替换双引号
                 message_content = re.sub(r"[‘’]", "", message_content)  # 替换单引号
                 message_content = re.sub(r"[‘’]", "", message_content)  # 替换单引号
@@ -120,22 +132,43 @@ class AiHelper:
             else:
             else:
                 raise Exception(f"解析 AI 响应错误: {response} {e}")
                 raise Exception(f"解析 AI 响应错误: {response} {e}")
 
 
-    def call_openai_with_image(self, image_path,system_prompt: str, user_prompt: str, api_url: str=None,api_key: str=None,api_model: str=None) -> json:
+    def call_openai_with_image(
+            self,
+            image_path,
+            system_prompt: str,
+            user_prompt: str,
+            api_url: str = None,
+            api_key: str = None,
+            api_model: str = None,
+    ) -> json:
         pass
         pass
 
 
-    def call_openai_with_file(self, file_path,system_prompt: str, user_prompt: str, api_url: str=None,api_key: str=None,api_model: str=None)->json:
+    def call_openai_with_file(
+            self,
+            file_path,
+            system_prompt: str,
+            user_prompt: str,
+            api_url: str = None,
+            api_key: str = None,
+            api_model: str = None,
+    ) -> json:
         self.check_api(api_key, api_model, api_url)
         self.check_api(api_key, api_model, api_url)
-        utils.get_logger().info(f"调用AI API File==> Url:{self._ai_api_url},Model:{self._api_model}")
+        utils.get_logger().info(
+            f"调用AI API File==> Url:{self._ai_api_url},Model:{self._api_model}"
+        )
 
 
         client = OpenAI(api_key=self._ai_api_key, base_url=self._ai_api_url)
         client = OpenAI(api_key=self._ai_api_key, base_url=self._ai_api_url)
-        file_object = client.files.create(    file=Path(file_path),purpose='file-extract',)
+        file_object = client.files.create(
+            file=Path(file_path),
+            purpose="file-extract",
+        )
         completion = client.chat.completions.create(
         completion = client.chat.completions.create(
             model=self._api_model,
             model=self._api_model,
             messages=[
             messages=[
                 {
                 {
                     "role": "system",
                     "role": "system",
                     # "content": system_prompt,
                     # "content": system_prompt,
-                    'content': f'fileid://{file_object.id}'
+                    "content": f"fileid://{file_object.id}",
                 },
                 },
                 {
                 {
                     "role": "user",
                     "role": "user",
@@ -165,4 +198,4 @@ class AiHelper:
             return result
             return result
         except Exception as e:
         except Exception as e:
             raise Exception(f"解析 AI 响应错误: {e}")
             raise Exception(f"解析 AI 响应错误: {e}")
-        pass
+        pass

+ 3 - 1
SourceCode/IntelligentRailwayCosting/app/tools/utils/config_helper.py

@@ -1,5 +1,6 @@
 import os, yaml
 import os, yaml
 
 
+
 class ConfigHelper:
 class ConfigHelper:
     _instance = None
     _instance = None
 
 
@@ -35,7 +36,7 @@ class ConfigHelper:
     def _merge_env_vars(self, env_prefix="APP_"):  # 环境变量前缀为 APP_
     def _merge_env_vars(self, env_prefix="APP_"):  # 环境变量前缀为 APP_
         for key, value in os.environ.items():
         for key, value in os.environ.items():
             if key.startswith(env_prefix):
             if key.startswith(env_prefix):
-                config_key = key[len(env_prefix) :].lower()
+                config_key = key[len(env_prefix):].lower()
                 self._set_nested_key(self._config, config_key.split("__"), value)
                 self._set_nested_key(self._config, config_key.split("__"), value)
 
 
     def _set_nested_key(self, config, keys, value):
     def _set_nested_key(self, config, keys, value):
@@ -69,6 +70,7 @@ class ConfigHelper:
         except yaml.YAMLError as e:
         except yaml.YAMLError as e:
             print(f"Error loading YAML object: {e}")
             print(f"Error loading YAML object: {e}")
             return default
             return default
+
     def get_bool(self, key: str) -> bool:
     def get_bool(self, key: str) -> bool:
         val = self.get(key, "0")
         val = self.get(key, "0")
         if isinstance(val, bool):
         if isinstance(val, bool):

+ 13 - 6
SourceCode/IntelligentRailwayCosting/app/tools/utils/file_helper.py

@@ -11,7 +11,6 @@ import base64
 
 
 
 
 class FileHelper:
 class FileHelper:
-
     DEFAULT_ATTACH_PATH = "./temp_files/attaches/"
     DEFAULT_ATTACH_PATH = "./temp_files/attaches/"
     DEFAULT_REPORT_PATH = "./temp_files/report/"
     DEFAULT_REPORT_PATH = "./temp_files/report/"
 
 
@@ -104,9 +103,13 @@ class FileHelper:
                                     f"  删除目录及其内容: {dir_path}"
                                     f"  删除目录及其内容: {dir_path}"
                                 )
                                 )
                             except PermissionError:
                             except PermissionError:
-                                utils.get_logger().error(f"  权限错误,无法删除目录: {dir_path}")
+                                utils.get_logger().error(
+                                    f"  权限错误,无法删除目录: {dir_path}"
+                                )
                             except Exception as e:
                             except Exception as e:
-                                utils.get_logger().error(f"  删除目录失败: {dir_path}。Exception: {e}")
+                                utils.get_logger().error(
+                                    f"  删除目录失败: {dir_path}。Exception: {e}"
+                                )
                     except ValueError:
                     except ValueError:
                         # 如果目录名称不符合 %Y-%m/%d 格式,跳过
                         # 如果目录名称不符合 %Y-%m/%d 格式,跳过
                         continue
                         continue
@@ -153,9 +156,13 @@ class FileHelper:
                                     f"  Report 删除目录及其内容: {dir_path}"
                                     f"  Report 删除目录及其内容: {dir_path}"
                                 )
                                 )
                             except PermissionError:
                             except PermissionError:
-                                utils.get_logger().error(f"  Report 权限错误,无法删除目录: {dir_path}")
+                                utils.get_logger().error(
+                                    f"  Report 权限错误,无法删除目录: {dir_path}"
+                                )
                             except Exception as e:
                             except Exception as e:
-                                utils.get_logger().error(f"  Report 删除目录失败: {dir_path}。Exception: {e}")
+                                utils.get_logger().error(
+                                    f"  Report 删除目录失败: {dir_path}。Exception: {e}"
+                                )
                     except ValueError:
                     except ValueError:
                         # 如果目录名称不符合 %Y-%m/%d 格式,跳过
                         # 如果目录名称不符合 %Y-%m/%d 格式,跳过
                         continue
                         continue
@@ -170,7 +177,7 @@ class FileHelper:
         # 根据文件扩展名获取 MIME 类型
         # 根据文件扩展名获取 MIME 类型
         mime_type, _ = mimetypes.guess_type(file_path)
         mime_type, _ = mimetypes.guess_type(file_path)
         if mime_type is None:
         if mime_type is None:
-            mime_type = 'image/jpeg'  # 默认使用 jpeg 类型
+            mime_type = "image/jpeg"  # 默认使用 jpeg 类型
         # 将图片编码为 base64 字符串
         # 将图片编码为 base64 字符串
         with open(file_path, "rb") as image_file:
         with open(file_path, "rb") as image_file:
             encoded_string = base64.b64encode(image_file.read())
             encoded_string = base64.b64encode(image_file.read())

+ 10 - 4
SourceCode/IntelligentRailwayCosting/app/tools/utils/string_helper.py

@@ -1,4 +1,6 @@
 import json
 import json
+
+
 class StringHelper:
 class StringHelper:
 
 
     @staticmethod
     @staticmethod
@@ -76,12 +78,14 @@ class StringHelper:
         return " ".join(s.split())
         return " ".join(s.split())
 
 
     @staticmethod
     @staticmethod
-    def to_str(data:dict|list|tuple):
+    def to_str(data: dict | list | tuple):
         def datetime_handler(obj):
         def datetime_handler(obj):
-            if hasattr(obj, 'isoformat'):
+            if hasattr(obj, "isoformat"):
                 return obj.isoformat()
                 return obj.isoformat()
             return str(obj)
             return str(obj)
+
         return json.dumps(data, ensure_ascii=False, default=datetime_handler)
         return json.dumps(data, ensure_ascii=False, default=datetime_handler)
+
     @staticmethod
     @staticmethod
     def is_email(s: str) -> bool:
     def is_email(s: str) -> bool:
         """
         """
@@ -91,7 +95,8 @@ class StringHelper:
         :return: 如果是有效的邮箱地址返回True,否则返回False。
         :return: 如果是有效的邮箱地址返回True,否则返回False。
         """
         """
         import re
         import re
-        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
+
+        pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
         return bool(re.match(pattern, s)) if s else False
         return bool(re.match(pattern, s)) if s else False
 
 
     @staticmethod
     @staticmethod
@@ -103,5 +108,6 @@ class StringHelper:
         :return: 如果是有效的手机号码返回True,否则返回False。
         :return: 如果是有效的手机号码返回True,否则返回False。
         """
         """
         import re
         import re
-        pattern = r'^1[3-9]\d{9}$'
+
+        pattern = r"^1[3-9]\d{9}$"
         return bool(re.match(pattern, s)) if s else False
         return bool(re.match(pattern, s)) if s else False

+ 2 - 1
SourceCode/IntelligentRailwayCosting/app/views/__init__.py

@@ -2,7 +2,8 @@ from views.login import auth_bp
 from views.project import project_bp
 from views.project import project_bp
 from views.log import log_bp
 from views.log import log_bp
 
 
+
 def register_views(app):
 def register_views(app):
     app.register_blueprint(auth_bp)
     app.register_blueprint(auth_bp)
     app.register_blueprint(project_bp)
     app.register_blueprint(project_bp)
-    app.register_blueprint(log_bp)
+    app.register_blueprint(log_bp)

+ 11 - 9
SourceCode/IntelligentRailwayCosting/app/views/log.py

@@ -1,18 +1,20 @@
 from flask import Blueprint, render_template
 from flask import Blueprint, render_template
-from core.enum import OperationType,OperationModule,OperationResult
+from core.enum import OperationType, OperationModule, OperationResult
 from core.user_session import Permission
 from core.user_session import Permission
 
 
-log_bp = Blueprint('log', __name__, template_folder='templates')
+log_bp = Blueprint("log", __name__, template_folder="templates")
 
 
-@log_bp.route('/log', methods=['GET'])
+
+@log_bp.route("/log", methods=["GET"])
 @Permission.authorize
 @Permission.authorize
 def index():
 def index():
     operation_type_list = [op.value for op in OperationType]
     operation_type_list = [op.value for op in OperationType]
     operation_module_list = [op.value for op in OperationModule]
     operation_module_list = [op.value for op in OperationModule]
     operation_result_list = OperationResult.get_dict()
     operation_result_list = OperationResult.get_dict()
-    return render_template('log/index.html',
-                           page_active='log',
-                           operation_type_list=operation_type_list,
-                           operation_module_list=operation_module_list,
-                           operation_result_list=operation_result_list,
-                           )
+    return render_template(
+        "log/index.html",
+        page_active="log",
+        operation_type_list=operation_type_list,
+        operation_module_list=operation_module_list,
+        operation_result_list=operation_result_list,
+    )

+ 4 - 3
SourceCode/IntelligentRailwayCosting/app/views/login.py

@@ -3,13 +3,14 @@ from flask_login import logout_user
 from core.user_session import UserSession
 from core.user_session import UserSession
 from core.configs import config
 from core.configs import config
 
 
-auth_bp = Blueprint('auth', __name__, template_folder='templates')
+auth_bp = Blueprint("auth", __name__, template_folder="templates")
 
 
-@auth_bp.route('/login', methods=['GET'])
+
+@auth_bp.route("/login", methods=["GET"])
 def login():
 def login():
     # 如果用户已登录,重定向到首页
     # 如果用户已登录,重定向到首页
     # if 'user_id' in session:
     # if 'user_id' in session:
     #     return redirect(url_for('project.index'))
     #     return redirect(url_for('project.index'))
     logout_user()
     logout_user()
     UserSession.clear_user()
     UserSession.clear_user()
-    return render_template('account/login.html', app_name=config.app.name)
+    return render_template("account/login.html", app_name=config.app.name)

+ 23 - 9
SourceCode/IntelligentRailwayCosting/app/views/project.py

@@ -2,27 +2,41 @@ from flask import Blueprint, render_template
 from core.user_session import Permission
 from core.user_session import Permission
 from stores import BudgetStore, ProjectStore, ProjectTaskStore
 from stores import BudgetStore, ProjectStore, ProjectTaskStore
 
 
-project_bp = Blueprint('project', __name__, template_folder='templates')
+project_bp = Blueprint("project", __name__, template_folder="templates")
 project_store = ProjectStore()
 project_store = ProjectStore()
 budget_store = BudgetStore()
 budget_store = BudgetStore()
 project_task_store = ProjectTaskStore()
 project_task_store = ProjectTaskStore()
 
 
-@project_bp.route('/', methods=['GET'])
+
+@project_bp.route("/", methods=["GET"])
 @Permission.authorize
 @Permission.authorize
 def index():
 def index():
-   return render_template('project/index.html',page_active='project')
+    return render_template("project/index.html", page_active="project")
+
 
 
-@project_bp.route('/budget_info/<project_id>', methods=['GET'])
+@project_bp.route("/budget_info/<project_id>", methods=["GET"])
 @Permission.authorize
 @Permission.authorize
-def budget_info(project_id:str):
+def budget_info(project_id: str):
     project = project_store.get(project_id)
     project = project_store.get(project_id)
     budgets = budget_store.get_budget_info(project_id)
     budgets = budget_store.get_budget_info(project_id)
-    return render_template('project/budget_info.html',page_active='project',project=project,budgets=budgets)
+    return render_template(
+        "project/budget_info.html",
+        page_active="project",
+        project=project,
+        budgets=budgets,
+    )
+
 
 
-@project_bp.route('/quota_info/<project_id>/<task_id>', methods=['GET'])
+@project_bp.route("/quota_info/<project_id>/<task_id>", methods=["GET"])
 @Permission.authorize
 @Permission.authorize
-def quota_info(project_id:str,task_id:str):
+def quota_info(project_id: str, task_id: str):
     project = project_store.get(project_id)
     project = project_store.get(project_id)
     budgets = budget_store.get_budget_info(project_id)
     budgets = budget_store.get_budget_info(project_id)
     task = project_task_store.get_task_dto(task_id)
     task = project_task_store.get_task_dto(task_id)
-    return render_template('project/quota_info.html',page_active='project',project=project,budgets=budgets,task=task)
+    return render_template(
+        "project/quota_info.html",
+        page_active="project",
+        project=project,
+        budgets=budgets,
+        task=task,
+    )