|
|
<!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>
|
|
|
|