瀏覽代碼

update 调整项目工程明细等结构

YueYunyun 9 月之前
父節點
當前提交
4c4ef036c4
共有 22 個文件被更改,包括 1192 次插入1090 次删除
  1. 2 1
      SourceCode/DataMiddleware/app/config.yml
  2. 5 12
      SourceCode/DataMiddleware/app/data_process/__init__.py
  3. 20 20
      SourceCode/DataMiddleware/app/data_process/pre_process.py
  4. 16 22
      SourceCode/DataMiddleware/app/data_process/process.py
  5. 0 56
      SourceCode/DataMiddleware/app/data_process/standard_data_process.py
  6. 2 2
      SourceCode/DataMiddleware/app/data_send/__init__.py
  7. 8 8
      SourceCode/DataMiddleware/app/data_send/send.py
  8. 27 33
      SourceCode/DataMiddleware/app/init.sql
  9. 53 14
      SourceCode/DataMiddleware/app/models/project_data.py
  10. 0 22
      SourceCode/DataMiddleware/app/models/standard_data.py
  11. 0 22
      SourceCode/DataMiddleware/app/models/standard_update_log.py
  12. 230 286
      SourceCode/DataMiddleware/app/stores/mysql_store.py
  13. 93 72
      SourceCode/DataMiddleware/app/ui/project_services.py
  14. 122 81
      SourceCode/DataMiddleware/app/ui/project_views.py
  15. 48 164
      SourceCode/DataMiddleware/app/ui/static/project_list.js
  16. 6 0
      SourceCode/DataMiddleware/app/ui/static/styles.css
  17. 3 3
      SourceCode/DataMiddleware/app/ui/static/sub_project_item_list.js
  18. 208 0
      SourceCode/DataMiddleware/app/ui/static/sub_project_list.js
  19. 57 239
      SourceCode/DataMiddleware/app/ui/templates/project/project_list.html
  20. 20 29
      SourceCode/DataMiddleware/app/ui/templates/project/sub_project_item_list.html
  21. 247 0
      SourceCode/DataMiddleware/app/ui/templates/project/sub_project_list.html
  22. 25 4
      SourceCode/DataMiddleware/app/utils/mysql_helper.py

+ 2 - 1
SourceCode/DataMiddleware/app/config.yml

@@ -1,7 +1,8 @@
 mysql:
   host: 192.168.0.81
   port: 3307
-  db: iwb_data_middleware_dev
+#  db: iwb_data_middleware_dev
+  db: iwb_data_middleware_v1_1
   user: root
   password: Iwb-2024
   charset: utf8mb4

+ 5 - 12
SourceCode/DataMiddleware/app/data_process/__init__.py

@@ -1,8 +1,8 @@
-from data_process import pre_process,process, standard_data_process
-from models.project_data import ProjectModel
+from data_process import pre_process,process
+from models.project_data import SubProjectModel
 
 
-def process_project(project: ProjectModel) -> bool:
+def process_project(project: SubProjectModel) -> bool:
     """
     分析处理数据
     :param project: 项目
@@ -17,7 +17,7 @@ def process_project(project: ProjectModel) -> bool:
         return False
 
 
-def _pre_process_data(project: ProjectModel) -> bool:
+def _pre_process_data(project: SubProjectModel) -> bool:
     """
     预处理数据
     :param project: 项目
@@ -25,17 +25,10 @@ def _pre_process_data(project: ProjectModel) -> bool:
     """
     return pre_process.PreProcess().run(project)
 
-def process_data(project: ProjectModel) -> bool:
+def process_data(project: SubProjectModel) -> bool:
     """
     处理数据
     :param project: 项目编号
     :return: None
     """
     return process.Process().run(project)
-def process_standard_data(version: str) -> None:
-    """
-    处理标准数据
-    :param version: 标准版本
-    :return: None
-    """
-    standard_data_process.StandardDataProcess().run(version)

+ 20 - 20
SourceCode/DataMiddleware/app/data_process/pre_process.py

@@ -1,7 +1,7 @@
 import utils, pandas as pd,os
 from pathlib import Path
 
-from models.project_data import ProjectModel, ProjectItemModel
+from models.project_data import SubProjectModel, SubProjectItemModel
 from stores.mysql_store import MysqlStore
 from ai.fast_gpt import FastGPTAi
 
@@ -16,10 +16,10 @@ class PreProcess:
         self.separate_ai_calls = False
         self._data={}
 
-    def run(self, project: ProjectModel, separate_ai_calls=True) ->bool:
+    def run(self, project: SubProjectModel, separate_ai_calls=True) ->bool:
         try:
-            self._logger.info(f"开始预处理项目:{project.project_name}[{project.project_no}_{project.standard_version}] ")
-            self._store.update_project_status(project.id,21)
+            self._logger.info(f"开始预处理项目:{project.sub_project_name}[{project.project_no}_{project.standard_version}] ")
+            self._store.update_sub_project_status(project.id, 21)
             self.separate_ai_calls = separate_ai_calls
             raw_data = self.read_excels(f"{utils.get_config_value("file.source_path","./temp_files")}/project/{project.project_no}/")
             if self.separate_ai_calls:
@@ -30,14 +30,14 @@ class PreProcess:
                 excel_data = self.normalize_data(raw_data)
                 self.call_ai(project.id, excel_data)
             project.items = self._data[project.id].items
-            self._store.re_insert_project(project)
+            self._store.re_insert_sub_project(project)
             del self._data[project.id]
-            self._logger.info(f"结束预处理项目:{project.project_name}[{project.project_no}_{project.standard_version}] [设备条数:{len(project.items)}]")
-            self._store.update_project_status(project.id,31)
+            self._logger.info(f"结束预处理项目:{project.sub_project_name}[{project.project_no}_{project.standard_version}] [设备条数:{len(project.items)}]")
+            self._store.update_sub_project_status(project.id, 31)
             return True
         except Exception as e:
             self._logger.error(f"预处理项目失败:[{project.project_no}] 错误: {e}")
-            self._store.update_project_status(project.id,11)
+            self._store.update_sub_project_status(project.id, 11)
             return False
 
     def read_excels(self, folder_path):
@@ -132,7 +132,7 @@ class PreProcess:
         return prompt
 
     def call_ai(self, project_id:int, excel_data):
-        project = ProjectModel(project_id=project_id)
+        project = SubProjectModel(project_id=project_id)
         api_key = utils.get_config_value("fastgpt.api_key_pre_process")
         if self.separate_ai_calls:
             # 初始化self._data[project_no],避免在循环中重复初始化
@@ -158,12 +158,12 @@ class PreProcess:
         self._data[project_id] = project
 
 
-    def format_data(self,project_id,new_data) ->list[ProjectItemModel]:
+    def format_data(self,project_id,new_data) ->list[SubProjectItemModel]:
         formatted_data = []
         for data in new_data:
             try:
-                item = ProjectItemModel(
-                    project_id=project_id,
+                item = SubProjectItemModel(
+                    sub_project_id=project_id,
                     device_name="",
                     device_model="",
                     device_unit="",
@@ -183,9 +183,9 @@ class PreProcess:
         return formatted_data
 
 
-    def run_1(self, project: ProjectModel) ->bool:
-        self._logger.info(f"开始预处理项目:{project.project_name}[{project.project_no}_{project.standard_version}] ")
-        self._store.update_project_status(project.id, 21)
+    def run_1(self, project: SubProjectModel) ->bool:
+        self._logger.info(f"开始预处理项目:{project.sub_project_name}[{project.project_no}_{project.standard_version}] ")
+        self._store.update_sub_project_status(project.id, 21)
         file_path =  f"{utils.get_config_value("file.source_path", "./temp_files")}/project/{project.project_no}/"
         file = os.listdir(file_path)[0]
         if not file:
@@ -216,17 +216,17 @@ class PreProcess:
             res_data = self.format_data(project.id, data)
             if len(res_data)<=0:
                 self._logger.error(f"项目:{project.project_no} 文件处理失败: {data}")
-                self._store.update_project_status(project.id, 11)
+                self._store.update_sub_project_status(project.id, 11)
                 return False
             project.items = res_data
-            self._store.re_insert_project(project)
+            self._store.re_insert_sub_project(project)
             self._logger.info(
-                f"结束预处理项目:{project.project_name}[{project.project_no}_{project.standard_version}] [设备条数:{len(project.items)}]")
-            self._store.update_project_status(project.id, 31)
+                f"结束预处理项目:{project.sub_project_name}[{project.project_no}_{project.standard_version}] [设备条数:{len(project.items)}]")
+            self._store.update_sub_project_status(project.id, 31)
             return True
         except Exception as e:
             self._logger.error(f"项目:{project.project_no} 文件处理失败: {e}")
-            self._store.update_project_status(project.id,11)
+            self._store.update_sub_project_status(project.id, 11)
             return False
 
 

+ 16 - 22
SourceCode/DataMiddleware/app/data_process/process.py

@@ -1,9 +1,7 @@
-from click import prompt
-
 import utils,json
 
 from stores.mysql_store import MysqlStore
-from models.project_data import ProjectModel, ProjectItemModel
+from models.project_data import SubProjectModel, SubProjectItemModel
 from ai.fast_gpt import FastGPTAi
 
 
@@ -14,30 +12,26 @@ class Process:
         self._ai = FastGPTAi()
         self._data={}
 
-    def run(self, project: ProjectModel) ->bool:
+    def run(self, sub_project: SubProjectModel) ->bool:
         try:
-            self._logger.info(f"开始处理数据:{project.project_no}")
-            self._store.update_project_status(project.id,22)
-            project_items = self._store.query_project_items_by_project(project.id)
+            self._logger.info(f"开始处理数据:{sub_project.sub_project_name}[{sub_project.id}]")
+            self._store.update_sub_project_status(sub_project.id, 22)
+            project_items = self._store.query_sub_project_items_by_project(sub_project.id)
             for project_item in project_items:
                 data = self.call_ai(project_item)
                 project_item.standard_no = data.standard_no
-                self._store.update_project_item(project_item)
-            # text = self.prompt_template(project,project_items)
-            # items = self.call_ai_process(text)
-            #
-            # self._store.update_project_item_standard_no_batch(items)
-            self._store.update_project_status(project.id,12)
-            self._logger.info(f"处理数据完成:{project.project_no}")
+                self._store.update_sub_project_item(project_item)
+            self._store.update_sub_project_status(sub_project.id, 12)
+            self._logger.info(f"处理数据完成:{sub_project.sub_project_name}[{sub_project.id}]")
             return True
         except Exception as e:
             self._logger.error(f"处理数据失败:{e}")
-            self._store.update_project_status(project.id,12)
+            self._store.update_sub_project_status(sub_project.id, 12)
             return False
 
-    def call_ai(self, project_item: ProjectItemModel) ->ProjectItemModel:
+    def call_ai(self, item: SubProjectItemModel) ->SubProjectItemModel:
         try:
-            self._logger.info(f"开始处理数据:{project_item.id}")
+            self._logger.info(f"开始处理数据:{item.id}")
             msg = """
             请分析提供的json数据,要求:
             1. 根据工作内容、类型、项目名称、规格型号、数量、单位查找计算出定额编号
@@ -61,14 +55,14 @@ class Process:
             5. 返回结构体item的json字符串,压缩成一行。
             6. 数据如下:
                 """
-            msg += project_item.to_ai_json()
+            msg += item.to_ai_json()
             api_key = utils.get_config_value("fastgpt.api_key_process")
             self._logger.info(f"开始调用AI:\n {msg}")
             json_data = self._ai.call_ai(msg, api_key)
             self._logger.info(f"AI返回结果:{json_data}")
             if not json_data:
                 raise Exception("AI返回结果为空")
-            data = ProjectItemModel(
+            data = SubProjectItemModel(
                 item_id=json_data["i"],
                 standard_no=json_data["s"]
             )
@@ -102,11 +96,11 @@ class Process:
         5. 返回结构体item的数组的json数组格式,压缩成一行。
         6. 数据如下:
         """
-        item_ai_json = ProjectItemModel.list_to_ai_json(items)
+        item_ai_json = SubProjectItemModel.list_to_ai_json(items)
         text += json.dumps(item_ai_json,ensure_ascii=False, separators=(',', ':'))
         return text
 
-    def call_ai_process(self, message:str) ->list[ProjectItemModel]:
+    def call_ai_process(self, message:str) ->list[SubProjectItemModel]:
         try:
             api_key = utils.get_config_value("fastgpt.api_key_process")
             self._logger.info(f"开始调用AI:\n {message}")
@@ -116,7 +110,7 @@ class Process:
                 raise  Exception("AI返回结果为空")
             data=[]
             for item in json_data:
