YueYunyun 1 сар өмнө
parent
commit
00959825f7

+ 1 - 1
SourceCode/IntelligentRailwayCosting/app/core/dtos/project_quota.py

@@ -6,7 +6,7 @@ from core.models import ProjectQuotaModel
 class ProjectQuotaDto(BaseModel):
     """项目定额DTO"""
     id: Optional[int] = None
-    task_id:int
+    task_id:Optional[int] = None
     project_id: str
     budget_id: int
     item_id: int

+ 1 - 1
SourceCode/IntelligentRailwayCosting/app/executor/sender.py

@@ -36,5 +36,5 @@ class Sender:
         except Exception as e:
             msg = f"发送失败,原因:{e}"
             self._logger.error(f"发送定额:{quota.id},{msg}")
-            self._quota_store.update_process_status(quota.id, 3, msg)
+            self._quota_store.update_send_status(quota.id, 3, msg)
             return msg

+ 4 - 5
SourceCode/IntelligentRailwayCosting/app/routes/project_quota.py

@@ -28,20 +28,19 @@ def get_page_list(budget_id:int,project_id:str,item_code:str):
 def get_quota(quota_id:int):
     try:
         data = quota_service.get_quota_dto(quota_id)
-        return ResponseBase.success(data)
+        return ResponseBase.success(data.to_dict())
     except Exception as e:
         return ResponseBase.error(f'获取定额条目失败:{str(e)}')
 
-@project_quota_api.route('/save/<int:quota_id>', methods=['POST'])
+@project_quota_api.route('/save', methods=['POST'])
 @Permission.authorize
-def save_quota(quota_id:int):
+def save_quota():
     try:
         data = request.get_json()
         quota_dto = ProjectQuotaDto(**data)
-        quota_dto.id = quota_id
         need_process = data.get('need_process',False)
         quota_dto = quota_service.save_quota(quota_dto,need_process)
-        return ResponseBase.success(quota_dto)
+        return ResponseBase.success(quota_dto.to_dict())
     except Exception as e:
         return ResponseBase.error(f'保存定额条目失败:{str(e)}')
 

+ 3 - 3
SourceCode/IntelligentRailwayCosting/app/services/project_quota.py

@@ -184,10 +184,10 @@ class ProjectQuotaService:
         try:
            msg = executor.process_quota(quota)
            if not msg:
-               self.start_send(quota.quota_id)
+               self.start_send(quota.id)
         except Exception as e:
             self._logger.error(f"处理定额条目失败: {str(e)}")
-            self.update_process_status(quota.quota_id, 3, str(e))
+            self.update_process_status(quota.id, 3, str(e))
             raise
 
     def start_send(self, quota_id: int) -> Optional[str]:
@@ -205,5 +205,5 @@ class ProjectQuotaService:
             executor.send_quota(quota)
         except Exception as e:
             self._logger.error(f"发送定额条目失败: {str(e)}")
-            self.update_send_status(quota.quota_id, 3, str(e))
+            self.update_send_status(quota.id, 3, str(e))
             raise

+ 1 - 1
SourceCode/IntelligentRailwayCosting/app/services/project_task.py

@@ -88,7 +88,7 @@ class ProjectTaskService:
 
         try:
             if task:
-                paths = self._process_file_upload(task_dto, files, delete_old)
+                paths = self._process_file_upload(task, files, delete_old)
                 self.store.update_task_files(task.id,paths)
                 if task_id == 0:
                     LogRecordHelper.log_success(OperationType.CREATE, OperationModule.TASK,

+ 41 - 38
SourceCode/IntelligentRailwayCosting/app/stores/project_quota.py

@@ -10,7 +10,7 @@ from core.user_session import UserSession
 
 class ProjectQuotaStore:
     def __init__(self, db_session: Session = None):
-        self.db_session = db_session or db_helper.create_mysql_session()
+        self.db_session = db_helper.create_mysql_session()
         self._current_user = None
 
     @property
@@ -30,6 +30,8 @@ class ProjectQuotaStore:
         process_status: Optional[int] = None,
         send_status: Optional[int] = None,
     ):
