|
|
|
|
|
<!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 rel="stylesheet" href="https://cdn.staticfile.org/bootstrap/5.3.0/css/bootstrap.min.css">
|
|
|
|
|
|
<link rel="stylesheet" href="https://cdn.staticfile.org/bootstrap-icons/1.11.0/font/bootstrap-icons.min.css">
|
|
|
|
|
|
<style>
|
|
|
|
|
|
:root {
|
|
|
|
|
|
--panel-bg: #fff;
|
|
|
|
|
|
--border: #e5e7eb;
|
|
|
|
|
|
--muted: #6b7280;
|
|
|
|
|
|
--primary: #4f46e5;
|
|
|
|
|
|
--a4-width: 210mm;
|
|
|
|
|
|
--a4-height: 297mm;
|
|
|
|
|
|
}
|
|
|
|
|
|
* { box-sizing: border-box; }
|
|
|
|
|
|
body {
|
|
|
|
|
|
background: #f5f7fb;
|
|
|
|
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", sans-serif;
|
|
|
|
|
|
color: #111827;
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.layout {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 380px 1fr 400px;
|
|
|
|
|
|
grid-template-rows: 1fr;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
height: calc(100vh - 60px);
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bottom-toolbar {
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
background: var(--panel-bg);
|
|
|
|
|
|
border-top: 1px solid var(--border);
|
|
|
|
|
|
padding: 10px 20px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
box-shadow: 0 -2px 8px rgba(0,0,0,0.04);
|
|
|
|
|
|
z-index: 100;
|
|
|
|
|
|
}
|
|
|
|
|
|
.panel {
|
|
|
|
|
|
background: var(--panel-bg);
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
|
box-shadow: 0 4px 16px rgba(0,0,0,0.05);
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
.panel-header {
|
|
|
|
|
|
padding: 12px 14px;
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #374151;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.panel-body { padding: 12px; overflow: auto; }
|
|
|
|
|
|
|
|
|
|
|
|
/* 分支配置区域 */
|
|
|
|
|
|
.branch-config-section {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.branch-list-table {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.branch-list-table table {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
border-collapse: collapse;
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.branch-list-table th {
|
|
|
|
|
|
background: #f9fafb;
|
|
|
|
|
|
padding: 8px 6px;
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
.branch-list-table td {
|
|
|
|
|
|
padding: 6px;
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
.branch-list-table tbody tr {
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: background 0.2s;
|
|
|
|
|
|
}
|
|
|
|
|
|
.branch-list-table tbody tr:hover {
|
|
|
|
|
|
background: #f3f4f6;
|
|
|
|
|
|
}
|
|
|
|
|
|
.branch-list-table tbody tr.active {
|
|
|
|
|
|
background: #eef2ff;
|
|
|
|
|
|
border-left: 3px solid var(--primary);
|
|
|
|
|
|
}
|
|
|
|
|
|
.branch-badge {
|
|
|
|
|
|
display: inline-block;
|
|
|
|
|
|
padding: 2px 6px;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
font-size: 10px;
|
|
|
|
|
|
background: #eef2ff;
|
|
|
|
|
|
color: var(--primary);
|
|
|
|
|
|
margin: 1px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.condition-editor {
|
|
|
|
|
|
background: #f9fafb;
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.condition-row {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 100px 1fr 80px;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* A4画布区域 */
|
|
|
|
|
|
.canvas-wrapper {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
overflow: auto;
|
|
|
|
|
|
background: #e5e7eb;
|
|
|
|
|
|
}
|
|
|
|
|
|
.a4-canvas {
|
|
|
|
|
|
width: var(--a4-width);
|
|
|
|
|
|
min-height: var(--a4-height);
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
|
|
|
|
|
|
padding: 20mm;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
.document-section {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
border: 1px dashed #d1d5db;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
min-height: 80px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.document-section:hover {
|
|
|
|
|
|
border-color: var(--primary);
|
|
|
|
|
|
background: #fafbff;
|
|
|
|
|
|
}
|
|
|
|
|
|
.section-header {
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
color: var(--primary);
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
padding-bottom: 8px;
|
|
|
|
|
|
border-bottom: 2px solid var(--primary);
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
.section-header .section-badge {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
padding: 2px 8px;
|
|
|
|
|
|
background: var(--primary);
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.field-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
.field-label {
|
|
|
|
|
|
min-width: 100px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: #374151;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.field-value {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
padding: 6px 10px;
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
background: #f9fafb;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
min-height: 32px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.field-value.empty {
|
|
|
|
|
|
color: #9ca3af;
|
|
|
|
|
|
font-style: italic;
|
|
|
|
|
|
}
|
|
|
|
|
|
.field-row {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 1fr 1fr;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.payment-round {
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
background: #f9fafb;
|
|
|
|
|
|
}
|
|
|
|
|
|
.payment-round-header {
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: var(--primary);
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 属性面板 */
|
|
|
|
|
|
.property-group {
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
background: #fafbff;
|
|
|
|
|
|
}
|
|
|
|
|
|
.property-group-title {
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
color: #374151;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.json-editor {
|
|
|
|
|
|
font-family: 'Courier New', monospace;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
min-height: 300px;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|
|
|
|
|
|
</head>
|
|
|
|
|
|
<body>
|
|
|
|
|
|
<div class="layout">
|
|
|
|
|
|
<!-- 左侧:分支配置区域 -->
|
|
|
|
|
|
<div class="panel">
|
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
|
<span>分支配置管理</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="panel-body">
|
|
|
|
|
|
<!-- 第一层:事前流程分类选择 -->
|
|
|
|
|
|
<div class="branch-config-section">
|
|
|
|
|
|
<div class="panel-header" style="padding: 8px 0; border-bottom: 1px solid var(--border); margin-bottom: 10px;">
|
|
|
|
|
|
<span style="font-size: 13px; font-weight: 600;">事前流程分类</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<select class="form-select form-select-sm mb-3" id="processCategorySelect" onchange="switchProcessCategory()">
|
|
|
|
|
|
<option value="">请选择分类</option>
|
|
|
|
|
|
<option value="采购管理">采购管理</option>
|
|
|
|
|
|
<option value="会议培训接待">会议、培训、接待</option>
|
|
|
|
|
|
<option value="车船管理及维修">车船管理及维修</option>
|
|
|
|
|
|
<option value="仪器管理">仪器管理</option>
|
|
|
|
|
|
<option value="出差管理">出差管理</option>
|
|
|
|
|
|
<option value="合同管理">合同管理</option>
|
|
|
|
|
|
<option value="安装维修">安装维修</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 第二层:该分类下的分支列表 -->
|
|
|
|
|
|
<div class="branch-config-section" id="branchListSection" style="display: none;">
|
|
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
|
|
|
|
<span style="font-size: 13px; font-weight: 600;">分支条件组合</span>
|
|
|
|
|
|
<button class="btn btn-sm btn-outline-primary" id="btnAddBranch" style="padding: 2px 8px; font-size: 11px;">
|
|
|
|
|
|
<i class="bi bi-plus"></i> 添加分支
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="branch-list-table">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th style="width: 30px;">#</th>
|
|
|
|
|
|
<th>条件组合</th>
|
|
|
|
|
|
<th style="width: 50px;">操作</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody id="branchListTableBody">
|
|
|
|
|
|
<!-- 动态生成 -->
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 第三层:当前分支条件设置 -->
|
|
|
|
|
|
<div class="branch-config-section" id="conditionSection" style="display: none;">
|
|
|
|
|
|
<div class="panel-header" style="padding: 8px 0; border-bottom: 1px solid var(--border); margin-bottom: 10px;">
|
|
|
|
|
|
<span style="font-size: 13px;">当前分支条件设置</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div id="conditionEditor">
|
|
|
|
|
|
<div class="condition-editor">
|
|
|
|
|
|
<div class="condition-row">
|
|
|
|
|
|
<label class="form-label small">合同分类</label>
|
|
|
|
|
|
<select class="form-select form-select-sm" id="condContractClass">
|
|
|
|
|
|
<option value="">全部</option>
|
|
|
|
|
|
<option value="合同类">合同类</option>
|
|
|
|
|
|
<option value="其他支出类">其他支出类</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<button class="btn btn-sm btn-outline-secondary" onclick="clearCondition('contract_classification')">清除</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="condition-row">
|
|
|
|
|
|
<label class="form-label small">事务类型</label>
|
|
|
|
|
|
<select class="form-select form-select-sm" id="condBusinessType">
|
|
|
|
|
|
<option value="">全部</option>
|
|
|
|
|
|
<option value="项目采购类">项目采购类</option>
|
|
|
|
|
|
<option value="信水借电类">信水借电类</option>
|
|
|
|
|
|
<option value="差旅报销">差旅报销</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<button class="btn btn-sm btn-outline-secondary" onclick="clearCondition('business_type')">清除</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="condition-row">
|
|
|
|
|
|
<label class="form-label small">合同类型</label>
|
|
|
|
|
|
<select class="form-select form-select-sm" id="condContractType">
|
|
|
|
|
|
<option value="">全部</option>
|
|
|
|
|
|
<option value="支出类">支出类</option>
|
|
|
|
|
|
<option value="收入类">收入类</option>
|
|
|
|
|
|
<option value="无费用发生类">无费用发生类</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<button class="btn btn-sm btn-outline-secondary" onclick="clearCondition('contract_type')">清除</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="condition-row">
|
|
|
|
|
|
<label class="form-label small">采购形式</label>
|
|
|
|
|
|
<select class="form-select form-select-sm" id="condProcurementMethod">
|
|
|
|
|
|
<option value="">全部</option>
|
|
|
|
|
|
<option value="政府采购">政府采购</option>
|
|
|
|
|
|
<option value="小型项目">小型项目</option>
|
|
|
|
|
|
<option value="直接发包">直接发包</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<button class="btn btn-sm btn-outline-secondary" onclick="clearCondition('procurement_method')">清除</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<button class="btn btn-primary btn-sm w-100 mt-2" onclick="applyConditions()">
|
|
|
|
|
|
<i class="bi bi-check-circle me-1"></i>应用条件
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 中间:A4画布区域 -->
|
|
|
|
|
|
<div class="panel">
|
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
|
<span>A4文档预览</span>
|
|
|
|
|
|
<span class="badge bg-info" id="canvasBranchBadge">全部可见</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="canvas-wrapper">
|
|
|
|
|
|
<div class="a4-canvas" id="a4Canvas">
|
|
|
|
|
|
<!-- 区域a:基本信息 -->
|
|
|
|
|
|
<div class="document-section" data-section="basic_info">
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span>a. 基本信息</span>
|
|
|
|
|
|
<span class="section-badge">基本信息</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div id="sectionBasicInfo" class="section-content">
|
|
|
|
|
|
<!-- 动态生成字段 -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 区域b:资金申请上会 -->
|
|
|
|
|
|
<div class="document-section" data-section="meeting_info">
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span>b. 资金申请上会</span>
|
|
|
|
|
|
<span class="section-badge">上会流程</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div id="sectionMeetingInfo" class="section-content">
|
|
|
|
|
|
<!-- 动态生成字段 -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 区域c:事前流程 -->
|
|
|
|
|
|
<div class="document-section" data-section="pre_approval">
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span>c. 事前流程</span>
|
|
|
|
|
|
<span class="section-badge">附件流程</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div id="sectionPreApproval" class="section-content">
|
|
|
|
|
|
<!-- 动态生成字段 -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 区域d:支付流程 -->
|
|
|
|
|
|
<div class="document-section" data-section="payment">
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
<span>d. 支付流程</span>
|
|
|
|
|
|
<span class="section-badge">多轮次支付</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div id="sectionPayment" class="section-content">
|
|
|
|
|
|
<!-- 动态生成字段 -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 右侧:JSON配置和属性面板 -->
|
|
|
|
|
|
<div class="panel">
|
|
|
|
|
|
<div class="panel-header">
|
|
|
|
|
|
<ul class="nav nav-tabs nav-tabs-sm" style="border-bottom: none; margin: -12px -14px 0;">
|
|
|
|
|
|
<li class="nav-item">
|
|
|
|
|
|
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#tab-json">JSON配置</button>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
<li class="nav-item">
|
|
|
|
|
|
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#tab-properties">字段属性</button>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="panel-body">
|
|
|
|
|
|
<div class="tab-content">
|
|
|
|
|
|
<div class="tab-pane fade show active" id="tab-json">
|
|
|
|
|
|
<div class="property-group">
|
|
|
|
|
|
<div class="property-group-title">区域配置JSON</div>
|
|
|
|
|
|
<textarea class="form-control json-editor" id="jsonConfig" rows="15"></textarea>
|
|
|
|
|
|
<button class="btn btn-primary btn-sm w-100 mt-2" onclick="applyJsonConfig()">
|
|
|
|
|
|
<i class="bi bi-check-circle me-1"></i>应用配置
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tab-pane fade" id="tab-properties">
|
|
|
|
|
|
<div id="propertyPanel">
|
|
|
|
|
|
<div class="text-muted small">点击画布区域进行配置</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 底部工具栏 -->
|
|
|
|
|
|
<div class="bottom-toolbar">
|
|
|
|
|
|
<button class="btn btn-outline-secondary btn-sm" id="btnImport">
|
|
|
|
|
|
<i class="bi bi-upload me-1"></i>导入
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button class="btn btn-outline-secondary btn-sm" id="btnExport">
|
|
|
|
|
|
<i class="bi bi-download me-1"></i>导出
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button class="btn btn-primary btn-sm" id="btnSave">
|
|
|
|
|
|
<i class="bi bi-save me-1"></i>保存
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button class="btn btn-success btn-sm" id="btnPreview">
|
|
|
|
|
|
<i class="bi bi-printer me-1"></i>打印预览
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<script src="https://cdn.staticfile.org/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
|
|
|
|
|
|
<script>
|
|
|
|
|
|
// 默认区域配置JSON
|
|
|
|
|
|
const defaultSectionConfig = {
|
|
|
|
|
|
basic_info: {
|
|
|
|
|
|
title: "基本信息",
|
|
|
|
|
|
fields: [
|
|
|
|
|
|
{ key: "title", label: "事项标题", type: "text", required: true },
|
|
|
|
|
|
{ key: "amount", label: "金额", type: "number", required: true },
|
|
|
|
|
|
{ key: "project_name", label: "项目名称", type: "text" },
|
|
|
|
|
|
{ key: "budget_source", label: "资金来源", type: "text" },
|
|
|
|
|
|
{ key: "apply_date", label: "申请日期", type: "date" }
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
meeting_info: {
|
|
|
|
|
|
title: "拟支上会",
|
|
|
|
|
|
fields: [
|
|
|
|
|
|
{ key: "meeting_date", label: "上会日期", type: "date" },
|
|
|
|
|
|
{ key: "meeting_result", label: "上会结果", type: "text" },
|
|
|
|
|
|
{ key: "meeting_amount", label: "上会金额", type: "number" },
|
|
|
|
|
|
{ key: "meeting_notes", label: "上会备注", type: "textarea" }
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
pre_approval: {
|
|
|
|
|
|
title: "事前流程",
|
|
|
|
|
|
fields: [
|
|
|
|
|
|
{ key: "procurement_approval", label: "采购审批", type: "checkbox" },
|
|
|
|
|
|
{ key: "contract_approval", label: "合同审批", type: "checkbox" },
|
|
|
|
|
|
{ key: "bidding_process", label: "招标流程", type: "checkbox" },
|
|
|
|
|
|
{ key: "attachments", label: "附件清单", type: "textarea" }
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
payment: {
|
|
|
|
|
|
title: "支付流程",
|
|
|
|
|
|
rounds: [
|
|
|
|
|
|
{
|
|
|
|
|
|
round: 1,
|
|
|
|
|
|
fields: [
|
|
|
|
|
|
{ key: "payment_amount_1", label: "支付金额", type: "number" },
|
|
|
|
|
|
{ key: "payment_date_1", label: "支付日期", type: "date" },
|
|
|
|
|
|
{ key: "payment_status_1", label: "支付状态", type: "text" }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let currentProcessCategory = ''; // 当前选中的事前流程分类
|
|
|
|
|
|
let currentBranch = ''; // 当前选中的分支ID
|
|
|
|
|
|
let processCategories = {}; // 数据结构:{ "采购管理": { branches: {...}, configs: {...} } }
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化分类结构
|
|
|
|
|
|
function initProcessCategories() {
|
|
|
|
|
|
const categories = ['采购管理', '会议培训接待', '车船管理及维修', '仪器管理', '出差管理', '合同管理', '安装维修'];
|
|
|
|
|
|
categories.forEach(category => {
|
|
|
|
|
|
if (!processCategories[category]) {
|
|
|
|
|
|
processCategories[category] = {
|
|
|
|
|
|
branches: {},
|
|
|
|
|
|
configs: {}
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化
|
|
|
|
|
|
function initialize() {
|
|
|
|
|
|
initProcessCategories();
|
|
|
|
|
|
|
|
|
|
|
|
// 绑定事件
|
|
|
|
|
|
document.getElementById('btnAddBranch').addEventListener('click', addNewBranch);
|
|
|
|
|
|
document.getElementById('btnSave').addEventListener('click', saveConfig);
|
|
|
|
|
|
document.getElementById('btnExport').addEventListener('click', exportConfig);
|
|
|
|
|
|
document.getElementById('btnImport').addEventListener('click', importConfig);
|
|
|
|
|
|
document.getElementById('btnPreview').addEventListener('click', previewPrint);
|
|
|
|
|
|
|
|
|
|
|
|
// 区域点击事件
|
|
|
|
|
|
document.querySelectorAll('.document-section').forEach(section => {
|
|
|
|
|
|
section.addEventListener('click', () => {
|
|
|
|
|
|
const sectionId = section.dataset.section;
|
|
|
|
|
|
showSectionProperties(sectionId);
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 切换事前流程分类
|
|
|
|
|
|
function switchProcessCategory() {
|
|
|
|
|
|
const category = document.getElementById('processCategorySelect').value;
|
|
|
|
|
|
currentProcessCategory = category;
|
|
|
|
|
|
currentBranch = '';
|
|
|
|
|
|
|
|
|
|
|
|
if (category) {
|
|
|
|
|
|
document.getElementById('branchListSection').style.display = 'block';
|
|
|
|
|
|
document.getElementById('conditionSection').style.display = 'none';
|
|
|
|
|
|
renderBranchListTable();
|
|
|
|
|
|
document.getElementById('canvasBranchBadge').textContent = category;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
document.getElementById('branchListSection').style.display = 'none';
|
|
|
|
|
|
document.getElementById('conditionSection').style.display = 'none';
|
|
|
|
|
|
document.getElementById('canvasBranchBadge').textContent = '请选择分类';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
renderDocument();
|
|
|
|
|
|
updateJsonConfig();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染分支列表(显示当前分类下的分支)
|
|
|
|
|
|
function renderBranchListTable() {
|
|
|
|
|
|
const tbody = document.getElementById('branchListTableBody');
|
|
|
|
|
|
tbody.innerHTML = '';
|
|
|
|
|
|
|
|
|
|
|
|
if (!currentProcessCategory || !processCategories[currentProcessCategory]) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const categoryData = processCategories[currentProcessCategory];
|
|
|
|
|
|
const branches = Object.values(categoryData.branches);
|
|
|
|
|
|
|
|
|
|
|
|
if (branches.length === 0) {
|
|
|
|
|
|
tbody.innerHTML = '<tr><td colspan="3" class="text-center text-muted" style="padding: 20px;">该分类下暂无分支,点击"添加分支"创建</td></tr>';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
branches.forEach((branch, index) => {
|
|
|
|
|
|
const tr = document.createElement('tr');
|
|
|
|
|
|
tr.className = branch.id === currentBranch ? 'active' : '';
|
|
|
|
|
|
tr.onclick = () => switchToBranch(branch.id);
|
|
|
|
|
|
|
|
|
|
|
|
const conditionBadges = branch.conditionLabels.map(label =>
|
|
|
|
|
|
`<span class="branch-badge">${label}</span>`
|
|
|
|
|
|
).join('');
|
|
|
|
|
|
|
|
|
|
|
|
tr.innerHTML = `
|
|
|
|
|
|
<td>${index + 1}</td>
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<div style="font-weight: 500; margin-bottom: 2px; font-size: 12px;">${branch.name}</div>
|
|
|
|
|
|
<div style="font-size: 10px;">${conditionBadges || '<span class="text-muted">默认分支</span>'}</div>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<button class="btn btn-xs btn-outline-danger" onclick="event.stopPropagation(); deleteBranch('${branch.id}')" title="删除">
|
|
|
|
|
|
<i class="bi bi-trash"></i>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
`;
|
|
|
|
|
|
tbody.appendChild(tr);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染文档
|
|
|
|
|
|
function renderDocument() {
|
|
|
|
|
|
let config = defaultSectionConfig;
|
|
|
|
|
|
|
|
|
|
|
|
if (currentProcessCategory && currentBranch) {
|
|
|
|
|
|
const categoryData = processCategories[currentProcessCategory];
|
|
|
|
|
|
if (categoryData && categoryData.configs[currentBranch]) {
|
|
|
|
|
|
config = categoryData.configs[currentBranch];
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (currentProcessCategory) {
|
|
|
|
|
|
// 如果只选择了分类,使用分类的默认配置
|
|
|
|
|
|
const categoryData = processCategories[currentProcessCategory];
|
|
|
|
|
|
if (categoryData && categoryData.defaultConfig) {
|
|
|
|
|
|
config = categoryData.defaultConfig;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染基本信息
|
|
|
|
|
|
renderSection('sectionBasicInfo', config.basic_info);
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染拟支上会
|
|
|
|
|
|
renderSection('sectionMeetingInfo', config.meeting_info);
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染事前流程
|
|
|
|
|
|
renderSection('sectionPreApproval', config.pre_approval);
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染支付流程
|
|
|
|
|
|
renderPaymentSection('sectionPayment', config.payment);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function renderSection(containerId, sectionConfig) {
|
|
|
|
|
|
const container = document.getElementById(containerId);
|
|
|
|
|
|
if (!container || !sectionConfig) return;
|
|
|
|
|
|
|
|
|
|
|
|
container.innerHTML = '';
|
|
|
|
|
|
|
|
|
|
|
|
if (sectionConfig.fields) {
|
|
|
|
|
|
sectionConfig.fields.forEach(field => {
|
|
|
|
|
|
const fieldDiv = document.createElement('div');
|
|
|
|
|
|
fieldDiv.className = 'field-item';
|
|
|
|
|
|
fieldDiv.innerHTML = `
|
|
|
|
|
|
<div class="field-label">${field.label}${field.required ? '<span style="color: red;">*</span>' : ''}:</div>
|
|
|
|
|
|
<div class="field-value ${!field.value ? 'empty' : ''}">${field.value || `[${field.type}]`}</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
container.appendChild(fieldDiv);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function renderPaymentSection(containerId, paymentConfig) {
|
|
|
|
|
|
const container = document.getElementById(containerId);
|
|
|
|
|
|
if (!container || !paymentConfig) return;
|
|
|
|
|
|
|
|
|
|
|
|
container.innerHTML = '';
|
|
|
|
|
|
|
|
|
|
|
|
if (paymentConfig.rounds) {
|
|
|
|
|
|
paymentConfig.rounds.forEach((round, index) => {
|
|
|
|
|
|
const roundDiv = document.createElement('div');
|
|
|
|
|
|
roundDiv.className = 'payment-round';
|
|
|
|
|
|
roundDiv.innerHTML = `<div class="payment-round-header">第 ${round.round} 轮支付</div>`;
|
|
|
|
|
|
|
|
|
|
|
|
const fieldsDiv = document.createElement('div');
|
|
|
|
|
|
fieldsDiv.className = 'field-row';
|
|
|
|
|
|
|
|
|
|
|
|
round.fields.forEach(field => {
|
|
|
|
|
|
const fieldDiv = document.createElement('div');
|
|
|
|
|
|
fieldDiv.className = 'field-item';
|
|
|
|
|
|
fieldDiv.innerHTML = `
|
|
|
|
|
|
<div class="field-label">${field.label}:</div>
|
|
|
|
|
|
<div class="field-value ${!field.value ? 'empty' : ''}">${field.value || `[${field.type}]`}</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
fieldsDiv.appendChild(fieldDiv);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
roundDiv.appendChild(fieldsDiv);
|
|
|
|
|
|
container.appendChild(roundDiv);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 切换分支
|
|
|
|
|
|
function switchToBranch(branchId) {
|
|
|
|
|
|
if (!currentProcessCategory) return;
|
|
|
|
|
|
|
|
|
|
|
|
currentBranch = branchId;
|
|
|
|
|
|
const categoryData = processCategories[currentProcessCategory];
|
|
|
|
|
|
const branch = categoryData.branches[branchId];
|
|
|
|
|
|
|
|
|
|
|
|
if (branch) {
|
|
|
|
|
|
document.getElementById('canvasBranchBadge').textContent = `${currentProcessCategory} - ${branch.name}`;
|
|
|
|
|
|
renderBranchListTable();
|
|
|
|
|
|
renderDocument();
|
|
|
|
|
|
updateJsonConfig();
|
|
|
|
|
|
|
|
|
|
|
|
// 显示条件设置区域
|
|
|
|
|
|
document.getElementById('conditionSection').style.display = 'block';
|
|
|
|
|
|
|
|
|
|
|
|
// 回填条件设置到编辑器
|
|
|
|
|
|
if (branch.conditions) {
|
|
|
|
|
|
const conditions = branch.conditions;
|
|
|
|
|
|
document.getElementById('condContractClass').value = conditions.contract_classification || '';
|
|
|
|
|
|
document.getElementById('condBusinessType').value = conditions.business_type || '';
|
|
|
|
|
|
document.getElementById('condContractType').value = conditions.contract_type || '';
|
|
|
|
|
|
document.getElementById('condProcurementMethod').value = conditions.procurement_method || '';
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 清空所有条件
|
|
|
|
|
|
document.getElementById('condContractClass').value = '';
|
|
|
|
|
|
document.getElementById('condBusinessType').value = '';
|
|
|
|
|
|
document.getElementById('condContractType').value = '';
|
|
|
|
|
|
document.getElementById('condProcurementMethod').value = '';
|
|
|
|
|
|
document.getElementById('conditionSection').style.display = 'none';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 应用条件
|
|
|
|
|
|
function applyConditions() {
|
|
|
|
|
|
if (!currentProcessCategory) {
|
|
|
|
|
|
alert('请先选择事前流程分类');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const conditions = {
|
|
|
|
|
|
contract_classification: document.getElementById('condContractClass').value,
|
|
|
|
|
|
business_type: document.getElementById('condBusinessType').value,
|
|
|
|
|
|
contract_type: document.getElementById('condContractType').value,
|
|
|
|
|
|
procurement_method: document.getElementById('condProcurementMethod').value
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const labels = Object.values(conditions).filter(v => v).join('-');
|
|
|
|
|
|
if (!labels) {
|
|
|
|
|
|
alert('请至少选择一个条件');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const branchId = 'branch_' + Date.now();
|
|
|
|
|
|
const categoryData = processCategories[currentProcessCategory];
|
|
|
|
|
|
|
|
|
|
|
|
categoryData.branches[branchId] = {
|
|
|
|
|
|
id: branchId,
|
|
|
|
|
|
name: labels || '新分支',
|
|
|
|
|
|
conditions,
|
|
|
|
|
|
conditionLabels: Object.values(conditions).filter(v => v)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
categoryData.configs[branchId] = JSON.parse(JSON.stringify(defaultSectionConfig));
|
|
|
|
|
|
|
|
|
|
|
|
switchToBranch(branchId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function clearCondition(key) {
|
|
|
|
|
|
// 清除对应条件的下拉框
|
|
|
|
|
|
const map = {
|
|
|
|
|
|
'contract_classification': 'condContractClass',
|
|
|
|
|
|
'business_type': 'condBusinessType',
|
|
|
|
|
|
'contract_type': 'condContractType',
|
|
|
|
|
|
'procurement_method': 'condProcurementMethod'
|
|
|
|
|
|
};
|
|
|
|
|
|
const el = document.getElementById(map[key]);
|
|
|
|
|
|
if (el) el.value = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新JSON配置
|
|
|
|
|
|
function updateJsonConfig() {
|
|
|
|
|
|
let config = defaultSectionConfig;
|
|
|
|
|
|
|
|
|
|
|
|
if (currentProcessCategory && currentBranch) {
|
|
|
|
|
|
const categoryData = processCategories[currentProcessCategory];
|
|
|
|
|
|
if (categoryData && categoryData.configs[currentBranch]) {
|
|
|
|
|
|
config = categoryData.configs[currentBranch];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
document.getElementById('jsonConfig').value = JSON.stringify(config, null, 2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 应用JSON配置
|
|
|
|
|
|
function applyJsonConfig() {
|
|
|
|
|
|
if (!currentProcessCategory || !currentBranch) {
|
|
|
|
|
|
alert('请先选择分类和分支');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const config = JSON.parse(document.getElementById('jsonConfig').value);
|
|
|
|
|
|
const categoryData = processCategories[currentProcessCategory];
|
|
|
|
|
|
categoryData.configs[currentBranch] = config;
|
|
|
|
|
|
renderDocument();
|
|
|
|
|
|
alert('配置已应用');
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
alert('JSON格式错误:' + e.message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示区域属性
|
|
|
|
|
|
function showSectionProperties(sectionId) {
|
|
|
|
|
|
let config = defaultSectionConfig;
|
|
|
|
|
|
|
|
|
|
|
|
if (currentProcessCategory && currentBranch) {
|
|
|
|
|
|
const categoryData = processCategories[currentProcessCategory];
|
|
|
|
|
|
if (categoryData && categoryData.configs[currentBranch]) {
|
|
|
|
|
|
config = categoryData.configs[currentBranch];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const sectionConfig = config[sectionId];
|
|
|
|
|
|
|
|
|
|
|
|
if (!sectionConfig) return;
|
|
|
|
|
|
|
|
|
|
|
|
const panel = document.getElementById('propertyPanel');
|
|
|
|
|
|
panel.innerHTML = `
|
|
|
|
|
|
<div class="property-group">
|
|
|
|
|
|
<div class="property-group-title">${sectionConfig.title || sectionId}</div>
|
|
|
|
|
|
<div class="mb-2">
|
|
|
|
|
|
<label class="form-label small">区域标题</label>
|
|
|
|
|
|
<input class="form-control form-control-sm" value="${sectionConfig.title || ''}"
|
|
|
|
|
|
onchange="updateSectionTitle('${sectionId}', this.value)">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="mb-2">
|
|
|
|
|
|
<label class="form-label small">字段数量</label>
|
|
|
|
|
|
<input type="number" class="form-control form-control-sm"
|
|
|
|
|
|
value="${sectionConfig.fields ? sectionConfig.fields.length : (sectionConfig.rounds ? sectionConfig.rounds.length : 0)}" readonly>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<button class="btn btn-primary btn-sm w-100" onclick="editSectionFields('${sectionId}')">
|
|
|
|
|
|
<i class="bi bi-pencil me-1"></i>编辑字段
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
// 切换到属性标签页
|
|
|
|
|
|
document.querySelector('[data-bs-target="#tab-properties"]').click();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function updateSectionTitle(sectionId, title) {
|
|
|
|
|
|
if (!currentProcessCategory || !currentBranch) return;
|
|
|
|
|
|
|
|
|
|
|
|
const categoryData = processCategories[currentProcessCategory];
|
|
|
|
|
|
if (!categoryData.configs[currentBranch]) {
|
|
|
|
|
|
categoryData.configs[currentBranch] = JSON.parse(JSON.stringify(defaultSectionConfig));
|
|
|
|
|
|
}
|
|
|
|
|
|
categoryData.configs[currentBranch][sectionId].title = title;
|
|
|
|
|
|
renderDocument();
|
|
|
|
|
|
updateJsonConfig();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function editSectionFields(sectionId) {
|
|
|
|
|
|
alert('字段编辑功能(可扩展为弹窗编辑)');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function addNewBranch() {
|
|
|
|
|
|
if (!currentProcessCategory) {
|
|
|
|
|
|
alert('请先选择事前流程分类');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示条件设置区域
|
|
|
|
|
|
document.getElementById('conditionSection').style.display = 'block';
|
|
|
|
|
|
// 清空条件
|
|
|
|
|
|
document.getElementById('condContractClass').value = '';
|
|
|
|
|
|
document.getElementById('condBusinessType').value = '';
|
|
|
|
|
|
document.getElementById('condContractType').value = '';
|
|
|
|
|
|
document.getElementById('condProcurementMethod').value = '';
|
|
|
|
|
|
currentBranch = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function deleteBranch(branchId) {
|
|
|
|
|
|
if (!currentProcessCategory) return;
|
|
|
|
|
|
|
|
|
|
|
|
if (confirm('确定要删除该分支吗?')) {
|
|
|
|
|
|
const categoryData = processCategories[currentProcessCategory];
|
|
|
|
|
|
delete categoryData.branches[branchId];
|
|
|
|
|
|
delete categoryData.configs[branchId];
|
|
|
|
|
|
|
|
|
|
|
|
if (currentBranch === branchId) {
|
|
|
|
|
|
currentBranch = '';
|
|
|
|
|
|
document.getElementById('conditionSection').style.display = 'none';
|
|
|
|
|
|
document.getElementById('canvasBranchBadge').textContent = currentProcessCategory;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
renderBranchListTable();
|
|
|
|
|
|
renderDocument();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存配置
|
|
|
|
|
|
function saveConfig() {
|
|
|
|
|
|
const data = {
|
|
|
|
|
|
processCategories: processCategories
|
|
|
|
|
|
};
|
|
|
|
|
|
console.log('保存配置:', data);
|
|
|
|
|
|
alert('配置已保存(模拟)');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 导出配置
|
|
|
|
|
|
function exportConfig() {
|
|
|
|
|
|
const data = {
|
|
|
|
|
|
processCategories: processCategories
|
|
|
|
|
|
};
|
|
|
|
|
|
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
|
|
|
|
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
|
|
const a = document.createElement('a');
|
|
|
|
|
|
a.href = url;
|
|
|
|
|
|
a.download = 'canvas-config.json';
|
|
|
|
|
|
a.click();
|
|
|
|
|
|
URL.revokeObjectURL(url);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 导入配置
|
|
|
|
|
|
function importConfig() {
|
|
|
|
|
|
const input = document.createElement('input');
|
|
|
|
|
|
input.type = 'file';
|
|
|
|
|
|
input.accept = '.json';
|
|
|
|
|
|
input.onchange = (e) => {
|
|
|
|
|
|
const file = e.target.files[0];
|
|
|
|
|
|
if (!file) return;
|
|
|
|
|
|
|
|
|
|
|
|
const reader = new FileReader();
|
|
|
|
|
|
reader.onload = (event) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const data = JSON.parse(event.target.result);
|
|
|
|
|
|
if (data.processCategories) {
|
|
|
|
|
|
processCategories = data.processCategories;
|
|
|
|
|
|
// 重新初始化分类选择器
|
|
|
|
|
|
if (currentProcessCategory && processCategories[currentProcessCategory]) {
|
|
|
|
|
|
renderBranchListTable();
|
|
|
|
|
|
renderDocument();
|
|
|
|
|
|
updateJsonConfig();
|
|
|
|
|
|
}
|
|
|
|
|
|
alert('配置已导入');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
alert('文件格式不正确');
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
alert('文件格式错误:' + e.message);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
reader.readAsText(file);
|
|
|
|
|
|
};
|
|
|
|
|
|
input.click();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 打印预览
|
|
|
|
|
|
function previewPrint() {
|
|
|
|
|
|
window.print();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 页面加载完成后初始化
|
|
|
|
|
|
if (document.readyState === 'loading') {
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', initialize);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
initialize();
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
</body>
|
|
|
|
|
|
</html>
|