Files
ocean/frontend/index.html
T
2026-02-01 15:57:42 +08:00

456 lines
28 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<section id="view-login" class="view-login">
<div class="login-card">
<div class="login-brand">
<span class="brand-icon"></span>
<h1 class="login-title">项目管理系统</h1>
<p class="login-desc">多部门协作维护项目信息</p>
</div>
<form id="loginForm" class="login-form" novalidate>
<div class="form-group">
<label for="loginUsername">账号</label>
<input type="text" id="loginUsername" class="input" name="username" placeholder="请输入账号" required autocomplete="username" />
</div>
<div class="form-group">
<label for="loginPassword">密码</label>
<input type="password" id="loginPassword" class="input" name="password" placeholder="请输入密码" required autocomplete="current-password" />
</div>
<div id="loginError" class="login-error" role="alert" style="display: none;"></div>
<button type="submit" class="btn btn-primary btn-login-submit" id="btnLoginSubmit">登录</button>
</form>
</div>
</section>
<div class="app" id="appMain" style="display: none;">
<main class="main">
<section id="view-list" class="view view-list active">
<header class="page-header">
<h1 class="page-title">项目列表</h1>
<div class="header-actions" id="listHeaderActions">
<button type="button" class="btn btn-secondary" id="btnExportXls" title="导出当前列表为 XLS 文件">
<span class="btn-icon"></span> 导出 XLS
</button>
<button type="button" class="btn btn-secondary" id="btnStats" title="按当前搜索条件统计并图表展示">
<span class="btn-icon">📊</span> 统计
</button>
<button type="button" class="btn btn-secondary" id="btnGlobalStats" title="调用后端统计 API 查看各类型项目">
<span class="btn-icon">📈</span> 全局统计
</button>
<button type="button" class="btn btn-primary btn-new-project" id="btnNewProject" style="display: none;">
<span class="btn-icon">+</span> 新建项目
</button>
<div id="topbarUserWrap" class="topbar-user">
<a href="#" class="topbar-link" id="btnUserManage" style="display: none;">用户管理</a>
<span class="user-info" id="userInfo"></span>
<button type="button" class="btn-logout" id="btnLogout">退出</button>
</div>
</div>
</header>
<div class="toolbar">
<div class="search-row">
<select id="searchType" class="input input-select">
<option value="name">项目名称</option>
<option value="code">合同编号</option>
</select>
<input type="text" id="searchKeyword" class="input input-search" placeholder="输入关键词搜索" />
<button type="button" class="btn btn-search" id="btnSearch">搜索</button>
</div>
<div class="filter-row">
<div class="filter-group">
<label>日期筛选</label>
<select id="dateFilterType" class="input input-filter">
<option value="">不按日期</option>
<option value="signDate">签订日期</option>
<option value="startDate">开工日期</option>
<option value="plannedCompletionDate">计划竣工日期</option>
<option value="actualCompletionDate">实际竣工日期</option>
</select>
</div>
<div class="filter-group">
<label></label>
<input type="date" id="dateFrom" class="input input-date" />
</div>
<div class="filter-group">
<label></label>
<input type="date" id="dateTo" class="input input-date" />
</div>
<div class="filter-group filter-check">
<label><input type="checkbox" id="dateAbnormal" /> 仅日期异常</label>
</div>
</div>
<div class="filter-row filter-row-amount">
<div class="filter-group">
<label>中标合同金额(万元)</label>
<input type="number" id="amountMin" class="input input-amount" placeholder="最小" step="0.01" min="0" />
</div>
<div class="filter-group">
<label></label>
<input type="number" id="amountMax" class="input input-amount" placeholder="最大" step="0.01" min="0" />
</div>
</div>
</div>
<div class="table-wrap">
<div class="table-loading" id="listLoading">加载中…</div>
<div class="table-empty" id="listEmpty" style="display: none;">
<span class="empty-icon">📋</span>
<p>暂无项目数据</p>
</div>
<table class="table" id="projectTable">
<thead>
<tr>
<th>合同编号</th>
<th>项目名称</th>
<th>合同金额</th>
<th>业主单位</th>
<th>签订日期</th>
<th>所属项目部</th>
<th>总体成本</th>
<th>项目负责人及电话</th>
<th>操作</th>
</tr>
</thead>
<tbody id="projectTableBody"></tbody>
</table>
</div>
<div class="pagination" id="pagination">
<span class="pagination-info" id="paginationInfo">共 0 条</span>
<span class="pagination-page" id="paginationPage">第 1 / 1 页</span>
<div class="pagination-btns">
<button type="button" class="btn btn-sm" id="btnPrev" disabled>上一页</button>
<button type="button" class="btn btn-sm" id="btnNext">下一页</button>
</div>
</div>
</section>
<section id="view-statistics" class="view view-statistics">
<header class="page-header">
<button type="button" class="btn-back" id="btnBackFromStats">← 返回列表</button>
<h1 class="page-title">统计</h1>
<div class="header-actions" id="statsHeaderActions"></div>
</header>
<div class="stats-loading" id="statsLoading">正在加载符合当前搜索条件的项目数据…</div>
<div class="stats-content" id="statsContent" style="display: none;">
<p class="stats-desc" id="statsDesc">以下为当前搜索条件下的统计结果</p>
<div class="stats-cards">
<div class="stats-card">
<h3 class="stats-card-title">项目个数</h3>
<div class="stats-card-value" id="statsCount">0</div>
<canvas id="chartCount" class="stats-chart" width="280" height="120"></canvas>
</div>
<div class="stats-card">
<h3 class="stats-card-title">合计合同金额(万元)</h3>
<div class="stats-card-value" id="statsAmount">0</div>
<canvas id="chartAmount" class="stats-chart" width="280" height="120"></canvas>
</div>
<div class="stats-card stats-card-wide">
<h3 class="stats-card-title">工程进度分布</h3>
<canvas id="chartProgress" class="stats-chart stats-chart-pie" width="360" height="240"></canvas>
</div>
<div class="stats-card">
<h3 class="stats-card-title">应收账款总额(万元)</h3>
<div class="stats-card-value" id="statsReceivable">0</div>
<canvas id="chartReceivable" class="stats-chart" width="280" height="120"></canvas>
</div>
<div class="stats-card">
<h3 class="stats-card-title">应付账款总额(万元)</h3>
<div class="stats-card-value" id="statsPayable">0</div>
<canvas id="chartPayable" class="stats-chart" width="280" height="120"></canvas>
</div>
</div>
</div>
<div class="stats-empty" id="statsEmpty" style="display: none;">
<span class="empty-icon">📊</span>
<p>当前搜索条件下暂无项目数据</p>
</div>
</section>
<section id="view-global-stats" class="view view-global-stats">
<header class="page-header">
<button type="button" class="btn-back" id="btnBackFromGlobalStats">← 返回列表</button>
<h1 class="page-title">全局统计</h1>
<div class="header-actions" id="globalStatsHeaderActions"></div>
</header>
<p class="global-stats-desc">按统计类型查看项目,数据来自后端统计 API。</p>
<div class="global-stats-tabs" id="globalStatsTabs" role="tablist">
<button type="button" class="tab global-stats-tab active" data-type="基建工程" role="tab">基建工程</button>
<button type="button" class="tab global-stats-tab" data-type="业扩项目" role="tab">业扩项目</button>
<button type="button" class="tab global-stats-tab" data-type="户表" role="tab">户表</button>
<button type="button" class="tab global-stats-tab" data-type="客户工程" role="tab">客户工程</button>
<button type="button" class="tab global-stats-tab" data-type="营销项目" role="tab">营销项目</button>
<button type="button" class="tab global-stats-tab" data-type="检修-技改-抢修" role="tab">检修-技改-抢修</button>
<button type="button" class="tab global-stats-tab" data-type="其他" role="tab">其他</button>
</div>
<div class="global-stats-content">
<div class="global-stats-loading" id="globalStatsLoading">加载中…</div>
<div class="global-stats-body" id="globalStatsBody" style="display: none;">
<p class="global-stats-total" id="globalStatsTotal">项目数:0</p>
<div class="global-stats-charts-wrap" id="globalStatsChartsWrap">
<div class="global-stats-charts-loading" id="globalStatsChartsLoading">加载图表数据…</div>
<div class="stats-cards global-stats-cards" id="globalStatsCards" style="display: none;">
<div class="stats-card">
<h3 class="stats-card-title">项目个数</h3>
<div class="stats-card-value" id="globalStatsCount">0</div>
<canvas id="chartGlobalCount" class="stats-chart" width="280" height="120"></canvas>
</div>
<div class="stats-card">
<h3 class="stats-card-title">合计合同金额(万元)</h3>
<div class="stats-card-value" id="globalStatsAmount">0</div>
<canvas id="chartGlobalAmount" class="stats-chart" width="280" height="120"></canvas>
</div>
<div class="stats-card stats-card-wide">
<h3 class="stats-card-title">工程进度分布</h3>
<canvas id="chartGlobalProgress" class="stats-chart stats-chart-pie" width="360" height="240"></canvas>
</div>
<div class="stats-card">
<h3 class="stats-card-title">应收账款总额(万元)</h3>
<div class="stats-card-value" id="globalStatsReceivable">0</div>
<canvas id="chartGlobalReceivable" class="stats-chart" width="280" height="120"></canvas>
</div>
<div class="stats-card">
<h3 class="stats-card-title">应付账款总额(万元)</h3>
<div class="stats-card-value" id="globalStatsPayable">0</div>
<canvas id="chartGlobalPayable" class="stats-chart" width="280" height="120"></canvas>
</div>
</div>
</div>
<div class="table-wrap">
<table class="table" id="globalStatsTable">
<thead>
<tr>
<th>合同编号</th>
<th>项目名称</th>
<th>合同金额</th>
<th>业主单位</th>
<th>签订日期</th>
<th>所属项目部</th>
<th>总体成本</th>
<th>项目负责人及电话</th>
<th>操作</th>
</tr>
</thead>
<tbody id="globalStatsTableBody"></tbody>
</table>
</div>
</div>
<div class="global-stats-empty" id="globalStatsEmpty" style="display: none;">
<span class="empty-icon">📋</span>
<p>该类型暂无项目</p>
</div>
</div>
</section>
<section id="view-detail" class="view view-detail">
<header class="page-header">
<button type="button" class="btn-back" id="btnBack">← 返回列表</button>
<h1 class="page-title detail-title" id="detailTitle">项目详情</h1>
<div class="header-actions" id="detailHeaderActions">
<button type="button" class="btn btn-ghost" id="btnViewLog">查看操作日志</button>
<button type="button" class="btn btn-primary" id="btnSave">
<span class="btn-text">保存</span>
<span class="btn-loading" style="display: none;">保存中…</span>
</button>
</div>
</header>
<div class="detail-loading" id="detailLoading">加载中…</div>
<div class="detail-content" id="detailContent" style="display: none;">
<div class="tabs">
<button type="button" class="tab active" data-tab="contract">合同信息</button>
<button type="button" class="tab" data-tab="costControl">成本控制</button>
<button type="button" class="tab" data-tab="receivable">应收款</button>
<button type="button" class="tab" data-tab="payable">应付款</button>
<button type="button" class="tab" data-tab="other">其他</button>
</div>
<div class="tab-panels">
<div class="tab-panel active" id="panel-contract">
<div class="form-grid" data-section="contract">
<div class="form-group"><label>序号</label><input type="text" class="input" data-field="serialNo" /></div>
<div class="form-group"><label>合同编号 <em>*</em></label><input type="text" class="input" data-field="contractCode" required /></div>
<div class="form-group"><label>供电局项目合同编号</label><input type="text" class="input" data-field="powerBureauContractCode" /></div>
<div class="form-group"><label>项目名称 <em>*</em></label><input type="text" class="input" data-field="projectName" required /></div>
<div class="form-group"><label>子项个数</label><input type="number" class="input" data-field="subItemCount" /></div>
<div class="form-group"><label>子项编码</label><input type="text" class="input" data-field="subItemCode" /></div>
<div class="form-group"><label>项目总投资(万元)</label><input type="number" class="input" data-field="totalInvestment" /></div>
<div class="form-group"><label>中标合同金额(万元)</label><input type="text" class="input" data-field="bidContractAmount" /></div>
<div class="form-group"><label>质保金比例</label><input type="text" class="input" data-field="warrantyRatio" /></div>
<div class="form-group"><label>结算金额(万元)</label><input type="number" class="input" data-field="settlementAmount" /></div>
<div class="form-group"><label>总成本测算</label><input type="number" class="input" data-field="totalCostEstimate" /></div>
<div class="form-group"><label>工程电压等级</label><input type="text" class="input" data-field="voltageLevel" /></div>
<div class="form-group"><label>工程类别</label><input type="text" class="input" data-field="projectCategory" /></div>
<div class="form-group"><label>业主单位</label><input type="text" class="input" data-field="ownerUnit" /></div>
<div class="form-group"><label>业主联系人及电话</label><input type="text" class="input" data-field="ownerContact" /></div>
<div class="form-group"><label>中标形式</label><input type="text" class="input" data-field="bidType" /></div>
<div class="form-group"><label>签订日期</label><input type="text" class="input input-date-or-text" data-field="signDate" placeholder="日期或文字" /></div>
<div class="form-group"><label>开工日期</label><input type="text" class="input input-date-or-text" data-field="startDate" placeholder="日期或文字" /></div>
<div class="form-group"><label>计划竣工日期</label><input type="text" class="input input-date-or-text" data-field="plannedCompletionDate" placeholder="日期或文字" /></div>
<div class="form-group"><label>实际竣工日期</label><input type="text" class="input input-date-or-text" data-field="actualCompletionDate" placeholder="日期或文字" /></div>
<div class="form-group"><label>质保金(万元)</label><input type="number" class="input" data-field="warrantyAmount" /></div>
<div class="form-group"><label>质保期截止日</label><input type="text" class="input" data-field="warrantyEndDate" /></div>
<div class="form-group"><label>实际退质保金日期</label><input type="text" class="input" data-field="actualWarrantyRefundDate" /></div>
<div class="form-group"><label>所属项目部</label><input type="text" class="input" data-field="projectDepartment" /></div>
<div class="form-group"><label>项目负责人及电话</label><input type="text" class="input" data-field="projectLeaderContact" /></div>
<div class="form-group form-group-full"><label>工程款拨付方式</label><input type="text" class="input" data-field="paymentMethod" /></div>
</div>
</div>
<div class="tab-panel" id="panel-costControl">
<div class="form-grid" data-section="costControl">
<div class="form-group"><label>总体成本</label><input type="number" class="input" data-field="totalCost" /></div>
<div class="form-group"><label>是否调整</label><select class="input" data-field="isAdjusted"><option value="">请选择</option><option value="是"></option><option value="否"></option></select></div>
<div class="form-group"><label>农民工工资(按进度计划)</label><input type="text" class="input" data-field="migrantWorkerPlan" /></div>
<div class="form-group"><label>农民工工资(实付)</label><input type="number" class="input" data-field="migrantWorkerActual" /></div>
<div class="form-group"><label>乙供材料费(控制)</label><input type="number" class="input" data-field="selfSupplyMaterialControl" /></div>
<div class="form-group"><label>应付材料费(按收款比例)</label><input type="number" class="input" data-field="materialPayableByRatio" /></div>
<div class="form-group"><label>实际发生材料费</label><input type="number" class="input" data-field="materialActualOccurred" /></div>
<div class="form-group"><label>实际支付材料费</label><input type="number" class="input" data-field="materialActualPaid" /></div>
<div class="form-group"><label>其他费用(控制)</label><input type="number" class="input" data-field="otherCostControl" /></div>
<div class="form-group"><label>应付其他费</label><input type="number" class="input" data-field="otherPayable" /></div>
<div class="form-group"><label>实际其他费用</label><input type="number" class="input" data-field="otherActual" /></div>
<div class="form-group"><label>税金</label><input type="number" class="input" data-field="tax" /></div>
<div class="form-group"><label>利润(万元)</label><input type="number" class="input" data-field="profit" /></div>
<div class="form-group"><label>实际利润(万元)</label><input type="number" class="input" data-field="actualProfit" /></div>
<div class="form-group"><label>成本结算金额(万元)</label><input type="number" class="input" data-field="costSettlementAmount" /></div>
</div>
</div>
<div class="tab-panel" id="panel-receivable">
<div class="form-grid" data-section="receivable">
<div class="form-group"><label>应收款(完成进度款)</label><input type="number" class="input" data-field="receivableProgress" /></div>
<div class="form-group"><label>开票金额(万元)</label><input type="number" class="input" data-field="invoiceAmount" /></div>
<div class="form-group"><label>实际收款金额(万元)</label><input type="number" class="input" data-field="actualReceiptAmount" /></div>
<div class="form-group"><label>实际收款完成率</label><input type="text" class="input" data-field="actualReceiptRate" placeholder="%" /></div>
</div>
</div>
<div class="tab-panel" id="panel-payable">
<div class="form-grid" data-section="payable">
<div class="form-group"><label>应付款金额(万元)</label><input type="number" class="input" data-field="payableAmount" /></div>
<div class="form-group"><label>实际付款金额(万元)</label><input type="number" class="input" data-field="actualPaymentAmount" /></div>
<div class="form-group"><label>未收款(万元)</label><input type="number" class="input" data-field="unreceivedAmount" /></div>
<div class="form-group"><label>实际付款完成率</label><input type="text" class="input" data-field="actualPaymentRate" placeholder="%" /></div>
<div class="form-group"><label>民工工资清欠金额(万元)</label><input type="number" class="input" data-field="migrantWorkerArrears" /></div>
</div>
</div>
<div class="tab-panel" id="panel-other">
<div class="form-grid" data-section="other">
<div class="form-group"><label>结算后成本测算金额</label><input type="number" class="input" data-field="settlementCostEstimate" /></div>
<div class="form-group"><label>结算人工费</label><input type="number" class="input" data-field="settlementLaborCost" /></div>
<div class="form-group"><label>结算材料费</label><input type="number" class="input" data-field="settlementMaterialCost" /></div>
<div class="form-group"><label>结算其他费</label><input type="number" class="input" data-field="settlementOtherCost" /></div>
<div class="form-group"><label>到期应结算项目个数</label><input type="number" class="input" data-field="dueSettlementCount" /></div>
<div class="form-group"><label>到期未完成结算个数</label><input type="number" class="input" data-field="overdueSettlementCount" /></div>
<div class="form-group form-group-full"><label>存在的问题</label><textarea class="input input-area" data-field="existingProblems" rows="2"></textarea></div>
<div class="form-group form-group-full"><label>建议措施</label><textarea class="input input-area" data-field="suggestions" rows="2"></textarea></div>
<div class="form-group"><label>累计进度</label><input type="text" class="input" data-field="cumulativeProgress" placeholder="%" /></div>
<div class="form-group form-group-full"><label>备注</label><textarea class="input input-area" data-field="remark" rows="2"></textarea></div>
</div>
</div>
</div>
</div>
</section>
<section id="view-users" class="view view-users">
<header class="page-header">
<button type="button" class="btn-back" id="btnBackFromUsers">← 返回列表</button>
<h1 class="page-title">用户管理</h1>
<div class="header-actions" id="usersHeaderActions">
<button type="button" class="btn btn-primary" id="btnAddUser">+ 新增用户</button>
</div>
</header>
<div class="table-wrap">
<div class="table-loading" id="usersLoading">加载中…</div>
<div class="table-empty" id="usersEmpty" style="display: none;">
<span class="empty-icon">👤</span>
<p>暂无用户</p>
</div>
<table class="table" id="usersTable">
<thead>
<tr>
<th>账号</th>
<th>显示名称</th>
<th>角色</th>
<th>更新时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="usersTableBody"></tbody>
</table>
</div>
</section>
</main>
</div>
<div class="modal-overlay" id="userModalOverlay" aria-hidden="true"></div>
<div class="modal" id="userModal">
<div class="modal-header">
<h2 class="modal-title" id="userModalTitle">新增用户</h2>
<button type="button" class="modal-close" id="userModalClose">×</button>
</div>
<form id="userForm" class="modal-form">
<input type="hidden" id="userFormId" value="" />
<div class="form-group">
<label for="userFormUsername">账号 <em>*</em></label>
<input type="text" id="userFormUsername" class="input" required placeholder="唯一账号" />
</div>
<div class="form-group">
<label for="userFormPassword">密码 <em>*</em></label>
<input type="password" id="userFormPassword" class="input" placeholder="留空则不修改(编辑时)" />
</div>
<div class="form-group">
<label for="userFormRole">角色 <em>*</em></label>
<select id="userFormRole" class="input" required>
<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="form-group">
<label for="userFormDisplayName">显示名称</label>
<input type="text" id="userFormDisplayName" class="input" placeholder="可选" />
</div>
<div class="modal-actions">
<button type="button" class="btn btn-ghost" id="userModalCancel">取消</button>
<button type="submit" class="btn btn-primary" id="userFormSubmit">保存</button>
</div>
</form>
</div>
<div class="drawer-overlay" id="logOverlay" aria-hidden="true"></div>
<div class="drawer" id="logDrawer">
<div class="drawer-header">
<h2 class="drawer-title">操作日志</h2>
<button type="button" class="drawer-close" id="logDrawerClose">×</button>
</div>
<div class="drawer-body">
<div class="drawer-loading" id="logLoading">加载中…</div>
<div class="drawer-empty" id="logEmpty" style="display: none;">
<span class="empty-icon">📜</span>
<p>暂无操作记录</p>
</div>
<ul class="log-list" id="logList"></ul>
</div>
</div>
<div id="toast" class="toast" role="alert" aria-live="polite"></div>
<!-- Agentation 可视化反馈工具栏(https://github.com/benjitaylor/agentation -->
<div id="agentation-root"></div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
<script src="js/api.js"></script>
<script src="js/app.js"></script>
<script type="module" src="dist/agentation.js"></script>
</body>
</html>