分享图
动画工坊
引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智能多重振动筛全局总控系统</title>
<style>
    @import url('https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Noto+Sans+SC:wght@300;500;700&display=swap');

    :root {
        --bg-dark: #050b14;
        --grid-color: rgba(30, 58, 138, 0.15);
        --neon-cyan: #00f0ff;
        --neon-green: #00ff66;
        --neon-red: #ff003c;
        --neon-yellow: #ffcc00;
        --panel-bg: rgba(10, 20, 40, 0.8);
        --text-main: #e2e8f0;
        --text-muted: #64748b;
    }

    body {
        margin: 0;
        padding: 0;
        background-color: #02060d;
        background-image: 
            linear-gradient(var(--grid-color) 1px, transparent 1px),
            linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
        background-size: 30px 30px;
        color: var(--text-main);
        font-family: 'Noto Sans SC', sans-serif;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        overflow: hidden;
    }

    #app-container {
        position: relative;
        width: 100vw;
        height: 100vh;
        max-width: 1600px;
        max-height: 900px;
        display: flex;
        justify-content: center;
        align-items: center;
        box-shadow: inset 0 0 150px rgba(0,0,0,0.9);
    }

    svg {
        width: 100%;
        height: 100%;
        filter: drop-shadow(0 0 20px rgba(0, 240, 255, 0.1));
    }

    /* Core Animations */
    .flow-fluid {
        stroke-dasharray: 12 12;
        animation: flowMove linear infinite;
        transition: stroke-width 0.8s cubic-bezier(0.4, 0, 0.2, 1), stroke 0.5s ease;
    }

    @keyframes flowMove {
        from { stroke-dashoffset: 24; }
        to { stroke-dashoffset: 0; }
    }

    .signal-pulse {
        stroke-dasharray: 5 10;
        animation: signalMove 0.5s linear infinite;
        opacity: 0;
        transition: opacity 0.3s;
    }

    .signal-active {
        opacity: 1;
    }

    @keyframes signalMove {
        from { stroke-dashoffset: 15; }
        to { stroke-dashoffset: 0; }
    }

    .vibrate-normal { animation: shakeNormal 0.1s linear infinite; }
    .vibrate-heavy { animation: shakeHeavy 0.08s linear infinite; }
    .vibrate-low { animation: shakeLow 0.15s linear infinite; }

    @keyframes shakeNormal {
        0%, 100% { transform: translate(0, 0); }
        25% { transform: translate(1px, 0.5px); }
        75% { transform: translate(-0.5px, -1px); }
    }
    
    @keyframes shakeHeavy {
        0%, 100% { transform: translate(0, 0); }
        25% { transform: translate(2px, 1.5px) rotate(0.5deg); }
        75% { transform: translate(-1.5px, -2px) rotate(-0.5deg); }
    }

    @keyframes shakeLow {
        0%, 100% { transform: translate(0, 0); }
        50% { transform: translate(0.5px, 0.5px); }
    }

    /* UI Overlay elements via HTML for sharper text rendering */
    .overlay-panel {
        position: absolute;
        background: var(--panel-bg);
        border: 1px solid rgba(0, 240, 255, 0.3);
        border-radius: 4px;
        padding: 15px;
        backdrop-filter: blur(4px);
        font-family: 'Share Tech Mono', monospace, 'Noto Sans SC';
        z-index: 10;
    }

    .top-left { top: 30px; left: 30px; }
    .bottom-right { bottom: 30px; right: 30px; }
    
    .panel-title {
        font-size: 12px;
        color: var(--neon-cyan);
        text-transform: uppercase;
        letter-spacing: 2px;
        margin-bottom: 8px;
        border-bottom: 1px solid rgba(0, 240, 255, 0.2);
        padding-bottom: 4px;
    }

    .panel-data {
        font-size: 11px;
        line-height: 1.6;
        color: var(--text-main);
    }
    
    .highlight-data { color: var(--neon-yellow); font-weight: bold; }
    
    .status-text {
        font-family: 'Share Tech Mono', monospace;
        font-size: 14px;
        font-weight: bold;
        transition: fill 0.3s;
    }

    /* PLC Node styles */
    .plc-core {
        transform-origin: center;
        transition: fill 0.3s, filter 0.3s;
    }
    
    .processing {
        animation: plcPulse 1s ease-in-out infinite alternate;
    }

    @keyframes plcPulse {
        from { filter: drop-shadow(0 0 10px var(--neon-cyan)); fill: rgba(0, 240, 255, 0.2); }
        to { filter: drop-shadow(0 0 25px var(--neon-cyan)); fill: rgba(0, 240, 255, 0.5); }
    }

    .valve-indicator {
        transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
        transform-origin: center;
    }

</style>
</head>
<body>

<div id="app-container">
    <!-- UI Panels -->
    <div class="overlay-panel top-left">
        <div class="panel-title">系统状态 | SCADA 总控</div>
        <div class="panel-data">
            <div>运行模式: <span style="color: var(--neon-green)">自动全局寻优</span></div>
            <div>总输入流量: 100% (240 m³/h)</div>
            <div>当前阶段: <span id="sys-phase" class="highlight-data">正常均分</span></div>
        </div>
    </div>

    <div class="overlay-panel bottom-right">
        <div class="panel-title">核心指标监控</div>
        <div class="panel-data">
            <div>分配误差控制: <span style="color: var(--neon-green)">≤±5%</span></div>
            <div>自适应切换时间: <span style="color: var(--neon-green)">≤5s</span></div>
            <div>联锁状态: 2-4台协同就绪</div>
            <div style="margin-top: 5px; font-size: 10px; color: var(--text-muted);">
                *最终理想解(IFR): 系统利用现有阀门与算法自发消除局部过载矛盾
            </div>
        </div>
    </div>

    <!-- Main SVG Animation -->
    <svg viewBox="0 0 1200 800" preserveAspectRatio="xMidYMid meet">
        <defs>
            <!-- Gradients -->
            <linearGradient id="pipe-grad" x1="0%" y1="0%" x2="100%" y2="0%">
                <stop offset="0%" stop-color="#1e293b" />
                <stop offset="50%" stop-color="#334155" />
                <stop offset="100%" stop-color="#1e293b" />
            </linearGradient>
            
            <linearGradient id="tank-grad" x1="0%" y1="0%" x2="0%" y2="100%">
                <stop offset="0%" stop-color="rgba(15, 23, 42, 0.9)" />
                <stop offset="100%" stop-color="rgba(2, 6, 23, 0.9)" />
            </linearGradient>

            <!-- Glow Filters -->
            <filter id="glow-cyan" x="-20%" y="-20%" width="140%" height="140%">
                <feGaussianBlur stdDeviation="8" result="blur" />
                <feComposite in="SourceGraphic" in2="blur" operator="over" />
            </filter>
            <filter id="glow-red" x="-20%" y="-20%" width="140%" height="140%">
                <feGaussianBlur stdDeviation="8" result="blur" />
                <feComposite in="SourceGraphic" in2="blur" operator="over" />
            </filter>
            <filter id="glow-green" x="-20%" y="-20%" width="140%" height="140%">
                <feGaussianBlur stdDeviation="4" result="blur" />
                <feComposite in="SourceGraphic" in2="blur" operator="over" />
            </filter>

            <!-- Grid Pattern for Shaker -->
            <pattern id="screen-mesh" width="10" height="10" patternUnits="userSpaceOnUse">
                <path d="M 10 0 L 0 10 M 0 0 L 10 10" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="0.5"/>
            </pattern>
        </defs>

        <!-- Background Infrastructure -->
        <g id="infrastructure" stroke="#334155" stroke-width="12" fill="none" stroke-linecap="round" stroke-linejoin="round">
            <!-- Main Input Pipe -->
            <path d="M600,0 L600,150" />
            
            <!-- Distribution Manifold Structure -->
            <rect x="450" y="150" width="300" height="80" rx="4" fill="#0f172a" stroke="#475569" stroke-width="2"/>
            <text x="600" y="195" fill="#64748b" font-size="12" text-anchor="middle" font-family="'Share Tech Mono', sans-serif" stroke="none">多路电动阀 / 流量分配器</text>
            
            <!-- Pipes to Shakers -->
            <path d="M500,230 L500,280 L250,280 L250,450" /> <!-- To Shaker 1 -->
            <path d="M600,230 L600,450" />                   <!-- To Shaker 2 -->
            <path d="M700,230 L700,280 L950,280 L950,450" /> <!-- To Shaker 3 -->
        </g>

        <!-- Active Fluid Flows -->
        <g id="fluid-flows" fill="none" stroke-linecap="round" stroke-linejoin="round" filter="url(#glow-cyan)">
            <!-- Main Input Fluid -->
            <path d="M600,0 L600,150" stroke="var(--neon-cyan)" stroke-width="12" class="flow-fluid" style="animation-duration: 0.8s;" />
            
            <!-- Distributed Fluids (Widths controlled by JS) -->
            <path id="fluid-1" d="M500,230 L500,280 L250,280 L250,450" stroke="var(--neon-cyan)" stroke-width="6" class="flow-fluid" style="animation-duration: 1s;" />
            <path id="fluid-2" d="M600,230 L600,450" stroke="var(--neon-cyan)" stroke-width="6" class="flow-fluid" style="animation-duration: 1s;" />
            <path id="fluid-3" d="M700,230 L700,280 L950,280 L950,450" stroke="var(--neon-cyan)" stroke-width="6" class="flow-fluid" style="animation-duration: 1s;" />
        </g>

        <!-- PLC Controller Brain -->
        <g id="plc-system" transform="translate(600, 100)">
            <!-- Signal lines from Shakers to PLC -->
            <g fill="none" stroke-width="2">
                <path id="sig-1" d="M-350,350 L-350,300 L-50,300 L-50,0" stroke="var(--neon-cyan)" class="signal-pulse"/>
                <path id="sig-2" d="M0,350 L0,0" stroke="var(--neon-cyan)" class="signal-pulse"/>
                <path id="sig-3" d="M350,350 L350,300 L50,300 L50,0" stroke="var(--neon-cyan)" class="signal-pulse"/>
            </g>

            <!-- PLC Node -->
            <rect x="-60" y="-40" width="120" height="80" rx="8" fill="rgba(15, 23, 42, 0.9)" stroke="var(--neon-cyan)" stroke-width="2" class="plc-core" id="plc-box"/>
            <polygon points="-70,0 -60,-10 -60,10" fill="var(--neon-cyan)"/>
            <polygon points="70,0 60,-10 60,10" fill="var(--neon-cyan)"/>
            
            <text x="0" y="-10" fill="#fff" font-size="14" font-weight="bold" text-anchor="middle" font-family="'Noto Sans SC'">总控 PLC</text>
            <text x="0" y="10" fill="var(--neon-cyan)" font-size="10" text-anchor="middle" font-family="'Share Tech Mono'" id="plc-algo-text">ALG: EQUILIBRIUM</text>
            
            <!-- Connection to manifold -->
            <path d="M0,40 L0,50" stroke="var(--neon-cyan)" stroke-width="4" stroke-dasharray="2 4" animation="flowMove 0.5s linear infinite"/>
        </g>

        <!-- Valve Mechanisms (Visual representation inside manifold) -->
        <g id="valves" transform="translate(600, 190)">
            <!-- Valve 1 -->
            <g transform="translate(-100, 0)">
                <circle cx="0" cy="0" r="15" fill="#1e293b" stroke="var(--neon-cyan)" stroke-width="2"/>
                <path id="valve-dial-1" d="M-10,0 L10,0" stroke="var(--neon-cyan)" stroke-width="3" class="valve-indicator" transform="rotate(0)"/>
            </g>
            <!-- Valve 2 -->
            <g transform="translate(0, 0)">
                <circle cx="0" cy="0" r="15" fill="#1e293b" stroke="var(--neon-cyan)" stroke-width="2"/>
                <path id="valve-dial-2" d="M-10,0 L10,0" stroke="var(--neon-cyan)" stroke-width="3" class="valve-indicator" transform="rotate(0)"/>
            </g>
            <!-- Valve 3 -->
            <g transform="translate(100, 0)">
                <circle cx="0" cy="0" r="15" fill="#1e293b" stroke="var(--neon-cyan)" stroke-width="2"/>
                <path id="valve-dial-3" d="M-10,0 L10,0" stroke="var(--neon-cyan)" stroke-width="3" class="valve-indicator" transform="rotate(0)"/>
            </g>
        </g>

        <!-- Shale Shakers (振动筛) -->
        <g id="shaker-system">
            <!-- Shaker 1 -->
            <g transform="translate(250, 520)">
                <!-- Base Buffer Tank -->
                <path d="M-80,40 L80,40 L60,120 L-60,120 Z" fill="url(#tank-grad)" stroke="#334155" stroke-width="2"/>
                <text x="0" y="90" fill="#64748b" font-size="12" text-anchor="middle">缓冲罐 1#</text>
                
                <!-- Vibrating Screen Unit -->
                <g id="screen-1" class="vibrate-normal">
                    <rect x="-90" y="-40" width="180" height="80" rx="4" fill="#0f172a" stroke="#475569" stroke-width="2"/>
                    <rect x="-80" y="-30" width="160" height="60" fill="url(#screen-mesh)"/>
                    <rect x="-90" y="40" width="180" height="5" fill="#334155"/> <!-- mount -->
                    <!-- Sensor -->
                    <circle cx="-70" cy="-20" r="5" fill="var(--neon-green)" filter="url(#glow-green)" id="sensor-1"/>
                </g>
                
                <!-- Data Display -->
                <rect x="-40" y="-80" width="80" height="30" rx="2" fill="rgba(0,0,0,0.6)" stroke="#334155" stroke-width="1"/>
                <text x="0" y="-60" fill="var(--neon-cyan)" font-size="14" text-anchor="middle" class="status-text" id="val-1">33.3%</text>
                <text x="0" y="140" fill="#e2e8f0" font-size="14" font-weight="bold" text-anchor="middle">振动筛 1#</text>
            </g>

            <!-- Shaker 2 (The one that will overload) -->
            <g transform="translate(600, 520)">
                <path d="M-80,40 L80,40 L60,120 L-60,120 Z" fill="url(#tank-grad)" stroke="#334155" stroke-width="2"/>
                <text x="0" y="90" fill="#64748b" font-size="12" text-anchor="middle">缓冲罐 2#</text>
                
                <g id="screen-2" class="vibrate-normal">
                    <rect x="-90" y="-40" width="180" height="80" rx="4" fill="#0f172a" stroke="#475569" stroke-width="2"/>
                    <rect x="-80" y="-30" width="160" height="60" fill="url(#screen-mesh)"/>
                    <rect x="-90" y="40" width="180" height="5" fill="#334155"/>
                    <circle cx="-70" cy="-20" r="5" fill="var(--neon-green)" filter="url(#glow-green)" id="sensor-2"/>
                    <!-- Mud buildup visualization (hidden initially) -->
                    <path id="mud-buildup" d="M-70,20 Q0,30 70,20 Q0,-10 -70,20" fill="rgba(255, 100, 0, 0)" transition="fill 1s"/>
                </g>

                <rect x="-40" y="-80" width="80" height="30" rx="2" fill="rgba(0,0,0,0.6)" stroke="#334155" stroke-width="1"/>
                <text x="0" y="-60" fill="var(--neon-cyan)" font-size="14" text-anchor="middle" class="status-text" id="val-2">33.3%</text>
                <text x="0" y="140" fill="#e2e8f0" font-size="14" font-weight="bold" text-anchor="middle">振动筛 2#</text>
            </g>

            <!-- Shaker 3 -->
            <g transform="translate(950, 520)">
                <path d="M-80,40 L80,40 L60,120 L-60,120 Z" fill="url(#tank-grad)" stroke="#334155" stroke-width="2"/>
                <text x="0" y="90" fill="#64748b" font-size="12" text-anchor="middle">缓冲罐 3#</text>
                
                <g id="screen-3" class="vibrate-normal">
                    <rect x="-90" y="-40" width="180" height="80" rx="4" fill="#0f172a" stroke="#475569" stroke-width="2"/>
                    <rect x="-80" y="-30" width="160" height="60" fill="url(#screen-mesh)"/>
                    <rect x="-90" y="40" width="180" height="5" fill="#334155"/>
                    <circle cx="-70" cy="-20" r="5" fill="var(--neon-green)" filter="url(#glow-green)" id="sensor-3"/>
                </g>

                <rect x="-40" y="-80" width="80" height="30" rx="2" fill="rgba(0,0,0,0.6)" stroke="#334155" stroke-width="1"/>
                <text x="0" y="-60" fill="var(--neon-cyan)" font-size="14" text-anchor="middle" class="status-text" id="val-3">33.3%</text>
                <text x="0" y="140" fill="#e2e8f0" font-size="14" font-weight="bold" text-anchor="middle">振动筛 3#</text>
            </g>
        </g>
    </svg>
