Yue преди 3 месеца
родител
ревизия
198bec2f2a

+ 2 - 1
SourceCode/IntelligentRailwayCosting/.script/cmd/main.run.xml

@@ -8,8 +8,9 @@
       <env name="PYTHONUNBUFFERED" value="1" />
     </envs>
     <option name="SDK_HOME" value="" />
+    <option name="SDK_NAME" value="Python 3.13 (IntelligentRailwayCosting)" />
     <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/app" />
-    <option name="IS_MODULE_SDK" value="true" />
+    <option name="IS_MODULE_SDK" value="false" />
     <option name="ADD_CONTENT_ROOTS" value="true" />
     <option name="ADD_SOURCE_ROOTS" value="true" />
     <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />

+ 4 - 2
SourceCode/IntelligentRailwayCosting/app/config.yml

@@ -25,14 +25,16 @@ db:
     trusted_connection: false
   sqlserver_mian_2020:
     driver: '{ODBC Driver 17 for SQL Server}'
-    server: 192.168.0.81,1433
+#    server: 192.168.0.81,1433
+    server: shvber.com,5030
     username: iwb
     password: 123456Qsc
     database: Iwb_RecoData2020
     trusted_connection: false
   Iwb_RailwayCosting:
     driver: '{ODBC Driver 17 for SQL Server}'
-    server: 192.168.0.81,1433
+#    server: 192.168.0.81,1433
+    server: shvber.com,5030
     username: iwb
     password: 123456Qsc
     database: iwb_railway_costing_v1

+ 19 - 2
SourceCode/IntelligentRailwayCosting/app/routes/project_quota.py

@@ -22,6 +22,21 @@ def get_page_list(budget_id:int,project_id:str,item_code:str):
         return TableResponse.success(data,count)
     except Exception as e:
         return ResponseBase.error(f'获取定额条目列表失败:{str(e)}')
+@project_quota_api.route('/list/task/<int:task_id>', methods=['POST'])
+@Permission.authorize
+def get_quotas_by_task_paginated(task_id:int):
+    try:
+        data = request.get_json()
+        page = int(data.get('pageNum', 1))
+        per_page = int(data.get('pageSize', 10))
+        keyword = data.get('keyword')
+        # process_status = int(data.get('process_status')) if data.get('process_status') else None
+        send_status = int(data.get('send_status')) if data.get('send_status') else None
+        data,count = quota_service.get_quotas_by_task_paginated( task_id,page, per_page, keyword, send_status)
+        return TableResponse.success(data,count)
+    except Exception as e:
+        return ResponseBase.error(f'获取任务定额条目列表失败:{str(e)}')
+
 
 @project_quota_api.route('/get/<int:quota_id>', methods=['POST'])
 @Permission.authorize
@@ -38,8 +53,10 @@ def save_quota():
     try:
         data = request.get_json()
         quota_dto = ProjectQuotaDto(**data)
-        need_process = data.get('need_process',False)
-        quota_dto = quota_service.save_quota(quota_dto,need_process)
+        run_now = data.get('run_now',False)
+        quota_dto = quota_service.save_quota(quota_dto)
+        if run_now:
+            quota_service.start_send(quota_dto.id)
         return ResponseBase.success(quota_dto.to_dict())
     except Exception as e:
         return ResponseBase.error(f'保存定额条目失败:{str(e)}')

+ 19 - 5
SourceCode/IntelligentRailwayCosting/app/services/project_quota.py

@@ -2,6 +2,7 @@ from typing import Optional
 
 import tools.utils as utils,threading
 from core.dtos import ProjectQuotaDto
+from core.enum import SendStatusEnum
 from core.models import ProjectQuotaModel
 from stores import ProjectQuotaStore
 import executor
@@ -47,6 +48,20 @@ class ProjectQuotaService:
             print(f"获取项目定额列表失败: {str(e)}")
             raise
 
+    def get_quotas_by_task_paginated(self, task_id: int, page: int = 1, page_size: int = 10,keyword: Optional[str]=None,send_status: Optional[int] = None):
+        try:
+            data = self.store.get_quotas_by_task_paginated(
+                task_id=task_id,
+                page=page,
+                page_size=page_size,
+                send_status=send_status,
+                keyword=keyword
+            )
+            return [ProjectQuotaDto.from_model(quota).to_dict() for quota in data.get('data',[])],data.get('total',0)
+        except Exception as e:
+            self._logger.error(f"获取任务项目定额列表失败: {str(e)}")
+            raise
+
     def get_quota_dto(self, quota_id: int):
         try:
             return self.store.get_quota_dto(quota_id)
@@ -68,7 +83,7 @@ class ProjectQuotaService:
             self._logger.error(f"获取定额条目失败: {str(e)}")
             raise
 
-    def save_quota(self, quota_dto: ProjectQuotaDto,need_process:bool=False) -> Optional[ProjectQuotaDto]:
+    def save_quota(self, quota_dto: ProjectQuotaDto) -> Optional[ProjectQuotaDto]:
         """保存定额"""
         try:
             # 业务验证
