独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>时空二维网格调度模型 - IFR最终理想解</title>
<style>
:root {
/* Core Theme Colors */
--bg-color: #06090f;
--panel-bg: #0d121e;
--grid-line: #1e293b;
--text-main: #e2e8f0;
--text-muted: #64748b;
--accent-cyan: #06b6d4;
--accent-emerald: #10b981;
--accent-amber: #f59e0b;
--alert-rose: #f43f5e;
--ui-border: rgba(30, 41, 59, 0.8);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-main);
font-family: 'SF Pro Display', 'Inter', -apple-system, 'Microsoft YaHei', sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
overflow: hidden;
background-image: radial-gradient(circle at 50% 50%, #111827 0%, #06090f 100%);
}
.dashboard-container {
position: relative;
width: 100%;
max-width: 1800px;
height: 100%;
display: flex;
flex-direction: column;
padding: 24px;
}
/* Header UI */
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
padding: 0 24px;
z-index: 10;
}
.title-group h1 {
font-size: 24px;
font-weight: 600;
letter-spacing: 2px;
color: #fff;
text-shadow: 0 0 20px rgba(6, 182, 212, 0.4);
display: flex;
align-items: center;
gap: 12px;
}
.title-group h1::before {
content: '';
display: inline-block;
width: 12px;
height: 12px;
background-color: var(--accent-cyan);
border-radius: 2px;
box-shadow: 0 0 10px var(--accent-cyan);
}
.subtitle {
font-size: 14px;
color: var(--text-muted);
margin-top: 6px;
font-family: monospace;
}
.clock-display {
display: flex;
align-items: center;
background: rgba(13, 18, 30, 0.8);
border: 1px solid var(--accent-emerald);
padding: 12px 24px;
border-radius: 8px;
box-shadow: 0 0 30px rgba(16, 185, 129, 0.1);
backdrop-filter: blur(10px);
}
.clock-time {
font-size: 32px;
font-weight: 700;
font-family: 'Courier New', Courier, monospace;
color: var(--accent-emerald);
margin-right: 16px;
text-shadow: 0 0 15px rgba(16, 185, 129, 0.5);
}
.system-status {
font-size: 14px;
color: var(--text-main);
display: flex;
flex-direction: column;
}
.status-badge {
font-size: 12px;
background: rgba(16, 185, 129, 0.2);
color: var(--accent-emerald);
padding: 2px 8px;
border-radius: 4px;
margin-bottom: 4px;
width: fit-content;
}
/* SVG Container */
.svg-container {
flex-grow: 1;
position: relative;
background: var(--panel-bg);
border: 1px solid var(--ui-border);
border-radius: 12px;
overflow: hidden;
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
}
svg {
width: 100%;
height: 100%;
display: block;
}
/* Interactive Controls */
.controls {
position: absolute;
bottom: 32px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 16px;
z-index: 20;
background: rgba(13, 18, 30, 0.9);
padding: 12px 24px;
border-radius: 30px;
border: 1px solid var(--ui-border);
backdrop-filter: blur(10px);
}
button {
background: transparent;
border: 1px solid var(--text-muted);
color: var(--text-main);
padding: 8px 16px;
border-radius: 20px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s ease;
}
button:hover {
background: rgba(255, 255, 255, 0.05);
border-color: var(--text-main);
}
button.active {
background: rgba(6, 182, 212, 0.1);
border-color: var(--accent-cyan);
color: var(--accent-cyan);
}
/* SVG Animations & Styles */
.anim-obj {
transition: transform 1.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.anim-slow {
transition: transform 1.8s cubic-bezier(0.65, 0, 0.35, 1);
}
.glow {
filter: drop-shadow(0 0 8px currentColor);
}
.matrix-cell {
transition: fill 0.5s ease;
}
.radar-sweep {
animation: sweep 4s linear infinite;
transform-origin: center;
}
@keyframes sweep {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes pulse {
0%, 100% { opacity: 0.3; }
50% { opacity: 0.8; }
}
.pulse {
animation: pulse 2s infinite;
}
.crane-arm {
transition: transform 1s ease-in-out;
transform-origin: 30px 30px;
}
.crane-working {
animation: craneWork 2s infinite alternate ease-in-out;
}
@keyframes craneWork {
0% { transform: rotate(-20deg); }
100% { transform: rotate(20deg); }
}
@keyframes dashMove {
to { stroke-dashoffset: -20; }
}
.path-line {
stroke-dasharray: 6;
animation: dashMove 1s linear infinite;
opacity: 0;
transition: opacity 0.5s ease;
}
.path-line.active {
opacity: 0.6;
}
/* Triz Callout */
.triz-panel {
position: absolute;
right: 32px;
bottom: 32px;
width: 320px;
background: rgba(13, 18, 30, 0.85);
border-left: 4px solid var(--accent-emerald);
padding: 16px;
border-radius: 4px;
backdrop-filter: blur(10px);
z-index: 10;
}
.triz-panel h3 {
color: var(--accent-emerald);
font-size: 16px;
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 8px;
}
.triz-panel p {
font-size: 13px;
color: #cbd5e1;
line-height: 1.6;
margin-bottom: 8px;
}
</style>
</head>
<body>
<div class="dashboard-container">
<!-- Header -->
<div class="header">
<div class="title-group">
<h1>基于“时间窗×空间格”的搬迁调度最终理想解</h1>
<div class="subtitle">TRIZ IFR | 无等待、无拥堵、资源完美利用系统</div>
</div>
<div class="clock-display">
<div class="clock-time" id="clock-display">08:00</div>
<div class="system-status">
<span class="status-badge" id="status-badge">系统就绪</span>
<span id="status-text">预排计划生成中...</span>
</div>
</div>
</div>
<!-- Main Visualization -->
<div class="svg-container">
<svg viewBox="0 0 1600 800" preserveAspectRatio="xMidYMid meet">
<defs>
<!-- Grid Pattern -->
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="rgba(30, 41, 59, 0.4)" stroke-width="1" />
</pattern>
<!-- Glowing Filters -->
<filter id="glow-cyan" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="5" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<filter id="glow-amber" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="5" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<!-- Truck Symbol -->
<g id="truck-icon">
<rect x="-15" y="-25" width="30" height="50" rx="4" fill="currentColor" opacity="0.9" />
<rect x="-11" y="-15" width="22" height="15" rx="2" fill="#000" opacity="0.4" />
<circle cx="-17" cy="-15" r="3" fill="#333" />
<circle cx="17" cy="-15" r="3" fill="#333" />
<circle cx="-17" cy="15" r="3" fill="#333" />
<circle cx="17" cy="15" r="3" fill="#333" />
</g>
<!-- Matrix Token Symbol -->
<g id="matrix-token">
<rect x="-35" y="-15" width="70" height="30" rx="15" fill="currentColor" fill-opacity="0.2" stroke="currentColor" stroke-width="2" />
<circle cx="-20" cy="0" r="4" fill="currentColor" class="glow" />
<text x="-5" y="4" fill="#fff" font-size="12" font-weight="bold" font-family="monospace">T-X</text>
</g>
</defs>
<!-- Background -->
<rect width="1600" height="800" fill="url(#grid)" />
<!-- ==================== LEFT PANEL: MATRIX ENGINE ==================== -->
<g transform="translate(50, 100)">
<!-- Panel BG -->
<rect width="650" height="600" fill="rgba(15, 23, 42, 0.6)" rx="12" stroke="rgba(30, 41, 59, 1)" />
<!-- Title -->
<text x="30" y="40" fill="#94a3b8" font-size="16" font-weight="bold" letter-spacing="1">时空二维网格排程引擎 (逻辑运算层)</text>
<line x1="30" y1="55" x2="620" y2="55" stroke="rgba(30, 41, 59, 1)" stroke-width="2" />
<!-- Y-Axis (Space Grid) -->
<g fill="#cbd5e1" font-size="14" font-weight="500">
<text x="30" y="160">上车道 (入场)</text>
<text x="30" y="280">缓冲等待区 (容量: 3)</text>
<text x="30" y="400">吊装站位 A (容量: 1)</text>
<text x="30" y="520">吊装站位 B (容量: 1)</text>
</g>
<!-- X-Axis (Time Windows) -->
<g fill="#cbd5e1" font-size="14" font-family="monospace" text-anchor="middle">
<text x="200" y="90">08:00</text>
<text x="300" y="90">08:30</text>
<text x="400" y="90">09:00</text>
<text x="500" y="90">09:30</text>
<text x="600" y="90">10:00</text>
</g>
<!-- Grid Cells -->
<g id="grid-cells" stroke="rgba(30, 41, 59, 0.5)" stroke-width="1" fill="none">
<!-- Generates via JS for concise code, but placing a few for structural integrity if JS fails -->
<path d="M 150 110 L 150 560 M 250 110 L 250 560 M 350 110 L 350 560 M 450 110 L 450 560 M 550 110 L 550 560" />
<path d="M 150 200 L 630 200 M 150 320 L 630 320 M 150 440 L 630 440" />
</g>
<!-- Active Time Scanner -->
<rect id="time-scanner" x="150" y="100" width="100" height="470" fill="url(#time-scan-grad)" opacity="0.3" class="anim-obj" />
<defs>
<linearGradient id="time-scan-grad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#06b6d4" stop-opacity="0" />
<stop offset="50%" stop-color="#06b6d4" stop-opacity="0.2" />
<stop offset="100%" stop-color="#06b6d4" stop-opacity="0" />
</linearGradient>
</defs>
<!-- Data Tokens (Injected via JS but defined here) -->
<g id="tokens-layer"></g>
</g>
<!-- ==================== RIGHT PANEL: PHYSICAL MAP ==================== -->
<g transform="translate(750, 100)">
<!-- Panel BG -->
<rect width="800" height="600" fill="rgba(15, 23, 42, 0.4)" rx="12" stroke="rgba(30, 41, 59, 1)" />
<text x="30" y="40" fill="#94a3b8" font-size="16" font-weight="bold" letter-spacing="1">井场物理空间映射 (物理执行层)</text>
<line x1="30" y1="55" x2="770" y2="55" stroke="rgba(30, 41, 59, 1)" stroke-width="2" />
<!-- Topography / Zones -->
<!-- Road -->
<path d="M 50 600 L 50 500 C 50 480 70 460 90 460 L 750 460" fill="none" stroke="rgba(255, 255, 255, 0.1)" stroke-width="60" stroke-linecap="round"/>
<text x="700" y="465" fill="#64748b" font-size="12" text-anchor="end">上车道 / 入场</text>
<!-- Buffer Zone -->
<rect x="350" y="320" width="300" height="120" rx="8" fill="none" stroke="var(--accent-amber)" stroke-width="2" stroke-dasharray="8 4" opacity="0.6" />
<text x="360" y="340" fill="var(--accent-amber)" font-size="12" opacity="0.8">缓冲等待区 (超时阈值: 15min)</text>
<rect x="380" y="360" width="50" height="60" fill="rgba(245, 158, 11, 0.1)" rx="4"/>
<rect x="470" y="360" width="50" height="60" fill="rgba(245, 158, 11, 0.1)" rx="4"/>
<rect x="560" y="360" width="50" height="60" fill="rgba(245, 158, 11, 0.1)" rx="4"/>
<!-- Crane Zone A -->
<rect x="150" y="100" width="220" height="180" rx="8" fill="rgba(16, 185, 129, 0.05)" stroke="var(--accent-emerald)" stroke-width="2" />
<text x="160" y="125" fill="var(--accent-emerald)" font-size="14" font-weight="bold">吊装站位区 A</text>
<!-- Crane A Graphic -->
<g transform="translate(260, 200)" id="crane-A">
<rect x="-40" y="-40" width="80" height="80" fill="none" stroke="#334155" stroke-dasharray="4"/>
<circle cx="0" cy="0" r="15" fill="#f59e0b" />
<rect x="-8" y="-10" width="16" height="20" fill="#333" rx="2" />
<g class="crane-arm" id="arm-A">
<rect x="-4" y="-80" width="8" height="80" fill="#f59e0b" />
<polygon points="-8,-80 8,-80 0,-90" fill="#f59e0b" />
</g>
</g>
<!-- Crane Zone B -->
<rect x="500" y="100" width="220" height="180" rx="8" fill="rgba(6, 182, 212, 0.05)" stroke="var(--accent-cyan)" stroke-width="2" />
<text x="510" y="125" fill="var(--accent-cyan)" font-size="14" font-weight="bold">吊装站位区 B</text>
<!-- Crane B Graphic -->
<g transform="translate(610, 200)" id="crane-B">
<rect x="-40" y="-40" width="80" height="80" fill="none" stroke="#334155" stroke-dasharray="4"/>
<circle cx="0" cy="0" r="15" fill="#06b6d4" />
<rect x="-8" y="-10" width="16" height="20" fill="#333" rx="2" />
<g class="crane-arm" id="arm-B">
<rect x="-4" y="-80" width="8" height="80" fill="#06b6d4" />
<polygon points="-8,-80 8,-80 0,-90" fill="#06b6d4" />
</g>
</g>
<!-- Active Paths (Glowing Lines showing intent) -->
<path id="path-road-to-buf" d="M 500 460 L 500 420" stroke="var(--accent-amber)" stroke-width="3" fill="none" class="path-line" />
<path id="path-buf-to-cA" d="M 380 320 L 380 200 L 320 200" stroke="var(--accent-emerald)" stroke-width="3" fill="none" class="path-line" />
<path id="path-buf-to-cB" d="M 560 320 L 560 200 L 550 200" stroke="var(--accent-cyan)" stroke-width="3" fill="none" class="path-line" />
<!-- Trucks Layer -->
<g id="trucks-layer"></g>
</g>
</svg>
</div>
<!-- TRIZ Info Panel -->
<div class="triz-panel">
<h3>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<path d="M12 16v-4"></path>
<path d="M12 8h.01"></path>
</svg>
最终理想解 (IFR) 原理
</h3>
<p><strong>矛盾破除:</strong>将无序的“等待”转化为精确的“时空网格匹配”。</p>
<p><strong>资源利用:</strong>极小增加复杂度,仅利用手机端回传状态与预设规则引擎。</p>
<p><strong>运作机制:</strong>系统自动进行时空冲突检测,动态重排(如 T2 避开满载的 A 区,自动导向 B 区),实现0拥堵进场。</p>
</div>
<!-- Controls -->
<div class="controls">
<button id="btn-pause" onclick="togglePlay()">暂停 / 播放</button>
<button id="btn-speed" onclick="toggleSpeed()">切换速度 (1x)</button>
</div>
</div>
<script>
// Data Configuration
const config = {
colors: {
T1: '#10b981', // Emerald
T2: '#f59e0b', // Amber
T3: '#06b6d4', // Cyan
T4: '#f43f5e' // Rose
},
matrixNodes: {
road: 155, buffer: 275, craneA: 395, craneB: 515
},
timeNodes: {
0: 200, 1: 300, 2: 400, 3: 500, 4: 600, 5: 700
},
mapNodes: {
start: {x: -50, y: 460},
roadWait: {x: 400, y: 460},
buf1: {x: 405, y: 390},
buf2: {x: 495, y: 390},
buf3: {x: 585, y: 390},
craneA: {x: 180, y: 200, rot: -90},
craneB: {x: 700, y: 200, rot: 90},
exitA: {x: 180, y: -50},
exitB: {x: 700, y: -50}
}
};
// Animation State Machine
let isPlaying = true;
let speedMultiplier = 1;
let currentStep = 0;
let stateMachineTimeout;
// Create Elements
function createElements() {
const tokenLayer = document.getElementById('tokens-layer');
const truckLayer = document.getElementById('trucks-layer');
// Create 3 trucks
[1, 2, 3].forEach(id => {
const color = config.colors[`T${id}`];
// Matrix Token
const token = document.createElementNS("http://www.w3.org/2000/svg", "g");
token.setAttribute("id", `tok-T${id}`);
token.setAttribute("color", color);
token.setAttribute("class", "anim-obj");
token.setAttribute("transform", `translate(-100, -100)`);
token.innerHTML = document.getElementById('matrix-token').innerHTML.replace('T-X', `车-${id}`);
tokenLayer.appendChild(token);
// Map Truck
const truck = document.createElementNS("http://www.w3.org/2000/svg", "g");
truck.setAttribute("id", `map-T${id}`);
truck.setAttribute("color", color);
truck.setAttribute("class", "anim-slow glow");
truck.setAttribute("transform", `translate(-100, -100)`);
truck.innerHTML = `<use href="#truck-icon" />`;
truckLayer.appendChild(truck);
});
}
// DOM Manipulators
function moveToken(id, timeIdx, zone) {
const el = document.getElementById(`tok-T${id}`);
if(el && config.timeNodes[timeIdx] !== undefined) {
const x = config.timeNodes[timeIdx];
const y = config.matrixNodes[zone];
el.setAttribute("transform", `translate(${x}, ${y})`);
el.style.opacity = 1;
} else if (el) {
el.style.opacity = 0; // hide if out of bounds
}
}
function moveTruck(id, nodeKey) {
const el = document.getElementById(`map-T${id}`);
const node = config.mapNodes[nodeKey];
if(el && node) {
const rot = node.rot ? `rotate(${node.rot})` : 'rotate(90)'; // Default face right
el.setAttribute("transform", `translate(${node.x}, ${node.y}) ${rot}`);
}
}
function setCrane(zone, active) {
const el = document.getElementById(`arm-${zone}`);
if(active) el.classList.add('crane-working');
else el.classList.remove('crane-working');
}
function setPath(id, active) {
const el = document.getElementById(id);
if (el) {
if (active) el.classList.add('active');
else el.classList.remove('active');
}
}
function updateUI(timeStr, statusStr, badgeStr) {
document.getElementById('clock-display').innerText = timeStr;
document.getElementById('status-text').innerText = statusStr;
document.getElementById('status-badge').innerText = badgeStr;
// Move time scanner
const timeIdx = {"08:00":0, "08:30":1, "09:00":2, "09:30":3, "10:00":4, "10:30":5}[timeStr];
if(timeIdx !== undefined) {
const scanner = document.getElementById('time-scanner');
scanner.setAttribute("transform", `translate(${timeIdx * 100}, 0)`);
}
}
// Sleep function adhering to speed
function sleep(ms) {
return new Promise(resolve => {
stateMachineTimeout = setTimeout(resolve, ms / speedMultiplier);
});
}
// Await Play State
async function waitIfPaused() {
while(!isPlaying) {
await new Promise(r => setTimeout(r, 100));
}
}
// Simulation Timeline
async function runSimulation() {
while(true) {
// Initialize
moveToken(1, -1, 'road'); moveTruck(1, 'start');
moveToken(2, -1, 'road'); moveTruck(2, 'start');
moveToken(3, -1, 'road'); moveTruck(3, 'start');
setCrane('A', false); setCrane('B', false);
setPath('path-road-to-buf', false); setPath('path-buf-to-cA', false); setPath('path-buf-to-cB', false);
await waitIfPaused();
await sleep(1000);
// --- T=0: 08:00 ---
updateUI('08:00', '预排计划下发: 车辆按时间窗进场', '规则引擎运行');
setPath('path-road-to-buf', true);
// T1 to Buffer
moveToken(1, 0, 'buffer');
moveTruck(1, 'buf1');
await waitIfPaused();
await sleep(3000);
// --- T=1: 08:30 ---
updateUI('08:30', '状态回传: A区无冲突,分配吊装站位', '时空检测 OK');
setPath('path-road-to-buf', false);
setPath('path-buf-to-cA', true);
// T1 to Crane A
moveToken(1, 1, 'craneA');
moveTruck(1, 'craneA');
// T2 arrives Buffer
moveToken(2, 1, 'buffer');
moveTruck(2, 'buf2');
await sleep(1000);
setCrane('A', true);
await waitIfPaused();
await sleep(2500);
// --- T=2: 09:00 ---
updateUI('09:00', '系统滚动刷新: A区满载,动态避让至B区', '触发避让逻辑');
setPath('path-buf-to-cA', false);
setPath('path-buf-to-cB', true);
setCrane('A', false);
// T1 leaves
moveToken(1, 2, 'road'); moveTruck(1, 'exitA');
// T2 to Crane B (Avoids waiting for A)
moveToken(2, 2, 'craneB');
moveTruck(2, 'craneB');
// T3 arrives Buffer
moveToken(3, 2, 'buffer');
moveTruck(3, 'buf1');
await sleep(1000);
setCrane('B', true);
await waitIfPaused();
await sleep(2500);
// --- T=3: 09:30 ---
updateUI('09:30', '并发执行: T3分配至释放的A区', '资源完美利用');
setPath('path-buf-to-cB', false);
setPath('path-buf-to-cA', true);
setCrane('B', false);
// T2 leaves
moveToken(2, 3, 'road'); moveTruck(2, 'exitB');
// T3 to Crane A
moveToken(3, 3, 'craneA');
moveTruck(3, 'craneA');
await sleep(1000);
setCrane('A', true);
await waitIfPaused();
await sleep(2500);
// --- T=4: 10:00 ---
updateUI('10:00', '所有任务在无等待状态下完成', 'IFR达成');
setPath('path-buf-to-cA', false);
setCrane('A', false);
// T3 leaves
moveToken(3, 4, 'road'); moveTruck(3, 'exitA');
await waitIfPaused();
await sleep(3000);
// Reset for loop
document.getElementById('tok-T1').style.opacity = 0;
document.getElementById('tok-T2').style.opacity = 0;
document.getElementById('tok-T3').style.opacity = 0;
await sleep(500);
}
}
// Controls Logic
function togglePlay() {
isPlaying = !isPlaying;
const btn = document.getElementById('btn-pause');
btn.innerText = isPlaying ? "暂停 / 播放" : "已暂停 (点击继续)";
btn.classList.toggle('active');
}
function toggleSpeed() {
speedMultiplier = speedMultiplier === 1 ? 2 : 1;
const btn = document.getElementById('btn-speed');
btn.innerText = `切换速度 (${speedMultiplier}x)`;
btn.classList.toggle('active');
// Update CSS transition speeds dynamically
const animTime = 1.2 / speedMultiplier;
const slowTime = 1.8 / speedMultiplier;
document.querySelectorAll('.anim-obj').forEach(el => el.style.transitionDuration = `${animTime}s`);
document.querySelectorAll('.anim-slow').forEach(el => el.style.transitionDuration = `${slowTime}s`);
}
// Initialize on Load (Must autoplay as per requirements)
window.addEventListener('DOMContentLoaded', () => {
createElements();
// Start simulation loop
runSimulation();
});
</script>
</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