</div>

<script>
document.addEventListener("DOMContentLoaded", () => {
    // DOM Elements
    const fluid1 = document.getElementById('fluid-1');
    const fluid2 = document.getElementById('fluid-2');
    const fluid3 = document.getElementById('fluid-3');
    
    const val1 = document.getElementById('val-1');
    const val2 = document.getElementById('val-2');
    const val3 = document.getElementById('val-3');
    
    const screen1 = document.getElementById('screen-1');
    const screen2 = document.getElementById('screen-2');
    const screen3 = document.getElementById('screen-3');
    
    const sensor1 = document.getElementById('sensor-1');
    const sensor2 = document.getElementById('sensor-2');
    const sensor3 = document.getElementById('sensor-3');
    
    const sig1 = document.getElementById('sig-1');
    const sig2 = document.getElementById('sig-2');
    const sig3 = document.getElementById('sig-3');
    
    const plcBox = document.getElementById('plc-box');
    const plcAlgoText = document.getElementById('plc-algo-text');
    const sysPhaseText = document.getElementById('sys-phase');
    
    const mudBuildup = document.getElementById('mud-buildup');

    const valveDial1 = document.getElementById('valve-dial-1');
    const valveDial2 = document.getElementById('valve-dial-2');
    const valveDial3 = document.getElementById('valve-dial-3');

    // Colors
    const colorCyan = 'var(--neon-cyan)';
    const colorRed = 'var(--neon-red)';
    const colorYellow = 'var(--neon-yellow)';
    const colorGreen = 'var(--neon-green)';

    // State Variables
    let currentPhase = 0; // 0: Normal, 1: Overload, 2: Rebalance
    
    // Animation Timeline Config
    const PHASE_NORMAL = 4000;    // Time spent in normal state
    const PHASE_OVERLOAD = 2000;  // Time indicating problem before action
    const PHASE_REBALANCE = 5000; // Time in rebalanced state solving the problem

    function updateValue(element, targetValue, duration = 1000) {
        const startValue = parseFloat(element.textContent);
        const startTime = performance.now();
        
        function animate(currentTime) {
            const elapsed = currentTime - startTime;
            const progress = Math.min(elapsed / duration, 1);
            
            // Easing: easeOutQuart
            const easeProgress = 1 - Math.pow(1 - progress, 4);
            
            const currentVal = startValue + (targetValue - startValue) * easeProgress;
            element.textContent = currentVal.toFixed(1) + '%';
            
            if (progress < 1) {
                requestAnimationFrame(animate);
            }
        }
        requestAnimationFrame(animate);
    }

    function setNormalState() {
        sysPhaseText.textContent = "正常均分";
        sysPhaseText.style.color = colorCyan;
        
        // Fluids
        fluid1.style.strokeWidth = '6';
        fluid2.style.strokeWidth = '6';
        fluid3.style.strokeWidth = '6';
        fluid1.style.stroke = colorCyan;
        fluid2.style.stroke = colorCyan;
        fluid3.style.stroke = colorCyan;
        
        // Values
        updateValue(val1, 33.3);
        updateValue(val2, 33.3);
        updateValue(val3, 33.3);
        val1.style.fill = colorCyan;
        val2.style.fill = colorCyan;
        val3.style.fill = colorCyan;

        // Shakers
        screen1.className.baseVal = 'vibrate-normal';
        screen2.className.baseVal = 'vibrate-normal';
        screen3.className.baseVal = 'vibrate-normal';
        mudBuildup.style.fill = 'rgba(255, 100, 0, 0)';

        // Sensors & Signals
        sensor2.style.fill = colorGreen;
        sensor2.setAttribute('filter', 'url(#glow-green)');
        sig1.classList.remove('signal-active');
        sig2.classList.remove('signal-active');
        sig3.classList.remove('signal-active');
        
        // PLC
        plcBox.classList.remove('processing');
        plcBox.style.stroke = colorCyan;
        plcAlgoText.textContent = "ALG: EQUILIBRIUM";
        plcAlgoText.style.fill = colorCyan;

        // Valves
        valveDial1.setAttribute('transform', 'rotate(0)');
        valveDial2.setAttribute('transform', 'rotate(0)');
        valveDial3.setAttribute('transform', 'rotate(0)');
    }

    function setOverloadState() {
        sysPhaseText.textContent = "2# 跑浆预警";
        sysPhaseText.style.color = colorRed;

        // Shaker 2 struggles
        screen2.className.baseVal = 'vibrate-heavy';
        mudBuildup.style.fill = 'rgba(255, 100, 0, 0.6)';
        
        // Sensor detects
        sensor2.style.fill = colorRed;
        sensor2.setAttribute('filter', 'url(#glow-red)');
        
        // Signal sent to PLC
        sig2.style.stroke = colorRed;
        sig2.classList.add('signal-active');
        
        // PLC Starts processing
        plcBox.classList.add('processing');
        plcBox.style.stroke = colorRed;
        plcAlgoText.textContent = "DETECT: OVERLOAD";
        plcAlgoText.style.fill = colorRed;
        
        val2.style.fill = colorRed;
    }

    function setRebalanceState() {
        sysPhaseText.textContent = "动态重分配解耦";
        sysPhaseText.style.color = colorYellow;

        // PLC executes algorithm
        plcBox.style.stroke = colorYellow;
        plcAlgoText.textContent = "EXEC: REALLOCATE";
        plcAlgoText.style.fill = colorYellow;
        
        // Signals indicating control action
        sig1.style.stroke = colorYellow;
        sig2.style.stroke = colorYellow;
        sig3.style.stroke = colorYellow;
        sig1.classList.add('signal-active');
        sig2.classList.add('signal-active');
        sig3.classList.add('signal-active');

        // VALVES ADJUST (IFR action)
        // Shaker 2 gets less flow, 1 & 3 get more
        fluid1.style.strokeWidth = '9';
        fluid2.style.strokeWidth = '2';
        fluid3.style.strokeWidth = '9';
        
        // Fluid color indicating active balancing
        fluid2.style.stroke = 'rgba(0, 240, 255, 0.4)';
        
        // Values update (Mathematical optimal distribution)
        updateValue(val1, 45.0);
        updateValue(val2, 10.0);
        updateValue(val3, 45.0);
        
        val1.style.fill = colorYellow;
        val2.style.fill = colorGreen; // Recovered
        val3.style.fill = colorYellow;

        // Visual representation of valve angles
        valveDial1.setAttribute('transform', 'rotate(45)');
        valveDial2.setAttribute('transform', 'rotate(-75)');
        valveDial3.setAttribute('transform', 'rotate(45)');

        // Shaker 2 recovers
        setTimeout(() => {
            screen2.className.baseVal = 'vibrate-low';
            mudBuildup.style.fill = 'rgba(255, 100, 0, 0)';
            sensor2.style.fill = colorGreen;
            sensor2.setAttribute('filter', 'url(#glow-green)');
            plcBox.classList.remove('processing');
            sysPhaseText.textContent = "最优稳态运行";
            sysPhaseText.style.color = colorGreen;
            plcAlgoText.textContent = "ALG: OPTIMIZED";
            plcAlgoText.style.fill = colorGreen;
        }, 1500);
    }

    // Main Animation Loop
    function runAnimationSequence() {
        // Step 1: Normal
        setNormalState();
        
        // Step 2: Overload (after normal phase)
        setTimeout(() => {
            setOverloadState();
            
            // Step 3: Rebalance (after overload detection)
            setTimeout(() => {
                setRebalanceState();
                
                // Loop back to start
                setTimeout(runAnimationSequence, PHASE_REBALANCE);
                
            }, PHASE_OVERLOAD);
            
        }, PHASE_NORMAL);
    }

    // Initial start
    setTimeout(runAnimationSequence, 500);
});
</script>
</body>
</html>
<!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 {
            --bg-color: #0b101e;
            --panel-bg: rgba(16, 26, 48, 0.85);
            --border-glow: #00f0ff;
            --normal-flow: #00e5ff;
            --warning-color: #ff3333;
            --adjust-color: #ffaa00;
            --success-color: #00ffaa;
            --text-main: #e0f2fe;
            --font-mono: 'Consolas', 'Courier New', monospace;
        }

        body {
            margin: 0;
            padding: 0;
            background-color: var(--bg-color);
            color: var(--text-main);
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            overflow: hidden;
            background-image: 
                radial-gradient(circle at 50% 50%, #152243 0%, #0b101e 100%),
                linear-gradient(rgba(0, 240, 255, 0.03) 1px, transparent 1px),
                linear-gradient(90deg, rgba(0, 240, 255, 0.03) 1px, transparent 1px);
            background-size: 100% 100%, 40px 40px, 40px 40px;
        }

        .container {
            width: 100%;
            max-width: 1400px;
            display: flex;
            flex-direction: column;
            align-items: center;
            position: relative;
        }

        svg {
            width: 100%;
            height: auto;
            max-height: 85vh;
            filter: drop-shadow(0 0 10px rgba(0, 240, 255, 0.1));
        }

        /* 动画类 */
        .flow-dash {
            stroke-dasharray: 15, 10;
            animation: flowAnim 1s linear infinite;
        }
        
        .flow-dash.fast {
            stroke-dasharray: 25, 15;
            animation-duration: 0.5s;
            stroke-width: 8px;
        }
        
        .flow-dash.slow {
            stroke-dasharray: 8, 12;
            animation-duration: 2s;
            stroke-width: 3px;
        }

        @keyframes flowAnim {
            to { stroke-dashoffset: -50; }
        }

        @keyframes flowAnimReverse {
            to { stroke-dashoffset: 50; }
        }

        .signal-dash {
            stroke-dasharray: 5, 5;
            animation: flowAnimReverse 0.8s linear infinite;
        }

        .shaker-box {
            transform-origin: center;
            animation: vibrate 0.1s linear infinite;
        }

        .shaker-box.heavy {
            animation: vibrate-heavy 0.1s linear infinite;
        }

        @keyframes vibrate {
            0%, 100% { transform: translateY(0); }
            25% { transform: translateY(-1px) translateX(-1px); }
            75% { transform: translateY(1px) translateX(1px); }
        }

        @keyframes vibrate-heavy {
            0%, 100% { transform: translateY(0); }
            25% { transform: translateY(-3px) translateX(-2px); }
            75% { transform: translateY(3px) translateX(2px); }
        }

        @keyframes blink {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.3; }
        }
        
        .blink {
            animation: blink 0.5s ease-in-out infinite;
        }

        /* UI Controls */
        .controls {
            position: absolute;
            bottom: 20px;
            display: flex;
            gap: 15px;
            background: var(--panel-bg);
            padding: 15px 30px;
            border-radius: 30px;
            border: 1px solid rgba(0, 240, 255, 0.3);
            backdrop-filter: blur(10px);
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
            z-index: 10;
        }

        button {
            background: rgba(0, 240, 255, 0.1);
            border: 1px solid var(--border-glow);
            color: var(--border-glow);
            padding: 8px 20px;
            border-radius: 20px;
            font-family: inherit;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s;
            text-transform: uppercase;
            letter-spacing: 1px;
        }

        button:hover, button.active {
            background: var(--border-glow);
            color: var(--bg-color);
            box-shadow: 0 0 15px rgba(0, 240, 255, 0.5);
        }

        .triz-label {
            position: absolute;
            top: 30px;
            left: 30px;
            background: linear-gradient(135deg, rgba(255, 170, 0, 0.2), rgba(255, 51, 51, 0.2));
            border-left: 4px solid var(--adjust-color);
            padding: 15px 25px;
            font-size: 14px;
            line-height: 1.5;
            backdrop-filter: blur(4px);
        }

        .triz-label h3 {
            margin: 0 0 5px 0;
            color: var(--adjust-color);
            font-size: 16px;
        }
    </style>