@@ -76,10 +91,9 @@ class ProjectQuotaService:
                 quota_dto = self.create_quota(quota_dto)
             else:
                 quota_dto = self.update_quota(quota_dto)
-                self.update_process_status(quota_dto.id,4)
-                self.update_send_status(quota_dto.id,4)
-            if need_process:
-                self.start_process(quota_dto.id)
+                # self.update_process_status(quota_dto.id,4)
+                if quota_dto.send_status != SendStatusEnum.NEW.value:
+                    self.update_send_status(quota_dto.id, SendStatusEnum.CHANGE.value)
             return quota_dto
         except Exception as e:
             self._logger.error(f"保存定额条目失败: {str(e)}")

+ 31 - 9
SourceCode/IntelligentRailwayCosting/app/stores/railway_costing_sqlserver/project_quota.py

@@ -80,6 +80,35 @@ class ProjectQuotaStore:
                 'data': quotas
             }
 
+    def get_quotas_by_task_paginated(self, task_id: int, page: int = 1, page_size: int = 10,keyword: Optional[str]=None,send_status: Optional[int] = None):
+        with db_helper.sqlserver_query_session(self._database) as db_session:
+            query = db_session.query(ProjectQuotaModel).filter(
+                and_(
+                    ProjectQuotaModel.task_id == task_id,
+                    ProjectQuotaModel.is_del == 0
+                )
+            )
+            if keyword:
+                query = query.filter(or_(
+                    ProjectQuotaModel.quota_code.like(f"%{keyword}%"),
+                    ProjectQuotaModel.entry_name.like(f"%{keyword}%"),
+                ))
+            if send_status is not None:
+                query = query.filter(ProjectQuotaModel.send_status == send_status)
+            # 计算总数
+            total_count = query.count()
+
+            # 分页
+            query = query.order_by(ProjectQuotaModel.created_at.desc()).offset((page - 1) * page_size).limit(
+                page_size)
+
+            quotas = query.all()
+
+            return {
+                'total': total_count,
+                'data': quotas
+            }
+
 
     def get_quotas_by_task_id(self,task_id:int, with_quota_code:bool=False):
         with db_helper.sqlserver_query_session(self._database) as db_session:
@@ -181,15 +210,8 @@ class ProjectQuotaStore:
         with db_helper.sqlserver_session(self._database) as db_session:
             quota.quota_code = quota_dto.quota_code
             quota.entry_name = quota_dto.entry_name
-            quota.unit = quota_dto.unit
-            quota.project_quantity = quota_dto.project_quantity
-            quota.project_quantity_input = quota_dto.project_quantity_input
-            quota.quota_adjustment = quota_dto.quota_adjustment
-            quota.unit_price = quota_dto.unit_price
-            quota.total_price = quota_dto.total_price
-            quota.unit_weight = quota_dto.unit_weight
-            quota.total_weight = quota_dto.total_weight
-            quota.labor_cost = quota_dto.labor_cost
+            quota.units = quota_dto.units
+            quota.amount = quota_dto.amount
             quota.updated_by = self.current_user.username
             quota.updated_at = datetime.now()
 

+ 12 - 3
SourceCode/IntelligentRailwayCosting/app/views/project.py

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

+ 7 - 220
SourceCode/IntelligentRailwayCosting/app/views/static/project/budget_info.js

@@ -1,7 +1,5 @@
 const table = '#table',
