You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2510 lines
107 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>非直接支付 - 资金使用管理系统</title>
<link href="https://cdn.staticfile.org/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.staticfile.org/bootstrap-icons/1.11.0/font/bootstrap-icons.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Microsoft YaHei', sans-serif;
background-color: #f5f7fa;
padding: 20px;
}
.page-header {
background: white;
padding: 25px 30px;
border-radius: 10px;
margin-bottom: 20px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
}
.page-title {
font-size: 24px;
font-weight: 600;
color: #333;
margin: 0;
}
.page-title i {
margin-right: 10px;
color: #667eea;
}
.wizard-container {
background: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
padding: 30px;
max-width: 1000px;
margin: 0 auto;
}
/* 步骤指示器 */
.wizard-steps {
display: flex;
justify-content: space-between;
margin-bottom: 40px;
position: relative;
}
.wizard-steps::before {
content: '';
position: absolute;
top: 20px;
left: 0;
right: 0;
height: 2px;
background: #e5e7eb;
z-index: 0;
}
.wizard-step {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
z-index: 1;
}
.step-number {
width: 40px;
height: 40px;
border-radius: 50%;
background: white;
border: 3px solid #e5e7eb;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
color: #9ca3af;
margin-bottom: 10px;
transition: all 0.3s;
}
.wizard-step.active .step-number {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-color: #667eea;
color: white;
}
.wizard-step.completed .step-number {
background: #10b981;
border-color: #10b981;
color: white;
}
.wizard-step.completed .step-number::after {
content: '\2713';
font-size: 20px;
}
.step-label {
font-size: 14px;
color: #6b7280;
text-align: center;
}
.wizard-step.active .step-label {
color: #667eea;
font-weight: 600;
}
.wizard-step.completed .step-label {
color: #10b981;
}
/* 步骤内容 */
.step-content {
display: none;
animation: fadeIn 0.3s;
}
.step-content.active {
display: block;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideOut {
from {
opacity: 1;
transform: translateX(0);
}
to {
opacity: 0;
transform: translateX(100%);
}
}
.step-title {
font-size: 20px;
font-weight: 600;
color: #333;
margin-bottom: 10px;
}
.step-description {
color: #6b7280;
margin-bottom: 30px;
}
/* 选项卡片 */
.option-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.option-card {
border: 2px solid #e5e7eb;
border-radius: 10px;
padding: 20px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
background: white;
}
.option-card:hover {
border-color: #667eea;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.15);
}
.option-card.selected {
border-color: #667eea;
background: #f0f0ff;
}
.option-card-icon {
font-size: 48px;
margin-bottom: 15px;
color: #667eea;
}
.option-card-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin-bottom: 5px;
}
.option-card-desc {
font-size: 12px;
color: #6b7280;
}
/* 表单样式 */
.form-section {
margin-bottom: 25px;
}
.section-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #e5e7eb;
}
.form-label {
font-weight: 500;
color: #333;
margin-bottom: 8px;
}
.form-label .required {
color: #ef4444;
margin-left: 3px;
}
.form-control, .form-select {
border: 1px solid #d1d5db;
border-radius: 6px;
padding: 10px 12px;
}
.form-control:focus, .form-select:focus {
border-color: #667eea;
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
}
/* 流程提示 */
.process-hint {
background: #f0f9ff;
border-left: 4px solid #3b82f6;
padding: 15px;
border-radius: 6px;
margin-bottom: 20px;
}
.process-hint-title {
font-weight: 600;
color: #1e40af;
margin-bottom: 10px;
}
.process-hint-steps {
list-style: none;
padding: 0;
}
.process-hint-steps li {
padding: 5px 0;
color: #1e40af;
display: flex;
align-items: center;
gap: 8px;
}
.process-hint-steps li i {
color: #3b82f6;
}
/* 确认信息 */
.summary-card {
background: #f8f9fa;
border-radius: 10px;
padding: 20px;
margin-bottom: 20px;
}
.summary-item {
display: flex;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid #e5e7eb;
}
.summary-item:last-child {
border-bottom: none;
}
.summary-label {
color: #6b7280;
font-weight: 500;
}
.summary-value {
color: #333;
font-weight: 600;
}
/* 按钮区域 */
.wizard-actions {
display: flex;
justify-content: space-between;
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #e5e7eb;
}
.btn {
padding: 10px 25px;
font-weight: 500;
border-radius: 6px;
}
.btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 6px;
}
.btn-primary:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.btn-outline-secondary {
border: 1px solid #6c757d;
color: #6c757d;
background: white;
border-radius: 6px;
}
.btn-outline-secondary:hover {
background: #6c757d;
color: white;
transform: translateY(-1px);
}
.btn-secondary {
border-radius: 6px;
}
.wizard-actions .btn-group {
display: flex;
gap: 10px;
}
.wizard-actions .btn-group .btn {
border-radius: 6px;
}
/* 金额范围显示卡片 */
.amount-range-display {
margin-top: 20px;
}
.range-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 10px;
padding: 20px;
display: flex;
align-items: center;
gap: 15px;
color: white;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
animation: fadeIn 0.3s;
}
.range-icon {
font-size: 32px;
}
.range-info {
flex: 1;
}
.range-title {
font-size: 18px;
font-weight: 600;
margin-bottom: 5px;
}
.range-desc {
font-size: 14px;
opacity: 0.9;
}
/* 流程实例列表样式 */
.table-hover tbody tr {
cursor: pointer;
}
.table-hover tbody tr:hover {
background-color: #f8f9fa;
}
.table-hover tbody tr.selected {
background-color: #e7f3ff;
}
.table-hover tbody tr.selected:hover {
background-color: #d0e7ff;
}
.status-badge {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status-approved {
background-color: #d1fae5;
color: #065f46;
}
.status-pending {
background-color: #fef3c7;
color: #92400e;
}
.status-completed {
background-color: #d1fae5;
color: #065f46;
}
.status-pending {
background-color: #fef3c7;
color: #92400e;
}
/* 本次支付数量输入框样式 */
#detailList input[type="number"] {
border: 1px solid #d1d5db;
border-radius: 4px;
padding: 4px 8px;
font-size: 14px;
}
#detailList input[type="number"]:focus {
border-color: #667eea;
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
outline: none;
}
</style>
</head>
<body>
<!-- 页面头部 -->
<div class="page-header">
<h1 class="page-title">
<i class="bi bi-building"></i> 非直接支付
</h1>
</div>
<!-- 向导容器 -->
<div class="wizard-container">
<!-- 步骤指示器 -->
<div class="wizard-steps">
<div class="wizard-step active" data-step="1">
<div class="step-number">1</div>
<div class="step-label">选择流程</div>
</div>
<div class="wizard-step" data-step="2">
<div class="step-number">2</div>
<div class="step-label" id="step2Label">选择实例</div>
</div>
<div class="wizard-step" data-step="3">
<div class="step-number">3</div>
<div class="step-label">选择金额</div>
</div>
<div class="wizard-step" data-step="4">
<div class="step-number">4</div>
<div class="step-label">招标流程</div>
</div>
<div class="wizard-step" data-step="5">
<div class="step-number">5</div>
<div class="step-label">合同流程</div>
</div>
<div class="wizard-step" data-step="6">
<div class="step-number">6</div>
<div class="step-label">上传材料</div>
</div>
<div class="wizard-step" data-step="7">
<div class="step-number">7</div>
<div class="step-label">填写信息</div>
</div>
<div class="wizard-step" data-step="8">
<div class="step-number">8</div>
<div class="step-label">确认提交</div>
</div>
</div>
<!-- 步骤1: 选择事前流程主体 -->
<div class="step-content active" id="step1">
<h2 class="step-title">选择事前流程主体</h2>
<p class="step-description">请选择要发起支付的事前流程类型</p>
<div class="option-cards">
<div class="option-card" onclick="selectProcessType('procurement')">
<div class="option-card-icon">
<i class="bi bi-cart"></i>
</div>
<div class="option-card-title">采购管理</div>
<div class="option-card-desc">课题/非课题采购审批</div>
</div>
<div class="option-card" onclick="selectProcessType('meeting')">
<div class="option-card-icon">
<i class="bi bi-people"></i>
</div>
<div class="option-card-title">会议、培训、接待</div>
<div class="option-card-desc">培训、会议、接待审批</div>
</div>
<div class="option-card" onclick="selectProcessType('vehicle')">
<div class="option-card-icon">
<i class="bi bi-truck"></i>
</div>
<div class="option-card-title">车船管理及维修</div>
<div class="option-card-desc">车船维修保养申请</div>
</div>
<div class="option-card" onclick="selectProcessType('instrument')">
<div class="option-card-icon">
<i class="bi bi-gear"></i>
</div>
<div class="option-card-title">仪器管理</div>
<div class="option-card-desc">仪器设备相关申请</div>
</div>
<div class="option-card" onclick="selectProcessType('travel')">
<div class="option-card-icon">
<i class="bi bi-airplane"></i>
</div>
<div class="option-card-title">出差管理</div>
<div class="option-card-desc">出差审批</div>
</div>
<div class="option-card" onclick="selectProcessType('contract')">
<div class="option-card-icon">
<i class="bi bi-file-earmark-text"></i>
</div>
<div class="option-card-title">合同管理</div>
<div class="option-card-desc">合同审批、变更审批</div>
</div>
<div class="option-card" onclick="selectProcessType('installation')">
<div class="option-card-icon">
<i class="bi bi-tools"></i>
</div>
<div class="option-card-title">安装维修</div>
<div class="option-card-desc">安装、维修申请</div>
</div>
</div>
</div>
<!-- 步骤2: 选择流程实例或明细 -->
<div class="step-content" id="step2">
<h2 class="step-title" id="step2Title">选择流程实例</h2>
<p class="step-description" id="step2Description">请选择要支付的流程实例</p>
<!-- 单条模式:流程实例列表 -->
<div id="singleModeContainer" style="display: none;">
<div class="form-section">
<div class="mb-3">
<label class="form-label">筛选条件</label>
<div class="row g-3">
<div class="col-md-4">
<input type="text" class="form-control" id="filterKeyword" placeholder="搜索流程编号、申请人...">
</div>
<div class="col-md-4">
<select class="form-select" id="filterStatus">
<option value="">全部状态</option>
<option value="approved">已批准</option>
<option value="pending">待审批</option>
<option value="completed">已完成</option>
</select>
</div>
<div class="col-md-4">
<button type="button" class="btn btn-outline-primary w-100" onclick="loadProcessInstances()">
<i class="bi bi-search"></i> 搜索
</button>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th width="50">选择</th>
<th>流程编号</th>
<th>流程名称</th>
<th>申请人</th>
<th>申请时间</th>
<th>金额</th>
<th>状态</th>
</tr>
</thead>
<tbody id="processInstanceList">
<!-- 动态加载流程实例列表 -->
</tbody>
</table>
</div>
<div id="processInstanceEmpty" class="text-center text-muted py-4" style="display: none;">
<i class="bi bi-inbox" style="font-size: 48px;"></i>
<p class="mt-2">暂无符合条件的流程实例</p>
</div>
</div>
</div>
<!-- 批量模式:流程实例列表 + 明细选择 -->
<div id="batchModeContainer" style="display: none;">
<div class="form-section">
<div class="mb-3">
<label class="form-label">筛选条件</label>
<div class="row g-3">
<div class="col-md-4">
<input type="text" class="form-control" id="batchFilterKeyword" placeholder="搜索流程编号、申请人...">
</div>
<div class="col-md-4">
<select class="form-select" id="batchFilterStatus">
<option value="">全部状态</option>
<option value="approved">已批准</option>
<option value="pending">待审批</option>
<option value="completed">已完成</option>
</select>
</div>
<div class="col-md-4">
<button type="button" class="btn btn-outline-primary w-100" onclick="loadProcessInstancesForBatch()">
<i class="bi bi-search"></i> 搜索
</button>
</div>
</div>
</div>
<!-- 流程实例列表 -->
<div class="mb-4">
<div class="d-flex justify-content-between align-items-center mb-3">
<h4 class="mb-0">选择流程实例</h4>
<div>
<button type="button" class="btn btn-sm btn-outline-primary" onclick="selectAllInstances()">
<i class="bi bi-check-square"></i> 全选
</button>
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="clearAllInstances()">
<i class="bi bi-x-square"></i> 清空
</button>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th width="50">
<input type="checkbox" id="selectAllInstances" onchange="toggleAllInstances()">
</th>
<th>流程编号</th>
<th>流程名称</th>
<th>申请人</th>
<th>申请时间</th>
<th>状态</th>
</tr>
</thead>
<tbody id="batchProcessInstanceList">
<!-- 动态加载流程实例列表 -->
</tbody>
</table>
</div>
</div>
<!-- 明细数据列表 -->
<div id="detailListContainer" style="display: none;">
<div class="d-flex justify-content-between align-items-center mb-3">
<h4 class="mb-0">选择明细数据</h4>
<div>
<button type="button" class="btn btn-sm btn-outline-primary" onclick="selectAllDetails()">
<i class="bi bi-check-square"></i> 全选明细
</button>
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="clearAllDetails()">
<i class="bi bi-x-square"></i> 清空明细
</button>
</div>
</div>
<div class="alert alert-info mb-3">
<i class="bi bi-info-circle"></i> 已选择 <strong id="selectedInstanceCount">0</strong> 个流程实例,请从下方明细列表中选择需要支付的明细
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th width="50">
<input type="checkbox" id="selectAllDetails" onchange="toggleAllDetails()">
</th>
<th>所属实例</th>
<th>明细名称</th>
<th>数量</th>
<th>单位</th>
<th>已支付数量</th>
<th>本次支付数量</th>
<th>状态</th>
<th>备注</th>
</tr>
</thead>
<tbody id="detailList">
<!-- 动态加载所有选中实例的明细列表 -->
</tbody>
</table>
</div>
<div id="detailListEmpty" class="text-center text-muted py-4" style="display: none;">
<i class="bi bi-inbox" style="font-size: 48px;"></i>
<p class="mt-2">请先选择流程实例</p>
</div>
</div>
</div>
</div>
</div>
<!-- 步骤3: 输入金额 -->
<div class="step-content" id="step3">
<h2 class="step-title">输入支付金额</h2>
<p class="step-description">请输入本次支付的金额,系统将自动匹配金额范围并确定所需的审批材料</p>
<div class="form-section">
<div class="mb-4">
<label class="form-label">支付金额<span class="required">*</span></label>
<div class="input-group" style="max-width: 400px;">
<span class="input-group-text">
<i class="bi bi-currency-yen"></i>
</span>
<input type="number" class="form-control" id="amountInput"
placeholder="请输入金额" step="0.01" min="0" required
oninput="handleAmountInput()">
</div>
<small class="text-muted">请输入数字金额,系统将自动匹配到对应区间</small>
</div>
<div id="amountRangeDisplay" class="amount-range-display" style="display: none;">
<div class="range-card">
<div class="range-icon">
<i class="bi bi-check-circle-fill"></i>
</div>
<div class="range-info">
<div class="range-title" id="rangeTitle">-</div>
<div class="range-desc" id="rangeDesc">-</div>
</div>
</div>
</div>
</div>
</div>
<!-- 步骤4: 招标流程仅30万元以上显示 -->
<div class="step-content" id="step4">
<h2 class="step-title">招标流程</h2>
<p class="step-description">请选择本次支付的招标类型</p>
<div id="processHint" class="process-hint" style="display: none;">
<div class="process-hint-title">所需材料:</div>
<ul class="process-hint-steps" id="hintSteps"></ul>
</div>
<div class="option-cards">
<div class="option-card" onclick="selectBidding('public')">
<div class="option-card-icon">
<i class="bi bi-file-earmark-check"></i>
</div>
<div class="option-card-title">公开招标</div>
<div class="option-card-desc">通过公开招标方式采购</div>
</div>
<div class="option-card" onclick="selectBidding('non-public')">
<div class="option-card-icon">
<i class="bi bi-file-earmark-lock"></i>
</div>
<div class="option-card-title">非公开招标</div>
<div class="option-card-desc">非公开招标方式采购</div>
</div>
</div>
</div>
<!-- 步骤5: 合同流程 -->
<div class="step-content" id="step5">
<h2 class="step-title">合同流程</h2>
<p class="step-description">请选择合同流程实例并填写合同基本信息</p>
<!-- 合同流程实例选择 -->
<div class="form-section mb-4">
<h3 class="section-title">选择合同流程实例</h3>
<div class="mb-3">
<label class="form-label">筛选条件</label>
<div class="row g-3">
<div class="col-md-4">
<input type="text" class="form-control" id="contractFilterKeyword" placeholder="搜索合同编号、合同名称...">
</div>
<div class="col-md-4">
<select class="form-select" id="contractFilterStatus">
<option value="">全部状态</option>
<option value="approved">已批准</option>
<option value="pending">待审批</option>
<option value="completed">已完成</option>
</select>
</div>
<div class="col-md-4">
<button type="button" class="btn btn-outline-primary w-100" onclick="loadContractInstances()">
<i class="bi bi-search"></i> 搜索
</button>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th width="50">选择</th>
<th>合同编号</th>
<th>合同名称</th>
<th>合同类型</th>
<th>签订日期</th>
<th>状态</th>
</tr>
</thead>
<tbody id="contractInstanceList">
<!-- 动态加载合同流程实例列表 -->
</tbody>
</table>
</div>
<div id="contractInstanceEmpty" class="text-center text-muted py-4" style="display: none;">
<i class="bi bi-inbox" style="font-size: 48px;"></i>
<p class="mt-2">暂无符合条件的合同流程实例</p>
</div>
</div>
<!-- 合同基本信息录入 -->
<div class="form-section" id="contractInfoSection" style="display: none;">
<h3 class="section-title">合同基本信息</h3>
<form id="contractInfoForm">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">合同编号<span class="required">*</span></label>
<input type="text" class="form-control" id="contractInfoNumber" required>
</div>
<div class="col-md-6">
<label class="form-label">合同名称<span class="required">*</span></label>
<input type="text" class="form-control" id="contractInfoName" required>
</div>
<div class="col-md-6">
<label class="form-label">合同类型<span class="required">*</span></label>
<select class="form-select" id="contractInfoType" required>
<option value="">请选择</option>
<option value="procurement">采购合同</option>
<option value="service">服务合同</option>
<option value="construction">工程合同</option>
<option value="other">其他</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label">签订日期<span class="required">*</span></label>
<input type="date" class="form-control" id="contractInfoDate" required>
</div>
<div class="col-md-6">
<label class="form-label">合同金额<span class="required">*</span></label>
<input type="number" class="form-control" id="contractInfoAmount" step="0.01" min="0" required>
</div>
<div class="col-md-6">
<label class="form-label">合同期限</label>
<input type="text" class="form-control" id="contractInfoPeriod" placeholder="如12个月">
</div>
<div class="col-md-6">
<label class="form-label">甲方(我方)<span class="required">*</span></label>
<input type="text" class="form-control" id="contractInfoPartyA" required>
</div>
<div class="col-md-6">
<label class="form-label">乙方(对方)<span class="required">*</span></label>
<input type="text" class="form-control" id="contractInfoPartyB" required>
</div>
<div class="col-md-12">
<label class="form-label">合同主要内容</label>
<textarea class="form-control" id="contractInfoContent" rows="4" placeholder="请输入合同主要内容"></textarea>
</div>
<div class="col-md-12">
<label class="form-label">备注</label>
<textarea class="form-control" id="contractInfoRemark" rows="3" placeholder="请输入备注信息"></textarea>
</div>
</div>
</form>
</div>
</div>
<!-- 步骤6: 上传材料 -->
<div class="step-content" id="step6">
<h2 class="step-title">上传所需材料</h2>
<p class="step-description">请根据流程要求上传相应的审批材料</p>
<div id="uploadRequirements" class="process-hint">
<div class="process-hint-title">需要上传的材料:</div>
<ul class="process-hint-steps" id="uploadSteps"></ul>
</div>
<div class="form-section">
<div class="mb-3">
<label class="form-label">中心主任会会议纪要</label>
<input type="file" class="form-control" id="directorMeeting" accept=".pdf,.doc,.docx">
<small class="text-muted">支持PDF、Word格式</small>
</div>
<div class="mb-3">
<label class="form-label">支委会会议纪要</label>
<input type="file" class="form-control" id="committeeMeeting" accept=".pdf,.doc,.docx">
<small class="text-muted">支持PDF、Word格式</small>
</div>
<div class="mb-3">
<label class="form-label">政府采购省厅审批表</label>
<input type="file" class="form-control" id="provincialApproval" accept=".pdf,.doc,.docx,.xls,.xlsx">
<small class="text-muted">支持PDF、Word、Excel格式</small>
</div>
</div>
</div>
<!-- 步骤7: 填写信息 -->
<div class="step-content" id="step7">
<h2 class="step-title">填写支付信息</h2>
<p class="step-description">请填写详细的支付信息</p>
<form id="paymentForm">
<div class="form-section">
<h3 class="section-title">基本信息</h3>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">支付事项<span class="required">*</span></label>
<input type="text" class="form-control" id="paymentItem" required>
</div>
<div class="col-md-6">
<label class="form-label">支付金额<span class="required">*</span></label>
<input type="number" class="form-control" id="paymentAmount" step="0.01" required>
</div>
<div class="col-md-6">
<label class="form-label">收款单位<span class="required">*</span></label>
<input type="text" class="form-control" id="payee" required>
</div>
<div class="col-md-6">
<label class="form-label">收款账号<span class="required">*</span></label>
<input type="text" class="form-control" id="accountNumber" required>
</div>
<div class="col-md-6">
<label class="form-label">开户银行<span class="required">*</span></label>
<input type="text" class="form-control" id="bankName" required>
</div>
<div class="col-md-6">
<label class="form-label">支付方式</label>
<select class="form-select" id="paymentMethod">
<option value="transfer">银行转账</option>
<option value="check">支票</option>
<option value="other">其他</option>
</select>
</div>
</div>
</div>
<div class="form-section">
<h3 class="section-title">详细信息</h3>
<div class="row g-3">
<div class="col-md-12">
<label class="form-label">支付说明<span class="required">*</span></label>
<textarea class="form-control" id="paymentDescription" rows="4" required></textarea>
</div>
<div class="col-md-12">
<label class="form-label">相关合同/协议编号</label>
<input type="text" class="form-control" id="contractNumber">
</div>
</div>
</div>
</form>
</div>
<!-- 步骤8: 确认提交 -->
<div class="step-content" id="step8">
<h2 class="step-title">确认支付信息</h2>
<p class="step-description">请确认以下信息无误后提交</p>
<div class="summary-card">
<div class="summary-item">
<span class="summary-label">金额范围</span>
<span class="summary-value" id="summaryAmountRange">-</span>
</div>
<div class="summary-item" id="summaryBiddingItem" style="display: none;">
<span class="summary-label">招标类型</span>
<span class="summary-value" id="summaryBidding">-</span>
</div>
<div class="summary-item">
<span class="summary-label">支付事项</span>
<span class="summary-value" id="summaryItem">-</span>
</div>
<div class="summary-item">
<span class="summary-label">支付金额</span>
<span class="summary-value" id="summaryAmount">-</span>
</div>
<div class="summary-item">
<span class="summary-label">收款单位</span>
<span class="summary-value" id="summaryPayee">-</span>
</div>
<div class="summary-item">
<span class="summary-label">收款账号</span>
<span class="summary-value" id="summaryAccount">-</span>
</div>
<div class="summary-item">
<span class="summary-label">开户银行</span>
<span class="summary-value" id="summaryBank">-</span>
</div>
</div>
</div>
<!-- 按钮区域 -->
<div class="wizard-actions">
<button type="button" class="btn btn-secondary" id="btnPrev" onclick="prevStep()" style="display: none;">
<i class="bi bi-arrow-left"></i> 上一步
</button>
<div class="btn-group">
<button type="button" class="btn btn-outline-secondary" id="btnSave" onclick="saveDraft()">
<i class="bi bi-save"></i> 暂存
</button>
</div>
<div class="btn-group">
<button type="button" class="btn btn-primary" id="btnNext" onclick="nextStep()">
下一步 <i class="bi bi-arrow-right"></i>
</button>
<button type="button" class="btn btn-primary" id="btnSubmit" onclick="submitPayment()" style="display: none;">
<i class="bi bi-check-circle"></i> 提交支付
</button>
</div>
</div>
</div>
<script src="https://cdn.staticfile.org/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
<script>
let currentStep = 1;
const totalSteps = 8;
let formData = {
processType: '',
paymentMode: '', // 根据流程主体自动决定
selectedInstanceId: '', // 单条模式下选中的流程实例ID
selectedInstanceName: '', // 单条模式下选中的流程实例名称
selectedInstances: [], // 批量模式下选中的流程实例数组,每个元素包含 {id, name, detailIds: []}
amountRange: '',
inputAmount: '',
biddingType: '',
contractInstanceId: '', // 选中的合同流程实例ID
contractInstanceName: '', // 选中的合同流程实例名称
contractInfo: {}, // 合同基本信息
paymentItem: '',
paymentAmount: '',
payee: '',
accountNumber: '',
bankName: '',
paymentMethod: 'transfer',
paymentDescription: '',
contractNumber: ''
};
// 金额范围映射
const amountRangeMap = {
'under-5': '5万元以下',
'5-10': '5-10万不含',
'10-30': '10-30万不含',
'over-30': '30万元及以上'
};
// 招标类型映射
const biddingTypeMap = {
'public': '公开招标',
'non-public': '非公开招标'
};
// 事前流程类型映射
const processTypeMap = {
'procurement': '采购管理',
'meeting': '会议、培训、接待',
'vehicle': '车船管理及维修',
'instrument': '仪器管理',
'travel': '出差管理',
'contract': '合同管理',
'installation': '安装维修'
};
// 支付方式映射
const paymentModeMap = {
'single': '单条流程实例支付',
'batch': '批量支付'
};
// 流程主体对应的支付方式规则
const processPaymentModeMap = {
'procurement': 'batch', // 采购管理 - 支持批量
'meeting': 'single', // 会议、培训、接待 - 单条
'vehicle': 'single', // 车船管理及维修 - 单条
'instrument': 'single', // 仪器管理 - 单条
'travel': 'batch', // 出差管理 - 支持批量
'contract': 'batch', // 合同管理 - 支持批量
'installation': 'single' // 安装维修 - 单条
};
// 选择事前流程类型
function selectProcessType(type) {
formData.processType = type;
// 根据流程主体自动决定支付方式
formData.paymentMode = processPaymentModeMap[type] || 'single';
document.querySelectorAll('#step1 .option-card').forEach(card => {
card.classList.remove('selected');
});
event.currentTarget.classList.add('selected');
// 自动保存
collectCurrentStepData();
saveDraftSilently();
// 进入步骤2显示流程实例选择界面
setTimeout(() => {
showProcessInstanceSelection();
nextStep();
}, 300);
}
// 显示流程实例选择界面
function showProcessInstanceSelection() {
const isBatch = formData.paymentMode === 'batch';
const singleContainer = document.getElementById('singleModeContainer');
const batchContainer = document.getElementById('batchModeContainer');
const step2Title = document.getElementById('step2Title');
const step2Description = document.getElementById('step2Description');
const step2Label = document.getElementById('step2Label');
if (isBatch) {
singleContainer.style.display = 'none';
batchContainer.style.display = 'block';
step2Title.textContent = '选择流程实例及明细';
step2Description.textContent = '请先选择流程实例,然后选择该实例下的明细数据进行批量支付';
step2Label.textContent = '选择明细';
loadProcessInstancesForBatch();
} else {
singleContainer.style.display = 'block';
batchContainer.style.display = 'none';
step2Title.textContent = '选择流程实例';
step2Description.textContent = '请选择要支付的流程实例';
step2Label.textContent = '选择实例';
loadProcessInstances();
}
}
// 加载流程实例列表(单条模式)
function loadProcessInstances() {
const tbody = document.getElementById('processInstanceList');
const emptyDiv = document.getElementById('processInstanceEmpty');
// 模拟数据实际应该从后端API获取
const mockInstances = [
{ id: '1', code: 'CG-2025-001', name: '办公设备采购', applicant: '张三', date: '2025-01-15', amount: 50000, status: 'approved' },
{ id: '2', code: 'CG-2025-002', name: '服务器采购', applicant: '李四', date: '2025-01-20', amount: 150000, status: 'approved' },
{ id: '3', code: 'HY-2025-001', name: '年度会议', applicant: '王五', date: '2025-01-25', amount: 30000, status: 'approved' }
];
tbody.innerHTML = '';
if (mockInstances.length === 0) {
emptyDiv.style.display = 'block';
return;
}
emptyDiv.style.display = 'none';
mockInstances.forEach(instance => {
const tr = document.createElement('tr');
tr.onclick = () => selectProcessInstance(instance.id, instance);
tr.innerHTML = `
<td>
<input type="radio" name="processInstance" value="${instance.id}"
${formData.selectedInstanceId === instance.id ? 'checked' : ''}>
</td>
<td>${instance.code}</td>
<td>${instance.name}</td>
<td>${instance.applicant}</td>
<td>${instance.date}</td>
<td>¥${instance.amount.toLocaleString()}</td>
<td><span class="status-badge status-${instance.status}">${getStatusText(instance.status)}</span></td>
`;
tbody.appendChild(tr);
});
}
// 加载流程实例列表(批量模式)
function loadProcessInstancesForBatch() {
const tbody = document.getElementById('batchProcessInstanceList');
// 模拟数据
const mockInstances = [
{ id: '1', code: 'CG-2025-001', name: '办公设备采购', applicant: '张三', date: '2025-01-15', status: 'approved' },
{ id: '2', code: 'CG-2025-002', name: '服务器采购', applicant: '李四', date: '2025-01-20', status: 'approved' },
{ id: '3', code: 'CC-2025-001', name: '出差审批', applicant: '王五', date: '2025-01-25', status: 'approved' }
];
tbody.innerHTML = '';
mockInstances.forEach(instance => {
const isSelected = formData.selectedInstances.some(inst => inst.id === instance.id);
const tr = document.createElement('tr');
tr.innerHTML = `
<td>
<input type="checkbox" value="${instance.id}"
${isSelected ? 'checked' : ''}
onchange="toggleBatchInstance('${instance.id}', '${instance.name}')">
</td>
<td>${instance.code}</td>
<td>${instance.name}</td>
<td>${instance.applicant}</td>
<td>${instance.date}</td>
<td><span class="status-badge status-${instance.status}">${getStatusText(instance.status)}</span></td>
`;
tbody.appendChild(tr);
});
// 更新明细列表
updateDetailList();
}
// 切换流程实例选择(批量模式)
function toggleBatchInstance(instanceId, instanceName) {
const index = formData.selectedInstances.findIndex(inst => inst.id === instanceId);
if (index > -1) {
// 取消选择
formData.selectedInstances.splice(index, 1);
} else {
// 添加选择
formData.selectedInstances.push({
id: instanceId,
name: instanceName,
detailIds: [],
detailData: []
});
}
// 更新明细列表
updateDetailList();
// 自动保存
collectCurrentStepData();
saveDraftSilently();
}
// 全选/取消全选流程实例
function toggleAllInstances() {
const selectAll = document.getElementById('selectAllInstances');
const checkboxes = document.querySelectorAll('#batchProcessInstanceList input[type="checkbox"]');
checkboxes.forEach(cb => {
cb.checked = selectAll.checked;
const instanceId = cb.value;
const tr = cb.closest('tr');
const instanceName = tr.cells[2].textContent;
if (selectAll.checked) {
// 检查是否已存在
const exists = formData.selectedInstances.some(inst => inst.id === instanceId);
if (!exists) {
formData.selectedInstances.push({
id: instanceId,
name: instanceName,
detailIds: [],
detailData: []
});
}
} else {
// 移除
const index = formData.selectedInstances.findIndex(inst => inst.id === instanceId);
if (index > -1) {
formData.selectedInstances.splice(index, 1);
}
}
});
// 更新明细列表
updateDetailList();
collectCurrentStepData();
saveDraftSilently();
}
// 全选流程实例
function selectAllInstances() {
document.getElementById('selectAllInstances').checked = true;
toggleAllInstances();
}
// 清空所有流程实例
function clearAllInstances() {
formData.selectedInstances = [];
document.getElementById('selectAllInstances').checked = false;
document.querySelectorAll('#batchProcessInstanceList input[type="checkbox"]').forEach(cb => {
cb.checked = false;
});
updateDetailList();
collectCurrentStepData();
saveDraftSilently();
}
// 更新明细列表(显示所有选中实例的明细)
function updateDetailList() {
const container = document.getElementById('detailListContainer');
const tbody = document.getElementById('detailList');
const emptyDiv = document.getElementById('detailListEmpty');
const countSpan = document.getElementById('selectedInstanceCount');
if (formData.selectedInstances.length === 0) {
container.style.display = 'none';
return;
}
container.style.display = 'block';
countSpan.textContent = formData.selectedInstances.length;
tbody.innerHTML = '';
// 收集所有选中实例的明细
let allDetails = [];
formData.selectedInstances.forEach(instance => {
// 模拟数据实际应该从后端API获取
const mockDetails = [
{ id: `${instance.id}-d1`, name: '明细项1', quantity: 100, unit: '件', paidQuantity: 0, status: 'incomplete', note: '第一批采购' },
{ id: `${instance.id}-d2`, name: '明细项2', quantity: 50, unit: '套', paidQuantity: 30, status: 'incomplete', note: '第二批采购' },
{ id: `${instance.id}-d3`, name: '明细项3', quantity: 200, unit: '个', paidQuantity: 200, status: 'completed', note: '第三批采购' },
{ id: `${instance.id}-d4`, name: '明细项4', quantity: 80, unit: '台', paidQuantity: 0, status: 'incomplete', note: '第四批采购' }
];
mockDetails.forEach(detail => {
allDetails.push({
...detail,
instanceId: instance.id,
instanceName: instance.name
});
});
});
if (allDetails.length === 0) {
emptyDiv.style.display = 'block';
return;
}
emptyDiv.style.display = 'none';
// 显示所有明细
allDetails.forEach(detail => {
// 检查该明细是否已被选中从所有实例的detailIds中查找
const instance = formData.selectedInstances.find(inst => inst.id === detail.instanceId);
const isSelected = instance && instance.detailIds && instance.detailIds.includes(detail.id);
const isCompleted = detail.status === 'completed';
const canSelect = !isCompleted;
// 获取本次支付数量(如果已选择)
const detailData = instance && instance.detailData ? instance.detailData.find(d => d.id === detail.id) : null;
const paymentQuantity = detailData ? detailData.paymentQuantity : '';
const tr = document.createElement('tr');
if (isCompleted) {
tr.style.opacity = '0.6';
tr.style.backgroundColor = '#f5f5f5';
}
tr.innerHTML = `
<td>
<input type="checkbox" value="${detail.id}"
data-instance-id="${detail.instanceId}"
${isSelected ? 'checked' : ''}
${canSelect ? '' : 'disabled'}
onchange="toggleDetail('${detail.id}', '${detail.instanceId}')">
</td>
<td>${detail.instanceName}</td>
<td>${detail.name}</td>
<td>${detail.quantity.toLocaleString()}</td>
<td>${detail.unit}</td>
<td>${detail.paidQuantity.toLocaleString()}</td>
<td>
${isSelected ? `
<input type="number"
class="form-control form-control-sm"
id="paymentQuantity_${detail.id}"
value="${paymentQuantity}"
min="0"
max="${detail.quantity - detail.paidQuantity}"
step="0.01"
onchange="updatePaymentQuantity('${detail.id}', '${detail.instanceId}', this.value)"
style="width: 100px;">
` : '<span class="text-muted">-</span>'}
</td>
<td>
<span class="status-badge ${isCompleted ? 'status-completed' : 'status-pending'}">
${isCompleted ? '已完成' : '未完成'}
</span>
</td>
<td>${detail.note}</td>
`;
tbody.appendChild(tr);
});
}
// 切换明细选择
function toggleDetail(detailId, instanceId) {
const instance = formData.selectedInstances.find(inst => inst.id === instanceId);
if (!instance) return;
if (!instance.detailIds) {
instance.detailIds = [];
}
if (!instance.detailData) {
instance.detailData = [];
}
const checkbox = document.querySelector(`#detailList input[value="${detailId}"]`);
const isChecked = checkbox.checked;
if (isChecked) {
// 选中:添加到列表
if (!instance.detailIds.includes(detailId)) {
instance.detailIds.push(detailId);
// 初始化本次支付数量数据
instance.detailData.push({
id: detailId,
paymentQuantity: ''
});
}
} else {
// 取消选中:从列表移除
const index = instance.detailIds.indexOf(detailId);
if (index > -1) {
instance.detailIds.splice(index, 1);
}
// 移除支付数量数据
const dataIndex = instance.detailData.findIndex(d => d.id === detailId);
if (dataIndex > -1) {
instance.detailData.splice(dataIndex, 1);
}
}
// 重新渲染明细列表以显示/隐藏输入框
updateDetailList();
// 自动保存
collectCurrentStepData();
saveDraftSilently();
}
// 更新本次支付数量
function updatePaymentQuantity(detailId, instanceId, quantity) {
const instance = formData.selectedInstances.find(inst => inst.id === instanceId);
if (!instance) return;
if (!instance.detailData) {
instance.detailData = [];
}
const detailData = instance.detailData.find(d => d.id === detailId);
if (detailData) {
detailData.paymentQuantity = quantity;
} else {
instance.detailData.push({
id: detailId,
paymentQuantity: quantity
});
}
// 自动保存
collectCurrentStepData();
saveDraftSilently();
}
// 全选/取消全选明细
function toggleAllDetails() {
const selectAll = document.getElementById('selectAllDetails');
const checkboxes = document.querySelectorAll('#detailList input[type="checkbox"]:not(:disabled)');
checkboxes.forEach(cb => {
cb.checked = selectAll.checked;
const detailId = cb.value;
const instanceId = cb.getAttribute('data-instance-id');
toggleDetail(detailId, instanceId);
});
}
// 全选明细
function selectAllDetails() {
document.getElementById('selectAllDetails').checked = true;
toggleAllDetails();
}
// 清空所有明细
function clearAllDetails() {
formData.selectedInstances.forEach(instance => {
instance.detailIds = [];
instance.detailData = [];
});
document.getElementById('selectAllDetails').checked = false;
document.querySelectorAll('#detailList input[type="checkbox"]').forEach(cb => {
cb.checked = false;
});
updateDetailList();
collectCurrentStepData();
saveDraftSilently();
}
// 选择流程实例(单条模式)
function selectProcessInstance(instanceId, instance) {
formData.selectedInstanceId = instanceId;
formData.selectedInstanceName = instance.name;
// 更新选中状态
document.querySelectorAll('#processInstanceList tr').forEach(tr => {
tr.classList.remove('selected');
});
event.currentTarget.classList.add('selected');
// 自动保存
collectCurrentStepData();
saveDraftSilently();
}
// 全选/取消全选明细
function toggleAllDetails() {
const selectAll = document.getElementById('selectAllDetails');
const checkboxes = document.querySelectorAll('#detailList input[type="checkbox"]');
checkboxes.forEach(cb => {
cb.checked = selectAll.checked;
});
}
// 获取状态文本
function getStatusText(status) {
const statusMap = {
'approved': '已批准',
'pending': '待审批',
'completed': '已完成',
'rejected': '已拒绝'
};
return statusMap[status] || status;
}
// 加载合同流程实例列表
function loadContractInstances() {
const tbody = document.getElementById('contractInstanceList');
const emptyDiv = document.getElementById('contractInstanceEmpty');
// 模拟数据实际应该从后端API获取
const mockContracts = [
{ id: 'c1', code: 'HT-2025-001', name: '办公设备采购合同', type: 'procurement', date: '2025-01-10', status: 'approved' },
{ id: 'c2', code: 'HT-2025-002', name: '服务器租赁合同', type: 'service', date: '2025-01-15', status: 'approved' },
{ id: 'c3', code: 'HT-2025-003', name: '系统开发合同', type: 'service', date: '2025-01-20', status: 'approved' }
];
tbody.innerHTML = '';
if (mockContracts.length === 0) {
emptyDiv.style.display = 'block';
return;
}
emptyDiv.style.display = 'none';
mockContracts.forEach(contract => {
const tr = document.createElement('tr');
tr.onclick = () => selectContractInstance(contract.id, contract);
tr.innerHTML = `
<td>
<input type="radio" name="contractInstance" value="${contract.id}"
${formData.contractInstanceId === contract.id ? 'checked' : ''}>
</td>
<td>${contract.code}</td>
<td>${contract.name}</td>
<td>${getContractTypeText(contract.type)}</td>
<td>${contract.date}</td>
<td><span class="status-badge status-${contract.status}">${getStatusText(contract.status)}</span></td>
`;
tbody.appendChild(tr);
});
}
// 获取合同类型文本
function getContractTypeText(type) {
const typeMap = {
'procurement': '采购合同',
'service': '服务合同',
'construction': '工程合同',
'other': '其他'
};
return typeMap[type] || type;
}
// 选择合同流程实例
function selectContractInstance(contractId, contract) {
formData.contractInstanceId = contractId;
formData.contractInstanceName = contract.name;
// 更新选中状态
document.querySelectorAll('#contractInstanceList tr').forEach(tr => {
tr.classList.remove('selected');
});
event.currentTarget.classList.add('selected');
// 显示合同基本信息录入区域
document.getElementById('contractInfoSection').style.display = 'block';
// 如果已有保存的合同信息,恢复数据
if (formData.contractInfo && formData.contractInfo.contractNumber) {
restoreContractInfo();
} else {
// 填充合同实例的基本信息
document.getElementById('contractInfoNumber').value = contract.code;
document.getElementById('contractInfoName').value = contract.name;
if (contract.type) {
document.getElementById('contractInfoType').value = contract.type;
}
}
// 自动保存
collectCurrentStepData();
saveDraftSilently();
}
// 恢复合同信息
function restoreContractInfo() {
const info = formData.contractInfo;
if (info.contractNumber) document.getElementById('contractInfoNumber').value = info.contractNumber;
if (info.contractName) document.getElementById('contractInfoName').value = info.contractName;
if (info.contractType) document.getElementById('contractInfoType').value = info.contractType;
if (info.contractDate) document.getElementById('contractInfoDate').value = info.contractDate;
if (info.contractAmount) document.getElementById('contractInfoAmount').value = info.contractAmount;
if (info.contractPeriod) document.getElementById('contractInfoPeriod').value = info.contractPeriod;
if (info.contractPartyA) document.getElementById('contractInfoPartyA').value = info.contractPartyA;
if (info.contractPartyB) document.getElementById('contractInfoPartyB').value = info.contractPartyB;
if (info.contractContent) document.getElementById('contractInfoContent').value = info.contractContent;
if (info.contractRemark) document.getElementById('contractInfoRemark').value = info.contractRemark;
}
// 处理金额输入
function handleAmountInput() {
const amountInput = document.getElementById('amountInput');
const amount = parseFloat(amountInput.value);
const rangeDisplay = document.getElementById('amountRangeDisplay');
if (!amount || amount <= 0) {
rangeDisplay.style.display = 'none';
formData.amountRange = '';
return;
}
// 自动匹配金额区间
let range = '';
let rangeTitle = '';
let rangeDesc = '';
if (amount < 50000) {
range = 'under-5';
rangeTitle = '5万元以下';
rangeDesc = '< ¥50,000';
} else if (amount >= 50000 && amount < 100000) {
range = '5-10';
rangeTitle = '5-10万不含';
rangeDesc = '¥50,000 - ¥100,000';
} else if (amount >= 100000 && amount < 300000) {
range = '10-30';
rangeTitle = '10-30万不含';
rangeDesc = '¥100,000 - ¥300,000';
} else {
range = 'over-30';
rangeTitle = '30万元及以上';
rangeDesc = '≥ ¥300,000';
}
// 更新显示
document.getElementById('rangeTitle').textContent = rangeTitle;
document.getElementById('rangeDesc').textContent = rangeDesc;
rangeDisplay.style.display = 'block';
// 保存金额和区间
formData.amountRange = range;
formData.inputAmount = amount;
// 显示流程提示
showProcessHint();
// 自动保存
collectCurrentStepData();
saveDraftSilently();
}
// 选择金额范围(保留用于兼容)
function selectAmount(range) {
formData.amountRange = range;
// 显示流程提示
showProcessHint();
// 自动保存
collectCurrentStepData();
saveDraftSilently();
// 如果金额不超过10万跳过招标类型选择
if (range === 'under-5' || range === '5-10') {
formData.biddingType = '';
setTimeout(() => {
currentStep = 3;
updateStepDisplay();
updateUploadRequirements();
updateButtons();
}, 300);
} else {
setTimeout(() => nextStep(), 300);
}
}
// 选择招标类型
function selectBidding(type) {
formData.biddingType = type;
document.querySelectorAll('#step4 .option-card').forEach(card => {
card.classList.remove('selected');
});
event.currentTarget.classList.add('selected');
// 显示流程提示
showProcessHint();
// 自动保存
collectCurrentStepData();
saveDraftSilently();
setTimeout(() => nextStep(), 300);
}
// 显示流程提示
function showProcessHint() {
const hintDiv = document.getElementById('processHint');
const hintSteps = document.getElementById('hintSteps');
hintSteps.innerHTML = '';
const range = formData.amountRange;
const bidding = formData.biddingType;
if (range === 'under-5' || range === '5-10') {
hintSteps.innerHTML = '<li><i class="bi bi-check-circle"></i> 中心主任会会议纪要</li><li><i class="bi bi-check-circle"></i> 申请</li><li><i class="bi bi-check-circle"></i> 支付</li>';
hintDiv.style.display = 'block';
} else if (range === '10-30') {
hintSteps.innerHTML = '<li><i class="bi bi-check-circle"></i> 支委会会议纪要</li><li><i class="bi bi-check-circle"></i> 申请</li><li><i class="bi bi-check-circle"></i> 支付</li>';
hintDiv.style.display = 'block';
} else if (range === 'over-30') {
if (bidding === 'public') {
hintSteps.innerHTML = '<li><i class="bi bi-check-circle"></i> 中心主任会会议纪要 或 支委会会议纪要</li><li><i class="bi bi-check-circle"></i> 申请</li><li><i class="bi bi-check-circle"></i> 支付</li>';
} else if (bidding === 'non-public') {
hintSteps.innerHTML = '<li><i class="bi bi-check-circle"></i> 支委会会议纪要 或 政府采购省厅审批表</li><li><i class="bi bi-check-circle"></i> 申请</li><li><i class="bi bi-check-circle"></i> 支付</li>';
}
hintDiv.style.display = 'block';
} else {
hintDiv.style.display = 'none';
}
}
// 更新上传要求
function updateUploadRequirements() {
const uploadSteps = document.getElementById('uploadSteps');
uploadSteps.innerHTML = '';
const range = formData.amountRange;
const bidding = formData.biddingType;
if (range === 'under-5' || range === '5-10') {
uploadSteps.innerHTML = '<li><i class="bi bi-file-earmark"></i> 中心主任会会议纪要</li>';
} else if (range === '10-30') {
uploadSteps.innerHTML = '<li><i class="bi bi-file-earmark"></i> 支委会会议纪要</li>';
} else if (range === 'over-30') {
if (bidding === 'public') {
uploadSteps.innerHTML = '<li><i class="bi bi-file-earmark"></i> 中心主任会会议纪要 或 支委会会议纪要(二选一)</li>';
} else if (bidding === 'non-public') {
uploadSteps.innerHTML = '<li><i class="bi bi-file-earmark"></i> 支委会会议纪要 或 政府采购省厅审批表(二选一)</li>';
}
}
}
// 下一步
function nextStep() {
// 步骤1验证检查是否选择了流程类型
if (currentStep === 1) {
if (!formData.processType) {
showToast('请选择事前流程类型', 'error');
return;
}
}
// 步骤2验证检查是否选择了流程实例
if (currentStep === 2) {
if (formData.paymentMode === 'single') {
// 单条模式
if (!formData.selectedInstanceId) {
showToast('请选择流程实例', 'error');
return;
}
} else {
// 批量模式
if (!formData.selectedInstances || formData.selectedInstances.length === 0) {
showToast('请至少选择一个流程实例', 'error');
return;
}
// 检查每个实例是否都选择了明细
const hasEmptyDetails = formData.selectedInstances.some(inst =>
!inst.detailIds || inst.detailIds.length === 0
);
if (hasEmptyDetails) {
showToast('请为每个流程实例至少选择一条明细数据', 'error');
return;
}
// 检查是否填写了本次支付数量
const hasEmptyQuantity = formData.selectedInstances.some(inst => {
if (!inst.detailData) return false;
return inst.detailData.some(d => {
if (!inst.detailIds.includes(d.id)) return false;
return !d.paymentQuantity || d.paymentQuantity === '';
});
});
if (hasEmptyQuantity) {
showToast('请填写所有选中明细的本次支付数量', 'error');
return;
}
}
}
// 步骤3验证检查是否输入了金额
if (currentStep === 3) {
const amountInput = document.getElementById('amountInput');
if (!amountInput.value || parseFloat(amountInput.value) <= 0) {
amountInput.focus();
showToast('请输入有效的支付金额', 'error');
return;
}
if (!formData.amountRange) {
handleAmountInput();
}
// 如果金额不超过10万跳过招标类型选择和合同流程
if (formData.amountRange === 'under-5' || formData.amountRange === '5-10') {
formData.biddingType = '';
formData.contractInstanceId = '';
formData.contractInfo = {};
currentStep = 6; // 跳过步骤4招标流程和步骤5合同流程直接到步骤6上传材料
updateStepDisplay();
updateUploadRequirements();
updateButtons();
return;
}
}
if (currentStep === 4) {
showProcessHint();
}
if (currentStep === 5) {
// 验证合同流程实例和基本信息
if (!formData.contractInstanceId) {
showToast('请选择合同流程实例', 'error');
return;
}
const contractForm = document.getElementById('contractInfoForm');
if (!contractForm.checkValidity()) {
contractForm.reportValidity();
return;
}
// 收集合同基本信息
formData.contractInfo = {
contractNumber: document.getElementById('contractInfoNumber').value,
contractName: document.getElementById('contractInfoName').value,
contractType: document.getElementById('contractInfoType').value,
contractDate: document.getElementById('contractInfoDate').value,
contractAmount: document.getElementById('contractInfoAmount').value,
contractPeriod: document.getElementById('contractInfoPeriod').value,
contractPartyA: document.getElementById('contractInfoPartyA').value,
contractPartyB: document.getElementById('contractInfoPartyB').value,
contractContent: document.getElementById('contractInfoContent').value,
contractRemark: document.getElementById('contractInfoRemark').value
};
// 自动保存
saveDraftSilently();
}
if (currentStep === 6) {
updateUploadRequirements();
}
if (currentStep === 7) {
// 验证表单
const form = document.getElementById('paymentForm');
if (!form.checkValidity()) {
form.reportValidity();
return;
}
// 收集表单数据
formData.paymentItem = document.getElementById('paymentItem').value;
formData.paymentAmount = document.getElementById('paymentAmount').value;
formData.payee = document.getElementById('payee').value;
formData.accountNumber = document.getElementById('accountNumber').value;
formData.bankName = document.getElementById('bankName').value;
formData.paymentMethod = document.getElementById('paymentMethod').value;
formData.paymentDescription = document.getElementById('paymentDescription').value;
formData.contractNumber = document.getElementById('contractNumber').value;
// 自动保存
saveDraftSilently();
// 更新确认页面
updateSummary();
}
if (currentStep < totalSteps) {
// 隐藏当前步骤
document.getElementById(`step${currentStep}`).classList.remove('active');
document.querySelector(`.wizard-step[data-step="${currentStep}"]`).classList.remove('active');
document.querySelector(`.wizard-step[data-step="${currentStep}"]`).classList.add('completed');
// 显示下一步
currentStep++;
document.getElementById(`step${currentStep}`).classList.add('active');
document.querySelector(`.wizard-step[data-step="${currentStep}"]`).classList.add('active');
// 更新按钮
updateButtons();
}
}
// 上一步
function prevStep() {
if (currentStep > 1) {
// 隐藏当前步骤
document.getElementById(`step${currentStep}`).classList.remove('active');
document.querySelector(`.wizard-step[data-step="${currentStep}"]`).classList.remove('active');
document.querySelector(`.wizard-step[data-step="${currentStep}"]`).classList.remove('completed');
// 显示上一步
currentStep--;
// 如果当前步骤是6且金额不超过10万应该返回到步骤3跳过步骤4和5
if (currentStep === 5 && (formData.amountRange === 'under-5' || formData.amountRange === '5-10')) {
currentStep = 3;
} else if (currentStep === 4 && (formData.amountRange === 'under-5' || formData.amountRange === '5-10')) {
currentStep = 3;
}
document.getElementById(`step${currentStep}`).classList.add('active');
document.querySelector(`.wizard-step[data-step="${currentStep}"]`).classList.add('active');
document.querySelector(`.wizard-step[data-step="${currentStep + 1}"]`).classList.remove('completed');
// 更新按钮和步骤显示
updateStepDisplay();
updateButtons();
}
}
// 更新步骤显示
function updateStepDisplay() {
// 如果金额不超过10万步骤4招标流程和步骤5合同流程应该被跳过
const shouldSkipSteps = (formData.amountRange === 'under-5' || formData.amountRange === '5-10');
for (let i = 1; i <= totalSteps; i++) {
const stepContent = document.getElementById(`step${i}`);
const stepIndicator = document.querySelector(`.wizard-step[data-step="${i}"]`);
// 跳过步骤4和步骤5的处理
if ((i === 4 || i === 5) && shouldSkipSteps) {
stepContent.classList.remove('active');
stepIndicator.classList.remove('active', 'completed');
continue;
}
if (i < currentStep) {
stepContent.classList.remove('active');
stepIndicator.classList.remove('active');
stepIndicator.classList.add('completed');
} else if (i === currentStep) {
stepContent.classList.add('active');
stepIndicator.classList.add('active');
stepIndicator.classList.remove('completed');
} else {
stepContent.classList.remove('active');
stepIndicator.classList.remove('active', 'completed');
}
}
}
// 更新按钮状态
function updateButtons() {
const btnPrev = document.getElementById('btnPrev');
const btnNext = document.getElementById('btnNext');
const btnSubmit = document.getElementById('btnSubmit');
if (currentStep === 1) {
btnPrev.style.display = 'none';
btnNext.style.display = 'inline-block';
btnSubmit.style.display = 'none';
} else if (currentStep === totalSteps) {
btnPrev.style.display = 'inline-block';
btnNext.style.display = 'none';
btnSubmit.style.display = 'inline-block';
} else {
btnPrev.style.display = 'inline-block';
btnNext.style.display = 'inline-block';
btnSubmit.style.display = 'none';
}
// 隐藏步骤4招标流程和步骤5合同流程如果金额不超过10万
if (formData.amountRange === 'under-5' || formData.amountRange === '5-10') {
const step4Indicator = document.querySelector('.wizard-step[data-step="4"]');
const step5Indicator = document.querySelector('.wizard-step[data-step="5"]');
if (step4Indicator) step4Indicator.style.display = 'none';
if (step5Indicator) step5Indicator.style.display = 'none';
} else {
const step4Indicator = document.querySelector('.wizard-step[data-step="4"]');
const step5Indicator = document.querySelector('.wizard-step[data-step="5"]');
if (step4Indicator) step4Indicator.style.display = 'flex';
if (step5Indicator) step5Indicator.style.display = 'flex';
}
}
// 更新确认信息
function updateSummary() {
// 添加流程类型和支付方式到确认页面
const summaryCard = document.querySelector('#step8 .summary-card');
if (summaryCard) {
// 检查是否已有流程类型和支付方式项,如果没有则添加
let processTypeItem = document.getElementById('summaryProcessType');
if (!processTypeItem) {
const firstItem = summaryCard.querySelector('.summary-item');
const processTypeDiv = document.createElement('div');
processTypeDiv.className = 'summary-item';
processTypeDiv.id = 'summaryProcessType';
processTypeDiv.innerHTML = '<span class="summary-label">事前流程类型</span><span class="summary-value" id="summaryProcessTypeValue">-</span>';
summaryCard.insertBefore(processTypeDiv, firstItem);
}
document.getElementById('summaryProcessTypeValue').textContent = processTypeMap[formData.processType] || '-';
let paymentModeItem = document.getElementById('summaryPaymentMode');
if (!paymentModeItem) {
const processTypeItem = document.getElementById('summaryProcessType');
const paymentModeDiv = document.createElement('div');
paymentModeDiv.className = 'summary-item';
paymentModeDiv.id = 'summaryPaymentMode';
paymentModeDiv.innerHTML = '<span class="summary-label">支付方式</span><span class="summary-value" id="summaryPaymentModeValue">-</span>';
summaryCard.insertBefore(paymentModeDiv, processTypeItem.nextSibling);
}
document.getElementById('summaryPaymentModeValue').textContent = paymentModeMap[formData.paymentMode] || '-';
// 添加流程实例信息
let instanceItem = document.getElementById('summaryInstance');
if (!instanceItem) {
const paymentModeItem = document.getElementById('summaryPaymentMode');
const instanceDiv = document.createElement('div');
instanceDiv.className = 'summary-item';
instanceDiv.id = 'summaryInstance';
instanceDiv.innerHTML = '<span class="summary-label">流程实例</span><span class="summary-value" id="summaryInstanceValue">-</span>';
summaryCard.insertBefore(instanceDiv, paymentModeItem.nextSibling);
}
document.getElementById('summaryInstanceValue').textContent = formData.selectedInstanceName || '-';
// 批量模式显示明细信息
if (formData.paymentMode === 'batch' && formData.selectedInstances && formData.selectedInstances.length > 0) {
let detailItem = document.getElementById('summaryDetails');
if (!detailItem) {
const instanceItem = document.getElementById('summaryInstance');
const detailDiv = document.createElement('div');
detailDiv.className = 'summary-item';
detailDiv.id = 'summaryDetails';
detailDiv.innerHTML = '<span class="summary-label">选中实例及明细</span><span class="summary-value" id="summaryDetailsValue">-</span>';
summaryCard.insertBefore(detailDiv, instanceItem.nextSibling);
}
const totalInstances = formData.selectedInstances.length;
const totalDetails = formData.selectedInstances.reduce((sum, inst) => sum + (inst.detailIds ? inst.detailIds.length : 0), 0);
document.getElementById('summaryDetailsValue').textContent = `${totalInstances} 个实例,共 ${totalDetails} 条明细`;
document.getElementById('summaryDetails').style.display = 'flex';
// 更新实例名称显示
const instanceNames = formData.selectedInstances.map(inst => inst.name).join('、');
document.getElementById('summaryInstanceValue').textContent = instanceNames;
} else {
const detailItem = document.getElementById('summaryDetails');
if (detailItem) {
detailItem.style.display = 'none';
}
}
}
document.getElementById('summaryAmountRange').textContent = amountRangeMap[formData.amountRange] || '-';
// 显示招标类型
if (formData.biddingType) {
document.getElementById('summaryBiddingItem').style.display = 'flex';
document.getElementById('summaryBidding').textContent = biddingTypeMap[formData.biddingType] || '-';
} else {
document.getElementById('summaryBiddingItem').style.display = 'none';
}
// 显示合同流程信息
if (formData.contractInstanceId && formData.contractInfo) {
let contractItem = document.getElementById('summaryContract');
if (!contractItem) {
const biddingItem = document.getElementById('summaryBiddingItem');
const contractDiv = document.createElement('div');
contractDiv.className = 'summary-item';
contractDiv.id = 'summaryContract';
contractDiv.innerHTML = '<span class="summary-label">合同流程</span><span class="summary-value" id="summaryContractValue">-</span>';
if (biddingItem && biddingItem.style.display !== 'none') {
summaryCard.insertBefore(contractDiv, biddingItem.nextSibling);
} else {
const amountRangeItem = summaryCard.querySelector('#summaryAmountRange').closest('.summary-item');
summaryCard.insertBefore(contractDiv, amountRangeItem.nextSibling);
}
}
const contractInfo = formData.contractInfo;
const contractText = `${contractInfo.contractName || formData.contractInstanceName}${contractInfo.contractNumber || '-'}`;
document.getElementById('summaryContractValue').textContent = contractText;
document.getElementById('summaryContract').style.display = 'flex';
} else {
const contractItem = document.getElementById('summaryContract');
if (contractItem) {
contractItem.style.display = 'none';
}
}
document.getElementById('summaryItem').textContent = formData.paymentItem || '-';
document.getElementById('summaryAmount').textContent = '¥' + (parseFloat(formData.paymentAmount).toLocaleString() || '-');
document.getElementById('summaryPayee').textContent = formData.payee || '-';
document.getElementById('summaryAccount').textContent = formData.accountNumber || '-';
document.getElementById('summaryBank').textContent = formData.bankName || '-';
}
// 暂存数据(带提示)
function saveDraft() {
// 收集当前步骤的所有数据
collectCurrentStepData();
const draftData = {
currentStep: currentStep,
formData: formData,
timestamp: new Date().toISOString()
};
try {
localStorage.setItem('beijingPaymentDraft', JSON.stringify(draftData));
// 显示成功提示
showToast('暂存成功!', 'success');
} catch (e) {
console.error('暂存失败:', e);
showToast('暂存失败,请重试', 'error');
}
}
// 静默暂存(不显示提示)
function saveDraftSilently() {
collectCurrentStepData();
const draftData = {
currentStep: currentStep,
formData: formData,
timestamp: new Date().toISOString()
};
try {
localStorage.setItem('beijingPaymentDraft', JSON.stringify(draftData));
} catch (e) {
console.error('暂存失败:', e);
}
}
// 收集当前步骤的数据
function collectCurrentStepData() {
// 步骤1的数据在选择时已收集包括自动决定的支付方式
// 收集步骤3的数据金额输入
if (currentStep >= 3) {
const amountInput = document.getElementById('amountInput');
if (amountInput && amountInput.value) {
formData.inputAmount = amountInput.value;
if (!formData.amountRange) {
handleAmountInput();
}
}
}
// 收集步骤4的数据招标类型
if (formData.biddingType) {
// 已收集
}
// 收集步骤5的数据合同信息
if (currentStep >= 5) {
const contractForm = document.getElementById('contractInfoForm');
if (contractForm && formData.contractInstanceId) {
formData.contractInfo = {
contractNumber: document.getElementById('contractInfoNumber').value,
contractName: document.getElementById('contractInfoName').value,
contractType: document.getElementById('contractInfoType').value,
contractDate: document.getElementById('contractInfoDate').value,
contractAmount: document.getElementById('contractInfoAmount').value,
contractPeriod: document.getElementById('contractInfoPeriod').value,
contractPartyA: document.getElementById('contractInfoPartyA').value,
contractPartyB: document.getElementById('contractInfoPartyB').value,
contractContent: document.getElementById('contractInfoContent').value,
contractRemark: document.getElementById('contractInfoRemark').value
};
}
}
// 收集步骤6的数据文件上传 - 文件名)
const directorMeeting = document.getElementById('directorMeeting');
const committeeMeeting = document.getElementById('committeeMeeting');
const provincialApproval = document.getElementById('provincialApproval');
if (directorMeeting && directorMeeting.files.length > 0) {
formData.directorMeetingFileName = directorMeeting.files[0].name;
}
if (committeeMeeting && committeeMeeting.files.length > 0) {
formData.committeeMeetingFileName = committeeMeeting.files[0].name;
}
if (provincialApproval && provincialApproval.files.length > 0) {
formData.provincialApprovalFileName = provincialApproval.files[0].name;
}
// 收集步骤7的数据表单信息
if (currentStep >= 7) {
const paymentItem = document.getElementById('paymentItem');
const paymentAmount = document.getElementById('paymentAmount');
const payee = document.getElementById('payee');
const accountNumber = document.getElementById('accountNumber');
const bankName = document.getElementById('bankName');
const paymentMethod = document.getElementById('paymentMethod');
const paymentDescription = document.getElementById('paymentDescription');
const contractNumber = document.getElementById('contractNumber');
if (paymentItem) formData.paymentItem = paymentItem.value;
if (paymentAmount) formData.paymentAmount = paymentAmount.value;
if (payee) formData.payee = payee.value;
if (accountNumber) formData.accountNumber = accountNumber.value;
if (bankName) formData.bankName = bankName.value;
if (paymentMethod) formData.paymentMethod = paymentMethod.value;
if (paymentDescription) formData.paymentDescription = paymentDescription.value;
if (contractNumber) formData.contractNumber = contractNumber.value;
}
}
// 加载暂存数据从URL参数或消息触发
function loadDraft() {
try {
const draftStr = localStorage.getItem('beijingPaymentDraft');
if (!draftStr) {
return;
}
const draftData = JSON.parse(draftStr);
// 恢复步骤
currentStep = draftData.currentStep || 1;
// 恢复表单数据
if (draftData.formData) {
formData = { ...formData, ...draftData.formData };
}
// 恢复UI状态
restoreUIState();
showToast('暂存数据已恢复', 'success');
} catch (e) {
console.error('加载暂存数据失败:', e);
showToast('恢复暂存数据失败', 'error');
}
}
// 恢复UI状态
function restoreUIState() {
// 恢复步骤1流程类型选择
if (formData.processType) {
const processCards = document.querySelectorAll('#step1 .option-card');
processCards.forEach(card => {
card.classList.remove('selected');
const onclick = card.getAttribute('onclick');
if (onclick && onclick.includes(formData.processType)) {
card.classList.add('selected');
}
});
}
// 恢复步骤2金额输入
if (formData.inputAmount) {
const amountInput = document.getElementById('amountInput');
if (amountInput) {
amountInput.value = formData.inputAmount;
handleAmountInput();
}
}
// 恢复步骤2流程实例选择
if (formData.processType) {
showProcessInstanceSelection();
if (formData.paymentMode === 'batch' && formData.selectedInstances.length > 0) {
updateDetailList();
}
}
// 恢复步骤4招标类型选择
if (formData.biddingType) {
const biddingCards = document.querySelectorAll('#step4 .option-card');
biddingCards.forEach(card => {
card.classList.remove('selected');
const onclick = card.getAttribute('onclick');
if (onclick && onclick.includes(formData.biddingType)) {
card.classList.add('selected');
}
});
showProcessHint();
}
// 恢复步骤5合同流程
if (formData.contractInstanceId) {
loadContractInstances();
setTimeout(() => {
const contract = { id: formData.contractInstanceId, name: formData.contractInstanceName };
selectContractInstance(formData.contractInstanceId, contract);
}, 100);
}
// 恢复步骤6文件上传 - 仅显示文件名,实际文件无法恢复)
// 注意:由于浏览器安全限制,无法恢复文件对象,只能显示文件名提示
// 恢复步骤7表单信息
if (formData.paymentItem) {
const paymentItem = document.getElementById('paymentItem');
if (paymentItem) paymentItem.value = formData.paymentItem;
}
if (formData.paymentAmount) {
const paymentAmount = document.getElementById('paymentAmount');
if (paymentAmount) paymentAmount.value = formData.paymentAmount;
}
if (formData.payee) {
const payee = document.getElementById('payee');
if (payee) payee.value = formData.payee;
}
if (formData.accountNumber) {
const accountNumber = document.getElementById('accountNumber');
if (accountNumber) accountNumber.value = formData.accountNumber;
}
if (formData.bankName) {
const bankName = document.getElementById('bankName');
if (bankName) bankName.value = formData.bankName;
}
if (formData.paymentMethod) {
const paymentMethod = document.getElementById('paymentMethod');
if (paymentMethod) paymentMethod.value = formData.paymentMethod;
}
if (formData.paymentDescription) {
const paymentDescription = document.getElementById('paymentDescription');
if (paymentDescription) paymentDescription.value = formData.paymentDescription;
}
if (formData.contractNumber) {
const contractNumber = document.getElementById('contractNumber');
if (contractNumber) contractNumber.value = formData.contractNumber;
}
// 更新步骤显示
updateStepDisplay();
updateUploadRequirements();
updateButtons();
// 如果恢复到步骤8更新确认信息
if (currentStep === 8) {
updateSummary();
}
}
// 显示提示消息
function showToast(message, type = 'info') {
// 简单的提示实现
const bgColor = type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : '#3b82f6';
const toast = document.createElement('div');
toast.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: ${bgColor};
color: white;
padding: 12px 20px;
border-radius: 6px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
z-index: 9999;
animation: slideIn 0.3s ease-out;
`;
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => {
toast.style.animation = 'slideOut 0.3s ease-out';
setTimeout(() => {
document.body.removeChild(toast);
}, 300);
}, 2000);
}
// 提交支付
function submitPayment() {
if (confirm('确定要提交支付申请吗?')) {
// 这里应该调用后端API提交数据
console.log('提交支付数据:', formData);
// 提交成功后清除暂存数据
clearDraft();
alert('支付申请提交成功!');
// 可以跳转到支付查询页面
// parent.loadPage('pages/payment/process-query.html');
}
}
// 防抖函数
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// 自动保存(防抖版本)
const autoSave = debounce(() => {
if (currentStep >= 7) {
saveDraftSilently();
}
}, 1000);
// 合同信息自动保存
const contractAutoSave = debounce(() => {
if (currentStep === 5 && formData.contractInstanceId) {
collectCurrentStepData();
saveDraftSilently();
}
}, 1000);
// 页面加载时绑定自动保存
document.addEventListener('DOMContentLoaded', function() {
// 检查URL参数如果需要恢复暂存
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('restore') === 'true') {
loadDraft();
}
// 监听来自父窗口的消息
window.addEventListener('message', function(event) {
if (event.data && event.data.action === 'restoreDraft' && event.data.draftType === 'beijing') {
loadDraft();
}
});
// 为表单输入绑定自动保存
const formInputs = document.querySelectorAll('#paymentForm input, #paymentForm textarea, #paymentForm select');
formInputs.forEach(input => {
input.addEventListener('input', autoSave);
input.addEventListener('change', autoSave);
});
// 为合同信息表单绑定自动保存
const contractInputs = document.querySelectorAll('#contractInfoForm input, #contractInfoForm textarea, #contractInfoForm select');
contractInputs.forEach(input => {
input.addEventListener('input', contractAutoSave);
input.addEventListener('change', contractAutoSave);
});
// 初始化按钮状态
updateButtons();
// 加载合同实例列表
loadContractInstances();
});
</script>
</body>
</html>