</head>
<body>

    <div class="container">
        <!-- 侧边 TRIZ 理念说明 -->
        <div class="triz-label">
            <h3>TRIZ 最终理想解 (IFR)</h3>
            系统无需增加额外的庞大缓冲罐<br>
            利用现有“总控PLC + 多路电动阀”<br>
            实现全局联锁与钻井液自平衡分配<br>
            <i>矛盾消除:流量冲击与处理能力的失配</i>
        </div>

        <svg viewBox="0 0 1200 800" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet">
            <defs>
                <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-warning" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="8" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>
                
                <linearGradient id="pipeGrad" x1="0%" y1="0%" x2="100%" y2="0%">
                    <stop offset="0%" stop-color="#1a253c" />
                    <stop offset="50%" stop-color="#2d3f61" />
                    <stop offset="100%" stop-color="#1a253c" />
                </linearGradient>

                <linearGradient id="pipeGradVert" x1="0%" y1="0%" x2="0%" y2="100%">
                    <stop offset="0%" stop-color="#1a253c" />
                    <stop offset="50%" stop-color="#2d3f61" />
                    <stop offset="100%" stop-color="#1a253c" />
                </linearGradient>
            </defs>

            <!-- 基础管道背景 -->
            <g id="base-pipes" stroke="#2d3f61" stroke-width="12" fill="none" stroke-linejoin="round">
                <!-- 主进料管 -->
                <path d="M 600 -10 L 600 150" />
                <!-- 横向分配管 -->
                <path d="M 250 150 L 950 150" />
                <!-- 三条支管 -->
                <path d="M 250 150 L 250 550" />
                <path d="M 600 150 L 600 550" />
                <path d="M 950 150 L 950 550" />
            </g>

            <!-- 流体动画路径 (通过 JS 动态控制颜色和粗细) -->
            <g id="flow-paths" fill="none" stroke-linecap="round" stroke-linejoin="round" filter="url(#glow-cyan)">
                <!-- 主进料流体 -->
                <path d="M 600 0 L 600 150" stroke="var(--normal-flow)" stroke-width="6" class="flow-dash fast" />
                
                <!-- 支流 1 -->
                <path id="flow1" d="M 600 150 L 250 150 L 250 550" stroke="var(--normal-flow)" stroke-width="6" class="flow-dash" />
                <!-- 支流 2 -->
                <path id="flow2" d="M 600 150 L 600 550" stroke="var(--normal-flow)" stroke-width="6" class="flow-dash" />
                <!-- 支流 3 -->
                <path id="flow3" d="M 600 150 L 950 150 L 950 550" stroke="var(--normal-flow)" stroke-width="6" class="flow-dash" />
            </g>

            <!-- 信号线 (通过 JS 控制显示隐藏和颜色) -->
            <g id="signal-lines" stroke-width="2" fill="none" opacity="0">
                <!-- S2 to PLC -->
                <path id="sig-s2-plc" d="M 600 550 L 600 180 L 800 180 L 800 130" stroke="var(--warning-color)" class="signal-dash" />
                <!-- PLC to Valves -->
                <path id="sig-plc-v1" d="M 750 130 L 750 200 L 250 200 L 250 250" stroke="var(--adjust-color)" class="signal-dash" />
                <path id="sig-plc-v2" d="M 800 130 L 800 200 L 600 200 L 600 250" stroke="var(--adjust-color)" class="signal-dash" />
                <path id="sig-plc-v3" d="M 850 130 L 850 200 L 950 200 L 950 250" stroke="var(--adjust-color)" class="signal-dash" />
            </g>

            <!-- 阀门组 (多路电动阀/分配器) -->
            <g id="valves">
                <!-- 阀 1 -->
                <g transform="translate(250, 280)">
                    <polygon points="-20,-15 20,15 20,-15 -20,15" fill="#1e293b" stroke="var(--border-glow)" stroke-width="2"/>
                    <circle cx="0" cy="0" r="6" fill="var(--border-glow)" id="valve-core-1"/>
                    <text x="-45" y="5" fill="#8ba3cb" font-size="14" font-family="var(--font-mono)">MV-01</text>
                    <text x="30" y="5" fill="#00f0ff" font-size="14" font-family="var(--font-mono)" id="valve-val-1">33.3%</text>
                </g>
                <!-- 阀 2 -->
                <g transform="translate(600, 280)">
                    <polygon points="-20,-15 20,15 20,-15 -20,15" fill="#1e293b" stroke="var(--border-glow)" stroke-width="2"/>
                    <circle cx="0" cy="0" r="6" fill="var(--border-glow)" id="valve-core-2"/>
                    <text x="-45" y="5" fill="#8ba3cb" font-size="14" font-family="var(--font-mono)">MV-02</text>
                    <text x="30" y="5" fill="#00f0ff" font-size="14" font-family="var(--font-mono)" id="valve-val-2">33.3%</text>
                </g>
                <!-- 阀 3 -->
                <g transform="translate(950, 280)">
                    <polygon points="-20,-15 20,15 20,-15 -20,15" fill="#1e293b" stroke="var(--border-glow)" stroke-width="2"/>
                    <circle cx="0" cy="0" r="6" fill="var(--border-glow)" id="valve-core-3"/>
                    <text x="-45" y="5" fill="#8ba3cb" font-size="14" font-family="var(--font-mono)">MV-03</text>
                    <text x="30" y="5" fill="#00f0ff" font-size="14" font-family="var(--font-mono)" id="valve-val-3">33.3%</text>
                </g>
            </g>

            <!-- 流量计 -->
            <g id="flowmeters">
                <!-- 计 1 -->
                <g transform="translate(250, 400)">
                    <circle cx="0" cy="0" r="18" fill="#0b101e" stroke="#8ba3cb" stroke-width="2"/>
                    <text x="0" y="4" fill="#8ba3cb" font-size="12" text-anchor="middle" font-family="var(--font-mono)">FM1</text>
                </g>
                <g transform="translate(600, 400)">
                    <circle cx="0" cy="0" r="18" fill="#0b101e" stroke="#8ba3cb" stroke-width="2"/>
                    <text x="0" y="4" fill="#8ba3cb" font-size="12" text-anchor="middle" font-family="var(--font-mono)">FM2</text>
                </g>
                <g transform="translate(950, 400)">
                    <circle cx="0" cy="0" r="18" fill="#0b101e" stroke="#8ba3cb" stroke-width="2"/>
                    <text x="0" y="4" fill="#8ba3cb" font-size="12" text-anchor="middle" font-family="var(--font-mono)">FM3</text>
                </g>
            </g>

            <!-- 振动筛组 -->
            <g id="shakers">
                <!-- Shaker 1 -->
                <g transform="translate(170, 550)" class="shaker-box" id="shaker-1">
                    <rect x="0" y="0" width="160" height="90" rx="8" fill="#16223b" stroke="#37538c" stroke-width="2"/>
                    <line x1="20" y1="30" x2="140" y2="30" stroke="#00f0ff" stroke-width="1" stroke-dasharray="4,4" opacity="0.5"/>
                    <line x1="20" y1="50" x2="140" y2="50" stroke="#00f0ff" stroke-width="1" stroke-dasharray="4,4" opacity="0.5"/>
                    <line x1="20" y1="70" x2="140" y2="70" stroke="#00f0ff" stroke-width="1" stroke-dasharray="4,4" opacity="0.5"/>
                    <text x="80" y="22" fill="#fff" font-size="16" text-anchor="middle" font-weight="bold">1# 振动筛</text>
                    <text x="80" y="80" fill="#00ffaa" font-size="12" text-anchor="middle" id="status-1">正常运行</text>
                </g>

                <!-- Shaker 2 -->
                <g transform="translate(520, 550)" class="shaker-box" id="shaker-2">
                    <rect x="0" y="0" width="160" height="90" rx="8" fill="#16223b" stroke="#37538c" stroke-width="2" id="shaker-rect-2"/>
                    <line x1="20" y1="30" x2="140" y2="30" stroke="#00f0ff" stroke-width="1" stroke-dasharray="4,4" opacity="0.5"/>
                    <line x1="20" y1="50" x2="140" y2="50" stroke="#00f0ff" stroke-width="1" stroke-dasharray="4,4" opacity="0.5"/>
                    <line x1="20" y1="70" x2="140" y2="70" stroke="#00f0ff" stroke-width="1" stroke-dasharray="4,4" opacity="0.5"/>
                    <text x="80" y="22" fill="#fff" font-size="16" text-anchor="middle" font-weight="bold">2# 振动筛</text>
                    <text x="80" y="80" fill="#00ffaa" font-size="12" text-anchor="middle" id="status-2">正常运行</text>
                    
                    <!-- 跑浆溢出效果 (隐藏默认) -->
                    <path d="M -10 90 Q 80 120 170 90 Q 80 140 -10 90" fill="var(--warning-color)" opacity="0" id="mud-overflow"/>
                </g>

                <!-- Shaker 3 -->
                <g transform="translate(870, 550)" class="shaker-box" id="shaker-3">
                    <rect x="0" y="0" width="160" height="90" rx="8" fill="#16223b" stroke="#37538c" stroke-width="2"/>
                    <line x1="20" y1="30" x2="140" y2="30" stroke="#00f0ff" stroke-width="1" stroke-dasharray="4,4" opacity="0.5"/>
                    <line x1="20" y1="50" x2="140" y2="50" stroke="#00f0ff" stroke-width="1" stroke-dasharray="4,4" opacity="0.5"/>
                    <line x1="20" y1="70" x2="140" y2="70" stroke="#00f0ff" stroke-width="1" stroke-dasharray="4,4" opacity="0.5"/>
                    <text x="80" y="22" fill="#fff" font-size="16" text-anchor="middle" font-weight="bold">3# 振动筛</text>
                    <text x="80" y="80" fill="#00ffaa" font-size="12" text-anchor="middle" id="status-3">正常运行</text>
                </g>
            </g>

            <!-- 总控 PLC 与 SCADA 面板 -->
            <g id="plc-panel" transform="translate(700, 30)">
                <rect x="0" y="0" width="300" height="100" rx="10" fill="rgba(16, 26, 48, 0.9)" stroke="var(--border-glow)" stroke-width="1.5" filter="url(#glow-cyan)"/>
                <text x="150" y="25" fill="#fff" font-size="18" text-anchor="middle" font-weight="bold" letter-spacing="2">总控 PLC 算法中心</text>
                <line x1="20" y1="35" x2="280" y2="35" stroke="var(--border-glow)" stroke-width="1" opacity="0.3"/>
                
                <text x="20" y="55" fill="#8ba3cb" font-size="13">全局流量分配误差:</text>
                <text x="280" y="55" fill="var(--success-color)" font-size="14" text-anchor="end" font-family="var(--font-mono)" font-weight="bold" id="data-error">≤ ±2.1%</text>
                
                <text x="20" y="75" fill="#8ba3cb" font-size="13">联锁切换响应时间:</text>
                <text x="280" y="75" fill="var(--success-color)" font-size="14" text-anchor="end" font-family="var(--font-mono)" font-weight="bold" id="data-time">0.0s (待命)</text>
                
                <text x="150" y="93" fill="var(--border-glow)" font-size="12" text-anchor="middle" id="plc-status-text">系统状态:正常均流监控中...</text>
            </g>
        </svg>

        <div class="controls">
            <button id="btn-normal" onclick="setMode('normal')" class="active">① 正常均衡模式</button>
            <button id="btn-warning" onclick="setMode('warning')">② 2#筛跑浆预警</button>
            <button id="btn-balance" onclick="setMode('balance')">③ IFR 系统自平衡</button>
        </div>
    </div>

    <script>
        // DOM Elements mapping
        const els = {
            flow1: document.getElementById('flow1'),
            flow2: document.getElementById('flow2'),
            flow3: document.getElementById('flow3'),
            
            val1: document.getElementById('valve-val-1'),
            val2: document.getElementById('valve-val-2'),
            val3: document.getElementById('valve-val-3'),
            
            core1: document.getElementById('valve-core-1'),
            core2: document.getElementById('valve-core-2'),
            core3: document.getElementById('valve-core-3'),

            shaker2: document.getElementById('shaker-2'),
            shakerRect2: document.getElementById('shaker-rect-2'),
            mudOverflow: document.getElementById('mud-overflow'),
            status2: document.getElementById('status-2'),
            
            sigLines: document.getElementById('signal-lines'),
            sigS2Plc: document.getElementById('sig-s2-plc'),
            
            plcStatus: document.getElementById('plc-status-text'),
            dataError: document.getElementById('data-error'),
            dataTime: document.getElementById('data-time'),

            btnNormal: document.getElementById('btn-normal'),
            btnWarning: document.getElementById('btn-warning'),
            btnBalance: document.getElementById('btn-balance')
        };

        // 动画状态机控制
        let autoPlayTimer = null;
        let timeCounter = 0;
        let timeInterval = null;

        function updateUIButtons(activeId) {
            [els.btnNormal, els.btnWarning, els.btnBalance].forEach(btn => btn.classList.remove('active'));
            document.getElementById(activeId).classList.add('active');
        }

        function setMode(mode) {
            // 清理原有状态
            clearInterval(timeInterval);
            els.shaker2.classList.remove('heavy');
            els.status2.classList.remove('blink');
            els.sigLines.style.opacity = '0';
            els.mudOverflow.style.opacity = '0';
            els.shakerRect2.setAttribute('stroke', '#37538c');

            if (mode === 'normal') {
                updateUIButtons('btn-normal');
                
                // 恢复等比例流量
                els.flow1.className.baseVal = 'flow-dash';
                els.flow2.className.baseVal = 'flow-dash';
                els.flow3.className.baseVal = 'flow-dash';
                els.flow1.setAttribute('stroke', 'var(--normal-flow)');
                els.flow2.setAttribute('stroke', 'var(--normal-flow)');
                els.flow3.setAttribute('stroke', 'var(--normal-flow)');

                // 恢复数值与颜色
                els.val1.textContent = '33.3%';
                els.val2.textContent = '33.3%';
                els.val3.textContent = '33.3%';
                [els.core1, els.core2, els.core3].forEach(c => c.setAttribute('fill', 'var(--border-glow)'));
                [els.val1, els.val2, els.val3].forEach(v => v.setAttribute('fill', 'var(--border-glow)'));
                
                // 面板复位
                els.status2.textContent = '正常运行';
                els.status2.setAttribute('fill', 'var(--success-color)');
                els.plcStatus.textContent = '系统状态:正常均流监控中...';
                els.plcStatus.setAttribute('fill', 'var(--border-glow)');
                els.dataTime.textContent = '0.0s (待命)';
                els.dataTime.setAttribute('fill', 'var(--success-color)');
                els.dataError.textContent = '≤ ±1.5%';

            } else if (mode === 'warning') {
                updateUIButtons('btn-warning');
                
                // 2# 筛超载跑浆
                els.shaker2.classList.add('heavy');
                els.shakerRect2.setAttribute('stroke', 'var(--warning-color)');
                els.mudOverflow.style.opacity = '0.8';
                els.status2.textContent = '跑浆溢出警告!';
                els.status2.setAttribute('fill', 'var(--warning-color)');
                els.status2.classList.add('blink');
                
                // 流量颜色变红暗示危险
                els.flow2.setAttribute('stroke', 'var(--warning-color)');
                els.core2.setAttribute('fill', 'var(--warning-color)');
                els.val2.setAttribute('fill', 'var(--warning-color)');
                
                // PLC报警响应
                els.plcStatus.textContent = '系统状态:检测到 2# 跑浆,启动预案';
                els.plcStatus.setAttribute('fill', 'var(--warning-color)');
                
                // 信号线闪烁传导
                els.sigLines.style.opacity = '1';
                els.sigS2Plc.setAttribute('stroke', 'var(--warning-color)');

            } else if (mode === 'balance') {
                updateUIButtons('btn-balance');
                
                // 展现 IFR 状态: 动态截流与分配
                els.shakerRect2.setAttribute('stroke', 'var(--adjust-color)');
                els.mudOverflow.style.opacity = '0';
                els.status2.textContent = '降载恢复中';
                els.status2.setAttribute('fill', 'var(--adjust-color)');
                
                // 流量粗细和速度调整 (核心)
                els.flow1.className.baseVal = 'flow-dash fast';
                els.flow3.className.baseVal = 'flow-dash fast';
                els.flow2.className.baseVal = 'flow-dash slow';
                
                els.flow2.setAttribute('stroke', 'var(--adjust-color)');
                els.flow1.setAttribute('stroke', 'var(--success-color)');
                els.flow3.setAttribute('stroke', 'var(--success-color)');
                
                els.val1.textContent = '45.0%';
                els.val2.textContent = '10.0%';
                els.val3.textContent = '45.0%';
                
                els.core2.setAttribute('fill', 'var(--adjust-color)');
                els.val2.setAttribute('fill', 'var(--adjust-color)');
                els.core1.setAttribute('fill', 'var(--success-color)');
                els.val1.setAttribute('fill', 'var(--success-color)');
                els.core3.setAttribute('fill', 'var(--success-color)');
                els.val3.setAttribute('fill', 'var(--success-color)');

                // 信号线下发控制指令
                els.sigLines.style.opacity = '1';
                els.sigS2Plc.setAttribute('stroke', '#37538c'); // 关闭报警上传,转为常规监控

                // 计时器视觉效果
                els.plcStatus.textContent = '系统状态:阀门重组完成 (理想解)';
                els.plcStatus.setAttribute('fill', 'var(--success-color)');
                
                timeCounter = 0;
                timeInterval = setInterval(() => {
                    timeCounter += 0.1;
                    els.dataTime.textContent = timeCounter.toFixed(1) + 's (≤5s)';
                    if(timeCounter >= 3.2) { // 模拟切换在 3.2s 处完成
                        clearInterval(timeInterval);
                        els.dataError.textContent = '±4.2% (≤±5%)';
                        els.dataError.setAttribute('fill', 'var(--adjust-color)');
                    }
                }, 100);
            }
        }

        // 自动循环播放机制,符合页面加载后自动播放以及重载重播的要求
        function startAutoPlay() {
            let step = 0;
            const sequence = ['normal', 'warning', 'balance'];
            const delays = [4000, 3000, 5000]; // 每个状态停留时间
            
            function nextStep() {
                setMode(sequence[step]);
                let currentDelay = delays[step];
                step = (step + 1) % sequence.length;
                autoPlayTimer = setTimeout(nextStep, currentDelay);
            }
            
            nextStep(); // 立即启动
        }

        // 绑定用户交互: 点击按钮时停止自动播放,改为手动控制
        ['btn-normal', 'btn-warning', 'btn-balance'].forEach(id => {
            document.getElementById(id).addEventListener('click', () => {
                clearTimeout(autoPlayTimer);
            });
        });

        // 页面初始化
        document.addEventListener('DOMContentLoaded', () => {
            // 不依赖用户点击,自动启动演示流
            startAutoPlay();
        });
    </script>