-	$modal = $('#modal'),
-	$modalQuota = $('#modal_quota')
-console.log(`加载项目:${project_id}`)
+	$modal = $('#modal')
 InitBody()
 $(function () {
 	BuildChapterInfo()
@@ -17,7 +15,7 @@ const nav_template = `<ul id="nav_tab" class="nav nav-tabs nav-line-tabs nav-lin
 		</li>`,
 	tab_content_template = `<div class="tab-pane h-100" id="iwb_tab_{0}" role="tabpanel">{1}</div>`,
 	table_add_task_btn_template = `<button type="button" class="task_add_btn btn btn-primary btn-sm" onclick="Add('{0}')">添加任务</button>`,
-	table_add_quota_btn_template = `<button type="button" class="quota_add_btn btn btn-primary btn-sm" onclick="Add_Quota('{0}')">添加定额</button>`,
+	table_add_quota_btn_template = `` //`<button type="button" class="quota_add_btn btn btn-primary btn-sm" onclick="Add_Quota('{0}')">添加定额</button>`,
 	table_run_select_template = `<select class="form-select form-select-sm me-5" name="process_status">
 												<option value="">全部运行状态</option>
 												<option value="0">草稿</option>
@@ -55,6 +53,7 @@ const nav_template = `<ul id="nav_tab" class="nav nav-tabs nav-line-tabs nav-lin
 								<div class="pagination-row"></div>
 							</div>`
 
+
 let _fileUploadDropzone = null;
 
 function InitFileUpload(){
@@ -360,6 +359,9 @@ function RenderRightBox(data){
 								str += `<button type="button" class="btn btn-icon btn-sm btn-light-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="编辑" onclick="Edit(${row.id})"><i class="ki-duotone ki-message-edit fs-1"><span class="path1"></span><span class="path2"></span></i></button>`
 							} 
 							str+=`<!--<button type="button" class="btn btn-icon btn-sm btn-light-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="编辑" onclick="Edit(${row.id})"><i class="ki-duotone ki-message-edit fs-1"><span class="path1"></span><span class="path2"></span></i></button>-->`
+							if (row.process_status === 2 || row.process_status ===200) {
+								str+=`<button type="button" class="btn btn-icon btn-sm btn-light-primary"  data-bs-toggle="tooltip" data-bs-placement="top" title="定额输入列表" onclick="GoTo('/quota_info/${project_id}/${row.id}')"><i class="ki-duotone ki-eye fs-1"><span class="path1"></span><span class="path2"></span><span class="path3"></span><span class="path4"></span></i></button>`
+							}
 							if (row.process_status !== 2 && row.process_status !==1) {
 								str+=`<button type="button" class="btn btn-icon btn-sm btn-light-danger"  data-bs-toggle="tooltip" data-bs-placement="top" title="删除" onclick="Delete(${row.id})"><i class="ki-duotone ki-trash-square fs-1"><span class="path1"></span><span class="path2"></span><span class="path3"></span><span class="path4"></span></i></button>`
 							}
@@ -442,138 +444,7 @@ function RenderQuotaTable(budget_id,data){
 	console.log('RenderQuotaTable', budget_id, data)
 	const $quotaBox = $('#body_box .right-box .box-body .quota')
 	const $table = $quotaBox.find(`#table_${budget_id}`)
-	IwbTable($table,{
-		url:`/api/quota/list/${budget_id}/${project_id}/${data.item_code}`,
-		columns: [
-			{
-				title: '序号',
-				data: 'id',
-				width: '80px',
-			},
-			{
-				title: '工程或费用项目名称',
-				data: 'entry_name',
-				width: '210px',
-				render: (row) => {
-						return `<span class="one-line mw-200px" data-bs-toggle="tooltip" data-bs-placement="top" title="${row.entry_name}" >${row.entry_name}</span>`
-				}
-			},
-			{
-				title: '工程数量',
-				data: 'amount',
-				width: '100px',
-			},
-			{
-				title: '单位',
-				data: 'units',
-				width: '80px',
-			},
-			{
-				title: '定额编号',
-				data: 'quota_code',
-				width: '100px',
-			},
-			{
-				title: 'Excel文件',
-				data: 'ex_file',
-				width: '150px',
-				render: (row) => {
-					const path = row.ex_file
-					if (!path) {
-						return '-'
-					}
-					const names = path.split('/')
-					const file_name = names[names.length - 1]
-					return `<span class="one-line mw-150px"><a href="#" onclick="DownloadFile('/api/task/download?filename=${encodeURIComponent(path)}','${file_name}')"  class="link link-info px-2">${file_name}</a></span>`
-				}
-			},
-			{
-				title: 'Excel整行内容',
-				data: 'ex_row',
-				width: 'auto',
-				render: (row) => {
-					return `<span class="one-line w-300px" data-bs-toggle="tooltip" data-bs-placement="top" title="${row.ex_row}" >${row.ex_row}</span>`
-				}
-			},
-			{
-				title: 'Excel数量',
-				data: 'ex_amount',
-				width: '100px',
-			},
-			{
-				title: '数量位置',
-				data: 'ex_cell',
-				width: '80px',
-			},
-			{
-				title: '数量单位',
-				data: 'ex_unit',
-				width: '80px',
-			},
-			{
-				title: '状态',
-				data: 'status',
-				width: '100px',
-				render: (row) => {
-					let str=''
-					// if(row.process_status === 0){
-					// 	str+= `<span class="badge badge-primary">未处理</span>`
-					// }else if (row.process_status === 1){
-					// 	str+= `<span class="badge badge-warning">处理中</span>`
-					// }else if (row.process_status === 2){
-					// 	str+= `<span class="badge badge-success">已处理</span>`
-					// }else if (row.process_status === 3){
-					// 	str+= `<span class="badge badge-danger">处理失败</span>`
-					// }else if (row.process_status === 4){
-					// 	str+= `<span class="badge badge-danger">数据变更</span>`
-					// }
-					if(row.send_status === 0){
-						str+= `<span class="badge badge-primary ms-3">未发送</span>`
-					}else if (row.send_status === 1){
-						str+= `<span class="badge badge-warning ms-3">发送中</span>`
-					}else if (row.send_status === 200){
-						str+= `<span class="badge badge-success ms-3">发送成功</span>`
-					}else if (row.send_status === 2){
-						str+= `<span class="badge badge-danger ms-3">发送失败</span>`
-					}else if (row.send_status === 3){
-						str+= `<span class="badge badge-danger ms-3">数据变更</span>`
-					}
-
-					return str
-				}
-			},
-			{
-				title: '操作',
-				data: 'id',
-				width: '120px',
-				render: (row) => {
-					let str=''
-					// if (row.process_status === 0) {
-					// 	str += `<button type="button" class="btn btn-icon btn-sm btn-light-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="开始处理" onclick="StartProcessQuota(${row.id}, ${budget_id})"><i class="ki-duotone ki-book-square fs-1"><span class="path1"></span><span class="path2"></span><span class="path3"></span></i></button>`
-					// } else if (row.process_status === 2) {
-					// 	str += `<button type="button" class="btn btn-icon btn-sm btn-light-warning" data-bs-toggle="tooltip" data-bs-placement="top" title="重新处理" onclick="ReStartProcessQuota(${row.id}, ${budget_id})"><i class="ki-duotone ki-book-square fs-1"><span class="path1"></span><span class="path2"></span><span class="path3"></span></i></button>`
-					//
-					// } else if (row.process_status === 3) {
-					// 	str += `<button type="button" class="btn btn-icon btn-sm btn-light-danger" data-bs-toggle="tooltip" data-bs-placement="top" title="重新处理" onclick="ReStartProcessQuota(${row.id}, ${budget_id})"><i class="ki-duotone ki-book-square fs-1"><span class="path1"></span><span class="path2"></span><span class="path3"></span></i></button>`
-					// } else if (row.process_status === 4) {
-					// 	str += `<button type="button" class="btn btn-icon btn-sm btn-light-info" data-bs-toggle="tooltip" data-bs-placement="top" title="重新处理" onclick="ReStartProcessQuota(${row.id}, ${budget_id})"><i class="ki-duotone ki-book-square fs-1"><span class="path1"></span><span class="path2"></span><span class="path3"></span></i></button>`
-					// }
-					if (row.send_status === 0) {
-						str += `<button type="button" class="btn btn-icon btn-sm btn-light-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="开始发送" onclick="StartSendQuota(${row.id}, ${budget_id})"><i class="ki-duotone ki-send fs-1"><span class="path1"></span><span class="path2"></span></i></button>`
-					} else if (row.send_status === 200) {
-						str += `<button type="button" class="btn btn-icon btn-sm btn-light-warning" data-bs-toggle="tooltip" data-bs-placement="top" title="重新发送" onclick="ReStartSendQuota(${row.id}, ${budget_id})"><i class="ki-duotone ki-send fs-1"><span class="path1"></span><span class="path2"></span></i></button>`
-					} else if (row.send_status === 2) {
-						str += `<button type="button" class="btn btn-icon btn-sm btn-light-danger" data-bs-toggle="tooltip" data-bs-placement="top" title="重新发送" onclick="ReStartSendQuota(${row.id}, ${budget_id})"><i class="ki-duotone ki-send fs-1"><span class="path1"></span><span class="path2"></span></i></button>`
-					} else if (row.send_status === 3) {
-						str += `<button type="button" class="btn btn-icon btn-sm btn-light-info" data-bs-toggle="tooltip" data-bs-placement="top" title="重新发送" onclick="ReStartSendQuota(${row.id}, ${budget_id})"><i class="ki-duotone ki-send fs-1"><span class="path1"></span><span class="path2"></span></i></button>`
-					}
-					str+=`<button type="button" class="btn btn-icon btn-sm btn-light-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="编辑" onclick="Edit_Quota(${row.id}, ${budget_id})"><i class="ki-duotone ki-message-edit fs-1"><span class="path1"></span><span class="path2"></span></i></button>`
-					str+=`<button type="button" class="btn btn-icon btn-sm btn-light-danger"  data-bs-toggle="tooltip" data-bs-placement="top" title="删除" onclick="Delete_Quota(${row.id}, ${budget_id})"><i class="ki-duotone ki-trash-square fs-1"><span class="path1"></span><span class="path2"></span><span class="path3"></span><span class="path4"></span></i></button>`
-					return str
-				}
-			},
-		]
-	}, true)
+	LoadQuotaTable($table,`/api/quota/list/${budget_id}/${project_id}/${data.item_code}`)
 }
 
 function SetBudgetData($el){
@@ -698,87 +569,3 @@ function CancelTask(id){
 // 	ConfirmUrl('确定重新开始发送吗?',`/api/task/start_send/${id}`,`#table_0`)
 // }
 
-function Add_Quota(budget_id,) {
-	AddModal($modalQuota, () => {
-		SetBudgetData($modalQuota)
-		$modalQuota.find('[name="quota_id"]').val('0');
-		$modalQuota.find('[name="task_id"]').val('0');
-		$modalQuota.find('[name="budget_id"]').val(budget_id);
-	})
-}
-
-function Edit_Quota(id) {
-    EditModal($modalQuota,()=>{
-        IwbAjax_1({
-            url:`/api/quota/get/${id}`,
-            success:res=>{
-				if(!res.success){
-					console.error(res.message)
-					return
-				}
-				const data = res.data
-				// SetBudgetData(budget_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);
-
-            }
-        })
-    })
-}
-
-function SaveQuota(){
-	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_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`,
-		data:{
-			id: quota_id,
-			task_id,
-			budget_id,
-			project_id,
-			item_id,
-			item_code,
-			project_name,
-			project_quantity,
-			unit,
-			quota_code
-		},
-		modal:$modalQuota,
-		table:`#table_${budget_id}`
-	})
-
-
-}
-
-function Delete_Quota(id,budget_id){
-	ConfirmUrl('确定删除吗?',`/api/quota/delete/${id}`,`#table_${budget_id}`)
-}
-
-// function StartProcessQuota(id,budget_id){
-// 	ConfirmUrl('确定开始处理吗?',`/api/quota/start_process/${id}`,`#table_${budget_id}`)
-// }
-// function ReStartProcessQuota(id,budget_id){
-// 	ConfirmUrl('确定重新开始处理吗?',`/api/quota/start_process/${id}`,`#table_${budget_id}`)
-// }
-function StartSendQuota(id,budget_id){
-	ConfirmUrl('确定开始发送吗?',`/api/quota/start_send/${id}`,`#table_${budget_id}`)
-}
-function ReStartSendQuota(id,budget_id){
-	ConfirmUrl('确定重新开始发送吗?',`/api/quota/start_send/${id}`,`#table_${budget_id}`)
-}

+ 314 - 0
SourceCode/IntelligentRailwayCosting/app/views/static/project/quota_info.js

@@ -0,0 +1,314 @@
+const modal_template = `
+<div class="modal fade" id="modal_quota" tabindex="-1" aria-hidden="true">
+  <div class="modal-dialog modal-lg modal-dialog-centered">
+    <div class="modal-content rounded">
+      <div class="modal-header">
+        <h3 class="modal-title"><span class="prefix"></span>定额</h3>
+        <div class="btn btn-sm btn-icon btn-active-color-primary" data-bs-dismiss="modal">
+          <i class="ki-duotone ki-cross fs-1">
+            <span class="path1"></span>
+            <span class="path2"></span>
+          </i>
+        </div>
+      </div>
+      <div class="modal-body">
+        <form>
+          <div class="form-group">
+            <input type="hidden" name="budget_id" value="">
+            <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>
+				<dl class="d-flex mb-1">
+					<dt class="" style="white-space: nowrap">源内容:</dt>
+					<dd id="ex_row" class="ms-3 mb-0"></dd>
+				</dl>
+				<div class="d-flex flex-wrap">
+					<dl class="d-flex mb-1 w-25">
+						<dt class="" style="white-space: nowrap">源数量:</dt>
+						<dd id="ex_amount" class="ms-3 mb-0"></dd>
+					</dl>
+					<dl class="d-flex mb-1 w-25">
+						<dt class="" style="white-space: nowrap">源数量位置:</dt>
+						<dd id="ex_cell" class="ms-3 mb-0"></dd>
+					</dl>
+					<dl class="d-flex mb-1 w-25">
+						<dt class="" style="white-space: nowrap">源数量单位:</dt>
+						<dd id="ex_unit" class="ms-3 mb-0"></dd>
+					</dl>
+				</div>
+			</div>
+            <span class="separator my-5"></span>
+            <div class="fv-row form-group mb-3">
+              <label for="entry_name" class="form-label required">工程或费用项目名称</label>
+              <input type="text" class="form-control" name="entry_name" id="entry_name" placeholder="请输入工程或费用项目名称" required />
+            </div>
+            <div class="fv-row form-group mb-3">
+              <label for="units" class="form-label required">单位</label>
+              <input type="text" class="form-control" name="units" id="units" placeholder="请输入单位" required />
+            </div>
+            <div class="fv-row form-group mb-3">
+              <label for="amount" class="form-label required">工程数量</label>
+              <input type="text" class="form-control" name="amount" id="amount" 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 class="d-flex pt-3 justify-content-center">
+			  <div class="form-check form-check-custom form-check-solid form-check-danger mb-3" id="is_edit_box">
+			    <input class="form-check-input" type="radio" checked value="0"  name="is_edit" id="is_edit_1"/>
+				<label class="form-check-label ms-3 text-danger" for="is_edit_1">覆盖(新增)源数据</label>
+			  </div>
+              <div class="form-check form-check-solid ms-5 mb-3" id="is_edit_box">
+                <input class="form-check-input" type="radio" value="1"  name="is_edit" id="is_edit_2"/>
+				<label class="form-check-label ms-3 text-primary" for="is_edit_2">修改(新增)源数据</label>
+              </div>
+            </div>
+          </div>
+        </form>
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-light" data-bs-dismiss="modal">取消</button>
+        <button type="button" class="btn btn-primary" onclick="SaveQuota(true)">提交</button>
+        <button type="button" class="btn btn-primary" onclick="SaveQuota()">保存草稿</button>
+      </div>
+    </div>
+  </div>
+</div>`
+	$('.app-main .app-container').append(modal_template)
+const $modalQuota = $('#modal_quota')
+console.log(`加载项目:${project_id}`)
+function  LoadQuotaTable(table,url){
+    IwbTable(table,{
+		url,
+		columns: [
+			{
+				title: '序号',
+				data: 'id',
+				width: '80px',
+			},
+			{
+				title: '工程或费用项目名称',
+				data: 'entry_name',
+				width: '210px',
+				render: (row) => {
+						return `<span class="one-line mw-200px" data-bs-toggle="tooltip" data-bs-placement="top" title="${row.entry_name}" >${row.entry_name}</span>`
+				}
+			},
+			{
+				title: '工程数量',
+				data: 'amount',
+				width: '100px',
+			},
+			{
+				title: '单位',
+				data: 'units',
+				width: '80px',
+			},
+			{
+				title: '定额编号',
+				data: 'quota_code',
+				width: '100px',
+			},
+			{
+				title: 'Excel文件',
+				data: 'ex_file',
+				width: '150px',
+				render: (row) => {
+					const path = row.ex_file
+					if (!path) {
+						return '-'
+					}
+					const names = path.split('/')
+					const file_name = names[names.length - 1]
+					return `<span class="one-line mw-150px"><a href="#" onclick="DownloadFile('/api/task/download?filename=${encodeURIComponent(path)}','${file_name}')"  class="link link-info px-2">${file_name}</a></span>`
+				}
+			},
+			{
+				title: 'Excel整行内容',
+				data: 'ex_row',
+				width: 'auto',
+				render: (row) => {
+					return `<span class="one-line w-300px" data-bs-toggle="tooltip" data-bs-placement="top" title="${row.ex_row}" >${row.ex_row}</span>`
+				}
+			},
+			{
+				title: 'Excel数量',
+				data: 'ex_amount',
+				width: '100px',
+			},
+			{
+				title: '数量位置',
+				data: 'ex_cell',
+				width: '80px',
+			},
+			{
+				title: '数量单位',
+				data: 'ex_unit',
+				width: '80px',
+			},
+			{
+				title: '状态',
+				data: 'status',
+				width: '100px',
+				render: (row) => {
+					let str=''
+					// if(row.process_status === 0){
+					// 	str+= `<span class="badge badge-primary">未处理</span>`
+					// }else if (row.process_status === 1){
+					// 	str+= `<span class="badge badge-warning">处理中</span>`
+					// }else if (row.process_status === 2){
+					// 	str+= `<span class="badge badge-success">已处理</span>`
+					// }else if (row.process_status === 3){
+					// 	str+= `<span class="badge badge-danger">处理失败</span>`
+					// }else if (row.process_status === 4){
+					// 	str+= `<span class="badge badge-danger">数据变更</span>`
+					// }
+					if(row.send_status === 0){
+						str+= `<span class="badge badge-primary ms-3">未发送</span>`
+					}else if (row.send_status === 1){
+						str+= `<span class="badge badge-warning ms-3">发送中</span>`
+					}else if (row.send_status === 200){
+						str+= `<span class="badge badge-success ms-3">发送成功</span>`
+					}else if (row.send_status === 2){
+						str+= `<span class="badge badge-danger ms-3">发送失败</span>`
+					}else if (row.send_status === 3){
+						str+= `<span class="badge badge-danger ms-3">数据变更</span>`
+					}
+
+					return str
+				}
+			},
+			{
+				title: '操作',
+				data: 'id',
+				width: '120px',
+				render: (row) => {
+					let str=''
+					// if (row.process_status === 0) {
+					// 	str += `<button type="button" class="btn btn-icon btn-sm btn-light-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="开始处理" onclick="StartProcessQuota(${row.id}, ${row.budget_id})"><i class="ki-duotone ki-book-square fs-1"><span class="path1"></span><span class="path2"></span><span class="path3"></span></i></button>`
+					// } else if (row.process_status === 2) {
+					// 	str += `<button type="button" class="btn btn-icon btn-sm btn-light-warning" data-bs-toggle="tooltip" data-bs-placement="top" title="重新处理" onclick="ReStartProcessQuota(${row.id}, ${row.budget_id})"><i class="ki-duotone ki-book-square fs-1"><span class="path1"></span><span class="path2"></span><span class="path3"></span></i></button>`
+					//
+					// } else if (row.process_status === 3) {
+					// 	str += `<button type="button" class="btn btn-icon btn-sm btn-light-danger" data-bs-toggle="tooltip" data-bs-placement="top" title="重新处理" onclick="ReStartProcessQuota(${row.id}, ${row.budget_id})"><i class="ki-duotone ki-book-square fs-1"><span class="path1"></span><span class="path2"></span><span class="path3"></span></i></button>`
+					// } else if (row.process_status === 4) {
+					// 	str += `<button type="button" class="btn btn-icon btn-sm btn-light-info" data-bs-toggle="tooltip" data-bs-placement="top" title="重新处理" onclick="ReStartProcessQuota(${row.id}, ${row.budget_id})"><i class="ki-duotone ki-book-square fs-1"><span class="path1"></span><span class="path2"></span><span class="path3"></span></i></button>`
+					// }
+					if (row.send_status === 0) {
+						str += `<button type="button" class="btn btn-icon btn-sm btn-light-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="开始发送" onclick="StartSendQuota(${row.id}, ${row.budget_id})"><i class="ki-duotone ki-send fs-1"><span class="path1"></span><span class="path2"></span></i></button>`
+					} else if (row.send_status === 200) {
+						str += `<button type="button" class="btn btn-icon btn-sm btn-light-warning" data-bs-toggle="tooltip" data-bs-placement="top" title="重新发送" onclick="ReStartSendQuota(${row.id}, ${row.budget_id})"><i class="ki-duotone ki-send fs-1"><span class="path1"></span><span class="path2"></span></i></button>`
+					} else if (row.send_status === 2) {
+						str += `<button type="button" class="btn btn-icon btn-sm btn-light-danger" data-bs-toggle="tooltip" data-bs-placement="top" title="重新发送" onclick="ReStartSendQuota(${row.id}, ${row.budget_id})"><i class="ki-duotone ki-send fs-1"><span class="path1"></span><span class="path2"></span></i></button>`
+					} else if (row.send_status === 3) {
+						str += `<button type="button" class="btn btn-icon btn-sm btn-light-info" data-bs-toggle="tooltip" data-bs-placement="top" title="重新发送" onclick="ReStartSendQuota(${row.id}, ${row.budget_id})"><i class="ki-duotone ki-send fs-1"><span class="path1"></span><span class="path2"></span></i></button>`
+					}
+					str+=`<button type="button" class="btn btn-icon btn-sm btn-light-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="编辑" onclick="Edit_Quota(${row.id}, ${row.budget_id})"><i class="ki-duotone ki-message-edit fs-1"><span class="path1"></span><span class="path2"></span></i></button>`
+					str+=`<button type="button" class="btn btn-icon btn-sm btn-light-danger"  data-bs-toggle="tooltip" data-bs-placement="top" title="删除" onclick="Delete_Quota(${row.id}, ${row.budget_id})"><i class="ki-duotone ki-trash-square fs-1"><span class="path1"></span><span class="path2"></span><span class="path3"></span><span class="path4"></span></i></button>`
+					return str
+				}
+			},
+		]
+	}, true)
+}
+
+function SetBudgetData($el){
+	const $tableBox = $(`.table-box`)
+	$el.find('[name="project_id"]').val($tableBox.find('input[name="project_id"]').val());
+	$el.find('[name="item_id"]').val($tableBox.find('input[name="item_id"]').val());
+	$el.find('[name="item_code"]').val($tableBox.find('input[name="item_code"]').val());
+}
+function Add_Quota(budget_id,) {
+	AddModal($modalQuota, () => {
+		SetBudgetData($modalQuota)
+		$modalQuota.find('[name="quota_id"]').val('0');
+		$modalQuota.find('[name="quota_id"]').val('0');
+		$modalQuota.find('[name="task_id"]').val('0');
+		$modalQuota.find('[name="budget_id"]').val(budget_id);
+	})
+}
+
+function Edit_Quota(id) {
+    EditModal($modalQuota,()=>{
+        IwbAjax_1({
+            url:`/api/quota/get/${id}`,
+            success:res=>{
+				if(!res.success){
+					console.error(res.message)
+					return
+				}
+				const data = res.data
+				// SetBudgetData(budget_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="entry_name"]').val(data.entry_name);
+                $modalQuota.find('[name="amount"]').val(data.amount);
+                $modalQuota.find('[name="units"]').val(data.units);
+                $modalQuota.find('[name="quota_code"]').val(data.quota_code);
+                $modalQuota.find('#ex_row').html(data.ex_row);
+                $modalQuota.find('#ex_amount').html(data.ex_amount);
+                $modalQuota.find('#ex_cell').html(data.ex_cell);
+                $modalQuota.find('#ex_unit').html(data.ex_unit);
+
+            }
+        })
+    })
+}
+
+function SaveQuota(isSubmit){
+	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(),
+		entry_name = $modalQuota.find('[name="entry_name"]').val(),
+		amount = $modalQuota.find('[name="amount"]').val(),
+		units = $modalQuota.find('[name="units"]').val(),
+		quota_code = $modalQuota.find('[name="quota_code"]').val()
+	IwbAjax({
+		url:`/api/quota/save`,
+		data:{
+			id: quota_id,
+			task_id,
+			budget_id,
+			project_id,
+			item_id,
+			item_code,
+			entry_name,
+			amount,
+			units,
+			quota_code,
+			run_now: isSubmit?'true':'false'
+		},
+		modal:$modalQuota,
+		table:`#table_${budget_id}`
+	})
+
+
+}
+
+function Delete_Quota(id,budget_id){
+	ConfirmUrl('确定删除吗?',`/api/quota/delete/${id}`,`#table_${budget_id}`)
+}
+
+// function StartProcessQuota(id,budget_id){
+// 	ConfirmUrl('确定开始处理吗?',`/api/quota/start_process/${id}`,`#table_${budget_id}`)
+// }
+// function ReStartProcessQuota(id,budget_id){
+// 	ConfirmUrl('确定重新开始处理吗?',`/api/quota/start_process/${id}`,`#table_${budget_id}`)
+// }
+function StartSendQuota(id,budget_id){
+	ConfirmUrl('确定开始发送吗?',`/api/quota/start_send/${id}`,`#table_${budget_id}`)
+}
+function ReStartSendQuota(id,budget_id){
+	ConfirmUrl('确定重新开始发送吗?',`/api/quota/start_send/${id}`,`#table_${budget_id}`)
+}

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

@@ -95,59 +95,14 @@
 		</div>
 	</div>
 </div>
-<div class="modal fade" id="modal_quota" tabindex="-1" aria-hidden="true">
-	<div class="modal-dialog modal-dialog-centered">
-		<div class="modal-content rounded">
-			<div class="modal-header">
-				<h3 class="modal-title"><span class="prefix"></span>定额</h3>
-				<div class="btn btn-sm btn-icon btn-active-color-primary" data-bs-dismiss="modal">
-					<i class="ki-duotone ki-cross fs-1">
-						<span class="path1"></span>
-						<span class="path2"></span>
-					</i>
-				</div>
-			</div>
-			<div class="modal-body">
-				<form>
-					<div class="form-group">
-						<input type="hidden" name="budget_id" value="">
-						<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="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>
-			</div>
-			<div class="modal-footer">
-				<button type="button" class="btn btn-light" data-bs-dismiss="modal">取消</button>
-				<button type="button" class="btn btn-primary" onclick="SaveQuota()">保存</button>
-			</div>
-		</div>
-	</div>
-</div>
+
 {% endblock %} {% block page_scripts %}
 <script>
 	ChangeHeadMenu('#{{page_active}}_menu')
 	const project_id = '{{project.project_id}}'
 </script>
 <script src="{{ url_for('static', filename='base/plugins/jstree/jstree.bundle.js') }}"></script>
+<script src="/static/project/quota_info.js"></script>
 <script src="/static/project/budget_info.js"></script>
 
 {% endblock %}

+ 66 - 0
SourceCode/IntelligentRailwayCosting/app/views/templates/project/quota_info.html

@@ -0,0 +1,66 @@
+{% extends "base/layout.html" %}
+
+{% block title %}定额输入管理{% endblock %}
+
+{% block page_content %}
+ <div class="app-body-header h-50px">
+    <h3>定额输入({{task.task_name}})</h3>
+    <ol class="breadcrumb breadcrumb-dot text-muted fs-6 fw-semibold ms-5">
+        <li class="breadcrumb-item"><a href="{{ url_for('project.index') }}" class="">项目管理</a></li>
+        <li class="breadcrumb-item"><a href="{{ url_for('project.budget_info',project_id=project.project_id) }}" class="">概算信息</a></li>
+		<li class="breadcrumb-item text-muted">定额输入</li>
+    </ol>
+</div>
+<div class="mx-10 my-5">
+    <div class="table-box table-responsive">
+        <section class="d-none">
+            <input type="hidden" name="project_id" value="{{project.project_id}}">
+            <input type="hidden" name="item_id" value="">
+            <input type="hidden" name="item_code" value="">
+        </section>
+        <div class="d-flex justify-content-between mb-5 mx-10">
+            <div>
+<!--                <button class="btn btn-primary btn-sm" onclick="Add()">添加</button>-->
+            </div>
+            <form class="search-box d-flex">
+                <div class="d-flex">
+                    <select class="form-select form-select-sm me-5" name="send_status">
+                        	<option value="">全部发送状态</option>
+                            <option value="0">未发送</option>
+                            <option value="1">发送中</option>
+                            <option value="200">发送成功</option>
+                            <option value="2">发送失败</option>
+                            <option value="3">数据变更</option>
+                    </select>
+                    <select class="form-select form-select-sm me-5" name="budget_id">
+                        	<option value="">全部概算单元</option>
+                            {% for budget in budgets %}
+                            <option value="{{ budget.budget_id }}">{{ budget.budget_code }}</option>
+                            {% endfor %}
+                    </select>
+                    <input type="text" class="form-control form-control-sm w-200px" placeholder="请输入关键字" name="keyword" />
+                </div>
+                <div class="btn-group ms-5">
+                    <button type="button" class="btn btn-primary btn-sm" onclick="IwbTableSearch(this)">查询</button>
+                    <button type="button" class="btn btn-danger btn-sm" onclick="IwbTableResetSearch(this)">重置</button>
+                </div>
+            </form>
+        </div>
+        <table class="table table-striped table-bordered table-hover  table-rounded" id="table">
+        </table>
+        <div class="pagination-row"></div>
+    </div>
+</div>
+
+{% endblock %}
+{% block page_scripts %}
+    <script>
+        ChangeHeadMenu("#{{page_active}}_menu")
+	    const project_id = '{{project.project_id}}', task_id = '{{task.id}}'
+        $(function (){
+            LoadQuotaTable($('#table'),`/api/quota/list/task/${task_id}`)
+        })
+    </script>
+    <script src="/static/project/quota_info.js"></script>
+
+{% endblock %}