+        # 每次查询创建新的会话
+        session = db_helper.create_mysql_session()
         """分页查询定额列表
 
         Args:
@@ -45,39 +47,42 @@ class ProjectQuotaStore:
         Returns:
             Tuple[total_count, quotas]
         """
-        query = self.db_session.query(ProjectQuotaModel)
-
-        # 构建查询条件
-        conditions = [
-            ProjectQuotaModel.is_del == 0,
-            ProjectQuotaModel.project_id == project_id,
-            ProjectQuotaModel.budget_id == budget_id,
-            ProjectQuotaModel.item_code.like(f"{item_code}%")
-        ]
-        if keyword:
-            conditions.append(or_(
-                ProjectQuotaModel.quota_code.like(f"%{keyword}%"),
-                ProjectQuotaModel.project_name.like(f"%{keyword}%"),
-            ))
-        if process_status is not None:
-            conditions.append(ProjectQuotaModel.process_status == process_status)
-        if send_status is not None:
-            conditions.append(ProjectQuotaModel.send_status == send_status)
-
-        query = query.filter(and_(*conditions))
-
-        # 计算总数
-        total_count = query.count()
-
-        # 分页
-        query = query.offset((page - 1) * page_size).limit(page_size)
-
-        quotas = query.all()
-
-        return {
-            'total': total_count,
-            'data': quotas
-        }
+        try:
+            query = session.query(ProjectQuotaModel)
+
+            # 构建查询条件
+            conditions = [
+                ProjectQuotaModel.is_del == 0,
+                ProjectQuotaModel.project_id == project_id,
+                ProjectQuotaModel.budget_id == budget_id,
+                ProjectQuotaModel.item_code.like(f"{item_code}%")
+            ]
+            if keyword:
+                conditions.append(or_(
+                    ProjectQuotaModel.quota_code.like(f"%{keyword}%"),
+                    ProjectQuotaModel.project_name.like(f"%{keyword}%"),
+                ))
+            if process_status is not None:
+                conditions.append(ProjectQuotaModel.process_status == process_status)
+            if send_status is not None:
+                conditions.append(ProjectQuotaModel.send_status == send_status)
+
+            query = query.filter(and_(*conditions))
+
+            # 计算总数
+            total_count = query.count()
+
+            # 分页
+            query = query.offset((page - 1) * page_size).limit(page_size)
+
+            quotas = query.all()
+
+            return {
+                'total': total_count,
+                'data': quotas
+            }
+        finally:
+            session.close()
 
     def get_quotas_by_task_id(self,task_id:int, with_quota_code:bool=False):
         query = self.db_session.query(ProjectQuotaModel).filter(
@@ -232,8 +237,7 @@ class ProjectQuotaStore:
         if not quota:
             return False
         quota.process_status = status
-        if err:
-            quota.process_error = err
+        quota.process_error = err
         quota.process_time = datetime.now()
         self.db_session.commit()
 
@@ -251,8 +255,7 @@ class ProjectQuotaStore:
         if not quota:
             return False
         quota.send_status = status
-        if err:
-            quota.send_error = err
+        quota.send_error = err
         quota.send_time = datetime.now()
         self.db_session.commit()
 

+ 4 - 1
SourceCode/IntelligentRailwayCosting/app/stores/project_task.py

@@ -154,7 +154,7 @@ class ProjectTaskStore:
         # task.budget_id = task_dto.budget_id
         # task.item_id = task_dto.item_id
         # task.item_code = task_dto.item_code
-        task.file_path = task_dto.file_path
+        # task.file_path = task_dto.file_path
         task.updated_by=self.current_user.username
         task.updated_at=datetime.now()
 
@@ -168,6 +168,9 @@ class ProjectTaskStore:
         if not task:
             return None
         task.file_path = files
+        task.collect_status=0
+        task.process_status=0
+        task.send_status=0
         task.updated_by=self.current_user.username
         task.updated_at=datetime.now()
         self.db_session.commit()

+ 7 - 9
SourceCode/IntelligentRailwayCosting/app/tools/db_helper/mysql_helper.py

@@ -34,9 +34,6 @@ class MySQLHelper(DBHelper):
         Returns:
             SQLAlchemy引擎实例
         """
-        if database in self._engines:
-            return self._engines[database]
-        
         conn_config = self._default_config.copy()
         db_config = self.get_config_for_database(database)
         conn_config.update(db_config)
@@ -47,14 +44,15 @@ class MySQLHelper(DBHelper):
             conn_config['db'] = database
         
         url = f"mysql+pymysql://{conn_config['user']}:{conn_config['password']}@{conn_config['host']}:{conn_config['port']}/{conn_config['db']}"
-        self._engines[database] = create_engine(
+        engine = create_engine(
             url,
-            pool_size=self._default_config['pool_size'],
-            max_overflow=self._default_config['max_overflow'],
-            pool_timeout=self._default_config['pool_timeout'],
-            pool_recycle=self._default_config['pool_recycle']
+            pool_size=3,  # 减小连接池大小
+            max_overflow=5,  # 减小最大溢出连接数
+            pool_timeout=30,
+            pool_recycle=1800,  # 缩短连接回收时间为30分钟
+            pool_pre_ping=True  # 启用连接健康检查
         )
-        return self._engines[database]
+        return engine
     
     def connect(self, database: str, config: Optional[Dict[str, str]] = None) -> pymysql.Connection:
         """连接到指定数据库

+ 82 - 9
SourceCode/IntelligentRailwayCosting/app/views/static/base/js/utils.js

@@ -9,7 +9,7 @@ function GoTo(url, isNewWindow) {
 function IwbAjax(opt) {
 	opt = opt || {}
 	if (!opt.url) {
-		alert('请传入url')
+		MsgWarning('请传入url')
 	}
 	if (opt.method === undefined) {
 		opt.method = 'POST'
@@ -35,7 +35,7 @@ function IwbAjax(opt) {
 		.then((data) => {
 			if (data.success) {
 				if (opt.isAlert) {
-					alert('操作成功')
+					MsgSuccess('操作成功')
 				}
 				if (opt.table) {
 					IwbTable($(opt.table))
@@ -47,7 +47,7 @@ function IwbAjax(opt) {
 			} else {
 				console.error(opt.url, data.message)
 				if ((opt.isAlert && opt.isAlertError === undefined) || opt.isAlertError) {
-					alert(data.message)
+					MsgError(data.message)
 				}
 			}
 		})
@@ -267,19 +267,92 @@ function EditModal(modal, callback) {
 	$modal.modal('show')
 }
 
-function Confirm(title, callback) {
-	if (confirm(title)) {
-		callback && callback()
+function Msg(msg, type){
+	const opts={
+        text: msg,
+        icon: type||"info",
+        buttonsStyling: false,
+        confirmButtonText: "确定",
+        customClass: {
+            confirmButton: "btn btn-primary"
+        },
+		toast:false
+    }
+	if(type==='success'){
+		opts.toast=true
+		opts.timer=3000
+		opts.showConfirmButton=false
 	}
+	Swal.fire(opts)
+	// toastr.options = {
+	//   "closeButton": false,
+	//   "debug": false,
+	//   "newestOnTop": false,
+	//   "progressBar": false,
+	//   "positionClass": "toastr-top-center",
+	//   "preventDuplicates": false,
+	//   "onclick": null,
+	//   "showDuration": "300",
+	//   "hideDuration": "1000",
+	//   "timeOut": "2000",
+	//   "extendedTimeOut": "1000",
+	//   "showEasing": "swing",
+	//   "hideEasing": "linear",
+	//   "showMethod": "fadeIn",
+	//   "hideMethod": "fadeOut"
+	// };
+	// if (type==='success'){
+	// 	title ? toastr.success(msg,title):toastr.success(msg);
+	// }else if (type==='error'){
+	// 	toastr.options.timeOut = "0";
+	// 	title ? toastr.error(msg,title):toastr.error(msg);
+	// }else if(type==='warning'){
+	// 	toastr.options.timeOut = "5000";
+	// 	title ? toastr.warning(msg,title):toastr.warning(msg);
+	// }else{
+	// 	toastr.options.timeOut = "0";
+	// 	title ? toastr.info(msg,title):toastr.info(msg);
+	// }
+}
+function MsgSuccess(msg, title) {
+	Msg(msg,  'success',title)
+}
+function MsgError(msg, title) {
+	Msg(msg,  'error',title)
+}
+function MsgWarning(msg, title) {
+	Msg(msg,  'warning',title)
+}
+function Confirm(title, callback) {
+	const opts={
+        text: title,
+        icon: "info",
+        buttonsStyling: false,
+		showCancelButton: true,
+		showConfirmButton: true,
+        cancelButtonText: "取消",
+        confirmButtonText: "确定",
+        customClass: {
+			cancelButton: "btn btn-light",
+            confirmButton: "btn btn-primary"
+        },
+		toast:false
+    }
+	Swal.fire(opts).then((result)=>{
+		console.log("CONFIRM",result)
+		if(result.isConfirmed){
+			callback && callback()
+		}
+	});
 }
 
 function ConfirmUrl(title, url, table) {
-	if (confirm(title)) {
+	Confirm(title,function () {
 		IwbAjax({
 			url: url,
 			table: table || '#table',
 		})
-	}
+	})
 }
 
 function ChangeHeadMenu(menu) {
@@ -309,7 +382,7 @@ function DownloadFile(url, fileName) {
 			document.body.removeChild(a)
 		})
 		.catch((error) => {
-			alert(error.message)
+			MsgError(error.message)
 		})
 }
 

+ 62 - 35
SourceCode/IntelligentRailwayCosting/app/views/static/project/budget_info.js

@@ -19,20 +19,22 @@ const nav_tab_template = `
 												<input type="hidden" name="item_id" value="">
 												<input type="hidden" name="item_code" value="">
 											</section>
-											<div class="my-2  d-flex align-items-center table-title mt-5">
+											<div class="my-2 d-flex align-items-center table-title mt-5">
 												<span class="fw-bolder me-5 title fs-2"></span>
-<!--												<span class="badge badge-primary fs-2">定额任务列表</span>-->
-												<div class="form-check form-check-custom form-check-primary form-check-solid">
-													<input class="form-check-input" name="table_radio" type="radio" value="task"  id="task_radio"/>
-													<label class="form-check-label fw-bolder text-primary" for="task_radio">
-														任务列表
-													</label>
-												</div>
-												<div class="form-check form-check-custom form-check-success form-check-solid ms-5">
-													<input class="form-check-input" name="table_radio" type="radio" value="quota"  id="quota_radio"/>
-													<label class="form-check-label fw-bolder text-success" for="quota_radio">
-														定额输入
-													</label>
+												<span class="badge d-none badge-primary fs-5 me-5"></span>
+												<div class="d-flex">
+													<div class="form-check form-check-custom form-check-primary form-check-solid">
+														<input class="form-check-input" name="table_radio" type="radio" value="task"  id="task_radio"/>
+														<label class="form-check-label fw-bolder text-primary" for="task_radio">
+															任务列表
+														</label>
+													</div>
+													<div class="form-check  form-check-custom form-check-success form-check-solid ms-5">
+														<input class="form-check-input" name="table_radio" type="radio" value="quota"  id="quota_radio"/>
+														<label class="form-check-label fw-bolder text-success" for="quota_radio">
+															定额输入
+														</label>
+													</div>
 												</div>
 											</div>
 											<div class="d-flex justify-content-between my-5">
@@ -120,7 +122,7 @@ function InitFileUpload(){
 			dropzoneItem.style.display = '';
 		});
 		if(_fileUploadDropzone.getAcceptedFiles().findIndex(item=>item.name===file.name)>=0){
-			alert('文件已存在')
+			MsgWarning('文件已存在')
 			_fileUploadDropzone.removeFile(file);
 		}
 	});
@@ -236,13 +238,14 @@ function RenderTabCondent(data) {
 			_taskTable($table,data)
 		}
 	})
-	if(data.children_count>0){
+	if(data.children_count>0||data.chapter){
 		$tableBox.find('.table-title .title').text(title)
-		// $tableBox.find('.table-title .badge').text('任务列表').removeClass('badge-success').addClass('badge-primary')
+		$tableBox.find('.table-title .badge').text('任务列表').removeClass('badge-success').addClass('badge-primary')
+		$tableBox.find('#task_radio').prop("checked",true)
 		_taskTable($table,data)
 	} else {
 		$tableBox.find('.table-title .title').text(title)
-		// $tableBox.find('.table-title .badge').text('定额输入明细').removeClass('badge-primary').addClass('badge-success')
+		$tableBox.find('.table-title .badge').text('定额输入明细').removeClass('badge-primary').addClass('badge-success')
 		$tableBox.find('#task_radio').prop("disabled",true)
 		$tableBox.find('#quota_radio').prop("checked",true)
 		_quotaTable($table,data)
@@ -298,22 +301,22 @@ function RenderTabCondent(data) {
 							} else if (row.collect_status === 2){
 								str += `<span class="badge badge-light-success">采集完成</span>`
 								if (row.process_status === 0) {
-									str += `<span class="badge badge-light-primary">未处理</span>`
+									str += `<span class="badge badge-light-primary ms-3">未处理</span>`
 								} else if (row.process_status === 1){
-									str += `<span class="badge badge-light-warning">处理中</span>`
+									str += `<span class="badge badge-light-warning ms-3">处理中</span>`
 								} else if (row.process_status === 2){
-									str += `<span class="badge badge-light-success">处理</span>`
+									str += `<span class="badge badge-light-success ms-3">处理完成</span>`
 									if (row.send_status === 0) {
-										str += `<span class="badge badge-light-primary">未发送</span>`
+										str += `<span class="badge badge-light-primary ms-3">未发送</span>`
 									} else if (row.send_status === 1){
-										str += `<span class="badge badge-light-warning">发送中</span>`
+										str += `<span class="badge badge-light-warning ms-3">发送中</span>`
 									} else if (row.send_status === 2){
-										str += `<span class="badge badge-light-success">发送</span>`
+										str += `<span class="badge badge-light-success ms-3">发送完成</span>`
 									} else if (row.send_status === 3){
-										str += `<span class="badge badge-light-danger">发送失败</span>`
+										str += `<span class="badge badge-light-danger ms-3">发送失败</span>`
 									}
 								} else if (row.process_status === 3){
-									str += `<span class="badge badge-light-danger">处理失败</span>`
+									str += `<span class="badge badge-light-danger ms-3">处理失败</span>`
 								}
 							} else if (row.collect_status === 3){
 								str += `<span class="badge badge-light-danger">采集失败</span>`
@@ -375,14 +378,24 @@ function RenderTabCondent(data) {
 					data: 'project_name',
 					width: 'auto',
 				},
+				{
+					title: '工程数量',
+					data: 'project_quantity',
+					width: '100px',
+				},
 				{
 					title: '单位',
 					data: 'unit',
 					width: '100px',
 				},
+				{
+					title: '定额编号',
+					data: 'quota_code',
+					width: '100px',
+				},
 				{
 					title: '状态',
-					data: 'task_desc',
+					data: 'status',
 					width: '150px',
 					render: (row) => {
 						let str=''
@@ -544,9 +557,10 @@ function ReStartSendTask(id,budget_id){
 	ConfirmUrl('确定重新开始发送吗?',`/api/task/start_send/${id}`,`#table_${budget_id}`)
 }
 
-function Add_Quota(budget_id) {
+function Add_Quota(budget_id,) {
 	AddModal($modalQuota, () => {
-		$modalQuota.find('#quota_id').val('0');
+		$modalQuota.find('[name="quota_id"]').val('0');
+		$modalQuota.find('[name="task_id"]').val('0');
 		SetBudgetData($modalQuota, budget_id)
 	})
 }
@@ -554,7 +568,7 @@ function Add_Quota(budget_id) {
 function Edit_Quota(id) {
     EditModal($modalQuota,()=>{
         IwbAjax_1({
-            url:`/api/task/get/${id}`,
+            url:`/api/quota/get/${id}`,
             success:res=>{
 				if(!res.success){
 					console.error(res.message)
@@ -562,12 +576,16 @@ function Edit_Quota(id) {
 				}
 				const data = res.data
 				// SetBudgetData(budget_id)
-        		$modalQuota.find('#quota_id').val(data.id);
+        		$modalQuota.find('[name="quota_id"]').val(data.id);
+        		$modalQuota.find('[name="task_id"]').val(data.task_id);
 				$modalQuota.find('[name="budget_id"]').val(data.budget_id);
 				$modalQuota.find('[name="project_id"]').val(data.project_id);
 				$modalQuota.find('[name="item_id"]').val(data.item_id);
 				$modalQuota.find('[name="item_code"]').val(data.item_code);
                 $modalQuota.find('[name="project_name"]').val(data.project_name);
+                $modalQuota.find('[name="project_quantity"]').val(data.project_quantity);
+                $modalQuota.find('[name="unit"]').val(data.unit);
+                $modalQuota.find('[name="quota_code"]').val(data.quota_code);
 
             }
         })
@@ -575,20 +593,29 @@ function Edit_Quota(id) {
 }
 
 function SaveQuota(){
-	const quota_id = $modalQuota.find('#quota_id').val(),
+	const quota_id = $modalQuota.find('[name="quota_id"]').val(),
+		task_id = $modalQuota.find('[name="task_id"]').val(),
 		budget_id = $modalQuota.find('[name="budget_id"]').val(),
 		project_id = $modalQuota.find('[name="project_id"]').val(),
 		item_id = $modalQuota.find('[name="item_id"]').val(),
 		item_code = $modalQuota.find('[name="item_code"]').val(),
-		project_name = $modalQuota.find('[name="project_name"]').val()
+		project_name = $modalQuota.find('[name="project_name"]').val(),
+		project_quantity = $modalQuota.find('[name="project_quantity"]').val(),
+		unit = $modalQuota.find('[name="unit"]').val(),
+		quota_code = $modalQuota.find('[name="quota_code"]').val()
 	IwbAjax({
-		url:`/api/quota/save/${quota_id}`,
-		body:{
+		url:`/api/quota/save`,
+		data:{
+			id: quota_id,
+			task_id,
 			budget_id,
 			project_id,
 			item_id,
 			item_code,
-			project_name
+			project_name,
+			project_quantity,
+			unit,
+			quota_code
 		},
 		modal:$modalQuota,
 		table:`#table_${budget_id}`

+ 1 - 0
SourceCode/IntelligentRailwayCosting/app/views/templates/log/index.html

@@ -45,6 +45,7 @@
     </table>
     <div class="pagination-row"></div>
 </div>
+
 <div class="modal fade" id="modal" tabindex="-1" aria-hidden="true">
     <div class="modal-dialog modal-dialog-centered">
         <div class="modal-content rounded">

+ 15 - 2
SourceCode/IntelligentRailwayCosting/app/views/templates/project/budget_info.html

@@ -105,10 +105,23 @@
 						<input type="hidden" name="project_id" value="">
 						<input type="hidden" name="item_id" value="">
 						<input type="hidden" name="item_code" value="">
+						<input type="hidden" name="quota_id" value="">
 						<input type="hidden" name="task_id" value="">
 						<div class="fv-row form-group mb-3">
-							<label for="task_name" class="form-label required">项目名称</label>
-							<input type="text" class="form-control" name="project_name" id="project_name" placeholder="请输入" required />
+							<label for="project_name" class="form-label required">工程或费用项目名称</label>
+							<input type="text" class="form-control" name="project_name" id="project_name" placeholder="请输入工程或费用项目名称" required />
+						</div>
+						<div class="fv-row form-group mb-3">
+							<label for="unit" class="form-label required">单位</label>
+							<input type="text" class="form-control" name="unit" id="unit" placeholder="请输入单位" required />
+						</div>
+						<div class="fv-row form-group mb-3">
+							<label for="project_quantity" class="form-label required">工程数量</label>
+							<input type="text" class="form-control" name="project_quantity" id="project_quantity" placeholder="请输入工程数量" required />
+						</div>
+						<div class="fv-row form-group mb-3">
+							<label for="quota_code" class="form-label">定额编号</label>
+							<input type="text" class="form-control" name="quota_code" id="quota_code" placeholder="请输入定额编号" />
 						</div>
 					</div>
 				</form>