-                data.append(ProjectItemModel(
+                data.append(SubProjectItemModel(
                     item_id=item["i"],
                     standard_no=item["s"]
                 ))

+ 0 - 56
SourceCode/DataMiddleware/app/data_process/standard_data_process.py

@@ -1,56 +0,0 @@
-import utils
-from pathlib import Path
-
-from stores.mysql_store import MysqlStore
-from models.standard_data import StandardModel
-import pandas as pd  # 添加对pandas库的导入,用于处理表格数据
-
-class StandardDataProcess:
-    def __init__(self):
-        self._logger= utils.get_logger()
-        self._store= MysqlStore()
-        self._ai_helper = utils.AiHelper()
-        self._ai_sys_prompt = "查询给定数据的标准编号信息,返回压缩的json字符传"
-
-    def run(self,version:str):
-        path= f"./temp_files/data/v{version}"
-        data = self.read_excels(path)
-        self.insert_data(version,data)
-
-    def read_excels(self, folder_path:str):
-        path = Path(folder_path)
-        # 验证路径是否存在
-        if not path.exists():
-            raise FileNotFoundError(f"目录不存在: {path.resolve()}")
-
-        # 验证是否是目录
-        if not path.is_dir():
-            raise NotADirectoryError(f"路径不是目录: {path.resolve()}")
-
-        excel_files = list(path.glob('.csv'))
-        for file in excel_files:
-            try:
-                # 读取CSV文件
-                df = pd.read_csv(file)
-                data =  df.to_dict(orient='records')
-                return data
-            except Exception as e:
-                self._logger.error(f"读取数据失败 {file}: {str(e)}")
-
-    def insert_data(self,version:str,data):
-        for row in data:
-            standard_no = row['电算代号']
-            if not standard_no:
-                continue
-            name = row['项目名称']
-            unit = row['单位']
-            item = self._store.query_standard_data_by_no(row['电算代号'],version)
-            if item:
-                item.standard_version=version
-                item.standard_name=name
-                item.device_model=None
-                item.device_unit=unit
-                self._store.update_standard_data(item)
-            else:
-                item= StandardModel(device_name=name, device_unit=unit, standard_no=standard_no, standard_version=version)
-            self._store.insert_standard_data(item)

+ 2 - 2
SourceCode/DataMiddleware/app/data_send/__init__.py

@@ -1,8 +1,8 @@
 from data_send import  send
-from models.project_data import ProjectModel
+from models.project_data import SubProjectModel
 
 
-def send_project_data(project: ProjectModel) -> bool:
+def send_project_data(project: SubProjectModel) -> bool:
     """
     发送项目数据到平台
     :param project

+ 8 - 8
SourceCode/DataMiddleware/app/data_send/send.py

@@ -1,6 +1,6 @@
 import  utils
 from stores.mysql_store import MysqlStore
-from models.project_data import ProjectModel, ProjectItemModel
+from models.project_data import SubProjectModel, SubProjectItemModel
 
 
 class DataSend:
@@ -8,26 +8,26 @@ class DataSend:
         self._logger= utils.get_logger()
         self._store= MysqlStore()
 
-    def send_by_project(self, project: ProjectModel) -> bool:
+    def send_by_project(self, project: SubProjectModel) -> bool:
         try:
 
             self._logger.info(f"开始发送数据,项目:{project.project_no}")
-            self._store.update_project_status(project.id,23)
-            data_list = self._store.query_project_items_by_project(project.id, with_empty=False)
+            self._store.update_sub_project_status(project.id, 23)
+            data_list = self._store.query_sub_project_items_by_project(project.id, with_empty=False)
             for data in data_list:
                 self.send_data(data)
-            self._store.update_project_status(project.id,33)
+            self._store.update_sub_project_status(project.id, 33)
             self._logger.info(f"发送数据成功,项目:{project.project_no} 共发送{len(data_list)}条")
             return True
         except Exception as e:
             self._logger.error(f"发送数据失败,项目:{project.project_no},错误信息:{e}")
-            self._store.update_project_status(project.id,13)
+            self._store.update_sub_project_status(project.id, 13)
             return False
 
     def send_by_item_id(self, item_id: int) -> bool:
         try:
             self._logger.info(f"开始发送数据,项目:{item_id}")
-            data = self._store.query_project_item_by_id(item_id)
+            data = self._store.query_sub_project_item_by_id(item_id)
             if self.send_data(data):
                 self._logger.info(f"发送数据成功,项目:{item_id}")
                 return True
@@ -36,7 +36,7 @@ class DataSend:
             self._logger.error(f"发送数据失败,项目:{item_id},错误信息:{e}")
             return False
 
-    def send_data(self, data: ProjectItemModel) -> bool:
+    def send_data(self, data: SubProjectItemModel) -> bool:
         try:
             self._logger.debug(f"开始远程请求发送数据,数据:{data}" )
         except Exception as e:

+ 27 - 33
SourceCode/DataMiddleware/app/init.sql

@@ -2,61 +2,55 @@
 CREATE DATABASE IF NOT EXISTS iwb_data_middleware_v1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
 USE iwb_data_middleware_v1;
 
--- 创建 SourceData
+-- 创建 sub_project
 CREATE TABLE IF NOT EXISTS project (
     id INT AUTO_INCREMENT PRIMARY KEY,
-    project_no VARCHAR(255) NOT NULL,
-    INDEX idx_project_no (project_no),
     project_name VARCHAR(255),
+    description VARCHAR(1000),
+    is_del TINYINT DEFAULT 0,
+    delete_by VARCHAR(255),
+    delete_time DATETIME,
+    update_by VARCHAR(255),
+    update_time DATETIME,
+    create_by VARCHAR(255),
+    create_time DATETIME
+) CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
+
+-- 创建 sub_project 表
+CREATE TABLE IF NOT EXISTS sub_project (
+    id INT AUTO_INCREMENT PRIMARY KEY,
+    project_id int,
+    INDEX idx_project_id (project_id),
+    sub_project_name VARCHAR(255),
     work_catalog VARCHAR(255),
     work_content VARCHAR(255),
     standard_version VARCHAR(50),
     status TINYINT DEFAULT 0,
-    completion_tokens INT DEFAULT 0,
-    prompt_tokens INT DEFAULT 0,
-    total_tokens INT DEFAULT 0,
     is_del TINYINT DEFAULT 0,
+    delete_by VARCHAR(255),
     delete_time DATETIME,
+    update_by VARCHAR(255),
     update_time DATETIME,
+    create_by VARCHAR(255),
     create_time DATETIME
 ) CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
 
--- 创建 SourceItemData 表
-CREATE TABLE IF NOT EXISTS project_item (
+-- 创建 project_item
+CREATE TABLE IF NOT EXISTS sub_project_item (
     id INT AUTO_INCREMENT PRIMARY KEY,
     project_id int NOT NULL,
+    sub_project_id int NOT NULL,
     device_name VARCHAR(255) NOT NULL,
     device_model VARCHAR(255) ,
     device_unit VARCHAR(50) ,
     device_count FLOAT DEFAULT 0,
     standard_version VARCHAR(50),
     standard_no VARCHAR(255) ,
+    process_status TINYINT DEFAULT 0,
+    process_time DATETIME,
+    send_status TINYINT DEFAULT 0,
+    send_time DATETIME,
     remark TEXT,
     update_time DATETIME 
 ) CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
 
--- 创建 StandardData 表
-CREATE TABLE IF NOT EXISTS standard_data (
-    id INT AUTO_INCREMENT PRIMARY KEY,
-    device_name VARCHAR(255),
-    device_model VARCHAR(255),
-    device_unit VARCHAR(50) ,
-    standard_version VARCHAR(50),
-    standard_no VARCHAR(255),
-    create_time DATETIME,
-    update_time DATETIME,
-    remark TEXT
-) CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
-
--- 创建 StandardUpdateLog 表
-CREATE TABLE IF NOT EXISTS standard_update_log (
-    id INT AUTO_INCREMENT PRIMARY KEY,
-    project_id int,
-    device_name VARCHAR(255) ,
-    device_model VARCHAR(255),
-    device_unit VARCHAR(50) ,
-    standard_version VARCHAR(50),
-    new_standard_no VARCHAR(255) ,
-    old_standard_no VARCHAR(255) ,
-    create_time DATETIME 
-) CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

+ 53 - 14
SourceCode/DataMiddleware/app/models/project_data.py

@@ -1,11 +1,32 @@
 from datetime import datetime
 
-
 class ProjectModel:
-
     def __init__(self,
-                 project_no: str= None,
                  project_name: str = None,
+                 description:str = None,
+                 project_id: int = None,
+                 delete_by:str = None,
+                 delete_time: datetime = None,
+                 create_by: str = None,
+                 create_time: datetime = None,
+                 update_by: str = None,
+                 update_time: datetime = None,
+                 ):
+        self.id = project_id
+        self.project_name = project_name
+        self.description = description
+        self.delete_by = delete_by
+        self.delete_time = delete_time
+        self.create_by = create_by
+        self.create_time = create_time
+        self.update_by = update_by
+        self.update_time = update_time
+
+class SubProjectModel:
+
+    def __init__(self,
+                 project_id: int = None,
+                 sub_project_name: str = None,
                  work_catalog: str = None,
                  work_content: str = None,
                  standard_version: str = None,
@@ -13,13 +34,17 @@ class ProjectModel:
                  completion_tokens: int = 0,
                  prompt_tokens: int = 0,
                  total_tokens: int = 0,
-                 update_time: datetime = None,
+                 sub_id: int = None,
+                 delete_by: str = None,
+                 delete_time: datetime = None,
+                 create_by: str = None,
                  create_time: datetime = None,
-                 project_id: int = None,
+                 update_by: str = None,
+                 update_time: datetime = None,
                  ):
-        self.id = project_id
-        self.project_no = project_no
-        self.project_name = project_name
+        self.id = sub_id
+        self.project_id = project_id
+        self.sub_project_name = sub_project_name
         self.work_catalog = work_catalog
         self.work_content = work_content
         self.standard_version = standard_version
@@ -27,45 +52,59 @@ class ProjectModel:
         self.completion_tokens = completion_tokens
         self.prompt_tokens = prompt_tokens
         self.total_tokens = total_tokens
-        self.update_time = update_time
+        self.delete_by = delete_by
+        self.delete_time = delete_time
+        self.create_by = create_by
         self.create_time = create_time
+        self.update_by = update_by
+        self.update_time = update_time
         self.items = []
 
     def __str__(self):
-        return f"SourceData(project_no={self.project_no}, project_name={self.project_name}, standard_version={self.standard_version})"
+        return f"SubProjectModel(id={self.id}, project_no={self.project_id}, project_name={self.sub_project_name}, work_catalog={self.work_catalog}, work_content={self.work_content}, standard_version={self.standard_version}, status={self.status}, completion_tokens={self.completion_tokens}, prompt_tokens={self.prompt_tokens}, total_tokens={self.total_tokens}, update_time={self.update_time}, create_time={self.create_time})"
 
     def set_items(self, items: list):
         self.items = items
 
-    def add_item(self, item: 'ProjectItemModel'):
+    def add_item(self, item: 'SubProjectItemModel'):
         self.items.append(item)
 
 
-class ProjectItemModel:
+class SubProjectItemModel:
     def __init__(self,
-                 project_id: int=None,
+                 project_id: int = None,
+                 sub_project_id: int=None,
                  device_name: str=None,
                  device_model: str=None,
                  device_unit: str = None,
                  device_count: float = 0,
                  standard_version: str = None,
                  standard_no: str = None,
+                 process_status: int = 0,
+                 process_time: datetime = None,
+                 send_status: int = 0,
+                 send_time: datetime = None,
                  item_id: int = None,
                  remark: str = None,
                  update_time: datetime = None):
         self.id = item_id
         self.project_id = project_id
+        self.sub_project_id = sub_project_id
         self.device_name = device_name
         self.device_model = device_model
         self.device_unit = device_unit
         self.device_count = device_count
         self.standard_no = standard_no
         self.standard_version = standard_version
+        self.process_status = process_status
+        self.process_time = process_time
+        self.send_status = send_status
+        self.send_time = send_time
         self.remark = remark
         self.update_time = update_time
 
     def __str__(self):
-        return f"SourceItemData(id={self.id}, project_no={self.project_id}, device_name={self.device_name}, device_model={self.device_model}, device_unit={self.device_unit}, device_count={self.device_count}, standard_no={self.standard_no}, standard_version={self.standard_version})"
+        return f"ProjectItemModel(id={self.id}, project_no={self.sub_project_id}, device_name={self.device_name}, device_model={self.device_model}, device_unit={self.device_unit}, device_count={self.device_count}, standard_no={self.standard_no}, standard_version={self.standard_version})"
 
     def to_ai_json(self):
         return {

+ 0 - 22
SourceCode/DataMiddleware/app/models/standard_data.py

@@ -1,22 +0,0 @@
-from datetime import datetime
-
-
-class StandardModel:
-
-    def __init__(self,
-                 device_name: str,
-                 device_model: str=None,
-                 device_unit: str=None,
-                 standard_no: str=None,
-                 standard_version: str=None,
-                 create_time: datetime = None,
-                 update_time: datetime = None,
-                 remark: str = None):
-        self.device_name = device_name
-        self.device_model = device_model
-        self.device_unit = device_unit
-        self.standard_no = standard_no
-        self.standard_version = standard_version
-        self.create_time = create_time
-        self.update_time = update_time
-        self.remark = remark

+ 0 - 22
SourceCode/DataMiddleware/app/models/standard_update_log.py

@@ -1,22 +0,0 @@
-from datetime import datetime
-
-
-class StandardUpdateLogModel:
-
-    def __init__(self,
-                 project_id: int,
-                 device_name: str = None,
-                 device_model: str = None,
-                 device_unit: str = None,
-                 standard_version: str = None,
-                 new_standard_no: str = None,
-                 old_standard_no: str = None,
-                 create_time: datetime = None):
-        self.project_id = project_id
-        self.device_name = device_name
-        self.device_model = device_model
-        self.device_unit = device_unit
-        self.standard_version = standard_version
-        self.new_standard_no = new_standard_no
-        self.old_standard_no = old_standard_no
-        self.create_time = create_time

+ 230 - 286
SourceCode/DataMiddleware/app/stores/mysql_store.py

@@ -2,9 +2,7 @@ from datetime import datetime
 
 from utils.mysql_helper import MySQLHelper
 
-from models.project_data import ProjectModel, ProjectItemModel
-from models.standard_data import StandardModel
-from models.standard_update_log import StandardUpdateLogModel
+from models.project_data import ProjectModel, SubProjectModel, SubProjectItemModel
 
 
 class MysqlStore:
@@ -12,19 +10,87 @@ class MysqlStore:
     def __init__(self):
         self._db_helper = MySQLHelper()
 
-    def query_project_all(self):
-        query = "SELECT project_no,project_name,work_catalog,work_content,standard_version,status,create_time FROM project WHERE is_del=0"
+    def query_project_all_paginated(self, page: int, per_page: int, keyword: str = None):
+        offset = (page - 1) * per_page
+        sql_count = "SELECT COUNT(*) as count FROM project WHERE is_del=%s"
+        sql = "SELECT id,project_name,description,delete_by,delete_time,create_by,create_time,update_by,update_time FROM project WHERE is_del=%s"
+        params_count = (0,)
+        params = (0,)
+        if keyword:
+            sql_count += " AND (project_name LIKE %s)"
+            sql += " AND (project_name LIKE %s)"
+            params_count += (f"%{keyword}%",)
+            params += (f"%{keyword}%",)
+        sql += " ORDER BY create_time DESC LIMIT %s OFFSET %s"
+        params += (per_page, offset)
         with self._db_helper:
+            result_count = self._db_helper.fetch_one(sql_count, params_count)
+            count = result_count["count"] if result_count else 0
+            result = self._db_helper.execute_query(sql, params)
             data = []
-            result = self._db_helper.execute_query(query)
             if not result:
-                return data
+                return data, count
             for item in result:
                 data.append(
                     ProjectModel(
                         project_id=item["id"],
-                        project_no=item["project_no"],
                         project_name=item["project_name"],
+                        description=item["description"],
+                        delete_by=item["delete_by"],
+                        delete_time=item["delete_time"],
+                        create_by=item["create_by"],
+                        create_time=item["create_time"],
+                        update_by=item["update_by"],
+                        update_time=item["update_time"],
+                    ))
+            return data, count
+
+    def query_project_by_id(self, project_id: int) -> ProjectModel | None:
+        sql = "SELECT id,project_name,description,delete_by,delete_time,create_by,create_time,update_by,update_time FROM project WHERE is_del=0 AND id = %s"
+        params = (project_id,)
+        with self._db_helper:
+            result = self._db_helper.fetch_one(sql, params)
+            if not result:
+                return None
+            return ProjectModel(
+                project_id=result["id"],
+                project_name=result["project_name"],
+                description=result["description"],
+                delete_by=result["delete_by"],
+                delete_time=result["delete_time"],
+                create_by=result["create_by"],
+                create_time=result["create_time"],
+                update_by=result["update_by"],
+                update_time=result["update_time"],
+            )
+    def insert_project(self, project_data: ProjectModel):
+        sql = "INSERT INTO project (project_name,description,create_by,create_time,update_by,update_time) VALUES (%s,%s,%s,%s,%s,%s)"
+        params = (project_data.project_name,project_data.description, project_data.create_by, datetime.now(), project_data.update_by, datetime.now())
+        with self._db_helper:
+            self._db_helper.execute_non_query(sql, params)
+    def update_project(self, project_data: ProjectModel):
+        sql = "UPDATE project SET project_name=%s,description=%s,update_by=%s,update_time=%s WHERE id=%s"
+        params = (project_data.project_name, project_data.description,project_data.update_by, datetime.now(), project_data.id)
+        with self._db_helper:
+            self._db_helper.execute_non_query(sql, params)
+    def delete_project(self, project_id: int,delete_by: str=""):
+        sql = "UPDATE project SET is_del=1,project.delete_by=%s,delete_time=%s WHERE id=%s"
+        params = (delete_by, datetime.now(), project_id)
+        with self._db_helper:
+            self._db_helper.execute_non_query(sql, params)
+    def query_sub_project_all(self):
+        sql = "SELECT id,project_id,sub_project_name,work_catalog,work_content,standard_version,status,create_time FROM sub_project WHERE is_del=0"
+        with self._db_helper:
+            data = []
+            result = self._db_helper.execute_query(sql)
+            if not result:
+                return data
+            for item in result:
+                data.append(
+                    SubProjectModel(
+                        sub_id=item["id"],
+                        project_id=item["project_id"],
+                        sub_project_name=item["sub_project_name"],
                         work_catalog=item["work_catalog"],
                         work_content=item["work_content"],
                         standard_version=item["standard_version"],
@@ -32,42 +98,42 @@ class MysqlStore:
                         create_time=item["create_time"],
                     ))
             return data
-    def query_project_all_paginated(self, page: int, per_page: int, keyword: str = None, status: int = None) -> (list[ProjectModel], None):
+    def query_sub_project_all_paginated(self, project_id: int, page: int, per_page: int, keyword: str = None, status: int = None) -> (list[SubProjectModel], None):
         offset = (page - 1) * per_page
-        query_count = "SELECT COUNT(*) as count FROM project WHERE is_del=%s"
-        query = "SELECT id,project_no,project_name,work_catalog,work_content,standard_version,status,create_time FROM project WHERE is_del=0 "
-        params_count = [0]
-        params = []
-        q_1=" AND (project_no LIKE %s OR project_name LIKE %s)"
+        sql_count = "SELECT COUNT(*) as count FROM sub_project WHERE is_del=0 AND project_id=%s"
+        sql = "SELECT id,project_id,sub_project_name,work_catalog,work_content,standard_version,status,create_time FROM sub_project WHERE is_del=0 AND project_id=%s"
+        params_count = (project_id,)
+        params =  (project_id,)
+        q_1=" AND (sub_project_name LIKE %s)"
         q_2=" AND status=%s"
         if keyword:
-            query_count += q_1
-            params_count.extend([f"%{keyword}%", f"%{keyword}%"])
-            query += q_1
-            params.extend([f"%{keyword}%", f"%{keyword}%"])
+            sql_count += q_1
+            params_count += (f"%{keyword}%",)
+            sql += q_1
+            params += (f"%{keyword}%",)
 
         if status is not None:
-            query_count += q_2
-            params_count.append(status)
-            query += q_2
-            params.append(status)
+            sql_count += q_2
+            params_count += (status,)
+            sql += q_2
+            params += (status,)
 
-        query += " ORDER BY status,create_time DESC LIMIT %s OFFSET %s"
-        params.extend([per_page, offset])
+        sql += " ORDER BY status,create_time DESC LIMIT %s OFFSET %s"
+        params += (per_page, offset)
 
         with self._db_helper:
-            result_count = self._db_helper.fetch_one(query_count, tuple(params_count))
+            result_count = self._db_helper.fetch_one(sql_count, params_count)
             count = result_count["count"] if result_count else 0
-            result = self._db_helper.execute_query(query, tuple(params))
+            result = self._db_helper.execute_query(sql, params)
             data = []
             if not result:
                 return [], count
             for item in result:
                 data.append(
-                    ProjectModel(
-                        project_id=item["id"],
-                        project_no=item["project_no"],
-                        project_name=item["project_name"],
+                    SubProjectModel(
+                        sub_id=item["id"],
+                        project_id=item["project_id"],
+                        sub_project_name=item["sub_project_name"],
                         work_catalog=item["work_catalog"],
                         work_content=item["work_content"],
                         standard_version=item["standard_version"],
@@ -75,87 +141,109 @@ class MysqlStore:
                         create_time=item["create_time"],
                     ))
         return data, count
-    def query_project(self, project_id: int, with_items=False) -> ProjectModel | None:
-        query = "SELECT id,project_no,project_name,work_catalog,work_content,standard_version,status,create_time FROM project WHERE is_del=0 AND id = %s"
-        params = (project_id,)
-        query_items = "SELECT id,project_id,device_name,device_model,standard_version,standard_no FROM project_item WHERE project_id = %s"
+    def query_sub_project(self, sub_project_id: int, with_items=False) -> SubProjectModel | None:
+        sql = "SELECT id,project_id,sub_project_name,work_catalog,work_content,standard_version,status,create_time FROM sub_project WHERE is_del=0 AND id = %s"
+        params = (sub_project_id,)
+        sql_items = "SELECT id,project_id,sub_project_id,device_name,device_model,standard_version,standard_no,process_status,process_time,send_status,send_time FROM sub_project_item WHERE sub_project_id = %s"
         with self._db_helper:
-            result = self._db_helper.fetch_one(query, params)
+            result = self._db_helper.fetch_one(sql, params)
             if not result:
                 return None
-            data = ProjectModel(result["project_no"],
-                                result["project_name"],
-                                result["work_catalog"],
-                                result["work_content"],
-                                result["standard_version"],
-                                result["status"],
-                                project_id=result["id"],
-                                create_time=result["create_time"])
+            data = SubProjectModel(
+                        project_id=result["project_id"],
+                        sub_project_name=result["sub_project_name"],
+                        work_catalog=result["work_catalog"],
+                        work_content=result["work_content"],
+                        standard_version=result["standard_version"],
+                        status=result["status"],
+                        sub_id=result["id"],
+                        create_time=result["create_time"])
             if not with_items:
                 return data
-            items_result = self._db_helper.execute_query(query_items, params)
+            items_result = self._db_helper.execute_query(sql_items, params)
             if items_result:
                 for item in items_result:
                     data.add_item(
-                        ProjectItemModel(
+                        SubProjectItemModel(
                             item_id=item["id"],
-                            project_id=item["project_no"],
+                            project_id=item["project_id"],
+                            sub_project_id=item["sub_project_id"],
                             device_name=item["device_name"],
                             device_model=item["device_model"],
                             standard_version=item["standard_version"],
                             standard_no=item["standard_no"],
+                            process_status=item["process_status"],
+                            process_time=item["process_time"],
+                            send_status=item["send_status"],
+                            send_time=item["send_time"],
                         ))
             return data
-    def query_project_items_by_project_paginated(self, project_id: int, page: int, per_page: int, keyword: str = None) -> (list[ProjectItemModel], int):
+    def query_sub_project_items_by_project_paginated(self, sub_project_id: int, page: int, per_page: int, keyword: str = None, process_status: int = None,send_status: int = None) -> (list[SubProjectItemModel], int):
         offset = (page - 1) * per_page
-        query_count = "SELECT COUNT(*) as count FROM project_item WHERE project_id = %s"
-        query = "SELECT id,project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no FROM project_item WHERE project_id = %s"
-        params_count = (project_id,)
-        params = (project_id,)
+        sql_count = "SELECT COUNT(*) as count FROM sub_project_item WHERE sub_project_id = %s"
+        sql = "SELECT id,project_id,sub_project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no,process_status,process_time,send_status,send_time FROM sub_project_item WHERE sub_project_id = %s"
+        params_count = (sub_project_id,)
+        params = (sub_project_id,)
 
         if keyword:
-            query_count += " AND (device_name LIKE %s OR device_model LIKE %s)"
+            sql_count += " AND (device_name LIKE %s OR device_model LIKE %s)"
             params_count += (f"%{keyword}%", f"%{keyword}%")
-            query += " AND (device_name LIKE %s OR device_model LIKE %s)"
+            sql += " AND (device_name LIKE %s OR device_model LIKE %s)"
             params += (f"%{keyword}%", f"%{keyword}%")
+        if process_status is not None:
+            sql_count += " AND process_status=%s"
+            params_count += (process_status,)
+            sql += " AND process_status=%s"
+            params += (process_status,)
+        if send_status is not None:
+            sql_count += " AND send_status=%s"
+            params_count += (send_status,)
+            sql += " AND send_status=%s"
+            params += (send_status,)
 
-        query += " ORDER BY device_name,device_model LIMIT %s OFFSET %s"
+        sql += " ORDER BY device_name,device_model LIMIT %s OFFSET %s"
         params += (per_page, offset)
 
         with self._db_helper:
-            result_count = self._db_helper.fetch_one(query_count, params_count)
+            result_count = self._db_helper.fetch_one(sql_count, params_count)
             count = result_count["count"] if result_count else 0
-            result = self._db_helper.execute_query(query, params)
+            result = self._db_helper.execute_query(sql, params)
             data = []
             if not result:
                 return data, count
             for item in result:
                 data.append(
-                    ProjectItemModel(
+                    SubProjectItemModel(
                         item_id=item["id"],
                         project_id=item["project_id"],
+                        sub_project_id=item["sub_project_id"],
                         device_name=item["device_name"],
                         device_model=item["device_model"],
                         device_unit=item["device_unit"],
                         device_count=item["device_count"],
                         standard_version=item["standard_version"],
                         standard_no=item["standard_no"],
+                        process_status=item["process_status"],
+                        process_time=item["process_time"],
+                        send_status=item["send_status"],
+                        send_time=item["send_time"],
                     ))
         return data, count
-    def query_project_items_by_project(self, project_id: int, with_empty=True) -> list[ProjectItemModel]:
-        query = "SELECT id,project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no FROM project_item WHERE project_id = %s"
-        query += "" if with_empty else " AND standard_no !='' AND standard_no IS NOT NULL"
-        params = (project_id,)
+    def query_sub_project_items_by_project(self, sub_project_id: int, with_empty=True) -> list[SubProjectItemModel]:
+        sql = "SELECT id,project_id,sub_project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no FROM sub_project_item WHERE sub_project_id = %s"
+        sql += "" if with_empty else " AND standard_no !='' AND standard_no IS NOT NULL"
+        params = (sub_project_id,)
         with self._db_helper:
-            result = self._db_helper.execute_query(query, params)
+            result = self._db_helper.execute_query(sql, params)
             data = []
             if not result:
                 return data
             for item in result:
                 data.append(
-                    ProjectItemModel(
+                    SubProjectItemModel(
                         item_id=item["id"],
                         project_id=item["project_id"],
+                        sub_project_id=item["sub_project_id"],
                         device_name=item["device_name"],
                         device_model=item["device_model"],
                         device_unit=item["device_unit"],
@@ -164,286 +252,142 @@ class MysqlStore:
                         standard_no=item["standard_no"],
                     ))
             return data
-    def insert_project(self, project: ProjectModel) -> bool:
-        query = "INSERT INTO project (project_no,project_name,work_catalog,work_content,standard_version,completion_tokens,prompt_tokens,total_tokens,create_time) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)"
+    def insert_sub_project(self, sub_project: SubProjectModel) -> int:
+        sql = "INSERT INTO sub_project (project_id,sub_project_name,work_catalog,work_content,standard_version,create_time,create_by) VALUES (%s,%s,%s,%s,%s,%s,%s)"
         params = (
-            project.project_no,
-            project.project_name,
-            project.work_catalog,
-            project.work_content,
-            project.standard_version,
-            project.completion_tokens,
-            project.prompt_tokens,
-            project.total_tokens,
+            sub_project.project_id,
+            sub_project.sub_project_name,
+            sub_project.work_catalog,
+            sub_project.work_content,
+            sub_project.standard_version,
             datetime.now(),
+            sub_project.create_by,
         )
-
         with self._db_helper:
-            self._db_helper.execute_non_query(query, params)
-        self.insert_project_item_list(project)
-        return True
-    def insert_project_item_list(self, project):
-        if len(project.items) <= 0:
+          new_id =  self._db_helper.execute_non_query(sql, params)
+        self.insert_sub_project_item_list(sub_project)
+        return new_id
+    def insert_sub_project_item_list(self, sub_project):
+        if len(sub_project.items) <= 0:
             return
-        query_items = "INSERT INTO project_item (project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no,update_time) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)"
+        sql = "INSERT INTO sub_project_item (project_id,sub_project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no,update_time) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)"
         params_items = []
-        for item in project.items:
+        for item in sub_project.items:
             params_items.append((
-                project.id,
+                sub_project.project_id,
+                sub_project.id,
                 item.device_name,
                 item.device_model,
                 item.device_unit,
                 item.device_count,
-                project.standard_version,
+                sub_project.standard_version,
                 item.standard_no,
                 datetime.now(),
             ))
         with self._db_helper:
-            self._db_helper.execute_many(query_items, params_items)
-    def update_project(self, project: ProjectModel):
-        query = "UPDATE project SET project_name = %s, work_catalog = %s, work_content = %s, standard_version = %s ,status = %s,update_time = %s WHERE id = %s"
+            self._db_helper.execute_many(sql, params_items)
+    def update_sub_project(self, sub_project: SubProjectModel):
+        sql = "UPDATE sub_project SET sub_project_name = %s, work_catalog = %s, work_content = %s, standard_version = %s ,status = %s,update_time = %s WHERE id = %s"
         params = (
-            project.project_name,
-            project.work_catalog,
-            project.work_content,
-            project.standard_version,
-            project.status,
+            sub_project.sub_project_name,
+            sub_project.work_catalog,
+            sub_project.work_content,
+            sub_project.standard_version,
+            sub_project.status,
             datetime.now(),
-            project.id,
+            sub_project.id,
         )
         with self._db_helper:
-            self._db_helper.execute_non_query(query, params)
-    def update_project_status(self,project_id:int, status:int):
-        query = "UPDATE project SET status = %s,update_time = %s WHERE id = %s"
-        params = (status, datetime.now(), project_id,)
+            self._db_helper.execute_non_query(sql, params)
+    def update_sub_project_status(self, sub_project_id:int, status:int):
+        sql = "UPDATE sub_project SET status = %s,update_time = %s WHERE id = %s"
+        params = (status, datetime.now(), sub_project_id,)
         with self._db_helper:
-            self._db_helper.execute_non_query(query, params)
-    def re_insert_project(self, project: ProjectModel) -> bool:
-        if not project.id:
+            self._db_helper.execute_non_query(sql, params)
+    def re_insert_sub_project(self, sub_project: SubProjectModel) -> bool:
+        if not sub_project.id:
             return False
-        self.update_project(project)
-        query = "DELETE FROM project_item WHERE project_id = %s"
-        params = (project.id,)
+        self.update_sub_project(sub_project)
+        sql = "DELETE FROM sub_project_item WHERE sub_project_id = %s"
+        params = (sub_project.id,)
         with self._db_helper:
-            self._db_helper.execute_non_query(query, params)
-        self.insert_project_item_list(project)
-    def delete_project(self, project_id: int) -> bool:
-        query_1 = "UPDATE project SET is_del=1,delete_time=%s WHERE id = %s"
-        # query_2 = "DELETE FROM project_item WHERE project_no = %s"
-        params = (datetime.now(), project_id,)
+            self._db_helper.execute_non_query(sql, params)
+        self.insert_sub_project_item_list(sub_project)
+    def delete_sub_project(self, sub_project_id: int, delete_by: str="") -> bool:
+        sql = "UPDATE sub_project SET is_del=1,delete_by=%s,delete_time=%s WHERE id = %s"
+        params = (delete_by, datetime.now(), sub_project_id,)
         with self._db_helper:
-            self._db_helper.execute_non_query(query_1, params)
-            # self._db_helper.execute_non_query(query_2, params)
+            self._db_helper.execute_non_query(sql, params)
             return True
-    def query_project_item_by_id(self, item_id:int) -> ProjectItemModel | None:
-        query = "SELECT id,project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no FROM project_item WHERE id = %s"
+    def query_sub_project_item_by_id(self, item_id:int) -> SubProjectItemModel | None:
+        sql = "SELECT id,project_id,sub_project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no,process_status,process_time,send_status,send_time FROM sub_project_item WHERE id = %s"
         params = (item_id,)
         with self._db_helper:
-            result = self._db_helper.fetch_one(query, params)
+            result = self._db_helper.fetch_one(sql, params)
             if not result:
                 return None
-            data = ProjectItemModel(
+            data = SubProjectItemModel(
                 item_id=result["id"],
                 project_id=result["project_id"],
+                sub_project_id=result["project_id"],
                 device_name=result["device_name"],
                 device_model=result["device_model"],
                 device_unit=result["device_unit"],
                 device_count=result["device_count"],
                 standard_version=result["standard_version"],
                 standard_no=result["standard_no"],
+                process_status=result["process_status"],
+                process_time=result["process_time"],
+                send_status=result["send_status"],
+                send_time=result["send_time"],
                 update_time=datetime.now()
             )
             return data
-    def query_project_item(self, project_id: int, device_name:str, device_model:str) -> ProjectItemModel | None:
-        query = "SELECT id,project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no FROM project_item WHERE project_id = %s AND device_name = %s AND device_model = %s"
-        params = (project_id,device_name, device_model )
-        with self._db_helper:
-            result = self._db_helper.fetch_one(query, params)
-            if not result:
-                return None
-            data = ProjectItemModel(
-                item_id=result["id"],
-                project_id=result["project_id"],
-                device_name=result["device_name"],
-                device_model=result["device_model"],
-                device_unit=result["device_unit"],
-                device_count=result["device_count"],
-                standard_version=result["standard_version"],
-                standard_no=result["standard_no"],
-            )
-            return data
-    def insert_project_item(self, project_item: ProjectItemModel) -> bool:
-        query = "INSERT INTO project_item (project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no,update_time) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)"
+    def insert_sub_project_item(self, project_item: SubProjectItemModel) -> bool:
+        sql = "INSERT INTO sub_project_item (project_id,sub_project_id,device_name,device_model,device_unit,device_count,standard_version,standard_no,process_status,send_status,update_time) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
         params = (
             project_item.project_id,
+            project_item.sub_project_id,
             project_item.device_name,
             project_item.device_model,
             project_item.device_unit,
             project_item.device_count,
             project_item.standard_version,
             project_item.standard_no,
+            project_item.process_status,
+            project_item.send_status,
             datetime.now(),
         )
         with self._db_helper:
-            self._db_helper.execute_non_query(query, params)
-            return True
-    def update_project_item(self, project_item: ProjectItemModel) -> bool:
-        query = "SElECT standard_no FROM project_item WHERE id = %s"
-        params = (project_item.id,)
-        u_query = "UPDATE project_item SET device_name= %s,device_model= %s,device_unit= %s,device_count= %s,standard_no = %s,update_time = %s WHERE id = %s"
-        u_params = (project_item.device_name, project_item.device_model,project_item.device_unit, project_item.device_count, project_item.standard_no, datetime.now(), project_item.id)
-        with self._db_helper:
-            result = self._db_helper.fetch_one(query, params)
-            if result:
-                self._db_helper.execute_non_query(u_query, u_params)
-                self.insert_or_update_standard_data(
-                    StandardModel(device_name=project_item.device_name,
-                                  device_model=project_item.device_model,
-                                  device_unit=project_item.device_unit,
-                                  standard_version=project_item.standard_version,
-                                  standard_no=project_item.standard_no),
-                    project_item.project_id)
+            self._db_helper.execute_non_query(sql, params)
             return True
-    def delete_project_item_by_id(self, item_id: int):
-        query = "DELETE FROM project_item WHERE id = %s"
-        params = (item_id, )
-        with self._db_helper:
-            self._db_helper.execute_non_query(query, params)
-            return True
-
-    def update_project_item_standard_no_batch(self,items:list[ProjectItemModel]):
-        data =datetime.now()
-        for item in items:
-            query = "UPDATE project_item SET standard_no = %s,update_time = %s WHERE id = %s"
-            params = (item.standard_no, data, item.id)
-            with self._db_helper:
-                self._db_helper.execute_non_query(query, params)
-
-    def query_standard_data_by_no(self, standard_no: str,version:str):
-        query = "SELECT device_model,device_name,device_unit,standard_version,standard_no FROM standard_data WHERE standard_no = %s AND standard_version = %s"
-        params = (standard_no,version,)
-        with self._db_helper:
-            result = self._db_helper.fetch_one(query, params)
-            if not result:
-                return None
-            data = StandardModel(
-                device_model=result["device_model"],
-                device_name=result["device_name"],
-                device_unit=result["device_unit"],
-                standard_version=result["standard_version"],
-                standard_no=result["standard_no"],
-            )
-            return data
-    def query_standard_data(self, device_name: str,
-                            device_model: str) -> list[StandardModel] | None:
-        query = "SELECT device_model,device_name,device_unit,standard_version,standard_no FROM standard_data WHERE device_name = %s AND device_model = %s "
-        params = (device_name, device_model)
-        with self._db_helper:
-            results = self._db_helper.execute_query(query, params)
-            if not results:
-                return None
-            data = []
-            for result in results:
-                data.append(StandardModel(
-                device_model=result["device_model"],
-                device_name=result["device_name"],
-                device_unit=result["device_unit"],
-                standard_version=result["standard_version"],
-                standard_no=result["standard_no"],
-            ))
-            return data
-
-    def insert_standard_data(self, standard_data: StandardModel) -> bool:
-        query = "INSERT INTO standard_data (device_name,device_model,device_unit,standard_version,standard_no,create_time) VALUES (%s,%s,%s,%s,%s,%s)"
+    def update_sub_project_item(self, project_item: SubProjectItemModel) -> bool:
+        sql = "UPDATE sub_project_item SET device_name= %s,device_model= %s,device_unit= %s,device_count= %s,standard_no = %s,update_time = %s WHERE id = %s"
         params = (
-            standard_data.device_name,
-            standard_data.device_model,
-            standard_data.device_unit,
-            standard_data.standard_version,
-            standard_data.standard_no,
+            project_item.device_name,
+            project_item.device_model,
+            project_item.device_unit,
+            project_item.device_count,
+            project_item.standard_no,
             datetime.now(),
+            project_item.id
         )
         with self._db_helper:
-            self._db_helper.execute_non_query(query, params)
+            self._db_helper.execute_non_query(sql, params)
             return True
-
-    def update_standard_data(self, standard_data: StandardModel) -> bool:
-        query = "UPDATE standard_data SET device_name = %s, device_model = %s, device_unit= %s WHERE standard_no = %s AND standard_version = %s"
-        params = (
-            standard_data.device_name,
-            standard_data.device_model,
-            standard_data.device_unit,
-            standard_data.standard_no,
-            standard_data.standard_version,
-        )
-        with self._db_helper:
-            self._db_helper.execute_non_query(query, params)
-            return True
-
-    def insert_or_update_standard_data(self,
-                                       standard_data: StandardModel,
-                                       project_id: int = None) -> bool:
-        query = "SELECT device_model,device_name,device_unit,standard_version,standard_no FROM standard_data WHERE device_name = %s AND device_model = %s AND standard_version = %s"
-        params = (standard_data.device_name, standard_data.device_model,standard_data.standard_version)
-        i_query = "INSERT INTO standard_data (device_name,device_model,device_unit,standard_version,standard_no,create_time) VALUES (%s,%s,%s,%s,%s,%s)"
-        i_params = (
-            standard_data.device_name,
-            standard_data.device_model,
-            standard_data.device_unit,
-            standard_data.standard_version,
-            standard_data.standard_no,
-            datetime.now(),
-        )
-        u_query = "UPDATE standard_data SET  device_unit=%s, standard_no = %s, update_time = %s WHERE device_name = %s AND device_model = %s AND standard_version = %s"
-        u_params = (
-            standard_data.device_unit,
-            standard_data.standard_no,
-            datetime.now(),
-            standard_data.device_name,
-            standard_data.device_model,
-            standard_data.standard_version,
-        )
+    def delete_sub_project_item_by_id(self, item_id: int):
+        sql = "DELETE FROM sub_project_item WHERE id = %s"
+        params = (item_id, )
         with self._db_helper:
-            data = self._db_helper.fetch_one(query, params)
-            if data:
-                self._db_helper.execute_non_query(u_query, u_params)
-                if project_id:
-                    self.insert_standard_update_log(
-                        StandardUpdateLogModel(
-                            project_id=project_id,
-                            device_name=standard_data.device_name,
-                            device_model=standard_data.device_model,
-                            device_unit= standard_data.device_unit,
-                            standard_version=standard_data.standard_version,
-                            new_standard_no=standard_data.standard_no,
-                            old_standard_no=data["standard_no"]))
-            else:
-                self._db_helper.execute_non_query(i_query, i_params)
+            self._db_helper.execute_non_query(sql, params)
             return True
-
-    def query_standard_update_log(self, project_id: int) -> list[StandardUpdateLogModel] | None:
-        query = "SELECT project_id,device_name,device_model,device_unit,standard_version,new_standard_no,old_standard_no,create_time FROM standard_update_log WHERE project_id = %s"
-        params = (project_id, )
+    def update_sub_project_item_process_status(self, item_id:int, status:int):
+        sql = "UPDATE sub_project_item SET process_status = %s,process_time = %s WHERE id = %s"
+        params = (status, datetime.now(), item_id,)
         with self._db_helper:
-            results = self._db_helper.execute_query(query, params)
-            if not results:
-                return None
-            data = [StandardUpdateLogModel(**result) for result in results]
-            return data
-
-    def insert_standard_update_log(
-            self, standard_update_log: StandardUpdateLogModel) -> bool:
-        query = "INSERT INTO standard_update_log (project_id,device_name,device_model,device_unit,standard_version,new_standard_no,old_standard_no,create_time) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)"
-        params = (
-            standard_update_log.project_id,
-            standard_update_log.device_name,
-            standard_update_log.device_model,
-            standard_update_log.device_unit,
-            standard_update_log.standard_version,
-            standard_update_log.new_standard_no,
-            standard_update_log.old_standard_no,
-            datetime.now(),
-        )
+            self._db_helper.execute_non_query(sql, params)
+    def update_sub_project_item_send_status(self, item_id:int, status:int):
+        sql = "UPDATE sub_project_item SET send_status = %s,send_time = %s WHERE id = %s"
+        params = (status, datetime.now(), item_id,)
         with self._db_helper:
-            self._db_helper.execute_non_query(query, params)
-            return True
+            self._db_helper.execute_non_query(sql, params)

+ 93 - 72
SourceCode/DataMiddleware/app/ui/project_services.py

@@ -1,37 +1,66 @@
 import threading,utils
 
-from models.project_data import ProjectModel, ProjectItemModel
+from models.project_data import ProjectModel,SubProjectModel, SubProjectItemModel
 from stores.mysql_store import MysqlStore
 import data_collect,data_process,data_send
 
 
-class SourceDataService:
+class ProjectService:
 
     def __init__(self):
         self._store = MysqlStore()
         self._logger = utils.get_logger()
+    def get_all_project_paginated(self, page: int, per_page: int, keyword: str = None) ->(list[ProjectModel], int):
+        sub_project_list, total_count = self._store.query_project_all_paginated(page, per_page, keyword)
+        return sub_project_list, total_count
 
-    def get_all_project_paginated(self, page: int, per_page: int, keyword: str = None, status: int = None) ->(list[ProjectModel], int):
-        project_list, total_count = self._store.query_project_all_paginated(page, per_page, keyword, status)
-        return project_list, total_count
-
-    def get_all_project(self) ->list[ProjectModel]:
-        project_list = self._store.query_project_all()
-        return project_list
-
-    def get_project_by_id(self, project_id:int) ->ProjectModel:
-        project = self._store.query_project(project_id)
+    def get_project_by_id(self ,project_id:int):
+        project = self._store.query_project_by_id(project_id)
         return project
 
     def add_project(self, project:ProjectModel):
-        self._store.insert_project(project)
+        try:
+            project.create_by = 'admin' if project.create_by is None else project.create_by
+            self._store.insert_project(project)
+            return True, ''
+        except Exception as e:
+            self._logger.error(f"添加项目失败:{e}")
+            return False, '添加项目失败'
+    def update_project(self, project:ProjectModel):
+        project = self._store.query_project_by_id(project.id)
+        if project:
+            self._store.update_project(project)
+            return True, ''
+        else:
+            return False, '项目不存在'
+    def delete_project(self, project_id:int):
+        project = self._store.query_project_by_id(project_id)
+        if project:
+            self._store.delete_project(project_id)
+            return True,''
+        else:
+            return False, '项目不存在'
 
+    def get_all_sub_project_paginated(self, project_id: int, page: int, per_page: int, keyword: str = None, status: int = None) ->(list[SubProjectModel], int):
+        sub_project_list, total_count = self._store.query_sub_project_all_paginated(project_id, page, per_page, keyword, status)
+        return sub_project_list, total_count
 
-    def update_project(self, project:ProjectModel):
-        self._store.update_project(project)
+    def get_all_sub_project(self) ->list[SubProjectModel]:
+        sub_project_list = self._store.query_sub_project_all()
+        return sub_project_list
 
-    def start_task(self, project_id: int) -> (bool, str):
-        data = self._store.query_project(project_id)
+    def get_sub_project_by_id(self, sub_project_id:int) ->SubProjectModel:
+        project = self._store.query_sub_project(sub_project_id)
+        return project
+
+    def add_sub_project(self, sub_project:SubProjectModel):
+       return self._store.insert_sub_project(sub_project)
+
+    def update_sub_project(self, sub_project:SubProjectModel):
+        self._store.update_sub_project(sub_project)
+
+    def start_sub_project_task(self, sub_project_id: int) -> (bool, str):
+        data = self._store.query_sub_project(sub_project_id)
         if data:
             if data.status == 21 or  data.status == 31:
                 return False, '正在采集数据中'
@@ -39,21 +68,20 @@ class SourceDataService:
                 return False, '正在分析处理中'
             if data.status == 32 or data.status == 33:
                 return False, '正在上传数据中'
-            thread = threading.Thread(target = self._process_and_send_project, args=(data,))
+            thread = threading.Thread(target = self._process_and_send_sub_project, args=(data,))
             thread.start()
             return True, ''
         else:
             return False, '项目不存在'
-
-    def _process_and_send_project(self, project: ProjectModel) :
+    def _process_and_send_sub_project(self, sub_project: SubProjectModel) :
         # 启动分析处理
-        if data_process.process_project(project):
+        if data_process.process_project(sub_project):
             # 更新远程数据
-            data_send.send_project_data(project)
-            self._store.update_project_status(project.id,5)
+            data_send.send_project_data(sub_project)
+            self._store.update_sub_project_status(sub_project.id, 5)
 
-    def process_project(self, project_id:int):
-        data = self._store.query_project(project_id)
+    def process_sub_project(self, sub_project_id:int):
+        data = self._store.query_sub_project(sub_project_id)
         if data:
             if data.status == 21 or data.status == 31:
                 return False, '正在采集数据中'
@@ -61,20 +89,20 @@ class SourceDataService:
                 return False, '正在分析处理中'
             if data.status == 32 or data.status == 33:
                 return False, '正在上传数据中'
-            thread = threading.Thread(target=self._process_project, args=(data,))
+            thread = threading.Thread(target=self._process_sub_project, args=(data,))
             thread.start()
             return True, ''
         else:
             return False, '项目不存在'
 
-    def _process_project(self, project: ProjectModel):
-        if data_process.process_data(project):
+    def _process_sub_project(self, sub_project: SubProjectModel):
+        if data_process.process_data(sub_project):
             return True, ''
         else:
-            self._logger.error(f"分析处理失败:{project.project_no}")
+            self._logger.error(f"分析处理失败:{sub_project.sub_project_name}")
         return False, '分析处理失败'
-    def start_send_data(self, project_id: int) -> (bool, str):
-        data = self._store.query_project(project_id)
+    def start_send_sub_project(self, sub_project_id: int) -> (bool, str):
+        data = self._store.query_sub_project(sub_project_id)
         if data:
             if data.status == 21 or data.status == 31:
                 return False, '正在采集数据中'
@@ -82,69 +110,62 @@ class SourceDataService:
                 return False, '正在分析处理中'
             if data.status == 32 or data.status == 33:
                 return False, '正在上传数据中'
-            thread = threading.Thread(target=self._send_project_data, args=(data,))
+            thread = threading.Thread(target=self._send_sub_project_data, args=(data,))
             thread.start()
 
-
-    def _send_project_data(self, project: ProjectModel):
+    def _send_sub_project_data(self, project: SubProjectModel):
         if data_send.send_project_data(project):
-            self._store.update_project_status(project.id,5)
+            self._store.update_sub_project_status(project.id, 5)
             return True, ''
         else:
             return False, '上传数据失败'
 
-    def delete_project(self, project_id:int):
-        project = self._store.query_project(project_id)
+    def delete_sub_project(self, sub_project_id:int):
+        project = self._store.query_sub_project(sub_project_id)
         if project:
-            self._store.delete_project(project_id)
+            self._store.delete_sub_project(sub_project_id)
             return True,''
         else:
             return False, '项目不存在'
 
-    def get_project_item_list_by_project_paginated(self, project_id: int, page: int, per_page: int, keyword: str = None) -> (list[ProjectItemModel], int):
-        return self._store.query_project_items_by_project_paginated(project_id, page, per_page, keyword)
-    def get_project_item_list_by_project_id(self, project_id:int) ->list[ProjectItemModel]:
-        return  self._store.query_project_items_by_project(project_id)
-
-    def get_project_item_by_id(self, item_id: int):
-        return self._store.query_project_item_by_id(item_id)
-
-    def add_project_item(self, item:ProjectItemModel):
-        project_item = self._store.query_project_item(item.project_id, item.device_name, item.device_model)
-        if project_item:
-            return False
-        else:
-            project = self._store.query_project(item.project_id)
-            project_item = ProjectItemModel(
-                project_id=item.project_id,
-                device_name=item.device_name,
-                device_model=item.device_model,
-                device_unit=item.device_unit,
-                standard_version=project.standard_version,
-                standard_no=item.standard_no,
-            )
-            self._store.insert_project_item(project_item)
-            return True
-    def update_project_item(self, item:ProjectItemModel):
-        project_item = self._store.query_project_item_by_id(item.id)
+    def get_sub_project_item_list_by_sub_project_paginated(self, project_id: int, page: int, per_page: int, keyword: str = None) -> (list[SubProjectItemModel], int):
+        return self._store.query_sub_project_items_by_project_paginated(project_id, page, per_page, keyword)
+    def get_sub_project_item_list_by_sub_project_id(self, project_id:int) ->list[SubProjectItemModel]:
+        return  self._store.query_sub_project_items_by_project(project_id)
+
+    def get_sub_project_item_by_id(self, item_id: int):
+        return self._store.query_sub_project_item_by_id(item_id)
+
+    def add_sub_project_item(self, item:SubProjectItemModel):
+        project = self._store.query_sub_project(item.sub_project_id)
+        project_item = SubProjectItemModel(
+            project_id=project.project_id,
+            sub_project_id=item.sub_project_id,
+            device_name=item.device_name,
+            device_model=item.device_model,
+            device_unit=item.device_unit,
+            standard_version=project.standard_version,
+            standard_no=item.standard_no,
+        )
+        self._store.insert_sub_project_item(project_item)
+        return True
+
+    def update_sub_project_item(self, item:SubProjectItemModel):
+        project_item = self._store.query_sub_project_item_by_id(item.id)
         if project_item:
             project_item.device_name = item.device_name
             project_item.device_model = item.device_model
             project_item.device_unit = item.device_unit
             project_item.device_count = item.device_count
             project_item.standard_no = item.standard_no
-            self._store.update_project_item(project_item)
-            #TODO 更新标准数据库
-
-            #TODO 更新远程数据
-
+            self._store.update_sub_project_item(project_item)
             return True
         else:
             return False
-    def delete_project_item(self, item_id:int):
-        project_item = self._store.query_project_item_by_id(item_id)
+    def delete_sub_project_item(self, item_id:int):
+        project_item = self._store.query_sub_project_item_by_id(item_id)
         if project_item:
-            self._store.delete_project_item_by_id(project_item.id)
+            self._store.delete_sub_project_item_by_id(project_item.id)
             return True
         else:
             return False

+ 122 - 81
SourceCode/DataMiddleware/app/ui/project_views.py

@@ -1,43 +1,85 @@
+from multiprocessing.util import sub_debug
+
 from flask import render_template, url_for, redirect, request, jsonify
 from flask import Blueprint
 import os,utils
 
-from .project_services import SourceDataService
-from models.project_data import ProjectModel,ProjectItemModel
+from .project_services import ProjectService
+from models.project_data import ProjectModel, SubProjectModel,SubProjectItemModel
 
-SourceDataService = SourceDataService()  # 确保 SourceDataService 是一个实例
+ProjectService = ProjectService()  # 确保 SourceDataService 是一个实例
 
 # 创建一个名为 'project' 的蓝图
 project = Blueprint('project', __name__, template_folder='templates/project')
 
 @project.route('/')
 def index():
-    return redirect(url_for('project.project_list'))
-@project.route('/project_list')
-def project_list():
+    return redirect(url_for('project.main_project_list'))
+
+@project.route('/main_project_list')
+def main_project_list():
+    page = request.args.get('p', 1, type=int)
+    per_page = request.args.get('pp', 15, type=int)
+    keyword = request.args.get('k', '')
+    projects, total_count = ProjectService.get_all_project_paginated(page, per_page, keyword)
+    return render_template('project_list.html', project_list=projects, page=page, per_page=per_page, total_count=total_count)
+
+@project.route('/save_project', methods=['POST'])
+def save_project():
+    data = request.get_json()
+    project_id = data.get('id')
+    project_name = data.get('project_name')
+    project_desc = data.get('project_desc')
+    if not project_name:
+        return jsonify({'success': False, 'error': '项目编号和名称不能为空'}), 400
+    try:
+        if project_id:
+            project_data = ProjectService.get_project_by_id(int(project_id))
+            if not project_data:
+                return jsonify({'success': False, 'error': '项目编号不存在'}), 400
+            project_data.project_name = project_name
+            project_data.description = project_desc
+            result,msg = ProjectService.update_project(project_data)
+        else:
+            project_data = ProjectModel(project_name=project_name, description=project_desc)
+            result, msg =  ProjectService.add_project(project_data)
+        if not result:
+            return jsonify({'success': False, 'error': msg}), 400
+        return jsonify({'success': True})
+    except Exception as e:
+        return jsonify({'success': False, 'error': str(e)}), 400
+
+@project.route('/delete_project/<int:project_id>', methods=['POST'])
+def delete_project(project_id:int):
+    success, message = ProjectService.delete_project(project_id)
+    if success:
+        return jsonify({'success': True})
+    return jsonify({'success': False, 'error': message}), 400
+
+@project.route('/sub_project_list/<int:project_id>')
+def sub_project_list(project_id:int):
+    project_data = ProjectService.get_project_by_id(project_id)
     keyword = request.args.get('k', '', type=str)
     page = request.args.get('p', 1, type=int)
     per_page = request.args.get('pp', 15, type=int)
     status = request.args.get('s',-1, type=int)
-    data_list, total_count = SourceDataService.get_all_project_paginated(page, per_page, keyword, None if status == -1 else status)  # 传递 status 参数
-    return render_template('project_list.html', project_list=data_list, keyword=keyword, page=page, per_page=per_page, total_count=total_count, status=status)  # 传递 status 参数到模板
+    data_list, total_count = ProjectService.get_all_sub_project_paginated(project_id, page, per_page, keyword, None if status == -1 else status)  # 传递 status 参数
+    return render_template('sub_project_list.html', project=project_data ,sub_project_list=data_list, keyword=keyword, page=page, per_page=per_page, total_count=total_count, status=status)  # 传递 status 参数到模板
 
-@project.route('/project_item_list/<project_id>')
-def project_item_list(project_id:int):
+@project.route('/project_item_list/<sub_project_id>')
+def project_item_list(sub_project_id:int):
     keyword = request.args.get('k', '', type=str)
     page = request.args.get('p', 1, type=int)
     per_page = request.args.get('pp', 15, type=int)
-    project_data= SourceDataService.get_project_by_id(project_id)
-    project_items, total_count = SourceDataService.get_project_item_list_by_project_paginated(project_id, page, per_page, keyword)
-    return render_template('project_item_list.html', project=project_data, project_items=project_items, keyword=keyword, page=page, per_page=per_page, total_count=total_count)
-
-@project.route('/save_project', methods=['POST'])
-def save_project():
-    project_id = request.form.get('id')
-    project_no = request.form.get('project_no')
-    if not project_no:
-        return jsonify({'success': False, 'error': 'ProjectNo不能为空'}), 400
-    project_name = request.form.get('project_name')
+    sub_project_data= ProjectService.get_sub_project_by_id(sub_project_id)
+    sub_items, total_count = ProjectService.get_sub_project_item_list_by_sub_project_paginated(sub_project_id, page, per_page, keyword)
+    return render_template('sub_project_item_list.html', sub_project=sub_project_data,items=sub_items, keyword=keyword, page=page, per_page=per_page, total_count=total_count)
+
+@project.route('/save_sub_project', methods=['POST'])
+def save_sub_project():
+    sub_id = request.form.get('id')
+    project_id = request.form.get('project_id')
+    sub_project_name = request.form.get('sub_project_name')
     standard_version = request.form.get('standard_version')
     work_catalog = request.form.get('work_catalog')
     work_content = request.form.get('work_content')
@@ -45,8 +87,25 @@ def save_project():
     # 处理多文件上传
     project_files = request.files.getlist('project_files')
     project_data = None
-    if project_id:
-        project_data = SourceDataService.get_project_by_id(int(project_id))
+    if sub_id:
+        sub_id= int(sub_id)
+        project_data = ProjectService.get_sub_project_by_id(sub_id)
+    if project_data:
+        project_data.sub_project_name = sub_project_name
+        project_data.standard_version = standard_version
+        project_data.work_catalog = work_catalog
+        project_data.work_content = work_content
+        ProjectService.update_sub_project(project_data)
+    else:
+        project_data = SubProjectModel(
+                                       project_id=project_id,
+                                       sub_project_name=sub_project_name,
+                                       standard_version=standard_version,
+                                       work_catalog=work_catalog,
+                                       work_content=work_content,
+                                       status=0)
+        new_id= ProjectService.add_sub_project(project_data)
+        project_data.id = new_id
     if len(project_files)<=0 and project_id and delete_old_data:
         return jsonify({'success': False, 'error': '请上传项目数据文件'}), 400
     elif project_files:
@@ -55,8 +114,8 @@ def save_project():
             if not os.path.exists(base_path):
                 os.makedirs(base_path)
             # 如果选择删除旧数据且目录存在,则删除目录下的所有文件
-            if delete_old_data and project_data :
-                del_path = os.path.join(base_path, f"project/{project_data.project_no}")
+            if delete_old_data:
+                del_path = os.path.join(base_path, f"project/sub_data_{project_data.id}")
                 if os.path.exists(del_path):
                     for filename in os.listdir(del_path):
                         file_path = os.path.join(del_path, filename)
@@ -65,7 +124,7 @@ def save_project():
                                 os.remove(file_path)
                         except Exception as e:
                             return jsonify({'success': False, 'error': f'删除旧文件失败:{str(e)}'}), 500
-            path = os.path.join(base_path, f"project/{project_no}")
+            path = os.path.join(base_path, f"project/sub_data_{project_data.id}")
             if not os.path.exists(path):
                 os.makedirs(path)
             for project_file in project_files:
@@ -84,65 +143,49 @@ def save_project():
     elif not project_id:
         return jsonify({'success': False, 'error': '请上传项目数据文件'}), 400
 
-    if project_data:
-        project_data.project_no = project_no
-        project_data.project_name = project_name
-        project_data.standard_version = standard_version
-        project_data.work_catalog = work_catalog
-        project_data.work_content = work_content
-        SourceDataService.update_project(project_data)
-    else:
-        project_data = ProjectModel(project_no=project_no,
-                                    project_name=project_name,
-                                    standard_version=standard_version,
-                                    work_catalog=work_catalog,
-                                    work_content=work_content,
-                                    status=0)
-        SourceDataService.add_project(project_data)
+
     return jsonify({'success': True})
 
-@project.route('/update_project', methods=['POST'])
-def update_project():
+@project.route('/update_sub_project', methods=['POST'])
+def update_sub_project():
     req = request.get_json()
-    project_id = req.get('id')
-    project_no = req.get('project_no')
+    sub_project_id = req.get('id')
     project_name= req.get('project_name')
     standard_version= req.get('standard_version')
     work_catalog = req.get('work_catalog')
     work_content = req.get('work_content')
-    project_data = SourceDataService.get_project_by_id(project_id)
+    project_data = ProjectService.get_sub_project_by_id(sub_project_id)
     if not project_data:
         return jsonify({'success': False, 'error': '项目不存在'}), 404
-    data= ProjectModel(project_id=project_id,
-                       project_no=project_no,
-                       project_name=project_name,
-                       standard_version=standard_version,
-                       work_catalog=work_catalog,
-                       work_content=work_content,
-                       status=project_data.status)
-    SourceDataService.update_project(data)
+    data= SubProjectModel(sub_id=sub_project_id,
+                          sub_project_name=project_name,
+                          standard_version=standard_version,
+                          work_catalog=work_catalog,
+                          work_content=work_content,
+                          status=project_data.status)
+    ProjectService.update_sub_project(data)
     return jsonify({'success': True})
 
-@project.route('/start_project_task/<project_id>', methods=['POST'])
-def start_project_task(project_id:int):
-    result, err_msg = SourceDataService.start_task(project_id)
+@project.route('/start_sub_project_task/<project_id>', methods=['POST'])
+def start_sub_project_task(project_id:int):
+    result, err_msg = ProjectService.start_sub_project_task(project_id)
     return jsonify({'success': result, 'error': err_msg})
 
-@project.route('/process_project/<project_id>', methods=['POST'])
-def process_project(project_id:int):
-    result, err_msg = SourceDataService.process_project(project_id)
+@project.route('/start_process_sub_project/<project_id>', methods=['POST'])
+def start_process_sub_project(project_id:int):
+    result, err_msg = ProjectService.process_sub_project(project_id)
     return jsonify({'success': result, 'error': err_msg})
-@project.route('/send_project/<project_id>', methods=['POST'])
-def send_project(project_id:int):
-    result, err_msg = SourceDataService.start_send_data(project_id)
+@project.route('/start_send_sub_project/<project_id>', methods=['POST'])
+def start_send_sub_project(project_id:int):
+    result, err_msg = ProjectService.start_send_sub_project(project_id)
     return jsonify({'success': result, 'error': err_msg})
-@project.route('/delete_project/<project_id>', methods=['POST'])
-def delete_project(project_id:int):
-    result, err_msg =  SourceDataService.delete_project(project_id)
+@project.route('/delete_sub_project/<project_id>', methods=['POST'])
+def delete_sub_project(project_id:int):
+    result, err_msg =  ProjectService.delete_sub_project(project_id)
     return jsonify({'success': result, 'error': err_msg})
 
-@project.route('/add_project_item', methods=['POST'])
-def add_project_item():
+@project.route('/add_sub_project_item', methods=['POST'])
+def add_sub_project_item():
     data = request.get_json()
     project_id = data.get('project_id')
     device_name = data.get('device_name')
@@ -150,12 +193,12 @@ def add_project_item():
     device_unit = data.get('device_unit')
     device_count = data.get('device_count')
     standard_no = data.get('standard_no')
-    new_item = ProjectItemModel(project_id=project_id, device_name=device_name, device_model=device_model, device_unit=device_unit, standard_no=standard_no)
-    item_id = SourceDataService.add_project_item(new_item)
+    new_item = SubProjectItemModel(sub_project_id=project_id, device_name=device_name, device_model=device_model, device_unit=device_unit, standard_no=standard_no)
+    item_id = ProjectService.add_sub_project_item(new_item)
     return jsonify({'success': True, 'id': item_id})
 
-@project.route('/update_data_item', methods=['POST'])
-def update_data_item():
+@project.route('/update_sub_project_item', methods=['POST'])
+def update_sub_project_item():
     data = request.get_json()
     item_id = data.get('id')
     if not item_id:
@@ -165,17 +208,15 @@ def update_data_item():
     device_unit = data.get('device_unit')
     device_count = data.get('device_count')
     standard_no = data.get('standard_no')
-    # if not standard_no:
-    #     return jsonify({'success': False, 'error': 'Standard No is missing'}), 400
-    item =ProjectItemModel(item_id=item_id,project_id=project_id, device_name=device_name, device_model=device_model, device_unit=device_unit, standard_no=standard_no)
-    SourceDataService.update_project_item(item)
+    item =SubProjectItemModel(item_id=item_id, device_name=device_name, device_model=device_model, device_unit=device_unit,device_count=device_count, standard_no=standard_no)
+    ProjectService.update_sub_project_item(item)
     return jsonify({'success': True})
 
-@project.route('/delete_project_item/<item_id>', methods=['POST'])
-def delete_project_item_route(item_id):
-    project_item = SourceDataService.get_project_item_by_id(item_id)
-    SourceDataService.delete_project_item(item_id)
-    return redirect(url_for('project.project_item_list', project_no=project_item.project_id))
+@project.route('/delete_sub_project_item/<item_id>', methods=['POST'])
+def delete_sub_project_item(item_id):
+    project_item = ProjectService.get_sub_project_item_by_id(item_id)
+    ProjectService.delete_sub_project_item(item_id)
+    return redirect(url_for('project.project_item_list', project_no=project_item.sub_project_id))
 
 
 

+ 48 - 164
SourceCode/DataMiddleware/app/ui/static/project_list.js

@@ -4,198 +4,80 @@ function addProject() {
 	inputs.forEach((input) => {
 		input.value = ''
 	})
-	// 移除已存在的delete_old_data复选框
-	const existingCheckbox = document.getElementById('delete_old_data')
-	if (existingCheckbox) {
-		existingCheckbox.parentNode.remove()
-	}
-	const file = document.getElementById('new_project_file').parentNode
-	file.innerHTML = `<label for="new_project_file">项目数据:</label><input type="file" id="new_project_file" class="form-control" accept=".xlsx,.xls,.csv" multiple>`
-
 	editBox.classList.add('show')
 }
 
-function updateProject(row, id) {
-	document.getElementById('project_id').value = id
-	document.getElementById('new_project_no').value = row.querySelector('.project_no .form-control').value
-	document.getElementById('new_project_name').value = row.querySelector('.project_name .form-control').value
-	const file = document.getElementById('new_project_file').parentNode
-	file.innerHTML = `<label for="new_project_file">项目数据:</label><input type="file" id="new_project_file" class="form-control" accept=".xlsx,.xls,.csv" multiple>`
-	// 移除已存在的delete_old_data复选框
-	const existingCheckbox = document.getElementById('delete_old_data')
-	if (existingCheckbox) {
-		existingCheckbox.parentNode.remove()
-	}
-	const checkboxDiv = document.createElement('div')
-	checkboxDiv.innerHTML = `<label for="delete_old_data">删除原数据:</label><input type="checkbox" id="delete_old_data" class="form-control" style="width: auto;flex: 0;">`
-	file.parentNode.insertBefore(checkboxDiv, file.nextSibling)
-	// document.getElementById('new_work_catalog').value = row.querySelector('.work_catalog .form-control').value
-	document.getElementById('new_work_content').value = row.querySelector('.work_content .form-control').value
-	// document.getElementById('new_standard_version').value = row.querySelector('.standard_version .form-control').value
-	const editBox = document.querySelector('div.edit-box')
-	editBox.classList.add('show')
-}
-function saveProject() {
-	const id = document.getElementById('project_id').value
-	const no = document.getElementById('new_project_no').value
-	const name = document.getElementById('new_project_name').value
-	const files = document.getElementById('new_project_file').files
-	// const catalog = document.getElementById('new_work_catalog').value
-	// const version = document.getElementById('new_standard_version').value
-	const catalog = " "
-	const version = "2"
-	const content = document.getElementById('new_work_content').value
-
-	if (no === '') {
-		alert('项目编号不能为空')
-		return
-	}
-	if (name === '') {
-		alert('项目名称不能为空')
-		return
-	}
-	if (files.length === 0 && !id) {
-		alert('请选择项目数据文件')
-		return
-	}
-	// if (catalog === '') {
-	// 	alert('工作目录不能为空')
-	// 	return
-	// }
-	if (content === '') {
-		alert('工作内容不能为空')
-		return
-	}
-
-	const formData = new FormData()
-	formData.append('id', id)
-	formData.append('project_no', no)
-	formData.append('project_name', name)
-	for (let i = 0; i < files.length; i++) {
-		formData.append('project_files', files[i])
-	}
-	formData.append('work_catalog', catalog)
-	formData.append('work_content', content)
-	formData.append('standard_version', version)
-	if (document.getElementById('delete_old_data')){
-		formData.append('delete_old_data', document.getElementById('delete_old_data').checked)
-	}
-
-	fetch('/save_project', {
-		method: 'POST',
-		body: formData,
-	})
-		.then((response) => response.json())
-		.then((data) => {
-			if (data.success) {
-				alert('保存成功')
-				window.location.reload()
-			} else {
-				alert('保存失败:' + data.error)
-			}
-		})
-		.catch((error) => {
-			console.error('保存失败:', error)
-			alert('保存失败')
-		})
-}
-function cancelAdd() {
+function hideAddForm() {
 	const editBox = document.querySelector('div.edit-box')
 	editBox.classList.remove('show')
 }
 
-function saveProjectUpdate(row, id) {
-	const no = row.querySelector('.project_no .form-control').value
-	const name = row.querySelector('.project_name .form-control').value
-	const work_catalog = row.querySelector('.work_catalog .form-control').value
-	const work_content = row.querySelector('.work_content .form-control').value
-	const version = row.querySelector('.standard_version .form-control').value
-	if (no === '') {
-		alert('名称不能为空')
-		return
-	}
-	if (name === '') {
-		alert('名称不能为空')
-		return
-	}
-	if (version === '') {
-		alert('版本不能为空')
-		return
-	}
-	fetch('/update_project', {
-		method: 'POST',
-		headers: {
-			'Content-Type': 'application/json',
-		},
-		body: JSON.stringify({
-			id: id,
-			project_no: no,
-			project_name: name,
-			work_catalog: work_catalog,
-			work_content: work_content,
-			standard_version: version,
-		}),
-	})
-		.then((response) => response.json())
-		.then((data) => {
-			if (data.success) {
-				alert('更新成功')
-				window.location.reload()
-			} else {
-				alert('更新失败:' + data.error)
-			}
-		})
-		.catch((error) => {
-			console.error('更新失败:', error)
-			alert('更新失败')
-		})
-}
-
-function confirmStartTask(id){
-	_confirm('确定要开始任务吗?',`/start_project_task/${id}`)
-}
-
-function confirmReStartTask(id){
-	_confirm('确定要重新采集数据吗?',`/start_project_task/${id}`)
-}
-
-function confirmReProcessData(id){
-	_confirm('确定要重新处理数据吗?',`/process_project/${id}`)
-}
+async function saveProject() {
+	const projectId = document.getElementById('project_id').value
+	const projectName = document.getElementById('project_name').value
+	const projectDesc = document.getElementById('project_desc').value
 
-function confirmSendData(id) {
-	_confirm('确定要开始上传数据吗?',`/send_project/${id}`)
-}
-
-function _confirm(text,url){
-	if (confirm(text)) {
-		fetch(url, {
+	try {
+		await fetch('/save_project', {
 			method: 'POST',
 			headers: {
 				'Content-Type': 'application/json',
 			},
+			body: JSON.stringify({
+				project_id: projectId,
+				project_name: projectName,
+				project_desc: projectDesc,
+			}),
 		})
 			.then((response) => response.json())
 			.then((data) => {
 				if (data.success) {
-					alert('操作成功')
+					alert('保存成功')
 					window.location.reload()
 				} else {
-					alert('操作失败:' + data.error)
+					alert('保存失败:' + data.error)
 				}
 			})
-			.catch((error) => {})
+			.catch((error) => {
+				alert('保存失败')
+			})
+	} catch (e) {
+		alert('网络请求异常')
 	}
 }
 
-
-function confirmProjectDelete(id) {
+async function confirmDelete(projectId) {
 	if (confirm('确定要删除该项目吗?')) {
-		fetch(`/delete_project/${id}`, {
+		try {
+			const response = await fetch(`/delete_project/${projectId}`, {
+				method: 'POST',
+			})
+		} catch (e) {
+			alert('网络请求异常')
+		}
+	}
+}
+
+function editProject(projectId) {
+	const row = document.querySelector(`tr[data-id='${projectId}']`)
+	row.querySelectorAll('.editable').forEach((cell) => {
+		cell.classList.add('edit-mode')
+	})
+}
+
+async function saveProjectUpdate(row, projectId) {
+	const data = {
+		project_code: row.querySelector('[name="project_code"]').value,
+		project_name: row.querySelector('[name="project_name"]').value,
+	}
+
+	try {
+		const response = await fetch(`/update_project/${projectId}`, {
 			method: 'POST',
 			headers: {
 				'Content-Type': 'application/json',
 			},
+			body: JSON.stringify(data),
 		})
 			.then((response) => response.json())
 			.then((data) => {
@@ -210,5 +92,7 @@ function confirmProjectDelete(id) {
 				console.error('删除失败:', error)
 				alert('删除失败')
 			})
+	} catch (e) {
+		alert('网络请求异常')
 	}
 }

+ 6 - 0
SourceCode/DataMiddleware/app/ui/static/styles.css

@@ -97,6 +97,12 @@ h6 {
 	border: 1px solid #ddd;
 	border-radius: 4px;
 }
+.box_header .project_info {
+	display: flex;
+	justify-content: left;
+	align-items: center;
+	width: 60%;
+}
 .box_header .box_title {
 	font-size: 18px;
 	font-weight: bolder;

+ 3 - 3
SourceCode/DataMiddleware/app/ui/static/project_item_list.js → SourceCode/DataMiddleware/app/ui/static/sub_project_item_list.js

@@ -50,7 +50,7 @@ function saveItemCreate(row, project_id) {
 	//     return;
 	// }
 
-	fetch(`/add_project_item`, {
+	fetch(`/add_sub_project_item`, {
 		method: 'POST',
 		headers: {
 			'Content-Type': 'application/json',
@@ -90,7 +90,7 @@ function saveItemEdit(row, itemId) {
 		alert('单位不能为空')
 		return
 	}
-	fetch(`/update_data_item`, {
+	fetch(`/update_sub_project_item`, {
 		method: 'POST',
 		headers: {
 			'Content-Type': 'application/json',
@@ -116,7 +116,7 @@ function saveItemEdit(row, itemId) {
 
 function confirmItemDelete(itemId) {
 	if (confirm('确定要删除该设备吗?')) {
-		fetch(`/delete_project_item/${itemId}`, {
+		fetch(`/delete_sub_project_item/${itemId}`, {
 			method: 'POST',
 			headers: {
 				'Content-Type': 'application/json',

+ 208 - 0
SourceCode/DataMiddleware/app/ui/static/sub_project_list.js

@@ -0,0 +1,208 @@
+function addSubProject() {
+	const editBox = document.querySelector('div.edit-box')
+	const inputs = editBox.querySelectorAll('.form-control')
+	inputs.forEach((input) => {
+		input.value = ''
+	})
+	// 移除已存在的delete_old_data复选框
+	const existingCheckbox = document.getElementById('delete_old_data')
+	if (existingCheckbox) {
+		existingCheckbox.parentNode.remove()
+	}
+	const file = document.getElementById('sub_project_file').parentNode
+	file.innerHTML = `<label for="sub_project_file">工程数据:</label><input type="file" id="sub_project_file" class="form-control" accept=".xlsx,.xls,.csv" multiple>`
+
+	editBox.classList.add('show')
+}
+
+function updateSubProject(row, id) {
+	document.getElementById('sub_id').value = id
+	document.getElementById('sub_project_name').value = row.querySelector('.sub_project_name .form-control').value
+	document.getElementById('work_catalog').value = row.querySelector('.work_catalog .form-control').value
+	document.getElementById('work_content').value = row.querySelector('.work_content .form-control').value
+	const file = document.getElementById('sub_project_file').parentNode
+	file.innerHTML = `<label for="sub_project_file">工程数据:</label><input type="file" id="sub_project_file" class="form-control" accept=".xlsx,.xls,.csv" multiple>`
+	// 移除已存在的delete_old_data复选框
+	const existingCheckbox = document.getElementById('delete_old_data')
+	if (existingCheckbox) {
+		existingCheckbox.parentNode.remove()
+	}
+	const checkboxDiv = document.createElement('div')
+	checkboxDiv.innerHTML = `<label for="delete_old_data">删除原数据:</label><input type="checkbox" id="delete_old_data" class="form-control" style="width: auto;flex: 0;">`
+	file.parentNode.insertBefore(checkboxDiv, file.nextSibling)
+	// document.getElementById('new_standard_version').value = row.querySelector('.standard_version .form-control').value
+	const editBox = document.querySelector('div.edit-box')
+	editBox.classList.add('show')
+}
+function saveSubProject() {
+	const id = document.getElementById('sub_id').value
+	const project_id = document.getElementById('project_id').value
+	const name = document.getElementById('sub_project_name').value
+	const files = document.getElementById('sub_project_file').files
+	const catalog = document.getElementById('work_catalog').value
+	// const version = document.getElementById('new_standard_version').value
+	const version = '2'
+	const content = document.getElementById('work_content').value
+
+
+	if (name === '') {
+		alert('工程名称不能为空')
+		return
+	}
+	if (files.length === 0 && !id) {
+		alert('请选择工程数据文件')
+		return
+	}
+	// if (catalog === '') {
+	// 	alert('工作目录不能为空')
+	// 	return
+	// }
+	if (content === '') {
+		alert('工作内容不能为空')
+		return
+	}
+
+	const formData = new FormData()
+	formData.append('id', id)
+	formData.append('project_id', project_id)
+	formData.append('sub_project_name', name)
+	for (let i = 0; i < files.length; i++) {
+		formData.append('project_files', files[i])
+	}
+	formData.append('work_catalog', catalog)
+	formData.append('work_content', content)
+	formData.append('standard_version', version)
+	if (document.getElementById('delete_old_data')) {
+		formData.append('delete_old_data', document.getElementById('delete_old_data').checked)
+	}
+
+	fetch('/save_sub_project', {
+		method: 'POST',
+		body: formData,
+	})
+		.then((response) => response.json())
+		.then((data) => {
+			if (data.success) {
+				alert('保存成功')
+				window.location.reload()
+			} else {
+				alert('保存失败:' + data.error)
+			}
+		})
+		.catch((error) => {
+			console.error('保存失败:', error)
+			alert('保存失败')
+		})
+}
+function cancelAdd() {
+	const editBox = document.querySelector('div.edit-box')
+	editBox.classList.remove('show')
+}
+
+function saveProjectUpdate(row, id) {
+	const no = row.querySelector('.project_no .form-control').value
+	const name = row.querySelector('.project_name .form-control').value
+	const work_catalog = row.querySelector('.work_catalog .form-control').value
+	const work_content = row.querySelector('.work_content .form-control').value
+	const version = row.querySelector('.standard_version .form-control').value
+	if (no === '') {
+		alert('名称不能为空')
+		return
+	}
+	if (name === '') {
+		alert('名称不能为空')
+		return
+	}
+	if (version === '') {
+		alert('版本不能为空')
+		return
+	}
+	fetch('/update_sub_project', {
+		method: 'POST',
+		headers: {
+			'Content-Type': 'application/json',
+		},
+		body: JSON.stringify({
+			id: id,
+			project_no: no,
+			project_name: name,
+			work_catalog: work_catalog,
+			work_content: work_content,
+			standard_version: version,
+		}),
+	})
+		.then((response) => response.json())
+		.then((data) => {
+			if (data.success) {
+				alert('更新成功')
+				window.location.reload()
+			} else {
+				alert('更新失败:' + data.error)
+			}
+		})
+		.catch((error) => {
+			console.error('更新失败:', error)
+			alert('更新失败')
+		})
+}
+
+function confirmStartTask(id) {
+	_confirm('确定要开始任务吗?', `/start_sub_project_task/${id}`)
+}
+
+function confirmReStartTask(id) {
+	_confirm('确定要重新采集数据吗?', `/start_sub_project_task/${id}`)
+}
+
+function confirmReProcessData(id) {
+	_confirm('确定要重新处理数据吗?', `/start_process_sub_project/${id}`)
+}
+
+function confirmSendData(id) {
+	_confirm('确定要开始上传数据吗?', `/start_send_sub_project/${id}`)
+}
+
+function _confirm(text, url) {
+	if (confirm(text)) {
+		fetch(url, {
+			method: 'POST',
+			headers: {
+				'Content-Type': 'application/json',
+			},
+		})
+			.then((response) => response.json())
+			.then((data) => {
+				if (data.success) {
+					alert('操作成功')
+					window.location.reload()
+				} else {
+					alert('操作失败:' + data.error)
+				}
+			})
+			.catch((error) => {})
+	}
+}
+
+function confirmProjectDelete(id) {
+	if (confirm('确定要删除该工程吗?')) {
+		fetch(`/delete_sub_project/${id}`, {
+			method: 'POST',
+			headers: {
+				'Content-Type': 'application/json',
+			},
+		})
+			.then((response) => response.json())
+			.then((data) => {
+				if (data.success) {
+					alert('删除成功')
+					window.location.reload()
+				} else {
+					alert('删除失败:' + data.error)
+				}
+			})
+			.catch((error) => {
+				console.error('删除失败:', error)
+				alert('删除失败')
+			})
+	}
+}

+ 57 - 239
SourceCode/DataMiddleware/app/ui/templates/project/project_list.html

@@ -1,249 +1,67 @@
 <!DOCTYPE html>
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
 <html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>项目列表</title>
-    <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
-    <script src="{{ url_for('static', filename='utils.js') }}"></script>
-    <script src="{{ url_for('static', filename='project_list.js') }}"></script>
-    <script>
-        function searchData(){
-            var keyword = document.getElementById('search_input').value;
-            var status = document.getElementById('status_select').value;
-            window.location.href = `{{ url_for('project.project_list') }}?k=${keyword}&s=${status}`;
-        }
-        function reSearchData(){
-            window.location.href = `{{ url_for('project.project_list') }}`;
-        }
-    </script>
-</head>
-<body>
-    <div class="box">
-        <div class="box_header">
-            <div><h3 class="box_title">项目列表</h3></div>
-        </div>
-        <div class="box_header">
+	<head>
+		<meta charset="UTF-8" />
+		<title>主项目管理</title>
+		<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}" />
+		<script src="{{ url_for('static', filename='utils.js') }}"></script>
+		<script src="{{ url_for('static', filename='project_list.js') }}"></script>
+	</head>
+	<body>
+		<div class="box">
+			<div class="box_header">
+				<h3 class="box_title">主项目列表</h3>
+			</div>
+			<div class="box_header">
             <div class="btn_box">
-                <button type="button" class="btn btn-success btn-large" onclick="addProject()">添加</button>
+                <button type="button" class="btn btn-success btn-large" onclick="addProject()">新建项目</button>
             </div>
             <div class="search_box">
-                <select id="status_select" class="form-control form-select" title="状态选择">
-                    <option value="-1" {% if status == -1 %}selected{% endif %}>所有状态</option>
-                    <option value="0" {% if status == 0 %}selected{% endif %}>新建</option>
-                    <option value="5" {% if status == 5 %}selected{% endif %}>完成</option>
-                     <option value="11" {% if status == 11 %}selected{% endif %}>采集失败</option>
-                    <option value="12" {% if status == 12 %}selected{% endif %}>分析失败</option>
-                    <option value="13" {% if status == 13 %}selected{% endif %}>上传失败</option>
-                     <option value="21" {% if status == 21 %}selected{% endif %}>采集中...</option>
-                    <option value="22" {% if status == 22 %}selected{% endif %}>分析中...</option>
-                    <option value="23" {% if status == 23 %}selected{% endif %}>上传中...</option>
-                    <option value="31" {% if status == 31 %}selected{% endif %}>采集完成</option>
-                    <option value="32" {% if status == 32 %}selected{% endif %}>分析完成</option>
-                    <option value="33" {% if status == 32 %}selected{% endif %}>上传完成</option>
-                </select>
                 <input type="text" id="search_input" class="form-control" placeholder="请输入查询关键字" value="{{ keyword }}">
                 <button type="button" class="btn btn-info btn-large" onclick="searchData()">查询</button>
                 <button type="button" class="btn btn-warning btn-large" onclick="reSearchData()">重置</button>
             </div>
         </div>
-        <div class="edit-box">
-            <div class="form-group">
-                <input type="hidden" id="project_id" class="form-control">
-                <div>
-                    <label for="new_project_no">项目编号:</label>
-                    <input type="text" id="new_project_no" class="form-control" placeholder="项目编号">
-                </div>
-                <div>
-                    <label for="new_project_name">项目名称:</label>
-                    <input type="text" id="new_project_name" class="form-control" placeholder="项目名称">
-                </div>
-                <div>
-                    <label for="new_project_file">项目数据:</label>
-                    <input type="file" id="new_project_file" class="form-control" accept=".xlsx,.xls,.csv" multiple>
-                </div>
-                <div></div>
-<!--                <div>-->
-<!--                    <label for="new_work_catalog">工作目录:</label>-->
-<!--                    <textarea id="new_work_catalog" class="form-control" placeholder="工作目录"></textarea>-->
-<!--                </div>-->
-                <div>
-                    <label for="new_work_content">工作内容:</label>
-                    <textarea id="new_work_content" class="form-control large" placeholder="工作内容"></textarea>
-                </div>
-<!--                <div>-->
-<!--                    <label for="new_standard_version">标准版本:</label>-->
-<!--                    <select id="new_standard_version" class="form-control">-->
-<!--                        <option value="1">旧版</option>-->
-<!--                        <option value="2">新版</option>-->
-<!--                    </select>-->
-<!--                </div>-->
-                <div class="button-group">
-                    <button type="button" class="btn btn-success btn-large" onclick="saveProject()">保存</button>
-                    <button type="button" class="btn btn-warning btn-large" onclick="cancelAdd()">关闭</button>
-                </div>
-            </div>
-        </div>
-        <div class="box-body">
-            <table class="table">
-                <thead>
-                    <tr>
-                        <th width="200px">项目编号</th>
-                        <th width="330px">项目名称</th>
-<!--                        <th width="15%">工作目录</th>-->
-                        <th width="">工作内容</th>
-<!--                        <th width="120px">标准版本</th>-->
-                        <th width="120px">状态</th>
-                        <th width="280px">操作</th>
-                    </tr>
-                </thead>
-                <tbody>
-                {% if project_list %}
-                    {% for project in project_list %}
-                        <tr>
-                            <td class="editable project_no">
-                                <span class="show">{{ project.project_no if project.project_no else '-' }}</span>
-                                <span class="edit">
-                                    <input type="text" class="form-control" title="项目编号" name="project_no" value="{{ project.project_no if project.project_no else '' }}">
-                                </span>
-                            </td>
-                            <td class="editable project_name">
-                                <span class="show">{{ project.project_name if project.project_name else '-' }}</span>
-                                <span class="edit">
-                                    <input type="text" class="form-control" title="项目名称" name="project_name" value="{{ project.project_name if project.project_name else '' }}">
-                                </span>
-                            </td>
-<!--                            <td class="editable work_catalog">-->
-<!--                                <span class="show">{{ project.work_catalog if project.work_catalog else '-' }}</span>-->
-<!--                                <span class="edit">-->
-<!--                                    <input type="text" class="form-control" title="工作目录" name="work_catalog" value="{{ project.work_catalog if project.work_catalog else '' }}">-->
-<!--                                </span>-->
-<!--                            </td>-->
-                            <td class="editable work_content">
-                                <span class="show">{{ project.work_content if project.work_content else '-' }}</span>
-                                <span class="edit">
-                                    <input type="text" class="form-control" title="工作内容" value="{{ project.work_content if project.work_content else '' }}">
-                                </span>
-                            </td>
-<!--                            <td class="editable standard_version">-->
-<!--                                <span class="show">-->
-<!--                                    {% if project.standard_version == '1' %}-->
-<!--                                    <span class="label label-warning">旧版</span>-->
-<!--                                    {% elif project.standard_version == '2' %}-->
-<!--                                    <span class="label label-info">新版</span>-->
-<!--                                    {% endif %}-->
-<!--                                </span>-->
-<!--                                <span class="edit">-->
-<!--                                    <select class="form-control" title="标准版本">-->
-<!--                                        <option value="1" {% if project.standard_version == '1' %}selected{% endif %}>旧版</option>-->
-<!--                                        <option value="2" {% if project.standard_version == '2' %}selected{% endif %}>新版</option>-->
-<!--                                    </select>-->
-<!--                                </span>-->
-<!--                            </td>-->
-                            <td>
-                                <span class="status">
-                                    {% if project.status == 0 %}
-                                    <span class="label label-default">新建</span>
-                                    {% elif project.status == 21 %}
-                                    <span class="label label-warning">采集中...</span>
-                                    {% elif project.status == 22 %}
-                                    <span class="label label-warning">分析中...</span>
-                                    {% elif project.status == 23 %}
-                                    <span class="label label-warning">上传中...</span>
-                                    {% elif project.status == 31 %}
-                                    <span class="label label-info">采集完成</span>
-                                    {% elif project.status == 32 %}
-                                    <span class="label label-info">分析完成</span>
-                                    {% elif project.status == 33 %}
-                                    <span class="label label-info">上传完成</span>
-                                    {% elif project.status == 11 %}
-                                    <span class="label label-danger">采集失败</span>
-                                    {% elif project.status == 12 %}
-                                    <span class="label label-danger">分析失败</span>
-                                    {% elif project.status == 13 %}
-                                    <span class="label label-danger">上传失败</span>
-                                    {% elif project.status == 5 %}
-                                    <span class="label label-success">完成</span>
-                                    {% endif %}
-                                </span>
-                            </td>
-                            <td class="editable">
-                                <span class="show">
-                                    {% if project.status == 0 %}
-                                    <button class="btn btn-success" type="button" onclick="confirmStartTask('{{ project.id }}')">开始</button>
-                                    <button class="btn btn-info" onclick="updateProject(this.parentNode.parentNode.parentNode,'{{ project.id }}')">编辑</button>
-                                    {% elif project.status == 11 %}
-                                    <button class="btn btn-success" type="button" onclick="confirmReStartTask('{{ project.id }}')">重新采集</button>
-                                    <button class="btn btn-info" onclick="updateProject(this.parentNode.parentNode.parentNode,'{{ project.id }}')">编辑</button>
-                                    {% elif project.status == 12 %}
-                                    <button class="btn btn-success" type="button" onclick="confirmReProcessData('{{ project.id }}')">重新处理</button>
-                                    {% elif project.status == 13 %}
-                                    <button class="btn btn-success" type="button" onclick="confirmSendData('{{ project.id }}')">重新发送</button>
-                                    {% elif project.status == 5 or project.status == 32 or project.status == 13 or project.status == 23 or project.status == 33 %}
-                                    <button class="btn btn-info" type="button" onclick="goTo(`{{ url_for('project.project_item_list', project_id=project.id) }}`)">详情</button>
-                                    {% endif %}
-                                    {% if project.status != 21  and project.status != 22 %}
-                                    <button class="btn btn-danger" onclick="confirmProjectDelete('{{ project.id }}')">删除</button>
-                                    {% endif %}
-                                </span>
-                                <span class="edit">
-                                    <button class="btn btn-success" onclick="saveProjectUpdate(this.parentNode.parentNode.parentNode,'{{ project.id }}')">确定</button>
-                                    <button class="btn btn-warning" onclick="cancelChanges(this.parentNode.parentNode.parentNode)">取消</button>
-                                </span>
-                            </td>
-                        </tr>
-                    {% endfor %}
-                {% else %}
-                    <tr>
-                        <td colspan="15">没有找到项目数据</td>
-                    </tr>
-                {% endif %}
-                </tbody>
-            </table>
-             <div class="pagination">
-            <div class="pagination-info">
-                {% set total_pages = (total_count|int + per_page|int - 1)//per_page %}
-               <span class="page">
-                    总共 {{ total_count }} 条数据,每页 {{ per_page }} 条,当前第 {{ page }} 页 / 共 {{ total_pages }} 页
-               </span>
-            </div>
-            <div class="pagination-links">
-                {% if page > 1 %}
-                    <a class="page page-link" href="{{ url_for('project.project_list', k=keyword, s=status, p=1, pp=per_page) }}">首页</a>
-                {% endif %}
-                {% if page > 1 %}
-                    <a class="page page-link" href="{{ url_for('project.project_list', k=keyword, p=page-1, pp=per_page) }}">上一页</a>
-                {% endif %}
-                {% set start_page = [1, page - 2]|max %}
-                {% set end_page = [total_pages, page + 2]|min %}
-                {% if start_page > 1 %}
-                    <a class="page page-link" href="{{ url_for('project.project_list', k=keyword, s=status, p=1, pp=per_page) }}">1</a>
-                    {% if start_page > 2 %}
-                        <span class="page">...</span>
-                    {% endif %}
-                {% endif %}
-                {% for p in range(start_page, end_page + 1) %}
-                    {% if p == page %}
-                    <a class="page page-link active" href="{{ url_for('project.project_list', k=keyword, p=p, pp=per_page) }}" >{{ p }}</a>
-                    {% else %}
-                    <a class="page page-link" href="{{ url_for('project.project_list', k=keyword, p=p, pp=per_page) }}" >{{ p }}</a>
-                    {% endif %}
-                {% endfor %}
-                {% if end_page < total_pages %}
-                    {% if end_page < total_pages - 1 %}
-                        <span class="page">...</span>
-                    {% endif %}
-                    <a class="page page-link" href="{{ url_for('project.project_list', k=keyword, p=total_pages, pp=per_page) }}">{{ total_pages }}</a>
-                {% endif %}
-                {% if page < total_pages %}
-                    <a class="page page-link" href="{{ url_for('project.project_list', k=keyword, p=page+1, pp=per_page) }}">下一页</a>
-                {% endif %}
-                {% if page < total_pages %}
-                    <a class="page page-link" href="{{ url_for('project.project_list', k=keyword, p=total_pages, pp=per_page) }}">末页</a>
-                {% endif %}
-            </div>
-        </div>
-        </div>
-    </div>
-</body>
-</html>
+
+			<div class="edit-box">
+				<div class="form-group">
+					<input type="hidden" id="project_id" class="form-control" />
+					<div>
+						<label for="project_name">项目名称:</label>
+						<input type="text" id="project_name" class="form-control" placeholder="项目名称" required />
+					</div>
+					<div>
+						<label for="project_desc">项目简介:</label>
+						<textarea id="project_desc" class="form-control large" placeholder="项目简介"></textarea>
+					</div>
+					<button class="btn btn-success" onclick="saveProject()">保存</button>
+					<button class="btn btn-warning" onclick="hideAddForm()">取消</button>
+				</div>
+			</div>
+
+			<table class="table">
+				<thead>
+					<tr>
+						<th width="350px">项目名称</th>
+						<th>项目简介</th>
+						<th width="300px">操作</th>
+					</tr>
+				</thead>
+				<tbody>
+					{% for project in project_list %}
+					<tr>
+						<td>{{ project.project_name }}</td>
+						<td>{{ project.description }}</td>
+						<td>
+							<button class="btn btn-info" onclick="goTo(`{{ url_for('project.sub_project_list', project_id=project.id) }}`)">子项目管理</button>
+							<button class="btn btn-warning" onclick="editProject('{{ project.id }}')">编辑</button>
+							<button class="btn btn-danger" onclick="confirmDelete('{{ project.id }}')">删除</button>
+						</td>
+					</tr>
+					{% endfor %}
+				</tbody>
+			</table>
+		</div>
+	</body>
+</html>

+ 20 - 29
SourceCode/DataMiddleware/app/ui/templates/project/project_item_list.html → SourceCode/DataMiddleware/app/ui/templates/project/sub_project_item_list.html

@@ -3,25 +3,20 @@
 	<head>
 		<meta charset="UTF-8" />
 		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
-		<title>设备列表</title>
+		<title>工程明细列表</title>
 		<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}" />
 		<style>
-			.box_header .project_info {
-				display: flex;
-				justify-content: left;
-				align-items: center;
-				width: 60%;
-			}
+
 		</style>
 		<script src="{{ url_for('static', filename='utils.js') }}"></script>
-		<script src="{{ url_for('static', filename='project_item_list.js') }}"></script>
+		<script src="{{ url_for('static', filename='sub_project_item_list.js') }}"></script>
 		<script>
 			function searchData() {
 				var keyword = document.getElementById('search_input').value
-				window.location.href = `{{ url_for('project.project_item_list', project_id=project.id) }}?k=` + keyword
+				window.location.href = `{{ url_for('project.project_item_list', sub_project_id=project.id) }}?k=` + keyword
 			}
 			function reSearchData() {
-				window.location.href = `{{ url_for('project.project_item_list', project_id=project.id) }}`
+				window.location.href = `{{ url_for('project.project_item_list', sub_project_id=project.id) }}`
 			}
 		</script>
 	</head>
@@ -29,16 +24,12 @@
 		<div class="box">
 			<div class="box_header">
 				<div class="project_info">
-					<button class="btn btn-info btn-large" onclick="goTo(`{{ url_for('project.project_list') }}`)">返回</button>
-					<h3 class="box_title">设备列表</h3>
+					<button class="btn btn-info btn-large" onclick="goTo(`{{ url_for('project.sub_project_list',project_id=sub_project.project_id) }}`)">返回</button>
+					<h3 class="box_title">工程明细列表</h3>
 					<span class="separator">|</span>
 					<dl>
-						<dt>项目编号:</dt>
-						<dd>{{ project.project_no }}</dd>
-					</dl>
-					<dl>
-						<dt>项目名称:</dt>
-						<dd>{{ project.project_name }}</dd>
+						<dt>工程名称:</dt>
+						<dd>{{ sub_project.sub_project_name }}</dd>
 					</dl>
 					<!--<dl>
 						<dt>标准版本:</dt>
@@ -54,10 +45,10 @@
 			</div>
 			<div class="box_header">
 				<div class="btn_box">
-					<button class="btn btn-success btn-large" onclick="addNewItem('{{ project.id}}')">添加</button>
+					<button class="btn btn-success btn-large" onclick="addNewItem('{{ sub_project.id}}')">新建工程明细</button>
 				</div>
 				<div class="search_box">
-					<input type="text" id="search_input" class="form-control" placeholder="请输入查询关键字" value="{{ keyword }}" />
+					<input type="text" id="search_input" title="" class="form-control" placeholder="请输入查询关键字" value="{{ keyword }}" />
 					<button type="button" class="btn btn-info btn-large" onclick="searchData()">查询</button>
 					<button type="button" class="btn btn-warning btn-large" onclick="reSearchData()">重置</button>
 				</div>
@@ -76,7 +67,7 @@
 						</tr>
 					</thead>
 					<tbody>
-						{% if project_items %} {% for item in project_items %}
+						{% if items %} {% for item in items %}
 						<tr>
 							<td class="editable name">
 								<span class="show">{{ item.device_name if item.device_name else '-' }}</span>
@@ -133,25 +124,25 @@
 					</div>
 					<div class="pagination-links">
 						{% if page > 1 %}
-						<a class="page page-link" href="{{ url_for('project.project_item_list', project_id=project.id, k=keyword, p=1, pp=per_page) }}">首页</a>
+						<a class="page page-link" href="{{ url_for('project.project_item_list', sub_project_id=sub_project.id, k=keyword, p=1, pp=per_page) }}">首页</a>
 						{% endif %} {% if page > 1 %}
-						<a class="page page-link" href="{{ url_for('project.project_item_list', project_id=project.id, k=keyword, p=page-1, pp=per_page) }}">上一页</a>
+						<a class="page page-link" href="{{ url_for('project.project_item_list', sub_project_id=sub_project.id, k=keyword, p=page-1, pp=per_page) }}">上一页</a>
 						{% endif %} {% set start_page = [1, page - 2]|max %} {% set end_page = [total_pages, page + 2]|min %} {% if start_page > 1 %}
-						<a class="page page-link" href="{{ url_for('project.project_item_list', project_id=project.id, k=keyword, p=1, pp=per_page) }}">1</a>
+						<a class="page page-link" href="{{ url_for('project.project_item_list', sub_project_id=sub_project.id, k=keyword, p=1, pp=per_page) }}">1</a>
 						{% if start_page > 2 %}
 						<span class="page">...</span>
 						{% endif %} {% endif %} {% for p in range(start_page, end_page + 1) %} {% if p == page %}
-						<a class="page page-link active" href="{{ url_for('project.project_item_list', project_id=project.id, k=keyword, p=p, pp=per_page) }}">{{ p }}</a>
+						<a class="page page-link active" href="{{ url_for('project.project_item_list', sub_project_id=sub_project.id, k=keyword, p=p, pp=per_page) }}">{{ p }}</a>
 						{% else %}
-						<a class="page page-link" href="{{ url_for('project.project_item_list', project_id=project.id, k=keyword, p=p, pp=per_page) }}">{{ p }}</a>
+						<a class="page page-link" href="{{ url_for('project.project_item_list', sub_project_id=sub_project.id, k=keyword, p=p, pp=per_page) }}">{{ p }}</a>
 						{% endif %} {% endfor %} {% if end_page < total_pages %} {% if end_page < total_pages - 1 %}
 						<span class="page">...</span>
 						{% endif %}
-						<a class="page page-link" href="{{ url_for('project.project_item_list', project_id=project.id, k=keyword, p=total_pages, pp=per_page) }}">{{ total_pages }}</a>
+						<a class="page page-link" href="{{ url_for('project.project_item_list', sub_project_id=sub_project.id, k=keyword, p=total_pages, pp=per_page) }}">{{ total_pages }}</a>
 						{% endif %} {% if page < total_pages %}
-						<a class="page page-link" href="{{ url_for('project.project_item_list', project_id=project.id, k=keyword, p=page+1, pp=per_page) }}">下一页</a>
+						<a class="page page-link" href="{{ url_for('project.project_item_list', sub_project_id=sub_project.id, k=keyword, p=page+1, pp=per_page) }}">下一页</a>
 						{% endif %} {% if page < total_pages %}
-						<a class="page page-link" href="{{ url_for('project.project_item_list', project_id=project.id, k=keyword, p=total_pages, pp=per_page) }}">末页</a>
+						<a class="page page-link" href="{{ url_for('project.project_item_list', sub_project_id=sub_project.id, k=keyword, p=total_pages, pp=per_page) }}">末页</a>
 						{% endif %}
 					</div>
 				</div>

+ 247 - 0
SourceCode/DataMiddleware/app/ui/templates/project/sub_project_list.html

@@ -0,0 +1,247 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>工程工程列表</title>
+    <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
+    <script src="{{ url_for('static', filename='utils.js') }}"></script>
+    <script src="{{ url_for('static', filename='sub_project_list.js') }}"></script>
+    <script>
+        function searchData(){
+            const keyword = document.getElementById('search_input').value;
+            const status = document.getElementById('status_select').value;
+            window.location.href = `{{ url_for('project.sub_project_list',project_id=project.id) }}?k=${keyword}&s=${status}`;
+        }
+        function reSearchData(){
+            window.location.href = `{{ url_for('project.sub_project_list',project_id=project.id) }}`;
+        }
+    </script>
+</head>
+<body>
+    <div class="box">
+        <div class="box_header">
+            <div class="project_info">
+                <button class="btn btn-info btn-large" onclick="goTo(`{{ url_for('project.main_project_list') }}`)">返回</button>
+                <h3 class="box_title">工程列表</h3>
+                <span class="separator">|</span>
+                <dl>
+                    <dt>工程名称:</dt>
+                    <dd>{{ project.project_name }}</dd>
+                </dl>
+            </div>
+        </div>
+        <div class="box_header">
+            <div class="btn_box">
+                <button type="button" class="btn btn-success btn-large" onclick="addSubProject()">新建工程</button>
+            </div>
+            <div class="search_box">
+                <select id="status_select" class="form-control form-select" title="状态选择">
+                    <option value="-1" {% if status == -1 %}selected{% endif %}>所有状态</option>
+                    <option value="0" {% if status == 0 %}selected{% endif %}>新建</option>
+                    <option value="5" {% if status == 5 %}selected{% endif %}>完成</option>
+                     <option value="11" {% if status == 11 %}selected{% endif %}>采集失败</option>
+                    <option value="12" {% if status == 12 %}selected{% endif %}>分析失败</option>
+                    <option value="13" {% if status == 13 %}selected{% endif %}>上传失败</option>
+                     <option value="21" {% if status == 21 %}selected{% endif %}>采集中...</option>
+                    <option value="22" {% if status == 22 %}selected{% endif %}>分析中...</option>
+                    <option value="23" {% if status == 23 %}selected{% endif %}>上传中...</option>
+                    <option value="31" {% if status == 31 %}selected{% endif %}>采集完成</option>
+                    <option value="32" {% if status == 32 %}selected{% endif %}>分析完成</option>
+                    <option value="33" {% if status == 32 %}selected{% endif %}>上传完成</option>
+                </select>
+                <input type="text" id="search_input" class="form-control" placeholder="请输入查询关键字" value="{{ keyword }}">
+                <button type="button" class="btn btn-info btn-large" onclick="searchData()">查询</button>
+                <button type="button" class="btn btn-warning btn-large" onclick="reSearchData()">重置</button>
+            </div>
+        </div>
+        <div class="edit-box">
+            <div class="form-group">
+                <input type="hidden" id="sub_id" class="form-control">
+                <input type="hidden" id="project_id" value="{{project.id}}">
+                <div>
+                    <label for="sub_project_name">工程名称:</label>
+                    <input type="text" id="sub_project_name" class="form-control" placeholder="工程名称">
+                </div>
+                <div>
+                    <label for="sub_project_file">工程数据:</label>
+                    <input type="file" id="sub_project_file" class="form-control" accept=".xlsx,.xls,.csv" multiple>
+                </div>
+                <div></div>
+                <div>
+                    <label for="work_catalog">工程类别:</label>
+                    <input type="text" id="work_catalog" class="form-control" placeholder="工作目录"></input>
+                </div>
+                <div>
+                    <label for="work_content">工程内容:</label>
+                    <textarea id="work_content" class="form-control large" placeholder="工作内容"></textarea>
+                </div>
+<!--                <div>-->
+<!--                    <label for="standard_version">标准版本:</label>-->
+<!--                    <select id="standard_version" class="form-control">-->
+<!--                        <option value="1">旧版</option>-->
+<!--                        <option value="2">新版</option>-->
+<!--                    </select>-->
+<!--                </div>-->
+                <div class="button-group">
+                    <button type="button" class="btn btn-success btn-large" onclick="saveSubProject()">保存</button>
+                    <button type="button" class="btn btn-warning btn-large" onclick="cancelAdd()">关闭</button>
+                </div>
+            </div>
+        </div>
+        <div class="box-body">
+            <table class="table">
+                <thead>
+                    <tr>
+                        <th width="330px">工程名称</th>
+                        <th width="15%">工程分类</th>
+                        <th width="">工作内容</th>
+<!--                        <th width="120px">标准版本</th>-->
+                        <th width="120px">状态</th>
+                        <th width="280px">操作</th>
+                    </tr>
+                </thead>
+                <tbody>
+                {% if sub_project_list %}
+                    {% for item in sub_project_list %}
+                        <tr>
+                            <td class="editable sub_project_name">
+                                <span class="show">{{ item.sub_project_name if item.sub_project_name else '-' }}</span>
+                                <span class="edit">
+                                    <input type="text" class="form-control" title="工程名称" name="sub_project_name" value="{{ item.sub_project_name if item.sub_project_name else '' }}">
+                                </span>
+                            </td>
+                            <td class="editable work_catalog">
+                                <span class="show">{{ item.work_catalog if item.work_catalog else '-' }}</span>
+                                <span class="edit">
+                                    <input type="text" class="form-control" title="工作目录" name="work_catalog" value="{{ item.work_catalog if item.work_catalog else '' }}">
+                                </span>
+                            </td>
+                            <td class="editable work_content">
+                                <span class="show">{{ item.work_content if item.work_content else '-' }}</span>
+                                <span class="edit">
+                                    <input type="text" class="form-control" title="工作内容" value="{{ item.work_content if item.work_content else '' }}">
+                                </span>
+                            </td>
+<!--                            <td class="editable standard_version">-->
+<!--                                <span class="show">-->
+<!--                                    {% if item.standard_version == '1' %}-->
+<!--                                    <span class="label label-warning">旧版</span>-->
+<!--                                    {% elif item.standard_version == '2' %}-->
+<!--                                    <span class="label label-info">新版</span>-->
+<!--                                    {% endif %}-->
+<!--                                </span>-->
+<!--                                <span class="edit">-->
+<!--                                    <select class="form-control" title="标准版本">-->
+<!--                                        <option value="1" {% if item.standard_version == '1' %}selected{% endif %}>旧版</option>-->
+<!--                                        <option value="2" {% if item.standard_version == '2' %}selected{% endif %}>新版</option>-->
+<!--                                    </select>-->
+<!--                                </span>-->
+<!--                            </td>-->
+                            <td>
+                                <span class="status">
+                                    {% if item.status == 0 %}
+                                    <span class="label label-default">新建</span>
+                                    {% elif item.status == 21 %}
+                                    <span class="label label-warning">采集中...</span>
+                                    {% elif item.status == 22 %}
+                                    <span class="label label-warning">分析中...</span>
+                                    {% elif item.status == 23 %}
+                                    <span class="label label-warning">上传中...</span>
+                                    {% elif item.status == 31 %}
+                                    <span class="label label-info">采集完成</span>
+                                    {% elif item.status == 32 %}
+                                    <span class="label label-info">分析完成</span>
+                                    {% elif item.status == 33 %}
+                                    <span class="label label-info">上传完成</span>
+                                    {% elif item.status == 11 %}
+                                    <span class="label label-danger">采集失败</span>
+                                    {% elif item.status == 12 %}
+                                    <span class="label label-danger">分析失败</span>
+                                    {% elif item.status == 13 %}
+                                    <span class="label label-danger">上传失败</span>
+                                    {% elif item.status == 5 %}
+                                    <span class="label label-success">完成</span>
+                                    {% endif %}
+                                </span>
+                            </td>
+                            <td class="editable">
+                                <span class="show">
+                                    {% if item.status == 0 %}
+                                    <button class="btn btn-success" type="button" onclick="confirmStartTask('{{ item.id }}')">开始</button>
+                                    <button class="btn btn-info" onclick="updateSubProject(this.parentNode.parentNode.parentNode,'{{ item.id }}')">编辑</button>
+                                    {% elif item.status == 11 %}
+                                    <button class="btn btn-success" type="button" onclick="confirmReStartTask('{{ item.id }}')">重新采集</button>
+                                    <button class="btn btn-info" onclick="updateSubProject(this.parentNode.parentNode.parentNode,'{{ item.id }}')">编辑</button>
+                                    {% elif item.status == 12 %}
+                                    <button class="btn btn-success" type="button" onclick="confirmReProcessData('{{ item.id }}')">重新处理</button>
+                                    {% elif item.status == 13 %}
+                                    <button class="btn btn-success" type="button" onclick="confirmSendData('{{ item.id }}')">重新发送</button>
+                                    {% elif item.status == 5 or project.status == 32 or project.status == 13 or project.status == 23 or project.status == 33 %}
+                                    <button class="btn btn-info" type="button" onclick="goTo(`{{ url_for('project.project_item_list', project_id=item.id) }}`)">详情</button>
+                                    {% endif %}
+                                    {% if item.status != 21  and project.status != 22 %}
+                                    <button class="btn btn-danger" onclick="confirmProjectDelete('{{ project.id }}')">删除</button>
+                                    {% endif %}
+                                </span>
+                                <span class="edit">
+                                    <button class="btn btn-success" onclick="saveProjectUpdate(this.parentNode.parentNode.parentNode,'{{ item.id }}')">确定</button>
+                                    <button class="btn btn-warning" onclick="cancelChanges(this.parentNode.parentNode.parentNode)">取消</button>
+                                </span>
+                            </td>
+                        </tr>
+                    {% endfor %}
+                {% else %}
+                    <tr>
+                        <td colspan="15">没有找到工程数据</td>
+                    </tr>
+                {% endif %}
+                </tbody>
+            </table>
+             <div class="pagination">
+            <div class="pagination-info">
+                {% set total_pages = (total_count|int + per_page|int - 1)//per_page %}
+               <span class="page">
+                    总共 {{ total_count }} 条数据,每页 {{ per_page }} 条,当前第 {{ page }} 页 / 共 {{ total_pages }} 页
+               </span>
+            </div>
+            <div class="pagination-links">
+                {% if page > 1 %}
+                    <a class="page page-link" href="{{ url_for('project.sub_project_list', k=keyword, s=status, p=1, pp=per_page) }}">首页</a>
+                {% endif %}
+                {% if page > 1 %}
+                    <a class="page page-link" href="{{ url_for('project.sub_project_list', k=keyword, p=page-1, pp=per_page) }}">上一页</a>
+                {% endif %}
+                {% set start_page = [1, page - 2]|max %}
+                {% set end_page = [total_pages, page + 2]|min %}
+                {% if start_page > 1 %}
+                    <a class="page page-link" href="{{ url_for('project.sub_project_list', k=keyword, s=status, p=1, pp=per_page) }}">1</a>
+                    {% if start_page > 2 %}
+                        <span class="page">...</span>
+                    {% endif %}
+                {% endif %}
+                {% for p in range(start_page, end_page + 1) %}
+                    {% if p == page %}
+                    <a class="page page-link active" href="{{ url_for('project.sub_project_list',project_id=project.id, k=keyword, p=p, pp=per_page) }}" >{{ p }}</a>
+                    {% else %}
+                    <a class="page page-link" href="{{ url_for('project.sub_project_list',project_id=project.id, k=keyword, p=p, pp=per_page) }}" >{{ p }}</a>
+                    {% endif %}
+                {% endfor %}
+                {% if end_page < total_pages %}
+                    {% if end_page < total_pages - 1 %}
+                        <span class="page">...</span>
+                    {% endif %}
+                    <a class="page page-link" href="{{ url_for('project.sub_project_list',project_id=project.id, k=keyword, p=total_pages, pp=per_page) }}">{{ total_pages }}</a>
+                {% endif %}
+                {% if page < total_pages %}
+                    <a class="page page-link" href="{{ url_for('project.sub_project_list',project_id=project.id, k=keyword, p=page+1, pp=per_page) }}">下一页</a>
+                {% endif %}
+                {% if page < total_pages %}
+                    <a class="page page-link" href="{{ url_for('project.sub_project_list',project_id=project.id, k=keyword, p=total_pages, pp=per_page) }}">末页</a>
+                {% endif %}
+            </div>
+        </div>
+        </div>
+    </div>
+</body>
+</html>

+ 25 - 4
SourceCode/DataMiddleware/app/utils/mysql_helper.py

@@ -51,22 +51,43 @@ class MySQLHelper:
             utils.get_logger().error(f"执行查询时出错:{e}")
             return None
 
+    # def execute_non_query(self, query, params=None):
+    #     if isinstance(params, list) and all(isinstance(p, tuple) for p in params):
+    #         self.execute_many(query, params)
+    #     elif isinstance(params, tuple):
+    #         self.execute(query, params)
+    #     else:
+    #         self.execute(query, (params,))
+
+    # def execute(self, query, params=None):
+    #     try:
+    #         with self.connection.cursor() as cursor:
+    #             cursor.execute(query, params)
+    #             self.connection.commit()
+    #     except pymysql.MySQLError as e:
+    #         utils.get_logger().error(f"执行非查询时出错:{e}")
+    #         self.connection.rollback()
+
+    # 修改 execute_non_query 使其返回ID
     def execute_non_query(self, query, params=None):
         if isinstance(params, list) and all(isinstance(p, tuple) for p in params):
-            self.execute_many(query, params)
+            return self.execute_many(query, params)
         elif isinstance(params, tuple):
-            self.execute(query, params)
+            return self.execute(query, params)
         else:
-            self.execute(query, (params,))
-
+            return self.execute(query, (params,))
     def execute(self, query, params=None):
         try:
             with self.connection.cursor() as cursor:
                 cursor.execute(query, params)
                 self.connection.commit()
+                return cursor.lastrowid  # 新增返回自增ID
         except pymysql.MySQLError as e:
             utils.get_logger().error(f"执行非查询时出错:{e}")
             self.connection.rollback()
+            return None
+
+
 
     def execute_many(self, query, params: list):
         if isinstance(params, list) and all(isinstance(p, tuple) for p in params):