1101 lines
36 KiB
HTML
1101 lines
36 KiB
HTML
<!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://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.2/dist/echarts.min.js"></script>
|
|
<style>
|
|
html, body {
|
|
height: 100%;
|
|
overflow: auto;
|
|
}
|
|
:root {
|
|
--primary: #20d3c2 ;
|
|
--secondary: #2c5c8c;
|
|
--accent: #4caf50;
|
|
--warning: #ff9800;
|
|
--danger: #f44336;
|
|
--light: #f5f7fa;
|
|
--dark: #8cc8c1;
|
|
--gray: #e4e7eb;
|
|
--card-shadow: 0 4px 15px rgba(0,0,0,0.08);
|
|
--bg-color: #ffffff;
|
|
}
|
|
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
font-family: 'Noto Sans SC', sans-serif;
|
|
}
|
|
body {
|
|
background-color: transparent;
|
|
color: var(--dark);
|
|
/* min-height: 98vh; */
|
|
height: 100%;
|
|
overflow: hidden;
|
|
/* padding: 20px; */
|
|
}
|
|
.container {
|
|
max-width: 1400px;
|
|
height: 100%;
|
|
margin: 0 auto;
|
|
|
|
/* padding: 20px; */
|
|
padding: 50px 20px 0 20px;
|
|
}
|
|
|
|
header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 30px;
|
|
padding-bottom: 20px;
|
|
border-bottom: 1px solid var(--gray);
|
|
}
|
|
|
|
.logo {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 15px;
|
|
}
|
|
|
|
.logo-icon {
|
|
background: var(--primary);
|
|
color: white;
|
|
width: 50px;
|
|
height: 50px;
|
|
border-radius: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 24px;
|
|
}
|
|
|
|
.logo-text {
|
|
font-size: 1.8rem;
|
|
font-weight: 700;
|
|
color: var(--primary);
|
|
}
|
|
|
|
.last-update {
|
|
color: #8cc8c1;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* 仪表盘样式 */
|
|
.dashboard {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
gap: 20px;
|
|
margin-bottom: 25px;
|
|
}
|
|
|
|
.kpi-card {
|
|
/* background: var(--bg-color); */
|
|
background: linear-gradient(135deg, rgba(22, 186, 170, 0.1) 0%, rgba(22, 186, 170, 0.05) 100%);
|
|
border: 1px solid rgba(22, 186, 170, 0.3);
|
|
box-shadow: 0 4px 20px rgb;
|
|
border-radius: 12px;
|
|
padding: 25px;
|
|
/* box-shadow: var(--card-shadow); */
|
|
display: flex;
|
|
flex-direction: column;
|
|
transition: transform 0.3s;
|
|
cursor: pointer;
|
|
border-top: 4px solid var(--primary);
|
|
}
|
|
|
|
.kpi-card:hover {
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.kpi-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
margin-bottom: 15px;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.kpi-icon {
|
|
width: 50px;
|
|
height: 50px;
|
|
border-radius: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 24px;
|
|
}
|
|
|
|
.kpi-icon.blue {
|
|
background: rgba(26, 58, 95, 0.1);
|
|
color: var(--primary);
|
|
}
|
|
|
|
.kpi-icon.green {
|
|
background: rgba(76, 175, 80, 0.1);
|
|
color: var(--accent);
|
|
}
|
|
|
|
.kpi-icon.orange {
|
|
background: rgba(255, 152, 0, 0.1);
|
|
color: var(--warning);
|
|
}
|
|
|
|
.kpi-icon.red {
|
|
background: rgba(244, 67, 54, 0.1);
|
|
color: var(--danger);
|
|
}
|
|
|
|
.kpi-title {
|
|
font-size: 1rem;
|
|
font-weight: 500;
|
|
color: #8cc8c1;
|
|
}
|
|
|
|
.kpi-value {
|
|
font-size: 2.2rem;
|
|
font-weight: 700;
|
|
margin: 10px 0;
|
|
color: #8cc8c1;
|
|
}
|
|
|
|
.kpi-trend {
|
|
display: flex;
|
|
align-items: center;
|
|
font-size: 0.9rem;
|
|
gap: 5px;
|
|
}
|
|
|
|
.trend-up {
|
|
color: var(--accent);
|
|
}
|
|
|
|
.trend-down {
|
|
color: var(--danger);
|
|
}
|
|
|
|
/* 分析部分 */
|
|
.analysis-section {
|
|
/* background: var(--bg-color); */
|
|
background: linear-gradient(135deg, rgba(22, 186, 170, 0.1) 0%, rgba(22, 186, 170, 0.05) 100%);
|
|
border-radius: 12px;
|
|
padding: 25px;
|
|
box-shadow: var(--card-shadow);
|
|
margin-bottom: 25px;
|
|
border-top: 4px solid var(--primary);
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 1.3rem;
|
|
color: var(--primary);
|
|
margin-bottom: 20px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 1px solid var(--gray);
|
|
}
|
|
|
|
.bottleneck-container {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
gap: 20px;
|
|
}
|
|
|
|
.bottleneck-card {
|
|
border-left: 4px solid var(--warning);
|
|
padding: 15px;
|
|
/* background: #fff9e6; */
|
|
background: rgba(22, 186, 170, 0.08);
|
|
border: 1px solid rgba(22, 186, 170, 0.2);
|
|
border-radius: 8px;
|
|
/* border-radius: 0 8px 8px 0; */
|
|
transition: all 0.3s;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.bottleneck-card:hover {
|
|
transform: translateX(5px);
|
|
/* background: #fff1cc; */
|
|
background: rgba(22, 186, 170, 0.15);
|
|
border-color: rgba(22, 186, 170, 0.4);
|
|
}
|
|
|
|
.bottleneck-title {
|
|
font-weight: 500;
|
|
margin-bottom: 8px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.bottleneck-desc {
|
|
font-size: 0.9rem;
|
|
color: #8cc8c1;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.optimization-card {
|
|
/* background: linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%); */
|
|
background: rgba(22, 186, 170, 0.08);
|
|
border: 1px solid rgba(22, 186, 170, 0.2);
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
}
|
|
|
|
.suggestion-item {
|
|
display: flex;
|
|
gap: 15px;
|
|
padding: 15px 0;
|
|
border-bottom: 1px dashed #ddd;
|
|
cursor: pointer;
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.suggestion-item:hover {
|
|
/* background: rgba(255,255,255,0.5); */
|
|
background: rgba(22, 186, 170, 0.15);
|
|
border-color: rgba(22, 186, 170, 0.4);
|
|
transform: translateX(5px);
|
|
/* box-shadow: -2px 0 10px rgba(22, 186, 170, 0.3); */
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
}
|
|
|
|
.suggestion-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.suggestion-icon {
|
|
background: var(--accent);
|
|
color: var(--bg-color);
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.suggestion-content h4 {
|
|
margin-bottom: 5px;
|
|
color: var(--primary);
|
|
}
|
|
|
|
.suggestion-content p {
|
|
color: #8cc8c1;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.priority-high {
|
|
color: var(--danger);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.priority-medium {
|
|
color: var(--warning);
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* 二级页面样式 */
|
|
.secondary-page {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(0,0,0,0.8);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 1000;
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.secondary-page.active {
|
|
opacity: 1;
|
|
visibility: visible;
|
|
}
|
|
|
|
.page-content {
|
|
/* background: white; */
|
|
background: url("../../img/video/child-back.png") no-repeat 0 0/100% 100% transparent;
|
|
width: 90%;
|
|
max-width: 1000px;
|
|
max-height: 90vh;
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
transform: translateY(20px);
|
|
transition: transform 0.4s;
|
|
}
|
|
|
|
.secondary-page.active .page-content {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
.page-header {
|
|
padding: 20px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
/* background: #f5f5f5; */
|
|
border-bottom: 1px solid #e0e0e0;
|
|
}
|
|
|
|
.page-header h3 {
|
|
font-size: 1.5rem;
|
|
color: var(--primary);
|
|
}
|
|
|
|
.close-btn {
|
|
background: rgba(0,0,0,0.1);
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: pointer;
|
|
font-size: 1.2rem;
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.close-btn:hover {
|
|
background: rgba(0,0,0,0.2);
|
|
}
|
|
|
|
.page-body {
|
|
padding: 30px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.detail-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
gap: 20px;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.detail-card {
|
|
background: var(--light);
|
|
border-radius: 10px;
|
|
padding: 20px;
|
|
box-shadow: var(--card-shadow);
|
|
}
|
|
|
|
.detail-card h4 {
|
|
color: var(--primary);
|
|
margin-bottom: 15px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 1px solid var(--gray);
|
|
}
|
|
|
|
.data-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 8px 0;
|
|
border-bottom: 1px dashed #ddd;
|
|
}
|
|
|
|
.data-row:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.progress-container {
|
|
margin: 15px 0;
|
|
}
|
|
|
|
.progress-label {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.progress-bar {
|
|
height: 10px;
|
|
background: #e0e0e0;
|
|
border-radius: 5px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.progress-fill {
|
|
height: 100%;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
.detail-chart {
|
|
height: 300px;
|
|
margin: 30px 0;
|
|
}
|
|
|
|
/* 页脚 */
|
|
footer {
|
|
text-align: center;
|
|
color: #8cc8c1;
|
|
padding: 20px;
|
|
font-size: 0.9rem;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.stat-badge {
|
|
display: inline-block;
|
|
padding: 3px 8px;
|
|
border-radius: 20px;
|
|
font-size: 0.8rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.badge-green {
|
|
background: rgba(76, 175, 80, 0.2);
|
|
color: var(--accent);
|
|
}
|
|
|
|
.badge-orange {
|
|
background: rgba(255, 152, 0, 0.2);
|
|
color: var(--warning);
|
|
}
|
|
|
|
.badge-red {
|
|
background: rgba(244, 67, 54, 0.2);
|
|
color: var(--danger);
|
|
}
|
|
|
|
.chart-container {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 20px;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.chart-box {
|
|
flex: 1 1 400px;
|
|
min-height: 300px;
|
|
/* background: white; */
|
|
border-radius: 10px;
|
|
padding: 15px;
|
|
box-shadow: var(--card-shadow);
|
|
}
|
|
|
|
.table-container {
|
|
margin-top: 20px;
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.data-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
background: white;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
box-shadow: var(--card-shadow);
|
|
}
|
|
|
|
.data-table th {
|
|
background: var(--primary);
|
|
color: white;
|
|
padding: 12px 15px;
|
|
text-align: left;
|
|
}
|
|
|
|
.data-table td {
|
|
padding: 10px 15px;
|
|
border-bottom: 1px solid var(--gray);
|
|
color: #000;
|
|
}
|
|
|
|
.data-table tr:nth-child(even) {
|
|
background: var(--light);
|
|
}
|
|
|
|
.data-table tr:hover {
|
|
background: rgba(26, 58, 95, 0.05);
|
|
}
|
|
|
|
/* background: rgba(22, 186, 170, 0.15);
|
|
border-color: rgba(22, 186, 170, 0.4);
|
|
transform: translateX(5px);
|
|
box-shadow: -2px 0 10px rgba(22, 186, 170, 0.3); */
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
|
|
<!-- 主仪表盘 -->
|
|
<div class="dashboard" id="dashboard"></div>
|
|
|
|
<!-- 瓶颈分析 -->
|
|
<div class="analysis-section">
|
|
<div class="section-title">瓶颈识别与分析</div>
|
|
<div class="bottleneck-container" id="bottleneck-container"></div>
|
|
</div>
|
|
|
|
<!-- 优化建议 -->
|
|
<div class="analysis-section">
|
|
<div class="section-title">优化建议与措施</div>
|
|
<div class="optimization-card" id="suggestion-container"></div>
|
|
</div>
|
|
|
|
<footer>
|
|
<p id="footer-text">工地整体效能分析</p>
|
|
</footer>
|
|
</div>
|
|
|
|
<!-- 二级页面容器 -->
|
|
<div id="secondary-pages"></div>
|
|
<script src="../../js/publics/sm4.js" type="text/javascript"></script>
|
|
<script src="../../js/publics/jquery-3.6.0.min.js" type="text/javascript"></script>
|
|
<script src="../../js/publics/public.js"></script>
|
|
<script src="../../plugin/scroll/jquery.nicescroll.min.js"></script>
|
|
<script src="../../js/publics/aescbc.js"></script>
|
|
<script src="../../js/publics/sm3.js"></script>
|
|
<script src="../../api/commonRequest.js"></script>
|
|
<script>
|
|
// 示例数据 - 模拟后台返回的数据结构
|
|
/* const pageData = {
|
|
"personnelPage": [
|
|
{
|
|
"page_id": "personnel",
|
|
"type": "chart",
|
|
"content": "{\"data\": [60, 70, 78, 80], \"title\": \"人员利用率趋势\"}"
|
|
},
|
|
{
|
|
"page_id": "personnel",
|
|
"type": "table",
|
|
"content": "{\"headers\": [\"工种\", \"数量\", \"利用率\"], \"rows\": [[\"焊工\", \"42人\", \"85%\"], [\"电工\", \"28人\", \"76%\"], [\"木工\", \"35人\", \"68%\"], [\"混凝土工\", \"53人\", \"92%\"]]}"
|
|
}
|
|
],
|
|
"footer": "工地整体效能分析系统 © 2023 | 数据更新时间: 2023-11-16 14:30",
|
|
"bottlenecks": [
|
|
{
|
|
"id": 1,
|
|
"title": "人员调配不均",
|
|
"description": "部分岗位人员长期闲置,部分岗位人力不足",
|
|
"impact": "高影响",
|
|
"delay": "影响范围: 整个项目"
|
|
},
|
|
{
|
|
"id": 2,
|
|
"title": "设备维护不足",
|
|
"description": "关键设备缺乏定期维护,导致故障率上升",
|
|
"impact": "中影响",
|
|
"delay": "预计延误: 2天"
|
|
},
|
|
{
|
|
"id": 3,
|
|
"title": "物料供应延迟",
|
|
"description": "钢筋和水泥供应不及时,影响施工进度",
|
|
"impact": "高影响",
|
|
"delay": "延误天数: 3天"
|
|
}
|
|
],
|
|
"equipmentPage": [
|
|
{
|
|
"page_id": "equipment",
|
|
"type": "chart",
|
|
"content": "{\"data\": [85, 92, 78, 88, 65], \"title\": \"设备完好率趋势\"}"
|
|
},
|
|
{
|
|
"page_id": "equipment",
|
|
"type": "table",
|
|
"content": "{\"headers\": [\"设备\", \"状态\", \"使用率\"], \"rows\": [[\"塔吊\", \"正常\", \"85%\"], [\"吊篮\", \"故障\", \"0%\"], [\"挖掘机\", \"正常\", \"92%\"], [\"搅拌机\", \"维护中\", \"65%\"], [\"起重机\", \"正常\", \"78%\"]]}"
|
|
}
|
|
],
|
|
"suggestions": [
|
|
{
|
|
"id": 1,
|
|
"title": "优化施工流程",
|
|
"description": "通过流程再造提升资源使用效率",
|
|
"priority": "高优先级"
|
|
},
|
|
{
|
|
"id": 2,
|
|
"title": "加强设备维护",
|
|
"description": "建立设备定期维护计划,减少故障率",
|
|
"priority": "中优先级"
|
|
},
|
|
{
|
|
"id": 3,
|
|
"title": "物料供应保障",
|
|
"description": "与供应商建立长期合作关系,确保物料及时供应",
|
|
"priority": "高优先级"
|
|
}
|
|
],
|
|
"kpis": [
|
|
{
|
|
"id": "equipment",
|
|
"title": "设备完好率",
|
|
"value": "91.2%",
|
|
"icon": "tools",
|
|
"color": "green",
|
|
"trend": {
|
|
"value": 2.3,
|
|
"direction": "up",
|
|
"text": "较上月提高 2.3%"
|
|
},
|
|
"description": "故障率下降至 1.8%"
|
|
},
|
|
{
|
|
"id": "personnel",
|
|
"title": "人员利用率",
|
|
"value": "78.3%",
|
|
"icon": "users",
|
|
"color": "blue",
|
|
"trend": {
|
|
"value": 5.2,
|
|
"direction": "up",
|
|
"text": "较上周提高 5.2%"
|
|
},
|
|
"description": "平均闲置时间 1.2 小时/天"
|
|
},
|
|
{
|
|
"id": "progress",
|
|
"title": "工程进度",
|
|
"value": "72.5%",
|
|
"icon": "tasks",
|
|
"color": "orange",
|
|
"trend": {
|
|
"value": 8.3,
|
|
"direction": "up",
|
|
"text": "较计划超前 2 天"
|
|
},
|
|
"description": "本周完成进度 8.3%"
|
|
}
|
|
],
|
|
"progressPage": [
|
|
{
|
|
"page_id": "progress",
|
|
"type": "chart",
|
|
"content": "{\"data\": [45, 60, 72, 85], \"title\": \"工程进度趋势\"}"
|
|
},
|
|
{
|
|
"page_id": "progress",
|
|
"type": "table",
|
|
"content": "{\"headers\": [\"区域\", \"进度\", \"状态\"], \"rows\": [[\"1号楼\", \"85%\", \"超前\"], [\"2号楼\", \"65%\", \"滞后\"], [\"3号楼\", \"78%\", \"正常\"], [\"地下车库\", \"92%\", \"超前\"]]}"
|
|
}
|
|
]
|
|
}; */
|
|
let pageData = {};
|
|
let url = commonUrl + "screen/Dashapi/pages/dashInfo";
|
|
ajaxRequest(url, "get", "", true, function () {
|
|
}, function (result) {
|
|
// console.log("22222222222222222")
|
|
// console.log(JSON.stringify(result));
|
|
pageData=result;
|
|
initPage();
|
|
}, function (xhr, status, error) {
|
|
error(xhr, status, error)
|
|
}, "application/json",aqEnnable);
|
|
// 渲染主页面
|
|
function renderMainPage() {
|
|
// 渲染KPI卡片
|
|
const dashboard = document.getElementById('dashboard');
|
|
dashboard.innerHTML = '';
|
|
|
|
pageData.kpis.forEach(kpi => {
|
|
const kpiCard = document.createElement('div');
|
|
kpiCard.className = 'kpi-card';
|
|
kpiCard.onclick = () => openPage(kpi.id);
|
|
|
|
kpiCard.innerHTML = `
|
|
<div class="kpi-header">
|
|
<div>
|
|
<div class="kpi-title">${kpi.title}</div>
|
|
<div class="kpi-value">${kpi.value}</div>
|
|
</div>
|
|
<div class="kpi-icon ${kpi.color}">
|
|
<i class="fas fa-${kpi.icon}"></i>
|
|
</div>
|
|
</div>
|
|
<div class="kpi-trend trend-${kpi.trend.direction}">
|
|
<i class="fas fa-arrow-${kpi.trend.direction}"></i> ${kpi.trend.text}
|
|
</div>
|
|
<div class="kpi-trend">
|
|
${kpi.description}
|
|
</div>
|
|
`;
|
|
|
|
dashboard.appendChild(kpiCard);
|
|
});
|
|
|
|
// 渲染瓶颈分析
|
|
const bottleneckContainer = document.getElementById('bottleneck-container');
|
|
bottleneckContainer.innerHTML = '';
|
|
|
|
pageData.bottlenecks.forEach(bottleneck => {
|
|
const bottleneckCard = document.createElement('div');
|
|
bottleneckCard.className = 'bottleneck-card';
|
|
bottleneckCard.onclick = () => openPage('bottleneck');
|
|
|
|
const impactClass = bottleneck.impact === '高影响' ? 'badge-red' :
|
|
bottleneck.impact === '中影响' ? 'badge-orange' : 'badge-green';
|
|
|
|
bottleneckCard.innerHTML = `
|
|
<div class="bottleneck-title">
|
|
<span><i class="fas fa-exclamation-triangle"></i> ${bottleneck.title}</span>
|
|
</div>
|
|
<div class="bottleneck-desc">
|
|
${bottleneck.description}
|
|
</div>
|
|
<div class="kpi-trend">
|
|
<span class="stat-badge ${impactClass}">${bottleneck.impact}</span> ${bottleneck.delay}
|
|
</div>
|
|
`;
|
|
|
|
bottleneckContainer.appendChild(bottleneckCard);
|
|
});
|
|
|
|
// 渲染优化建议
|
|
const suggestionContainer = document.getElementById('suggestion-container');
|
|
suggestionContainer.innerHTML = '';
|
|
|
|
pageData.suggestions.forEach((suggestion, index) => {
|
|
const suggestionItem = document.createElement('div');
|
|
suggestionItem.className = 'suggestion-item';
|
|
suggestionItem.onclick = () => openPage(suggestion.id);
|
|
|
|
const priorityClass = suggestion.priority === '高优先级' ? 'priority-high' :
|
|
suggestion.priority === '中优先级' ? 'priority-medium' : '';
|
|
|
|
suggestionItem.innerHTML = `
|
|
<div class="suggestion-icon">${index + 1}</div>
|
|
<div class="suggestion-content">
|
|
<h4>${suggestion.title} <span class="${priorityClass}">(${suggestion.priority})</span></h4>
|
|
<p>${suggestion.description}</p>
|
|
</div>
|
|
`;
|
|
|
|
suggestionContainer.appendChild(suggestionItem);
|
|
});
|
|
|
|
// 渲染页脚
|
|
// document.getElementById('footer-text').textContent = pageData.footer;
|
|
document.getElementById('footer-text').textContent = '';
|
|
}
|
|
|
|
// 渲染二级页面
|
|
function renderSecondaryPages() {
|
|
const secondaryPages = document.getElementById('secondary-pages');
|
|
secondaryPages.innerHTML = '';
|
|
|
|
// 人员效能分析页面
|
|
const personnelPage = createSecondaryPage('personnel', '人员效能分析', 'users');
|
|
secondaryPages.appendChild(personnelPage);
|
|
|
|
// 设备使用分析页面
|
|
const equipmentPage = createSecondaryPage('equipment', '设备使用分析', 'tools');
|
|
secondaryPages.appendChild(equipmentPage);
|
|
|
|
// 工程进度分析页面
|
|
const progressPage = createSecondaryPage('progress', '工程进度分析', 'tasks');
|
|
secondaryPages.appendChild(progressPage);
|
|
|
|
// 瓶颈分析页面
|
|
const bottleneckPage = createBottleneckPage();
|
|
secondaryPages.appendChild(bottleneckPage);
|
|
}
|
|
|
|
// 创建二级页面
|
|
function createSecondaryPage(id, title, icon) {
|
|
const page = document.createElement('div');
|
|
page.className = 'secondary-page';
|
|
page.id = `${id}-page`;
|
|
|
|
page.innerHTML = `
|
|
<div class="page-content">
|
|
<div class="page-header">
|
|
<h3><i class="fas fa-${icon}"></i> ${title}</h3>
|
|
<div class="close-btn" onclick="closePage('${id}')">
|
|
<i class="fas fa-times"></i>
|
|
</div>
|
|
</div>
|
|
<div class="page-body" id="${id}-page-body">
|
|
<div class="chart-container" id="${id}-charts"></div>
|
|
<div class="table-container" id="${id}-tables"></div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
return page;
|
|
}
|
|
|
|
// 创建瓶颈分析页面
|
|
function createBottleneckPage() {
|
|
const page = document.createElement('div');
|
|
page.className = 'secondary-page';
|
|
page.id = 'bottleneck-page';
|
|
|
|
page.innerHTML = `
|
|
<div class="page-content">
|
|
<div class="page-header">
|
|
<h3><i class="fas fa-exclamation-triangle"></i> 瓶颈详细分析</h3>
|
|
<div class="close-btn" onclick="closePage('bottleneck')">
|
|
<i class="fas fa-times"></i>
|
|
</div>
|
|
</div>
|
|
<div class="page-body" id="bottleneck-page-body">
|
|
<div class="bottleneck-container" id="bottleneck-details"></div>
|
|
<div class="chart-container">
|
|
<div class="chart-box" id="bottleneck-chart1"></div>
|
|
<div class="chart-box" id="bottleneck-chart2"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
return page;
|
|
}
|
|
|
|
// 渲染二级页面内容
|
|
function renderSecondaryContent() {
|
|
// 人员页面
|
|
renderPageContent('personnel');
|
|
|
|
// 设备页面
|
|
renderPageContent('equipment');
|
|
|
|
// 进度页面
|
|
renderPageContent('progress');
|
|
|
|
// 瓶颈页面
|
|
renderBottleneckContent();
|
|
}
|
|
|
|
function renderPageContent(pageId) {
|
|
const chartsContainer = document.getElementById(`${pageId}-charts`);
|
|
const tablesContainer = document.getElementById(`${pageId}-tables`);
|
|
|
|
if (!chartsContainer || !tablesContainer) return;
|
|
|
|
chartsContainer.innerHTML = '';
|
|
tablesContainer.innerHTML = '';
|
|
|
|
const pageDataItems = pageData[`${pageId}Page`];
|
|
|
|
if (pageDataItems && pageDataItems.length > 0) {
|
|
pageDataItems.forEach(item => {
|
|
if (item.type === 'chart') {
|
|
const chartBox = document.createElement('div');
|
|
chartBox.className = 'chart-box';
|
|
chartBox.id = `${pageId}-${item.type}-${Date.now()}`;
|
|
chartsContainer.appendChild(chartBox);
|
|
|
|
const content = JSON.parse(item.content);
|
|
renderChart(chartBox.id, content.title, content.data);
|
|
}
|
|
else if (item.type === 'table') {
|
|
const content = JSON.parse(item.content);
|
|
renderTable(tablesContainer, content.headers, content.rows);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function renderBottleneckContent() {
|
|
const bottleneckDetails = document.getElementById('bottleneck-details');
|
|
if (!bottleneckDetails) return;
|
|
|
|
bottleneckDetails.innerHTML = '';
|
|
|
|
pageData.bottlenecks.forEach(bottleneck => {
|
|
const impactClass = bottleneck.impact === '高影响' ? 'badge-red' :
|
|
bottleneck.impact === '中影响' ? 'badge-orange' : 'badge-green';
|
|
|
|
const bottleneckCard = document.createElement('div');
|
|
bottleneckCard.className = 'bottleneck-card';
|
|
|
|
bottleneckCard.innerHTML = `
|
|
<div class="bottleneck-title">
|
|
<span><i class="fas fa-exclamation-triangle"></i> ${bottleneck.title}</span>
|
|
</div>
|
|
<div class="bottleneck-desc">
|
|
${bottleneck.description}
|
|
</div>
|
|
<div class="kpi-trend">
|
|
<span class="stat-badge ${impactClass}">${bottleneck.impact}</span> ${bottleneck.delay}
|
|
</div>
|
|
<div class="progress-container" style="margin-top: 15px;">
|
|
<div class="progress-label">
|
|
<span>影响程度</span>
|
|
<span>${bottleneck.impact === '高影响' ? '85%' : bottleneck.impact === '中影响' ? '60%' : '30%'}</span>
|
|
</div>
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" style="width: ${bottleneck.impact === '高影响' ? '85%' : bottleneck.impact === '中影响' ? '60%' : '30%'}; background: ${impactClass === 'badge-red' ? 'var(--danger)' : impactClass === 'badge-orange' ? 'var(--warning)' : 'var(--accent)'}"></div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
bottleneckDetails.appendChild(bottleneckCard);
|
|
});
|
|
|
|
// 渲染瓶颈图表
|
|
renderChart('bottleneck-chart1', '瓶颈影响程度', [85, 60, 75]);
|
|
renderChart('bottleneck-chart2', '解决优先级', [90, 70, 85]);
|
|
}
|
|
|
|
// 渲染图表
|
|
function renderChart(containerId, title, data) {
|
|
const chartDom = document.getElementById(containerId);
|
|
if (!chartDom) return;
|
|
|
|
const chart = echarts.init(chartDom);
|
|
const option = {
|
|
title: {
|
|
text: title,
|
|
left: 'center',
|
|
textStyle: {
|
|
fontSize: 16,
|
|
fontWeight: 'bold',
|
|
color:'#fff'
|
|
}
|
|
},
|
|
tooltip: {
|
|
trigger: 'axis'
|
|
},
|
|
grid: {
|
|
left: '3%',
|
|
right: '4%',
|
|
bottom: '3%',
|
|
containLabel: true
|
|
},
|
|
xAxis: {
|
|
type: 'category',
|
|
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'].slice(0, data.length),
|
|
axisLabel: {
|
|
textStyle: {
|
|
color: '#fff', // 文字颜色
|
|
fontSize: 12 // 文字像素
|
|
}
|
|
},
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
name: '百分比 (%)',
|
|
min: 0,
|
|
max: 100,
|
|
nameTextStyle: {
|
|
color: '#fff',
|
|
fontSize: 14
|
|
},
|
|
axisLabel: {
|
|
textStyle: {
|
|
color: '#fff', // 文字颜色
|
|
fontSize: 12 // 文字像素
|
|
}
|
|
},
|
|
},
|
|
series: [
|
|
{
|
|
name: title,
|
|
type: 'line',
|
|
data: data,
|
|
smooth: true,
|
|
label: {
|
|
show: true, // 线条折点处显示值
|
|
position: 'top', // 标签的位置
|
|
color: "#fff", // 文字颜色
|
|
fontSize: 12, // 文字像素
|
|
},
|
|
lineStyle: {
|
|
width: 3,
|
|
color: '#20d3c2'
|
|
},
|
|
itemStyle: {
|
|
color: '#2c5c8c'
|
|
},
|
|
areaStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: 'rgba(26, 58, 95, 0.5)' },
|
|
{ offset: 1, color: 'rgba(26, 58, 95, 0.1)' }
|
|
])
|
|
}
|
|
}
|
|
]
|
|
};
|
|
|
|
chart.setOption(option);
|
|
|
|
// 响应窗口大小变化
|
|
window.addEventListener('resize', function() {
|
|
chart.resize();
|
|
});
|
|
}
|
|
|
|
// 渲染表格
|
|
function renderTable(container, headers, rows) {
|
|
const table = document.createElement('table');
|
|
table.className = 'data-table';
|
|
|
|
// 创建表头
|
|
const thead = document.createElement('thead');
|
|
const headerRow = document.createElement('tr');
|
|
|
|
headers.forEach(header => {
|
|
const th = document.createElement('th');
|
|
th.textContent = header;
|
|
headerRow.appendChild(th);
|
|
});
|
|
|
|
thead.appendChild(headerRow);
|
|
table.appendChild(thead);
|
|
|
|
// 创建表体
|
|
const tbody = document.createElement('tbody');
|
|
|
|
rows.forEach(rowData => {
|
|
const row = document.createElement('tr');
|
|
|
|
rowData.forEach(cellData => {
|
|
const td = document.createElement('td');
|
|
td.textContent = cellData;
|
|
row.appendChild(td);
|
|
});
|
|
|
|
tbody.appendChild(row);
|
|
});
|
|
|
|
table.appendChild(tbody);
|
|
container.appendChild(table);
|
|
}
|
|
|
|
// 页面控制函数
|
|
function openPage(pageId) {
|
|
document.getElementById(pageId + '-page').classList.add('active');
|
|
document.body.style.overflow = 'hidden';
|
|
}
|
|
|
|
function closePage(pageId) {
|
|
document.getElementById(pageId + '-page').classList.remove('active');
|
|
document.body.style.overflow = 'auto';
|
|
}
|
|
|
|
// 初始化页面
|
|
function initPage() {
|
|
renderMainPage();
|
|
renderSecondaryPages();
|
|
renderSecondaryContent();
|
|
|
|
// 添加点击页面外部关闭弹窗功能
|
|
document.querySelectorAll('.secondary-page').forEach(page => {
|
|
page.addEventListener('click', function(e) {
|
|
if (e.target === this) {
|
|
const pageId = this.id.replace('-page', '');
|
|
closePage(pageId);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// 页面加载完成后初始化
|
|
// window.onload = initPage;
|
|
</script>
|
|
</body>
|
|
</html>
|