</body>
</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>
    <style>
        :root {
            --bg-color: #0b1120;
            --grid-color: #1e293b;
            --text-main: #f8fafc;
            --text-muted: #94a3b8;
            --accent-blue: #38bdf8;
            --accent-green: #34d399;
            --accent-warning: #fbbf24;
            --accent-danger: #f87171;
            --pipe-bg: #334155;
            --panel-bg: rgba(30, 41, 59, 0.7);
        }

        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            background-color: var(--bg-color);
            color: var(--text-main);
            font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            overflow: hidden;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            background-image: 
                linear-gradient(var(--grid-color) 1px, transparent 1px),
                linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
            background-size: 40px 40px;
            background-position: center center;
        }

        .animation-container {
            width: 100%;
            max-width: 1400px;
            height: 85vh;
            display: flex;
            justify-content: center;
            align-items: center;
            position: relative;
        }

        svg {
            width: 100%;
            height: 100%;
            filter: drop-shadow(0 0 20px rgba(0,0,0,0.5));
        }

        /* SVG Typography */
        .scada-title { font-size: 18px; font-weight: bold; fill: var(--accent-blue); letter-spacing: 2px; }
        .scada-text { font-size: 14px; fill: var(--text-muted); }
        .scada-value { font-size: 20px; font-weight: bold; font-family: monospace; fill: var(--accent-green); transition: fill 0.3s; }
        .scada-value.warning { fill: var(--accent-danger); }
        .component-label { font-size: 16px; font-weight: bold; fill: #fff; text-anchor: middle; }
        .triz-label { font-size: 12px; fill: var(--accent-warning); opacity: 0.8; font-style: italic; }

        /* Animations */
        @keyframes dash-flow {
            to { stroke-dashoffset: -100; }
        }

        @keyframes signal-flow {
            to { stroke-dashoffset: -40; }
        }

        @keyframes pulse-danger {
            0% { filter: drop-shadow(0 0 5px var(--accent-danger)); opacity: 0.8; }
            50% { filter: drop-shadow(0 0 20px var(--accent-danger)); opacity: 1; }
            100% { filter: drop-shadow(0 0 5px var(--accent-danger)); opacity: 0.8; }
        }

        .flow-line {
            fill: none;
            stroke-dasharray: 15, 10;
            animation: dash-flow linear infinite;
            transition: stroke-width 0.5s ease, stroke 0.5s ease;
        }

        .signal-line {
            fill: none;
            stroke: var(--accent-blue);
            stroke-width: 2;
            stroke-dasharray: 8, 8;
            opacity: 0.3;
            transition: opacity 0.3s, stroke 0.3s;
        }

        .signal-line.active {
            opacity: 1;
            animation: signal-flow 1s linear infinite;
            stroke: var(--accent-danger);
        }
        
        .signal-line.active-control {
            opacity: 1;
            animation: signal-flow 0.5s linear infinite;
            stroke: var(--accent-warning);
        }

        .shaker-box {
            transition: all 0.5s ease;
        }

        .shaker-warning-light {
            fill: #475569;
            transition: fill 0.3s ease;
        }
        .shaker-warning-light.alert {
            fill: var(--accent-danger);
            animation: pulse-danger 1s infinite;
        }

        .valve-core {
            transition: transform 0.5s ease, fill 0.5s ease;
            transform-origin: center;
        }

        /* Controls */
        .controls {
            position: absolute;
            bottom: 30px;
            display: flex;
            gap: 15px;
            background: var(--panel-bg);
            padding: 15px 30px;
            border-radius: 50px;
            border: 1px solid var(--grid-color);
            backdrop-filter: blur(10px);
            box-shadow: 0 10px 30px rgba(0,0,0,0.5);
            z-index: 10;
        }

        .btn {
            background: #1e293b;
            color: var(--text-main);
            border: 1px solid #334155;
            padding: 10px 20px;
            border-radius: 25px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 600;
            transition: all 0.3s ease;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .btn:hover {
            background: #334155;
            border-color: var(--accent-blue);
            box-shadow: 0 0 15px rgba(56, 189, 248, 0.3);
        }

        .btn.active {
            background: var(--accent-blue);
            color: #000;
            border-color: var(--accent-blue);
            box-shadow: 0 0 20px rgba(56, 189, 248, 0.5);
        }

        .btn-danger.active {
            background: var(--accent-danger);
            border-color: var(--accent-danger);
            box-shadow: 0 0 20px rgba(248, 113, 113, 0.5);
        }
        
        .triz-panel {
            position: absolute;
            top: 30px;
            left: 30px;
            width: 320px;
            background: var(--panel-bg);
            border-left: 4px solid var(--accent-warning);
            padding: 20px;
            border-radius: 4px;
            backdrop-filter: blur(5px);
        }
        .triz-panel h3 { color: var(--accent-warning); margin-bottom: 10px; font-size: 16px; }
        .triz-panel p { font-size: 13px; color: #cbd5e1; line-height: 1.6; margin-bottom: 8px; }
        .triz-highlight { color: #fff; font-weight: bold; background: rgba(251, 191, 36, 0.2); padding: 2px 4px; border-radius: 3px; }

    </style>
</head>
<body>

    <div class="triz-panel">
        <h3>TRIZ 最终理想解 (IFR)</h3>
        <p>系统自动消除“局部跑浆”与“全局效率”的矛盾,实现<span class="triz-highlight">无人工干预的动态平衡</span>。</p>
        <p><strong>资源利用:</strong>复用现有PLC与多路阀,以<span class="triz-highlight">极低复杂度</span>引入“流量再分配算法”,变被动停机为主动均衡。</p>
    </div>

    <div class="animation-container">
        <svg viewBox="0 0 1400 800" preserveAspectRatio="xMidYMid meet">
            <defs>
                <!-- Glow Filters -->
                <filter id="glow-blue" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="5" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>
                <filter id="glow-green" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="8" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>
                
                <!-- Gradients -->
                <linearGradient id="mud-grad" x1="0%" y1="0%" x2="100%" y2="0%">
                    <stop offset="0%" stop-color="#92400e" />
                    <stop offset="100%" stop-color="#d97706" />
                </linearGradient>
                <linearGradient id="tank-grad" x1="0%" y1="0%" x2="0%" y2="100%">
                    <stop offset="0%" stop-color="#1e293b" />
                    <stop offset="100%" stop-color="#0f172a" />
                </linearGradient>
                <linearGradient id="shaker-grad" x1="0%" y1="0%" x2="0%" y2="100%">
                    <stop offset="0%" stop-color="#334155" />
                    <stop offset="100%" stop-color="#1e293b" />
                </linearGradient>
                <linearGradient id="plc-grad" x1="0%" y1="0%" x2="100%" y2="100%">
                    <stop offset="0%" stop-color="#0f172a" />
                    <stop offset="100%" stop-color="#1e3a8a" />
                </linearGradient>

                <!-- Patterns -->
                <pattern id="mesh" width="10" height="10" patternUnits="userSpaceOnUse">
                    <path d="M 10 0 L 0 10 M 0 0 L 10 10" fill="none" stroke="#475569" stroke-width="0.5" opacity="0.3"/>
                </pattern>
            </defs>

            <!-- Background Grid (Optional enhancement within SVG) -->
            <rect width="1400" height="800" fill="transparent" />

            <!-- ================= PIPING BACKGROUNDS ================= -->
            <!-- Main to Distributor -->
            <path d="M 700 150 L 700 280" fill="none" stroke="var(--pipe-bg)" stroke-width="24" stroke-linecap="round" />
            
            <!-- Distributor to Shakers -->
            <path d="M 680 320 L 350 320 L 350 520" fill="none" stroke="var(--pipe-bg)" stroke-width="20" stroke-linejoin="round" />
            <path d="M 700 320 L 700 520" fill="none" stroke="var(--pipe-bg)" stroke-width="20" stroke-linejoin="round" />
            <path d="M 720 320 L 1050 320 L 1050 520" fill="none" stroke="var(--pipe-bg)" stroke-width="20" stroke-linejoin="round" />


            <!-- ================= ANIMATED MUD FLOWS ================= -->
            <!-- Main Flow -->
            <path d="M 700 150 L 700 280" class="flow-line" stroke="#fbbf24" stroke-width="14" style="animation-duration: 1.5s;" stroke-linecap="round" />
            
            <!-- Branches -->
            <path id="flow-A" d="M 680 320 L 350 320 L 350 520" class="flow-line" stroke="#fbbf24" stroke-width="10" style="animation-duration: 2s;" stroke-linejoin="round" />
            <path id="flow-B" d="M 700 320 L 700 520" class="flow-line" stroke="#fbbf24" stroke-width="10" style="animation-duration: 2s;" stroke-linejoin="round" />
            <path id="flow-C" d="M 720 320 L 1050 320 L 1050 520" class="flow-line" stroke="#fbbf24" stroke-width="10" style="animation-duration: 2s;" stroke-linejoin="round" />


            <!-- ================= SIGNAL LINES ================= -->
            <!-- Shaker to PLC Sensors -->
            <path id="sig-sensor-A" d="M 350 520 L 350 480 L 1150 480 L 1150 250" class="signal-line" />
            <path id="sig-sensor-B" d="M 700 520 L 700 490 L 1150 490 L 1150 250" class="signal-line" />
            <path id="sig-sensor-C" d="M 1050 520 L 1050 500 L 1150 500 L 1150 250" class="signal-line" />

            <!-- PLC to Valve Controls -->
            <path id="sig-ctrl-A" d="M 1150 250 L 1150 200 L 670 200 L 670 290" class="signal-line" />
            <path id="sig-ctrl-B" d="M 1150 250 L 1150 210 L 700 210 L 700 290" class="signal-line" />
            <path id="sig-ctrl-C" d="M 1150 250 L 1150 220 L 730 220 L 730 290" class="signal-line" />


            <!-- ================= COMPONENTS ================= -->
            
            <!-- Buffer Tank (Inlet) -->
            <g transform="translate(600, 50)">
                <rect width="200" height="100" rx="10" fill="url(#tank-grad)" stroke="#475569" stroke-width="2" />
                <rect x="10" y="10" width="180" height="80" rx="5" fill="url(#mesh)" />
                <text x="100" y="55" class="component-label">缓冲罐 (泥浆源)</text>
                <text x="100" y="80" font-size="12" fill="#94a3b8" text-anchor="middle">总流量: 100%</text>
            </g>

            <!-- Distributor (Multi-way Valve) -->
            <g transform="translate(620, 270)">
                <rect width="160" height="60" rx="8" fill="#1e293b" stroke="#64748b" stroke-width="2" />
                <text x="80" y="20" font-size="12" fill="#cbd5e1" text-anchor="middle" font-weight="bold">多路执行器阀组</text>
                
                <!-- Valve A -->
                <circle cx="50" cy="40" r="12" fill="#334155" />
                <circle id="valve-core-A" class="valve-core" cx="50" cy="40" r="8" fill="var(--accent-green)" />
                
                <!-- Valve B -->
                <circle cx="80" cy="40" r="12" fill="#334155" />
                <circle id="valve-core-B" class="valve-core" cx="80" cy="40" r="8" fill="var(--accent-green)" />
                
                <!-- Valve C -->
                <circle cx="110" cy="40" r="12" fill="#334155" />
                <circle id="valve-core-C" class="valve-core" cx="110" cy="40" r="8" fill="var(--accent-green)" />
            </g>

            <!-- Multiple Flow Meters -->
            <g transform="translate(280, 420)">
                <rect width="50" height="30" rx="4" fill="#0f172a" stroke="#38bdf8" stroke-width="1" />
                <text x="25" y="20" font-size="10" fill="#38bdf8" text-anchor="middle">流量计</text>
            </g>
            <g transform="translate(630, 420)">
                <rect width="50" height="30" rx="4" fill="#0f172a" stroke="#38bdf8" stroke-width="1" />
                <text x="25" y="20" font-size="10" fill="#38bdf8" text-anchor="middle">流量计</text>
            </g>
            <g transform="translate(980, 420)">
                <rect width="50" height="30" rx="4" fill="#0f172a" stroke="#38bdf8" stroke-width="1" />
                <text x="25" y="20" font-size="10" fill="#38bdf8" text-anchor="middle">流量计</text>
            </g>

            <!-- Shakers -->
            <!-- Shaker A -->
            <g transform="translate(270, 520)" class="shaker-box" id="shaker-group-A">
                <rect width="160" height="120" rx="8" fill="url(#shaker-grad)" stroke="#475569" stroke-width="2" />
                <rect x="10" y="40" width="140" height="70" fill="#0f172a" rx="4" />
                <!-- Filter meshes -->
                <line x1="20" y1="50" x2="140" y2="50" stroke="#475569" stroke-width="2" stroke-dasharray="4,2"/>
                <line x1="20" y1="70" x2="140" y2="70" stroke="#475569" stroke-width="2" stroke-dasharray="4,2"/>
                <line x1="20" y1="90" x2="140" y2="90" stroke="#475569" stroke-width="2" stroke-dasharray="4,2"/>
                
                <text x="80" y="25" class="component-label">振动筛 A</text>
                <circle id="light-A" cx="140" cy="20" r="6" class="shaker-warning-light" />
                <text id="shaker-val-A" x="80" y="105" font-size="18" fill="var(--accent-green)" text-anchor="middle" font-weight="bold">33.3%</text>
            </g>

            <!-- Shaker B -->
            <g transform="translate(620, 520)" class="shaker-box" id="shaker-group-B">
                <rect width="160" height="120" rx="8" fill="url(#shaker-grad)" stroke="#475569" stroke-width="2" />
                <rect x="10" y="40" width="140" height="70" fill="#0f172a" rx="4" />
                <line x1="20" y1="50" x2="140" y2="50" stroke="#475569" stroke-width="2" stroke-dasharray="4,2"/>
                <line x1="20" y1="70" x2="140" y2="70" stroke="#475569" stroke-width="2" stroke-dasharray="4,2"/>
                <line x1="20" y1="90" x2="140" y2="90" stroke="#475569" stroke-width="2" stroke-dasharray="4,2"/>
                
                <text x="80" y="25" class="component-label">振动筛 B</text>
                <circle id="light-B" cx="140" cy="20" r="6" class="shaker-warning-light" />
                <text id="shaker-val-B" x="80" y="105" font-size="18" fill="var(--accent-green)" text-anchor="middle" font-weight="bold">33.3%</text>
            </g>

            <!-- Shaker C -->
            <g transform="translate(970, 520)" class="shaker-box" id="shaker-group-C">
                <rect width="160" height="120" rx="8" fill="url(#shaker-grad)" stroke="#475569" stroke-width="2" />
                <rect x="10" y="40" width="140" height="70" fill="#0f172a" rx="4" />
                <line x1="20" y1="50" x2="140" y2="50" stroke="#475569" stroke-width="2" stroke-dasharray="4,2"/>
                <line x1="20" y1="70" x2="140" y2="70" stroke="#475569" stroke-width="2" stroke-dasharray="4,2"/>
                <line x1="20" y1="90" x2="140" y2="90" stroke="#475569" stroke-width="2" stroke-dasharray="4,2"/>
                
                <text x="80" y="25" class="component-label">振动筛 C</text>
                <circle id="light-C" cx="140" cy="20" r="6" class="shaker-warning-light" />
                <text id="shaker-val-C" x="80" y="105" font-size="18" fill="var(--accent-green)" text-anchor="middle" font-weight="bold">33.3%</text>
            </g>


            <!-- ================= SCADA / PLC PANEL ================= -->
            <g transform="translate(1050, 50)" filter="url(#glow-blue)">
                <!-- PLC Body -->
                <rect width="280" height="200" rx="12" fill="url(#plc-grad)" stroke="var(--accent-blue)" stroke-width="2" />
                <rect x="10" y="40" width="260" height="150" rx="6" fill="#020617" />
                
                <text x="140" y="25" class="scada-title" text-anchor="middle">总控 PLC / SCADA</text>
                
                <!-- SCADA Data -->
                <text x="20" y="65" class="scada-text">实时流量分配:</text>
                
                <text x="30" y="90" class="scada-text">筛 A:</text>
                <text id="scada-a" x="80" y="92" class="scada-value">33.3%</text>
                
                <text x="140" y="90" class="scada-text">筛 B:</text>
                <text id="scada-b" x="190" y="92" class="scada-value">33.3%</text>
                
                <text x="30" y="120" class="scada-text">筛 C:</text>
                <text id="scada-c" x="80" y="122" class="scada-value">33.3%</text>

                <line x1="20" y1="135" x2="260" y2="135" stroke="#334155" stroke-dasharray="2,2" />
                
                <text x="20" y="160" class="scada-text">分配误差:</text>
                <text id="scada-error" x="90" y="162" class="scada-value" fill="var(--accent-green)">≤±2.1%</text>

                <text x="20" y="180" class="scada-text">切换时间:</text>
                <text id="scada-time" x="90" y="182" class="scada-value" fill="var(--accent-blue)">- -</text>
                
                <text id="scada-status" x="200" y="172" font-size="16" fill="var(--accent-green)" font-weight="bold" text-anchor="middle">系统均衡</text>
            </g>
        </svg>
    </div>

    <div class="controls">
        <button class="btn active" id="btn-normal" onclick="forceState('normal')">
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>
            正常均分
        </button>
        <button class="btn btn-danger" id="btn-overload-b" onclick="forceState('overloadB')">
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>
            模拟筛B跑浆
        </button>
        <button class="btn btn-danger" id="btn-overload-a" onclick="forceState('overloadA')">
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>
            模拟筛A跑浆
        </button>
    </div>

    <script>
        // Constants for configurations
        const COLORS = {
            green: 'var(--accent-green)',
            red: 'var(--accent-danger)',
            orange: 'var(--accent-warning)',
            muted: '#475569'
        };

        let autoPlayTimer = null;
        let currentStateIndex = 0;
        const stateSequence = ['normal', 'overloadB', 'normal', 'overloadA'];

        // DOM Elements
        const els = {
            flows: { A: document.getElementById('flow-A'), B: document.getElementById('flow-B'), C: document.getElementById('flow-C') },
            valves: { A: document.getElementById('valve-core-A'), B: document.getElementById('valve-core-B'), C: document.getElementById('valve-core-C') },
            lights: { A: document.getElementById('light-A'), B: document.getElementById('light-B'), C: document.getElementById('light-C') },
            scada: { A: document.getElementById('scada-a'), B: document.getElementById('scada-b'), C: document.getElementById('scada-c'),
                     err: document.getElementById('scada-error'), time: document.getElementById('scada-time'), status: document.getElementById('scada-status') },
            shakerVals: { A: document.getElementById('shaker-val-A'), B: document.getElementById('shaker-val-B'), C: document.getElementById('shaker-val-C') },
            sigsSensor: { A: document.getElementById('sig-sensor-A'), B: document.getElementById('sig-sensor-B'), C: document.getElementById('sig-sensor-C') },
            sigsCtrl: { A: document.getElementById('sig-ctrl-A'), B: document.getElementById('sig-ctrl-B'), C: document.getElementById('sig-ctrl-C') },
            btns: { normal: document.getElementById('btn-normal'), overloadB: document.getElementById('btn-overload-b'), overloadA: document.getElementById('btn-overload-a') }
        };

        // State Definitions
        const states = {
            normal: {
                flows: { A: { w: 10, spd: '2s' }, B: { w: 10, spd: '2s' }, C: { w: 10, spd: '2s' } },
                vals: { A: '33.3%', B: '33.3%', C: '33.3%' },
                valves: { A: COLORS.green, B: COLORS.green, C: COLORS.green },
                lights: { A: false, B: false, C: false },
                scadaStatus: '系统均衡',
                scadaColor: COLORS.green,
                time: '- -',
                activeBtn: 'btn-normal'
            },
            overloadB: {
                flows: { A: { w: 14, spd: '1s' }, B: { w: 4, spd: '4s' }, C: { w: 14, spd: '1s' } },
                vals: { A: '45.0%', B: '10.0%', C: '45.0%' },
                valves: { A: COLORS.green, B: COLORS.red, C: COLORS.green },
                lights: { A: false, B: true, C: false },
                scadaStatus: '联锁干预',
                scadaColor: COLORS.orange,
                time: '1.2s',
                activeBtn: 'btn-overload-b'
            },
            overloadA: {
                flows: { A: { w: 4, spd: '4s' }, B: { w: 14, spd: '1s' }, C: { w: 14, spd: '1s' } },
                vals: { A: '10.0%', B: '45.0%', C: '45.0%' },
                valves: { A: COLORS.red, B: COLORS.green, C: COLORS.green },
                lights: { A: true, B: false, C: false },
                scadaStatus: '联锁干预',
                scadaColor: COLORS.orange,
                time: '1.4s',
                activeBtn: 'btn-overload-a'
            }
        };

        function updateElementState(stateData, key) {
            // Update Pipe Flows
            els.flows[key].style.strokeWidth = stateData.flows[key].w;
            els.flows[key].style.animationDuration = stateData.flows[key].spd;
            
            // Update Text Values
            els.scada[key].textContent = stateData.vals[key];
            els.shakerVals[key].textContent = stateData.vals[key];
            
            // Update Colors & Warnings
            els.valves[key].style.fill = stateData.valves[key];
            if(stateData.lights[key]) {
                els.lights[key].classList.add('alert');
                els.scada[key].classList.add('warning');
                els.shakerVals[key].style.fill = COLORS.red;
                els.sigsSensor[key].classList.add('active');
                els.sigsCtrl[key].classList.add('active-control');
            } else {
                els.lights[key].classList.remove('alert');
                els.scada[key].classList.remove('warning');
                els.shakerVals[key].style.fill = COLORS.green;
                els.sigsSensor[key].classList.remove('active');
                els.sigsCtrl[key].classList.remove('active-control');
            }
        }

        function applyState(stateName) {
            const data = states[stateName];
            
            ['A', 'B', 'C'].forEach(key => updateElementState(data, key));
            
            els.scada.status.textContent = data.scadaStatus;
            els.scada.status.style.fill = data.scadaColor;
            
            if(stateName !== 'normal') {
                // Simulate time counter animation
                let t = 0.0;
                let finalT = parseFloat(data.time);
                let intv = setInterval(() => {
                    t += 0.2;
                    if(t >= finalT) {
                        t = finalT;
                        clearInterval(intv);
                    }
                    els.scada.time.textContent = t.toFixed(1) + 's';
                }, 50);
            } else {
                els.scada.time.textContent = data.time;
            }

            // Update UI Buttons
            Object.values(els.btns).forEach(btn => btn.classList.remove('active'));
            document.getElementById(data.activeBtn).classList.add('active');
        }

        function playSequence() {
            applyState(stateSequence[currentStateIndex]);
            currentStateIndex = (currentStateIndex + 1) % stateSequence.length;
            autoPlayTimer = setTimeout(playSequence, 6000); // Change state every 6 seconds
        }

        function forceState(stateName) {
            clearTimeout(autoPlayTimer);
            applyState(stateName);
            // Resume autoplay after manual intervention
            setTimeout(() => {
                currentStateIndex = stateSequence.indexOf(stateName) + 1;
                if(currentStateIndex >= stateSequence.length) currentStateIndex = 0;
                playSequence();
            }, 8000);
        }

        // Initialize: Ensure auto-play on load as requested
        document.addEventListener('DOMContentLoaded', () => {
            playSequence();
        });
    </script>
</body>
</html>

这里为您提供一份基于“深色工业SCADA控制系统”风格(Dark Industrial Cyber-Physical)的高保真 SVG 交互式动画代码。

设觉设计与 TRIZ (IFR) 结合点说明:

  1. 最终理想解 (IFR) 呈现:动画不展示传统的人工发现与排查过程,而是直接展示“智能化闭环”的最终形态——当局部(2号振动筛)发生跑浆风险时,系统无需人工干预,通过自身算法瞬间完成流量全局重分配。
  2. 资源巧妙利用:突出展示“总控PLC + 多路分配阀”作为关键资源,如何在极短的切换时间(<5s)内,不增加额外处理设备,仅靠分配逻辑就化解了局部负荷过大的矛盾。
  3. 视觉引导:采用霓虹荧光色系进行状态区分。正常流量为青色(Cyan),跑浆告警为橙红色(Orange/Red),重分配后的最优状态为翠绿色(Green)。PLC信号脉冲和阀门动态缩放直观呈现了系统的控制逻辑。
  4. 交互体验:内置了状态自循环(默认自动播放满足要求),同时也提供了一个右上角的“SCADA 手动介入面板”,允许用户亲自拖拽滑块,体验流量动态平衡和误差计算的过程。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>多振动筛联锁全局流量优化系统</title>
    <style>
        :root {
            --bg-color: #0b0f19;
            --grid-color: #1a2235;
            --text-main: #94a3b8;
            --text-highlight: #f8fafc;
            --accent-cyan: #00f0ff;
            --accent-green: #00ffa3;
            --accent-red: #ff3c00;
            --pipe-base: #2a364a;
            --panel-bg: rgba(15, 23, 42, 0.85);
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            background-color: var(--bg-color);
            font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            overflow: hidden;
            color: var(--text-main);
        }

        .scada-container {
            position: relative;
            width: 100%;
            max-width: 1400px;
            height: 100%;
            max-height: 900px;
            background-image: 
                linear-gradient(var(--grid-color) 1px, transparent 1px),
                linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
            background-size: 30px 30px;
            box-shadow: inset 0 0 100px rgba(0,0,0,0.8);
            border: 1px solid #1e293b;
            border-radius: 8px;
            overflow: hidden;
        }

        /* Top HUD Panel */
        .hud-top {
            position: absolute;
            top: 20px;
            left: 30px;
            z-index: 10;
        }
        .hud-title {
            font-size: 24px;
            font-weight: 600;
            color: var(--accent-cyan);
            letter-spacing: 2px;
            text-transform: uppercase;
            text-shadow: 0 0 10px rgba(0, 240, 255, 0.3);
            margin-bottom: 5px;
        }
        .hud-subtitle {
            font-size: 12px;
            font-family: 'Courier New', Courier, monospace;
            color: #64748b;
        }

        /* SCADA Interactive Panel */
        .scada-panel {
            position: absolute;
            top: 20px;
            right: 30px;
            background: var(--panel-bg);
            border: 1px solid #334155;
            padding: 20px;
            border-radius: 8px;
            backdrop-filter: blur(10px);
            width: 320px;
            z-index: 10;
            box-shadow: 0 10px 30px rgba(0,0,0,0.5);
        }
        
        .panel-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 1px solid #334155;
            padding-bottom: 10px;
            margin-bottom: 15px;
        }
        
        .mode-toggle {
            display: flex;
            gap: 10px;
        }
        .btn-mode {
            background: transparent;
            border: 1px solid #475569;
            color: #94a3b8;
            padding: 5px 10px;
            font-size: 12px;
            cursor: pointer;
            border-radius: 4px;
            transition: all 0.3s;
        }
        .btn-mode.active {
            background: rgba(0, 240, 255, 0.1);
            border-color: var(--accent-cyan);
            color: var(--accent-cyan);
            box-shadow: 0 0 8px rgba(0, 240, 255, 0.2);
        }

        .data-row {
            display: flex;
            justify-content: space-between;
            margin-bottom: 10px;
            font-family: 'Courier New', Courier, monospace;
            font-size: 13px;
        }
        .data-val {
            color: var(--text-highlight);
            font-weight: bold;
        }
        .data-val.cyan { color: var(--accent-cyan); }
        .data-val.green { color: var(--accent-green); }
        .data-val.red { color: var(--accent-red); }

        .slider-group {
            margin-top: 15px;
            display: none; /* Shown in manual mode */
        }
        .slider-group.active { display: block; }
        .slider-row { margin-bottom: 12px; }
        .slider-label {
            font-size: 12px;
            margin-bottom: 5px;
            display: flex;
            justify-content: space-between;
        }
        input[type=range] {
            width: 100%;
            -webkit-appearance: none;
            background: #1e293b;
            height: 4px;
            border-radius: 2px;
            outline: none;
        }
        input[type=range]::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 14px;
            height: 14px;
            border-radius: 50%;
            background: var(--accent-cyan);
            cursor: pointer;
            box-shadow: 0 0 5px var(--accent-cyan);
        }

        /* SVG Animation Specifics */
        svg {
            width: 100%;
            height: 100%;
        }
        .flow-dash {
            stroke-dasharray: 10 15;
            animation: flowMove 1s linear infinite;
        }
        @keyframes flowMove {
            to { stroke-dashoffset: -25; }
        }
        .signal-dash {
            stroke-dasharray: 5 10;
            animation: signalMove 0.5s linear infinite;
        }
        @keyframes signalMove {
            to { stroke-dashoffset: -15; }
        }
        .shaker-mesh {
            animation: vibrate 0.1s linear infinite;
        }
        @keyframes vibrate {
            0% { transform: translate(0, 0); }
            50% { transform: translate(1px, -1px); }
            100% { transform: translate(0, 0); }
        }
        .plc-pulse {
            animation: plcGlow 2s ease-in-out infinite alternate;
        }
        @keyframes plcGlow {
            from { filter: drop-shadow(0 0 5px rgba(0,240,255,0.2)); }
            to { filter: drop-shadow(0 0 20px rgba(0,240,255,0.6)); }
        }
    </style>
</head>
<body>

<div class="scada-container">
    <!-- Top Left HUD -->
    <div class="hud-top">
        <div class="hud-title">VIBRATION SHAKER INTERLOCK MGT</div>
        <div class="hud-subtitle">TOTAL FLOW ALLOCATION ALGORITHM V2.4 // STATUS: ONLINE</div>
    </div>

    <!-- Top Right SCADA Control Panel -->
    <div class="scada-panel">
        <div class="panel-header">
            <span style="font-size: 14px; font-weight: bold; color: #cbd5e1;">系统状态监控</span>
            <div class="mode-toggle">
                <button class="btn-mode active" id="btn-auto">AUTO</button>
                <button class="btn-mode" id="btn-manual">MANUAL</button>
            </div>
        </div>
        <div class="data-row">
            <span>主回路总流量:</span>
            <span class="data-val cyan" id="txt-total-flow">1500 L/min</span>
        </div>
        <div class="data-row">
            <span>分配误差界限:</span>
            <span class="data-val">≤ ±5%</span>
        </div>
        <div class="data-row">
            <span>当前最大分配误差:</span>
            <span class="data-val green" id="txt-error">±1.2%</span>
        </div>
        <div class="data-row">
            <span>动作切换耗时:</span>
            <span class="data-val" id="txt-time">-- s (限值≤5s)</span>
        </div>
        <div class="data-row" style="margin-top: 15px; border-top: 1px dashed #334155; padding-top: 10px;">
            <span>系统状态:</span>
            <span class="data-val cyan" id="txt-status">正常均衡运行</span>
        </div>

        <div class="slider-group" id="manual-controls">
            <div class="slider-row">
                <div class="slider-label"><span>1#分配阀开度</span><span id="val-v1">33.3%</span></div>
                <input type="range" id="slider-v1" min="10" max="80" value="33.3" step="0.1">
            </div>
            <div class="slider-row">
                <div class="slider-label"><span>2#分配阀开度</span><span id="val-v2">33.3%</span></div>
                <input type="range" id="slider-v2" min="10" max="80" value="33.3" step="0.1">
            </div>
            <div class="slider-row">
                <div class="slider-label"><span>3#分配阀开度</span><span id="val-v3">33.3%</span></div>
                <input type="range" id="slider-v3" min="10" max="80" value="33.3" step="0.1">
            </div>
            <div style="font-size: 11px; color: #64748b; margin-top: 10px; line-height: 1.4;">
                * 手动模式下,调整单阀开度将自动通过PLC算法补偿其他阀门,维持总进料量100%恒定。
            </div>
        </div>
    </div>

    <!-- Main SVG Canvas -->
    <svg viewBox="0 0 1400 900" preserveAspectRatio="xMidYMid meet" id="main-svg">
        <defs>
            <!-- Glow Filters -->
            <filter id="glow-cyan" x="-20%" y="-20%" width="140%" height="140%">
                <feGaussianBlur stdDeviation="8" result="blur" />
                <feComposite in="SourceGraphic" in2="blur" operator="over" />
            </filter>
            <filter id="glow-red" x="-20%" y="-20%" width="140%" height="140%">
                <feGaussianBlur stdDeviation="8" result="blur" />
                <feComposite in="SourceGraphic" in2="blur" operator="over" />
            </filter>
            <filter id="glow-green" x="-20%" y="-20%" width="140%" height="140%">
                <feGaussianBlur stdDeviation="8" result="blur" />
                <feComposite in="SourceGraphic" in2="blur" operator="over" />
            </filter>

            <!-- Pipe Gradient -->
            <linearGradient id="pipe-grad" x1="0%" y1="0%" x2="100%" y2="0%">
                <stop offset="0%" stop-color="#1e293b"/>
                <stop offset="50%" stop-color="#334155"/>
                <stop offset="100%" stop-color="#1e293b"/>
            </linearGradient>

            <linearGradient id="pipe-grad-v" x1="0%" y1="0%" x2="0%" y2="100%">
                <stop offset="0%" stop-color="#1e293b"/>
                <stop offset="50%" stop-color="#334155"/>
                <stop offset="100%" stop-color="#1e293b"/>
            </linearGradient>

            <!-- Valve Symbol Component -->
            <g id="valve">
                <polygon points="-15,-15 15,15 -15,15 15,-15" fill="#475569" stroke="#94a3b8" stroke-width="2"/>
                <line x1="0" y1="0" x2="0" y2="-25" stroke="#94a3b8" stroke-width="3"/>
                <rect x="-12" y="-35" width="24" height="10" fill="#0ea5e9" rx="2"/>
            </g>
        </defs>

        <!-- ================= BACKGROUND STRUCTURAL PIPES ================= -->
        <!-- Main Feed Pipe -->
        <rect x="670" y="80" width="60" height="200" fill="url(#pipe-grad-v)" stroke="#0f172a" stroke-width="2"/>
        <text x="740" y="150" fill="#64748b" font-family="monospace" font-size="14">MAIN FEED / 缓冲罐来料</text>

        <!-- Manifold Horizontal -->
        <rect x="270" y="250" width="860" height="60" fill="url(#pipe-grad)" stroke="#0f172a" stroke-width="2"/>
        
        <!-- Branches (1, 2, 3) -->
        <rect x="270" y="310" width="60" height="250" fill="url(#pipe-grad-v)" stroke="#0f172a" stroke-width="2"/>
        <rect x="670" y="310" width="60" height="250" fill="url(#pipe-grad-v)" stroke="#0f172a" stroke-width="2"/>
        <rect x="1070" y="310" width="60" height="250" fill="url(#pipe-grad-v)" stroke="#0f172a" stroke-width="2"/>


        <!-- ================= ACTIVE FLUID FLOW PATHS ================= -->
        <!-- Main Flow -->
        <path d="M 700 80 L 700 280" stroke="var(--accent-cyan)" stroke-width="24" fill="none" class="flow-dash" filter="url(#glow-cyan)" id="flow-main"/>
        
        <!-- Manifold Distribution Flows -->
        <path d="M 700 280 L 300 280 L 300 560" stroke="var(--accent-cyan)" stroke-width="12" fill="none" class="flow-dash" filter="url(#glow-cyan)" id="flow-branch1"/>
        <path d="M 700 280 L 700 560" stroke="var(--accent-cyan)" stroke-width="12" fill="none" class="flow-dash" filter="url(#glow-cyan)" id="flow-branch2"/>
        <path d="M 700 280 L 1100 280 L 1100 560" stroke="var(--accent-cyan)" stroke-width="12" fill="none" class="flow-dash" filter="url(#glow-cyan)" id="flow-branch3"/>


        <!-- ================= PLC CONTROLLER ================= -->
        <g transform="translate(600, 750)" class="plc-pulse">
            <rect x="-150" y="-50" width="300" height="100" fill="#0f172a" stroke="var(--accent-cyan)" stroke-width="2" rx="8"/>
            <rect x="-140" y="-40" width="280" height="80" fill="#1e293b" rx="4"/>
            <text x="0" y="-10" fill="#f8fafc" font-size="20" font-weight="bold" text-anchor="middle">TOTAL CONTROL PLC</text>
            <text x="0" y="15" fill="var(--accent-cyan)" font-size="12" font-family="monospace" text-anchor="middle">最优分配算法运算核心</text>
            
            <!-- PLC Status Leds -->
            <circle cx="-110" cy="20" r="5" fill="var(--accent-cyan)" id="led-normal"/>
            <text x="-95" y="24" fill="#64748b" font-size="10">SYS OK</text>
            
            <circle cx="-30" cy="20" r="5" fill="#334155" id="led-warn"/>
            <text x="-15" y="24" fill="#64748b" font-size="10">OVERLOAD</text>

            <circle cx="50" cy="20" r="5" fill="#334155" id="led-calc"/>
            <text x="65" y="24" fill="#64748b" font-size="10">CALC</text>
        </g>

        <!-- ================= SIGNAL LINES ================= -->
        <g stroke="#0ea5e9" stroke-width="1.5" fill="none" class="signal-dash" opacity="0.6" id="signal-lines">
            <!-- To Valve 1 -->
            <path d="M 450 750 L 370 750 L 370 420 L 320 420" />
            <!-- To Valve 2 -->
            <path d="M 600 700 L 600 650 L 730 650 L 730 420 L 715 420" />
            <!-- To Valve 3 -->
            <path d="M 750 750 L 1030 750 L 1030 420 L 1080 420" />
            
            <!-- Feedback from flow meters -->
            <path d="M 320 350 L 400 350 L 400 690 L 550 690" stroke="#10b981" />
            <path d="M 720 350 L 770 350 L 770 690 L 650 690" stroke="#10b981" />
            <path d="M 1080 350 L 980 350 L 980 690 L 680 690" stroke="#10b981" />
        </g>


        <!-- ================= HARDWARE COMPONENTS (VALVES & METERS) ================= -->
        <!-- Branch 1 -->
        <g transform="translate(300, 350)">
            <circle cx="0" cy="0" r="25" fill="#1e293b" stroke="#64748b" stroke-width="2"/>
            <text x="0" y="5" fill="#0ea5e9" font-family="monospace" font-size="12" text-anchor="middle" id="meter1">33%</text>
            <text x="-40" y="5" fill="#94a3b8" font-size="12" text-anchor="end">流量计(FI-01)</text>
        </g>
        <g transform="translate(300, 420)">
            <use href="#valve" />
            <text x="-40" y="0" fill="#94a3b8" font-size="12" text-anchor="end">电液分配阀(XV-01)</text>
            <text x="40" y="0" fill="var(--accent-cyan)" font-size="14" font-weight="bold" id="valve-val-1">33%</text>
        </g>

        <!-- Branch 2 -->
        <g transform="translate(700, 350)">
            <circle cx="0" cy="0" r="25" fill="#1e293b" stroke="#64748b" stroke-width="2"/>
            <text x="0" y="5" fill="#0ea5e9" font-family="monospace" font-size="12" text-anchor="middle" id="meter2">33%</text>
            <text x="40" y="5" fill="#94a3b8" font-size="12" text-anchor="start">流量计(FI-02)</text>
        </g>
        <g transform="translate(700, 420)">
            <use href="#valve" />
            <text x="40" y="0" fill="#94a3b8" font-size="12" text-anchor="start">电液分配阀(XV-02)</text>
            <text x="-40" y="0" fill="var(--accent-cyan)" font-size="14" font-weight="bold" text-anchor="end" id="valve-val-2">33%</text>
        </g>

        <!-- Branch 3 -->
        <g transform="translate(1100, 350)">
            <circle cx="0" cy="0" r="25" fill="#1e293b" stroke="#64748b" stroke-width="2"/>
            <text x="0" y="5" fill="#0ea5e9" font-family="monospace" font-size="12" text-anchor="middle" id="meter3">33%</text>
            <text x="40" y="5" fill="#94a3b8" font-size="12" text-anchor="start">流量计(FI-03)</text>
        </g>
        <g transform="translate(1100, 420)">
            <use href="#valve" />
            <text x="40" y="0" fill="#94a3b8" font-size="12" text-anchor="start">电液分配阀(XV-03)</text>
            <text x="-40" y="0" fill="var(--accent-cyan)" font-size="14" font-weight="bold" text-anchor="end" id="valve-val-3">33%</text>
        </g>


        <!-- ================= SHALE SHAKERS ================= -->
        <!-- Shaker Base Function -->
        <defs>
            <g id="shaker-model">
                <!-- Base Frame -->
                <path d="M -80 0 L 80 0 L 90 60 L -90 60 Z" fill="#1e293b" stroke="#475569" stroke-width="2"/>
                <!-- Support Legs -->
                <line x1="-70" y1="60" x2="-70" y2="90" stroke="#475569" stroke-width="8"/>
                <line x1="70" y1="60" x2="70" y2="90" stroke="#475569" stroke-width="8"/>
                <rect x="-85" y="90" width="30" height="10" fill="#0f172a"/>
                <rect x="55" y="90" width="30" height="10" fill="#0f172a"/>
                <!-- Vibrating Mesh -->
                <path d="M -75 10 L 75 10 M -78 20 L 78 20 M -80 30 L 80 30" stroke="#94a3b8" stroke-width="2" class="shaker-mesh" stroke-dasharray="4 4"/>
            </g>
        </defs>

        <!-- Shaker 1 -->
        <g transform="translate(300, 560)">
            <!-- Mud Pool Volume Inside Shaker -->
            <path d="M -60 50 L 60 50 L 70 50 L -70 50 Z" fill="var(--accent-cyan)" opacity="0.6" filter="url(#glow-cyan)" id="mud-pool-1" style="transition: all 0.5s;"/>
            <use href="#shaker-model" />
            <text x="0" y="120" fill="#f8fafc" font-size="14" font-weight="bold" text-anchor="middle">1# 振动筛</text>
            <text x="0" y="140" fill="#64748b" font-size="12" text-anchor="middle">承载率: <tspan id="load-1">33%</tspan></text>
        </g>

        <!-- Shaker 2 (The one that will overload) -->
        <g transform="translate(700, 560)">
            <path d="M -60 50 L 60 50 L 70 50 L -70 50 Z" fill="var(--accent-cyan)" opacity="0.6" filter="url(#glow-cyan)" id="mud-pool-2" style="transition: all 0.5s;"/>
            <use href="#shaker-model" />
            <text x="0" y="120" fill="#f8fafc" font-size="14" font-weight="bold" text-anchor="middle">2# 振动筛</text>
            <text x="0" y="140" fill="#64748b" font-size="12" text-anchor="middle">承载率: <tspan id="load-2">33%</tspan></text>
            
            <!-- Alert Icon (Hidden normally) -->
            <g id="alert-icon-2" opacity="0" style="transition: opacity 0.3s;">
                <circle cx="0" cy="-30" r="16" fill="var(--accent-red)" />
                <text x="0" y="-25" fill="#fff" font-size="16" font-weight="bold" text-anchor="middle">!</text>
                <text x="0" y="-55" fill="var(--accent-red)" font-size="14" font-weight="bold" text-anchor="middle" filter="url(#glow-red)">跑浆风险告警</text>
            </g>
        </g>

        <!-- Shaker 3 -->
        <g transform="translate(1100, 560)">
            <path d="M -60 50 L 60 50 L 70 50 L -70 50 Z" fill="var(--accent-cyan)" opacity="0.6" filter="url(#glow-cyan)" id="mud-pool-3" style="transition: all 0.5s;"/>
            <use href="#shaker-model" />
            <text x="0" y="120" fill="#f8fafc" font-size="14" font-weight="bold" text-anchor="middle">3# 振动筛</text>
            <text x="0" y="140" fill="#64748b" font-size="12" text-anchor="middle">承载率: <tspan id="load-3">33%</tspan></text>
        </g>

    </svg>
</div>

<script>
    // --- State Management ---
    let mode = 'auto'; // 'auto' | 'manual'
    let autoPhase = 0;
    let autoTimer = null;
    let valves = [33.3, 33.3, 33.4]; // Current distribution
    const BASE_THICKNESS = 36; // Max stroke width for 100% flow

    // --- DOM Elements ---
    const els = {
        flows: [document.getElementById('flow-branch1'), document.getElementById('flow-branch2'), document.getElementById('flow-branch3')],
        meters: [document.getElementById('meter1'), document.getElementById('meter2'), document.getElementById('meter3')],
        valveVals: [document.getElementById('valve-val-1'), document.getElementById('valve-val-2'), document.getElementById('valve-val-3')],
        mudPools: [document.getElementById('mud-pool-1'), document.getElementById('mud-pool-2'), document.getElementById('mud-pool-3')],
        loads: [document.getElementById('load-1'), document.getElementById('load-2'), document.getElementById('load-3')],
        alert2: document.getElementById('alert-icon-2'),
        ledNormal: document.getElementById('led-normal'),
        ledWarn: document.getElementById('led-warn'),
        ledCalc: document.getElementById('led-calc'),
        signalLines: document.getElementById('signal-lines'),
        txtError: document.getElementById('txt-error'),
        txtTime: document.getElementById('txt-time'),
        txtStatus: document.getElementById('txt-status'),
        sliders: [document.getElementById('slider-v1'), document.getElementById('slider-v2'), document.getElementById('slider-v3')],
        sliderVals: [document.getElementById('val-v1'), document.getElementById('val-v2'), document.getElementById('val-v3')]
    };

    // --- Core Logic: Update UI based on Valve Distribution ---
    function updateSystem(v, isAlarm = false, isOptimized = false) {
        valves = v;
        let maxError = Math.abs(valves[0] - 33.3);
        maxError = Math.max(maxError, Math.abs(valves[1] - 33.3), Math.abs(valves[2] - 33.3));
        
        for (let i=0; i<3; i++) {
            let p = valves[i];
            let width = (p / 100) * BASE_THICKNESS;
            if(width < 2) width = 2; // Min visibility
            
            // Update Flows
            els.flows[i].style.strokeWidth = width + 'px';
            
            // Update Texts
            let pStr = p.toFixed(1) + '%';
            els.meters[i].textContent = pStr;
            els.valveVals[i].textContent = pStr;
            els.loads[i].textContent = pStr;
            if(mode === 'manual') {
                els.sliders[i].value = p.toFixed(1);
                els.sliderVals[i].textContent = pStr;
            }

            // Update Mud Pool Visuals (d attribute animation)
            // Normal base is M -75 40 L 75 40 (approx). Height scales with %
            let h = 50 - (p / 50) * 45; // Higher % = lower Y value (higher pool)
            if (h < 5) h = 5;
            let d = `M -60 ${h} L 60 ${h} L 70 50 L -70 50 Z`;
            els.mudPools[i].setAttribute('d', d);

            // Color logic
            if (isAlarm && i === 1) {
                els.flows[i].setAttribute('stroke', 'var(--accent-red)');
                els.flows[i].setAttribute('filter', 'url(#glow-red)');
                els.mudPools[i].setAttribute('fill', 'var(--accent-red)');
                els.mudPools[i].setAttribute('filter', 'url(#glow-red)');
                els.loads[i].style.fill = 'var(--accent-red)';
            } else if (isOptimized && !isAlarm) {
                els.flows[i].setAttribute('stroke', 'var(--accent-green)');
                els.flows[i].setAttribute('filter', 'url(#glow-green)');
                els.mudPools[i].setAttribute('fill', 'var(--accent-cyan)'); // pool returns to normal color
                els.mudPools[i].setAttribute('filter', 'url(#glow-cyan)');
                els.loads[i].style.fill = '#94a3b8';
            } else {
                els.flows[i].setAttribute('stroke', 'var(--accent-cyan)');
                els.flows[i].setAttribute('filter', 'url(#glow-cyan)');
                els.mudPools[i].setAttribute('fill', 'var(--accent-cyan)');
                els.mudPools[i].setAttribute('filter', 'url(#glow-cyan)');
                els.loads[i].style.fill = '#94a3b8';
            }
        }

        // SCADA Data Updates
        els.txtError.textContent = '±' + (isAlarm ? '18.5%' : (maxError > 0 ? (maxError/10).toFixed(1) + '%' : '1.2%')); // Simulating algorithm error bound
        els.txtError.className = isAlarm ? 'data-val red' : 'data-val green';
        
        if (isAlarm) {
            els.txtStatus.textContent = '检测到2#区域跑浆风险,计算中...';
            els.txtStatus.className = 'data-val red';
            els.alert2.style.opacity = '1';
            els.ledNormal.setAttribute('fill', '#334155');
            els.ledWarn.setAttribute('fill', 'var(--accent-red)');
            els.ledCalc.setAttribute('fill', 'var(--accent-cyan)');
            els.signalLines.style.stroke = 'var(--accent-red)';
        } else if (isOptimized) {
            els.txtStatus.textContent = '流量重分配完成,全局最优平衡';
            els.txtStatus.className = 'data-val green';
            els.alert2.style.opacity = '0';
            els.ledNormal.setAttribute('fill', 'var(--accent-cyan)');
            els.ledWarn.setAttribute('fill', '#334155');
            els.ledCalc.setAttribute('fill', '#334155');
            els.signalLines.style.stroke = 'var(--accent-green)';
        } else {
            els.txtStatus.textContent = '正常均衡运行';
            els.txtStatus.className = 'data-val cyan';
            els.alert2.style.opacity = '0';
            els.ledNormal.setAttribute('fill', 'var(--accent-cyan)');
            els.ledWarn.setAttribute('fill', '#334155');
            els.ledCalc.setAttribute('fill', '#334155');
            els.signalLines.style.stroke = '#0ea5e9';
        }
    }

    // --- Auto Play Storyline (IFR Implementation) ---
    function runAutoSequence() {
        if (mode !== 'auto') return;

        // Phase 1: Normal (0-4s)
        if (autoPhase === 0) {
            updateSystem([33.3, 33.3, 33.4], false, false);
            els.txtTime.textContent = '-- s (限值≤5s)';
            setTimeout(() => { autoPhase = 1; runAutoSequence(); }, 3000);
        }
        // Phase 2: Overload on #2 (4-6s)
        else if (autoPhase === 1) {
            updateSystem([33.3, 50.0, 16.7], true, false); // Simulated sudden surge to #2
            let ms = 0;
            let counter = setInterval(()=>{
                ms+=100;
                if(ms <= 2400 && mode === 'auto') {
                    els.txtTime.textContent = (ms/1000).toFixed(1) + ' s (限值≤5s)';
                }
            }, 100);
            
            setTimeout(() => { 
                clearInterval(counter);
                autoPhase = 2; 
                runAutoSequence(); 
            }, 2400); // PLC reaction time + Valve switch time 2.4s (<5s)
        }
        // Phase 3: Optimized / Adjusted (6-12s)
        else if (autoPhase === 2) {
            // PLC redistributes: limits #2 to 15%, pushes excess to #1 and #3
            updateSystem([42.5, 15.0, 42.5], false, true);
            setTimeout(() => { autoPhase = 0; runAutoSequence(); }, 6000); // Hold state then reset loop
        }
    }

    // --- Manual Interaction Logic ---
    function handleSliderChange(changedIdx, val) {
        if(mode !== 'manual') return;
        val = parseFloat(val);
        let rem = 100 - val;
        let newV = [0,0,0];
        newV[changedIdx] = val;
        
        // Auto balance the other two
        let otherIndices = [0,1,2].filter(i => i !== changedIdx);
        let ratio = valves[otherIndices[0]] / (valves[otherIndices[0]] + valves[otherIndices[1]]);
        if (isNaN(ratio)) ratio = 0.5;
        
        newV[otherIndices[0]] = rem * ratio;
        newV[otherIndices[1]] = rem * (1 - ratio);
        
        updateSystem(newV, false, true);
        els.txtTime.textContent = 'Manual Override';
    }

    // --- Initialization & Listeners ---
    document.addEventListener("DOMContentLoaded", () => {
        // UI Listeners
        document.getElementById('btn-auto').addEventListener('click', (e) => {
            mode = 'auto';
            e.target.classList.add('active');
            document.getElementById('btn-manual').classList.remove('active');
            document.getElementById('manual-controls').classList.remove('active');
            autoPhase = 0;
            runAutoSequence();
        });

        document.getElementById('btn-manual').addEventListener('click', (e) => {
            mode = 'manual';
            e.target.classList.add('active');
            document.getElementById('btn-auto').classList.remove('active');
            document.getElementById('manual-controls').classList.add('active');
            els.txtStatus.textContent = '手动覆盖模式 (PLC辅助配平)';
            els.txtStatus.className = 'data-val';
        });

        // Sliders
        els.sliders.forEach((slider, idx) => {
            slider.addEventListener('input', (e) => {
                handleSliderChange(idx, e.target.value);
            });
        });

        // Start animation loop automatically (Requirement 6 & 7)
        runAutoSequence();
    });

</script>
</body>
</html>
<!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>
    /* 基础页面设置 */
    body, html {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
        background-color: #020617; /* 极深蓝底色 */
        display: flex;
        justify-content: center;
        align-items: center;
        font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
        overflow: hidden;
    }
    
    #animation-container {
        width: 100%;
        height: 100%;
        max-width: 1200px;
        max-height: 800px;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    svg {
        width: 100%;
        height: 100%;
        box-shadow: 0 0 40px rgba(0, 0, 0, 0.5);
    }

    /* SVG 元素样式及过渡 */
    .pipe {
        stroke: #334155;
        stroke-width: 16px;
        fill: none;
        stroke-linecap: round;
        stroke-linejoin: round;
    }

    .fluid {
        fill: none;
        stroke-linecap: round;
        stroke-linejoin: round;
        transition: stroke-width 1s ease-in-out, stroke 1s ease-in-out;
    }

    /* 正常流体的流动动画 */
    .dash-flow {
        stroke-dasharray: 12, 16;
        animation: flow 1.2s linear infinite;
    }

    @keyframes flow {
        from { stroke-dashoffset: 28; }
        to { stroke-dashoffset: 0; }
    }

    /* 信号线默认与激活状态 */
    .signal-line {
        stroke-linecap: round;
        stroke-linejoin: round;
        transition: opacity 0.5s ease, stroke 0.5s ease;
    }

    .signal-flow {
        stroke-dasharray: 6, 8;
        animation: flowSignal 0.6s linear infinite;
    }

    @keyframes flowSignal {
        from { stroke-dashoffset: 14; }
        to { stroke-dashoffset: 0; }
    }

    /* 发光滤镜增强效果 */
    .glow-warn { filter: drop-shadow(0 0 10px rgba(239, 68, 68, 0.8)); }
    .glow-active { filter: drop-shadow(0 0 12px rgba(16, 185, 129, 0.8)); }

    /* 振动筛液位平滑过渡 */
    .level-rect {
        transition: height 1s ease-in-out, y 1s ease-in-out, fill 1s ease-in-out;
    }

    /* 机器振动效果 */
    @keyframes vibrate {
        0% { transform: translate(0, 0); }
        25% { transform: translate(0, 1.5px); }
        50% { transform: translate(0, -0.5px); }
        75% { transform: translate(0, 1px); }
        100% { transform: translate(0, 0); }
    }
    .vibrating {
        animation: vibrate 0.08s linear infinite;
    }

    /* 交互按钮 */
    #btn-trigger { cursor: pointer; transition: transform 0.1s; }
    #btn-trigger:hover rect { fill: #2563eb; }
    #btn-trigger:active { transform: scale(0.97); }

    /* 文本过渡 */
    .val-text { transition: fill 1s ease; }
    .sieve-box { transition: stroke 1s ease; }
    .plc-box { transition: stroke 0.5s ease; }
</style>
</head>
<body>

<div id="animation-container">
    <svg viewBox="0 0 1000 650" preserveAspectRatio="xMidYMid meet">
        <!-- 定义渐变、图案与复用元件 -->
        <defs>
            <pattern id="bg-grid" width="40" height="40" patternUnits="userSpaceOnUse">
                <path d="M 40 0 L 0 0 0 40" fill="none" stroke="#1e293b" stroke-width="1"/>
            </pattern>
            <g id="valve-icon">
                <path d="M-15,-12 L15,12 L-15,12 L15,-12 Z" fill="#0f172a" stroke="#94a3b8" stroke-width="2" stroke-linejoin="round"/>
                <rect x="-5" y="-15" width="10" height="6" fill="#94a3b8" rx="2"/>
                <line x1="0" y1="-9" x2="0" y2="0" stroke="#94a3b8" stroke-width="2"/>
            </g>
        </defs>

        <!-- 背景网格 -->
        <rect width="100%" height="100%" fill="url(#bg-grid)" />

        <!--================ 顶部面板区域 ================-->
        <!-- 左侧:IFR 理念解说 -->
        <g transform="translate(30, 30)">
            <rect width="300" height="135" rx="8" fill="#0f172a" fill-opacity="0.85" stroke="#334155" stroke-width="2"/>
            <text x="15" y="28" fill="#f8fafc" font-size="16" font-weight="bold">最终理想解 (IFR) 原理</text>
            <line x1="15" y1="40" x2="285" y2="40" stroke="#1e293b" stroke-width="2"/>
            <foreignObject x="15" y="48" width="270" height="85">
                <div xmlns="http://www.w3.org/1999/xhtml" style="color:#94a3b8; font-size:13px; line-height:1.6; font-family:sans-serif;">
                    利用既有执行器与总控PLC组成系统级联锁。<br/>
                    单机(如2号)跑浆时,系统不增加冗余处理设备,而是<span style="color:#f59e0b; font-weight:bold;">主动自适应重分配</span>进料比例,用全局空间协同化解局部过载矛盾。
                </div>
            </foreignObject>
        </g>

        <!-- 右侧:关键参数监控面板 -->
        <g transform="translate(730, 30)">
            <rect width="240" height="135" rx="8" fill="#0f172a" fill-opacity="0.85" stroke="#334155" stroke-width="2"/>
            <text x="15" y="28" fill="#f8fafc" font-size="16" font-weight="bold">系统联锁状态监控</text>
            <line x1="15" y1="40" x2="225" y2="40" stroke="#1e293b" stroke-width="2"/>
            
            <circle cx="20" cy="62" r="4" fill="#3b82f6"/>
            <text x="32" y="66" fill="#cbd5e1" font-size="13">分配误差限制: <tspan fill="#10b981" font-weight="bold">≤±5%</tspan></text>
            
            <circle cx="20" cy="87" r="4" fill="#3b82f6"/>
            <text x="32" y="91" fill="#cbd5e1" font-size="13">设定切换时间: <tspan fill="#10b981" font-weight="bold">≤5.0 s</tspan></text>
            
            <circle cx="20" cy="112" r="4" fill="#3b82f6"/>
            <text x="32" y="116" fill="#cbd5e1" font-size="13">当前响应实测: <tspan id="actual-time" fill="#f59e0b" font-weight="bold" font-family="monospace">0.00 s</tspan></text>
        </g>

        <!-- 交互触发按钮 -->
        <g transform="translate(415, 60)" id="btn-trigger">
            <rect width="170" height="40" rx="20" fill="#3b82f6" stroke="#2563eb" stroke-width="2"/>
            <text x="85" y="25" fill="#ffffff" font-size="14" font-weight="bold" text-anchor="middle" style="pointer-events: none;">⚡ 模拟 2号筛跑浆</text>
        </g>

        <!--================ 物理管线与设备 ================-->
        <!-- 进料总管与底色管网 -->
        <g id="pipe-network">
            <!-- 总入料 -->
            <path d="M500,-10 L500,200" class="pipe"/>
            <!-- 顶部分配横梁管 -->
            <path d="M220,200 L780,200" class="pipe"/>
            <!-- 向下分支管 -->
            <path d="M220,200 L220,480" class="pipe"/>
            <path d="M500,200 L500,480" class="pipe"/>
            <path d="M780,200 L780,480" class="pipe"/>
        </g>

        <!-- 信号控制网络 (背景层) -->
        <g id="signals">
            <path id="sig-3" class="signal-line" d="M850,220 L810,220 L810,165 L780,165 L780,200" stroke="#10b981" stroke-width="2" fill="none" opacity="0.2" />
            <path id="sig-2" class="signal-line" d="M850,220 L810,220 L810,155 L500,155 L500,200" stroke="#10b981" stroke-width="2" fill="none" opacity="0.2" />
            <path id="sig-1" class="signal-line" d="M850,220 L810,220 L810,145 L220,145 L220,200" stroke="#10b981" stroke-width="2" fill="none" opacity="0.2" />
        </g>

        <!-- 动态流体层 -->
        <g id="fluid-network">
            <path id="fluid-1" class="fluid dash-flow" d="M500,-10 L500,200 L220,200 L220,480" stroke="#06b6d4" style="stroke-width: 6px;"/>
            <path id="fluid-2" class="fluid dash-flow" d="M500,-10 L500,480" stroke="#06b6d4" style="stroke-width: 6px;"/>
            <path id="fluid-3" class="fluid dash-flow" d="M500,-10 L500,200 L780,200 L780,480" stroke="#06b6d4" style="stroke-width: 6px;"/>
        </g>

        <!-- 分配器与阀门节点 -->
        <!-- 整体外壳罩住结合部 -->
        <rect x="180" y="180" width="640" height="40" rx="8" fill="#1e293b" fill-opacity="0.9" stroke="#64748b" stroke-width="2"/>
        <text x="500" y="193" fill="#64748b" font-size="10" font-weight="bold" text-anchor="middle" letter-spacing="4">多路电动分配器</text>
        
        <!-- 阀门 1, 2, 3 -->
        <use href="#valve-icon" x="220" y="205" />
        <use href="#valve-icon" x="500" y="205" />
        <use href="#valve-icon" x="780" y="205" />

        <!-- 流量计与当前分配比例显示 -->
        <g transform="translate(220, 240)">
            <rect x="-30" y="-12" width="60" height="24" rx="4" fill="#020617" stroke="#3b82f6" stroke-width="1"/>
            <text id="val-1" class="val-text" x="0" y="4" fill="#06b6d4" font-size="14" font-weight="bold" font-family="monospace" text-anchor="middle">33%</text>
        </g>
        <g transform="translate(500, 240)">
            <rect x="-30" y="-12" width="60" height="24" rx="4" fill="#020617" stroke="#3b82f6" stroke-width="1"/>
            <text id="val-2" class="val-text" x="0" y="4" fill="#06b6d4" font-size="14" font-weight="bold" font-family="monospace" text-anchor="middle">33%</text>
        </g>
        <g transform="translate(780, 240)">
            <rect x="-30" y="-12" width="60" height="24" rx="4" fill="#020617" stroke="#3b82f6" stroke-width="1"/>
            <text id="val-3" class="val-text" x="0" y="4" fill="#06b6d4" font-size="14" font-weight="bold" font-family="monospace" text-anchor="middle">33%</text>
        </g>

        <!--================ 振动筛机组 (1, 2, 3) ================-->
        <!-- 振动筛 1 -->
        <g transform="translate(220, 480)">
            <g class="vibrating">
                <!-- 机体外壳 -->
                <rect id="sieve-box-1" class="sieve-box" x="-70" y="0" width="140" height="100" rx="8" fill="#1e293b" stroke="#475569" stroke-width="2"/>
                <!-- 内部液池底槽 -->
                <rect x="-66" y="4" width="132" height="92" rx="4" fill="#0f172a" />
                <!-- 动态液位块,最大高度 92 -->
                <rect id="liq-1" class="level-rect" x="-66" y="50" width="132" height="46" rx="2" fill="#06b6d4" opacity="0.75" />
                <!-- 筛网层结构 -->
                <path d="M-75,25 L75,25" stroke="#94a3b8" stroke-width="4" stroke-dasharray="6,4" />
                <path d="M-75,38 L75,38" stroke="#94a3b8" stroke-width="2" stroke-dasharray="3,3" opacity="0.4"/>
                <!-- 标识号 -->
                <text x="0" y="85" fill="#f8fafc" font-size="16" font-weight="bold" text-anchor="middle" opacity="0.9">1# 振动筛</text>
            </g>
        </g>

        <!-- 振动筛 2 -->
        <g transform="translate(500, 480)">
            <g class="vibrating">
                <rect id="sieve-box-2" class="sieve-box" x="-70" y="0" width="140" height="100" rx="8" fill="#1e293b" stroke="#475569" stroke-width="2"/>
                <rect x="-66" y="4" width="132" height="92" rx="4" fill="#0f172a" />
                <rect id="liq-2" class="level-rect" x="-66" y="50" width="132" height="46" rx="2" fill="#06b6d4" opacity="0.75" />
                <path d="M-75,25 L75,25" stroke="#94a3b8" stroke-width="4" stroke-dasharray="6,4" />
                <path d="M-75,38 L75,38" stroke="#94a3b8" stroke-width="2" stroke-dasharray="3,3" opacity="0.4"/>
                <text x="0" y="85" fill="#f8fafc" font-size="16" font-weight="bold" text-anchor="middle" opacity="0.9">2# 振动筛</text>
            </g>
        </g>

        <!-- 振动筛 3 -->
        <g transform="translate(780, 480)">
            <g class="vibrating">
                <rect id="sieve-box-3" class="sieve-box" x="-70" y="0" width="140" height="100" rx="8" fill="#1e293b" stroke="#475569" stroke-width="2"/>
                <rect x="-66" y="4" width="132" height="92" rx="4" fill="#0f172a" />
                <rect id="liq-3" class="level-rect" x="-66" y="50" width="132" height="46" rx="2" fill="#06b6d4" opacity="0.75" />
                <path d="M-75,25 L75,25" stroke="#94a3b8" stroke-width="4" stroke-dasharray="6,4" />
                <path d="M-75,38 L75,38" stroke="#94a3b8" stroke-width="2" stroke-dasharray="3,3" opacity="0.4"/>
                <text x="0" y="85" fill="#f8fafc" font-size="16" font-weight="bold" text-anchor="middle" opacity="0.9">3# 振动筛</text>
            </g>
        </g>

        <!--================ 总控 PLC 单元 ================-->
        <g transform="translate(850, 220)">
            <!-- 连线接口底座 -->
            <rect x="-10" y="-15" width="20" height="30" fill="#334155"/>
            <!-- 主机体 -->
            <rect id="plc-box" class="plc-box" x="-60" y="-55" width="120" height="110" rx="6" fill="#0f172a" stroke="#10b981" stroke-width="2"/>
            <!-- 屏幕区 -->
            <rect x="-50" y="-45" width="100" height="40" rx="2" fill="#020617"/>
            <text x="0" y="-30" fill="#10b981" font-size="12" font-weight="bold" text-anchor="middle" letter-spacing="2">SCADA/PLC</text>
            <text id="plc-status" x="0" y="-15" fill="#e2e8f0" font-size="11" text-anchor="middle">常态均分监控</text>
            <!-- 状态灯 -->
            <circle id="plc-led" cx="0" cy="15" r="8" fill="#10b981" />
            <circle cx="-25" cy="15" r="4" fill="#3b82f6" />
            <circle cx="25" cy="15" r="4" fill="#3b82f6" />
            <circle cx="-25" cy="35" r="4" fill="#475569" />
            <circle cx="0" cy="35" r="4" fill="#475569" />
            <circle cx="25" cy="35" r="4" fill="#475569" />
        </g>

    </svg>
</div>

<script>
    document.addEventListener("DOMContentLoaded", () => {
        // UI DOM 引用抓取
        const UI = {
            fluids: [document.getElementById('fluid-1'), document.getElementById('fluid-2'), document.getElementById('fluid-3')],
            levels: [document.getElementById('liq-1'), document.getElementById('liq-2'), document.getElementById('liq-3')],
            vals: [document.getElementById('val-1'), document.getElementById('val-2'), document.getElementById('val-3')],
            sigs: [document.getElementById('sig-1'), document.getElementById('sig-2'), document.getElementById('sig-3')],
            sieves: [document.getElementById('sieve-box-1'), document.getElementById('sieve-box-2'), document.getElementById('sieve-box-3')],
            plcStatus: document.getElementById('plc-status'),
            plcLed: document.getElementById('plc-led'),
            plcBox: document.getElementById('plc-box'),
            actualTime: document.getElementById('actual-time'),
            btnTrigger: document.getElementById('btn-trigger')
        };

        const MAX_LIQ_HEIGHT = 92; // 容器内液位最大高度,y基准为4

        /**
         * 更新单台振动筛与管线状态
         * @param {number} index - 索引 0, 1, 2
         * @param {number} flowRate - 进料比例 0~100
         * @param {number} levelPercent - 液位负载 0~100
         * @param {string} state - 'normal', 'warn', 'active'
         */
        function updateSieve(index, flowRate, levelPercent, state) {
            // 1. 更新流动管径粗细模拟流量 (33%基准宽度为6px,系数约0.18)
            let strokeW = Math.max(2, flowRate * 0.18);
            UI.fluids[index].style.strokeWidth = strokeW + 'px';
            UI.vals[index].textContent = flowRate + '%';

            // 2. 更新液位高度与Y轴位置 (y基准为4, 底部为 4+92=96)
            let h = MAX_LIQ_HEIGHT * (levelPercent / 100);
            let y = 4 + (MAX_LIQ_HEIGHT - h);
            UI.levels[index].setAttribute('height', h);
            UI.levels[index].setAttribute('y', y);

            // 3. 根据状态应用主题色系
            if (state === 'warn') {
                // 红色告警
                UI.fluids[index].style.stroke = '#ef4444';
                UI.levels[index].setAttribute('fill', '#ef4444');
                UI.vals[index].style.fill = '#ef4444';
                UI.sieves[index].style.stroke = '#ef4444';
                UI.sieves[index].classList.add('glow-warn');
            } else if (state === 'active') {
                // 橙色增压负担
                UI.fluids[index].style.stroke = '#f59e0b';
                UI.levels[index].setAttribute('fill', '#f59e0b');
                UI.vals[index].style.fill = '#f59e0b';
                UI.sieves[index].style.stroke = '#64748b';
                UI.sieves[index].classList.remove('glow-warn');
            } else {
                // 青蓝色正常
                UI.fluids[index].style.stroke = '#06b6d4';
                UI.levels[index].setAttribute('fill', '#06b6d4');
                UI.vals[index].style.fill = '#06b6d4';
                UI.sieves[index].style.stroke = '#475569';
                UI.sieves[index].classList.remove('glow-warn');
            }
        }

        /**
         * 设置控制中枢视觉状态
         */
        function setPlc(statusText, isAlert) {
            UI.plcStatus.textContent = statusText;
            if (isAlert) {
                UI.plcLed.setAttribute('fill', '#ef4444');
                UI.plcBox.style.stroke = '#ef4444';
                UI.plcBox.classList.remove('glow-active');
                UI.plcBox.classList.add('glow-warn');
                
                UI.sigs.forEach(s => {
                    s.style.opacity = '1';
                    s.style.stroke = '#ef4444';
                    s.classList.add('signal-flow');
                });
            } else {
                UI.plcLed.setAttribute('fill', '#10b981');
                UI.plcBox.style.stroke = '#10b981';
                UI.plcBox.classList.remove('glow-warn');
                UI.plcBox.classList.add('glow-active');

                UI.sigs.forEach(s => {
                    s.style.opacity = '0.2';
                    s.style.stroke = '#10b981';
                    s.classList.remove('signal-flow');
                });
            }
        }

        // 模拟切换计时器
        let timeInterval;
        function runTimer(targetTime) {
            let t = 0;
            clearInterval(timeInterval);
            UI.actualTime.style.fill = "#f59e0b";
            UI.actualTime.textContent = "0.00 s";
            timeInterval = setInterval(() => {
                t += 0.08;
                if(t >= targetTime) {
                    t = targetTime;
                    clearInterval(timeInterval);
                    UI.actualTime.style.fill = "#10b981"; // 完成后变绿
                }
                UI.actualTime.textContent = t.toFixed(2) + " s";
            }, 50);
        }

        // 主状态机控制循环
        let cycleTimeout;
        let currentPhase = 0;

        function runPhase(phase) {
            clearTimeout(cycleTimeout);
            currentPhase = phase;
            
            switch(phase) {
                case 0: 
                    // [正常状态] 3台机均分负荷
                    updateSieve(0, 33, 40, 'normal');
                    updateSieve(1, 34, 40, 'normal');
                    updateSieve(2, 33, 40, 'normal');
                    setPlc("常态均分监控", false);
                    UI.actualTime.style.fill = "#64748b";
                    
                    // 维持 4 秒后进入异常
                    cycleTimeout = setTimeout(() => runPhase(1), 4000);
                    break;
                    
                case 1: 
                    // [突发过载] 2号筛突发跑浆危机,流量来不及减少,液位暴涨
                    updateSieve(1, 34, 92, 'warn');
                    setPlc("警报: 2#液位超限", true);
                    
                    // 维持 1.5 秒引起注意,PLC开始响应
                    cycleTimeout = setTimeout(() => runPhase(2), 1500);
                    break;
                    
                case 2: 
                    // [IFR自适应重分配] 联锁介入,执行器调优流量
                    runTimer(2.14); // 模拟耗时小于5s要求
                    setPlc("联锁介入: 流量重分配", true);
                    
                    // 减少2号进料化解矛盾,分摊给1号和3号
                    updateSieve(0, 45, 60, 'active'); 
                    updateSieve(1, 10, 40, 'normal'); // 负荷骤降,脱离危险
                    updateSieve(2, 45, 60, 'active');
                    
                    // 维持 4.5 秒展示重分配成果
                    cycleTimeout = setTimeout(() => runPhase(3), 4500);
                    break;
                    
                case 3: 
                    // [危险解除,准备恢复]
                    setPlc("状态平稳: 准备复位", false);
                    
                    // 维持 1.5 秒后回正
                    cycleTimeout = setTimeout(() => runPhase(0), 1500);
                    break;
            }
        }

        // 绑定手动干扰逻辑
        UI.btnTrigger.addEventListener('click', () => {
            if (currentPhase === 0 || currentPhase === 3) {
                runPhase(1); // 强制跳跃至跑浆告警阶段
            }
        });

        // 页面加载就绪,自动开始理想解展示循环
        setTimeout(() => runPhase(0), 500);
    });
</script>

</body>
</html>
积分规则:每轮对话扣10分