From 7804a7fa8eff2d3086eb32bb7a2fadb9fdcb36ab Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Tue, 19 Aug 2025 11:19:25 +0800
Subject: [PATCH] feat(mall): 双击删除图片功能

---
 src/main/java/cc/mrbird/febs/mall/quartz/OrderOvertimeJob.java                   |    2 
 src/main/resources/static/febs/quant/okxCandle.html                              |  289 +++++++++++++++++
 src/main/resources/static/febs/quant/okxWebsocketChannels.html                   |  381 ++++++++++++++++++++++
 src/main/resources/static/febs/quant/okxWebsocketMonitor.html                    |  180 ++++++++++
 src/main/resources/templates/febs/views/modules/banner/platformBannerDetail.html |   70 ++-
 src/main/resources/templates/febs/views/modules/banner/platformBannerAdd.html    |   69 ++-
 6 files changed, 948 insertions(+), 43 deletions(-)

diff --git a/src/main/java/cc/mrbird/febs/mall/quartz/OrderOvertimeJob.java b/src/main/java/cc/mrbird/febs/mall/quartz/OrderOvertimeJob.java
index c31acb3..bab9b03 100644
--- a/src/main/java/cc/mrbird/febs/mall/quartz/OrderOvertimeJob.java
+++ b/src/main/java/cc/mrbird/febs/mall/quartz/OrderOvertimeJob.java
@@ -24,7 +24,7 @@
  **/
 @Slf4j
 @Component
-@ConditionalOnProperty(prefix = "system", name = "job", havingValue = "true")
+@ConditionalOnProperty(prefix = "system", name = "job", havingValue = "false")
 public class OrderOvertimeJob {
 
     @Autowired
diff --git a/src/main/resources/static/febs/quant/okxCandle.html b/src/main/resources/static/febs/quant/okxCandle.html
new file mode 100644
index 0000000..6eea97b
--- /dev/null
+++ b/src/main/resources/static/febs/quant/okxCandle.html
@@ -0,0 +1,289 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>OKX 标记价格K线频道</title>
+    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns"></script>
+    <script src="https://cdn.jsdelivr.net/npm/chartjs-chart-financial"></script>
+    <style>
+        body {
+            font-family: Arial, sans-serif;
+            margin: 20px;
+        }
+        .channel {
+            margin-bottom: 20px;
+            padding: 15px;
+            border: 1px solid #ccc;
+            border-radius: 5px;
+        }
+        .channel h3 {
+            margin-top: 0;
+        }
+        .status {
+            font-weight: bold;
+        }
+        .connected {
+            color: green;
+        }
+        .disconnected {
+            color: red;
+        }
+        .messages {
+            height: 300px;
+            overflow-y: scroll;
+            border: 1px solid #eee;
+            padding: 10px;
+            margin-top: 10px;
+            background-color: #f9f9f9;
+        }
+        .chart-container {
+            width: 100%;
+            height: 300px;
+            margin-top: 20px;
+        }
+        .mode-toggle {
+            margin: 10px 0;
+            padding: 10px;
+            background-color: #f0f0f0;
+            border-radius: 5px;
+        }
+        .mode-toggle button {
+            margin: 0 5px;
+            padding: 5px 10px;
+            border: 1px solid #ccc;
+            background-color: #fff;
+            cursor: pointer;
+        }
+        .mode-toggle button.active {
+            background-color: #007bff;
+            color: white;
+        }
+    </style>
+</head>
+<body>
+    <h1>OKX 标记价格K线频道</h1>
+    
+    <div class="mode-toggle">
+        <span>当前模式:</span>
+        <button id="demoModeBtn" class="active" onclick="switchMode('demo')">模拟盘 (wspap)</button>
+        <button id="liveModeBtn" onclick="switchMode('live')">实盘 (ws)</button>
+    </div>
+    
+    <div class="channel" id="markPriceCandleChannel">
+        <h3>标记价格K线频道</h3>
+        <p>URL: <span id="markPriceCandleUrl">wss://wspap.okx.com:8443/ws/v5/business</span></p>
+        <p>状态: <span class="status disconnected" id="markPriceCandleStatus">未连接</span></p>
+        <button onclick="toggleConnection()">连接/断开</button>
+        <button onclick="clearMessages()">清除消息</button>
+        <div class="chart-container">
+            <canvas id="markPriceCandleChart"></canvas>
+        </div>
+        <div class="messages" id="markPriceCandleMessages"></div>
+    </div>
+
+    <script>
+        // 存储WebSocket连接对象
+        let connection = null;
+        
+        // 存储各模式的URL
+        const urls = {
+            demo: 'wss://wspap.okx.com:8443/ws/v5/business',
+            live: 'wss://ws.okx.com:8443/ws/v5/business'
+        };
+        
+        // 当前模式,默认为模拟盘
+        let currentMode = 'demo';
+        
+        // 标记价格K线数据
+        const markPriceCandleData = [];
+        const markPriceCandleTimes = [];
+        let markPriceCandleChart = null;
+        
+        // 初始化图表
+        function initChart() {
+            const ctx = document.getElementById('markPriceCandleChart').getContext('2d');
+            markPriceCandleChart = new Chart(ctx, {
+                type: 'line',
+                data: {
+                    labels: [],
+                    datasets: [{
+                        label: 'ETH-USDT Mark Price',
+                        data: [],
+                        borderColor: 'rgb(75, 192, 192)',
+                        tension: 0.1
+                    }]
+                },
+                options: {
+                    responsive: true,
+                    maintainAspectRatio: false,
+                    scales: {
+                        x: {
+                            type: 'time',
+                            time: {
+                                unit: 'minute'
+                            }
+                        },
+                        y: {
+                            beginAtZero: false
+                        }
+                    }
+                }
+            });
+        }
+        
+        // 更新图表
+        function updateChart() {
+            if (markPriceCandleChart) {
+                // 为折线图准备数据
+                const times = markPriceCandleData.map(item => item.x);
+                const prices = markPriceCandleData.map(item => item.c); // 使用收盘价
+                
+                markPriceCandleChart.data.labels = times;
+                markPriceCandleChart.data.datasets[0].data = prices;
+                markPriceCandleChart.update();
+            }
+        }
+        
+        // 连接/断开WebSocket连接
+        function toggleConnection() {
+            if (connection) {
+                // 如果已经连接,则断开连接
+                connection.close();
+                connection = null;
+                document.getElementById('markPriceCandleStatus').textContent = '未连接';
+                document.getElementById('markPriceCandleStatus').className = 'status disconnected';
+            } else {
+                // 如果未连接,则建立连接
+                connectToChannel();
+            }
+        }
+        
+        // 清除消息
+        function clearMessages() {
+            const messagesDiv = document.getElementById('markPriceCandleMessages');
+            messagesDiv.innerHTML = '';
+            
+            // 清除图表数据
+            markPriceCandleData.length = 0;
+            updateChart();
+        }
+        
+        // 切换模式
+        function switchMode(mode) {
+            // 更新当前模式
+            currentMode = mode;
+            
+            // 更新按钮状态
+            document.getElementById('demoModeBtn').classList.toggle('active', mode === 'demo');
+            document.getElementById('liveModeBtn').classList.toggle('active', mode === 'live');
+            
+            // 更新URL显示
+            document.getElementById('markPriceCandleUrl').textContent = urls[mode];
+        }
+        
+        // 连接到频道
+        function connectToChannel() {
+            const ws = new WebSocket(urls[currentMode]);
+            
+            ws.onopen = function() {
+                console.log('标记价格K线频道连接成功');
+                document.getElementById('markPriceCandleStatus').textContent = '已连接';
+                document.getElementById('markPriceCandleStatus').className = 'status connected';
+                
+                // 订阅标记价格K线数据 (BTC-USD-190628, 1分钟K线)
+                const subscribeMsg = {
+                    op: 'subscribe',
+                    args: [
+                        {
+                            channel: 'mark-price-candle1m',
+                            instId: 'ETH-USDT'
+                        }
+                    ]
+                };
+                ws.send(JSON.stringify(subscribeMsg));
+                
+                // 初始化图表
+                if (!markPriceCandleChart) {
+                    initChart();
+                }
+            };
+            
+            ws.onmessage = function(event) {
+                const message = event.data;
+                console.log('标记价格K线频道收到消息:', message);
+                
+                // 在页面上显示消息
+                const messagesDiv = document.getElementById('markPriceCandleMessages');
+                const messageElement = document.createElement('div');
+                
+                // 尝试解析JSON消息并格式化显示
+                try {
+                    const jsonData = JSON.parse(message);
+                    
+                    // 检查是否为标记价格K线数据
+                    if (jsonData.arg && jsonData.arg.channel && jsonData.arg.channel.startsWith('mark-price-candle') && 
+                        jsonData.arg.instId === 'ETH-USDT' && jsonData.data && jsonData.data.length > 0) {
+                        // 处理标记价格K线数据
+                        // 标记价格K线数据格式: [ts, o, h, l, c]
+                        // ts: 开始时间, o: 开盘价, h: 最高价, l: 最低价, c: 收盘价
+                        const candleData = jsonData.data[0];
+                        const ts = parseInt(candleData[0]); // 时间戳
+                        const o = parseFloat(candleData[1]); // 开盘价
+                        const h = parseFloat(candleData[2]); // 最高价
+                        const l = parseFloat(candleData[3]); // 最低价
+                        const c = parseFloat(candleData[4]); // 收盘价
+                        
+                        // 添加时间戳到时间数组
+                        markPriceCandleTimes.push(ts);
+                        
+                        // 添加K线数据到数组
+                        markPriceCandleData.push({
+                            x: ts,
+                            o: o,
+                            h: h,
+                            l: l,
+                            c: c
+                        });
+                        
+                        // 限制数据点数量,只保留最近的30个
+                        if (markPriceCandleData.length > 30) {
+                            markPriceCandleData.shift();
+                            markPriceCandleTimes.shift();
+                        }
+                        
+                        // 更新图表
+                        updateChart();
+                        
+                        console.log('标记价格K线数据:', candleData);
+                    }
+                    
+                    messageElement.innerHTML = `<strong>[${new Date().toLocaleTimeString()}]</strong> ${JSON.stringify(jsonData, null, 2)}`;
+                } catch (e) {
+                    // 如果不是JSON格式,则直接显示
+                    messageElement.innerHTML = `<strong>[${new Date().toLocaleTimeString()}]</strong> ${message}`;
+                }
+                
+                messagesDiv.appendChild(messageElement);
+                messagesDiv.scrollTop = messagesDiv.scrollHeight;
+            };
+            
+            ws.onerror = function(error) {
+                console.error('标记价格K线频道连接错误:', error);
+                document.getElementById('markPriceCandleStatus').textContent = '连接错误';
+                document.getElementById('markPriceCandleStatus').className = 'status disconnected';
+            };
+            
+            ws.onclose = function() {
+                console.log('标记价格K线频道连接已关闭');
+                document.getElementById('markPriceCandleStatus').textContent = '连接已关闭';
+                document.getElementById('markPriceCandleStatus').className = 'status disconnected';
+                connection = null;
+            };
+            
+            connection = ws;
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/resources/static/febs/quant/okxWebsocketChannels.html b/src/main/resources/static/febs/quant/okxWebsocketChannels.html
new file mode 100644
index 0000000..3a8a41d
--- /dev/null
+++ b/src/main/resources/static/febs/quant/okxWebsocketChannels.html
@@ -0,0 +1,381 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>OKX WebSocket 频道连接</title>
+    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns"></script>
+    <style>
+        body {
+            font-family: Arial, sans-serif;
+            margin: 20px;
+        }
+        .channel {
+            margin-bottom: 20px;
+            padding: 15px;
+            border: 1px solid #ccc;
+            border-radius: 5px;
+        }
+        .channel h3 {
+            margin-top: 0;
+        }
+        .status {
+            font-weight: bold;
+        }
+        .connected {
+            color: green;
+        }
+        .disconnected {
+            color: red;
+        }
+        .messages {
+            height: 200px;
+            overflow-y: scroll;
+            border: 1px solid #eee;
+            padding: 10px;
+            margin-top: 10px;
+            background-color: #f9f9f9;
+        }
+        .chart-container {
+            width: 100%;
+            height: 300px;
+            margin-top: 20px;
+        }
+        .mode-toggle {
+            margin: 10px 0;
+            padding: 10px;
+            background-color: #f0f0f0;
+            border-radius: 5px;
+        }
+        .mode-toggle button {
+            margin: 0 5px;
+            padding: 5px 10px;
+            border: 1px solid #ccc;
+            background-color: #fff;
+            cursor: pointer;
+        }
+        .mode-toggle button.active {
+            background-color: #007bff;
+            color: white;
+        }
+    </style>
+</head>
+<body>
+    <h1>OKX WebSocket 频道连接</h1>
+    
+    <div class="mode-toggle">
+        <span>当前模式:</span>
+        <button id="demoModeBtn" class="active" onclick="switchMode('demo')">模拟盘 (wspap)</button>
+        <button id="liveModeBtn" onclick="switchMode('live')">实盘 (ws)</button>
+    </div>
+    
+    <div class="channel" id="publicChannel">
+        <h3>公共频道</h3>
+        <p>URL: <input type="text" id="publicUrl" value="wss://wspap.okx.com:8443/ws/v5/public" style="width: 300px;"></p>
+        <p>状态: <span class="status disconnected" id="publicStatus">未连接</span></p>
+        <button onclick="toggleConnection('public')">连接/断开</button>
+        <button onclick="clearMessages('public')">清除消息</button>
+        <div class="chart-container">
+            <canvas id="ethUsdtChart"></canvas>
+        </div>
+        <div class="messages" id="publicMessages"></div>
+    </div>
+    
+    <div class="channel" id="privateChannel">
+        <h3>私有频道</h3>
+        <p>URL: <input type="text" id="privateUrl" value="wss://wspap.okx.com:8443/ws/v5/private" style="width: 300px;"></p>
+        <p>状态: <span class="status disconnected" id="privateStatus">未连接</span></p>
+        <button onclick="toggleConnection('private')">连接/断开</button>
+        <div class="messages" id="privateMessages"></div>
+    </div>
+    
+    <div class="channel" id="businessChannel">
+        <h3>业务频道</h3>
+        <p>URL: <input type="text" id="businessUrl" value="wss://wspap.okx.com:8443/ws/v5/business" style="width: 300px;"></p>
+        <p>状态: <span class="status disconnected" id="businessStatus">未连接</span></p>
+        <button onclick="toggleConnection('business')">连接/断开</button>
+        <div class="messages" id="businessMessages"></div>
+    </div>
+    
+    <div class="channel" id="markPriceCandleChannel">
+        <h3>标记价格K线频道</h3>
+        <p>URL: <input type="text" id="markPriceCandleUrl" value="wss://wspap.okx.com:8443/ws/v5/business" style="width: 300px;"></p>
+        <p>状态: <span class="status disconnected" id="markPriceCandleStatus">未连接</span></p>
+        <button onclick="toggleConnection('markPriceCandle')">连接/断开</button>
+        <div class="messages" id="markPriceCandleMessages"></div>
+    </div>
+
+    <script>
+        // 存储WebSocket连接对象
+        const connections = {
+            public: null,
+            private: null,
+            business: null,
+            markPriceCandle: null
+        };
+        
+        // 存储各频道的URL
+        const urls = {
+            demo: {
+                public: 'wss://wspap.okx.com:8443/ws/v5/public',
+                private: 'wss://wspap.okx.com:8443/ws/v5/private',
+                business: 'wss://wspap.okx.com:8443/ws/v5/business'
+            },
+            live: {
+                public: 'wss://ws.okx.com:8443/ws/v5/public',
+                private: 'wss://ws.okx.com:8443/ws/v5/private',
+                business: 'wss://ws.okx.com:8443/ws/v5/business'
+            }
+        };
+        
+        // 为markPriceCandle频道添加URL配置
+        urls.demo.markPriceCandle = urls.demo.business;
+        urls.live.markPriceCandle = urls.live.business;
+        
+        // 当前模式,默认为模拟盘
+        let currentMode = 'demo';
+        
+        // ETH-USDT 价格数据
+        const ethUsdtPrices = [];
+        const ethUsdtTimes = [];
+        let ethUsdtChart = null;
+        
+        // 初始化图表
+        function initChart() {
+            const ctx = document.getElementById('ethUsdtChart').getContext('2d');
+            ethUsdtChart = new Chart(ctx, {
+                type: 'line',
+                data: {
+                    labels: ethUsdtTimes,
+                    datasets: [{
+                        label: 'ETH-USDT Price',
+                        data: ethUsdtPrices,
+                        borderColor: 'rgb(75, 192, 192)',
+                        backgroundColor: 'rgba(75, 192, 192, 0.2)',
+                        tension: 0.1,
+                        fill: false
+                    }]
+                },
+                options: {
+                    responsive: true,
+                    maintainAspectRatio: false,
+                    scales: {
+                        x: {
+                            type: 'time',
+                            time: {
+                                unit: 'minute'
+                            }
+                        },
+                        y: {
+                            beginAtZero: false
+                        }
+                    }
+                }
+            });
+        }
+        
+        // 更新图表
+        function updateChart() {
+            if (ethUsdtChart) {
+                // 对于折线图,我们需要重新设置labels和data并调用update
+                ethUsdtChart.data.labels = ethUsdtTimes;
+                ethUsdtChart.data.datasets[0].data = ethUsdtPrices;
+                ethUsdtChart.update();
+            }
+        }
+        
+        // 连接/断开WebSocket连接
+        function toggleConnection(channel) {
+            if (connections[channel]) {
+                // 如果已经连接,则断开连接
+                connections[channel].close();
+                connections[channel] = null;
+                document.getElementById(`${channel}Status`).textContent = '未连接';
+                document.getElementById(`${channel}Status`).className = 'status disconnected';
+            } else {
+                // 如果未连接,则建立连接
+                connectToChannel(channel);
+            }
+        }
+        
+        // 清除指定频道的消息
+        function clearMessages(channel) {
+            const messagesDiv = document.getElementById(`${channel}Messages`);
+            messagesDiv.innerHTML = '';
+            
+            // 清除图表数据
+            if (channel === 'public') {
+                ethUsdtPrices.length = 0;
+                ethUsdtTimes.length = 0;
+                updateChart();
+            }
+        }
+        
+        // 切换模式
+        function switchMode(mode) {
+            // 更新当前模式
+            currentMode = mode;
+            
+            // 更新按钮状态
+            document.getElementById('demoModeBtn').classList.toggle('active', mode === 'demo');
+            document.getElementById('liveModeBtn').classList.toggle('active', mode === 'live');
+            
+            // 更新所有频道的URL输入框的值
+            document.querySelectorAll('.channel').forEach(channelDiv => {
+                const channelId = channelDiv.id.replace('Channel', '');
+                // 更新输入框的值而不是替换整个元素
+                const urlInput = document.getElementById(`${channelId}Url`);
+                if (urlInput && urls[mode] && urls[mode][channelId]) {
+                    urlInput.value = urls[mode][channelId];
+                }
+            });
+        }
+        
+        // 连接到指定频道
+        function connectToChannel(channel) {
+            // 获取用户输入的URL
+            let url;
+            switch(channel) {
+                case 'public':
+                    url = document.getElementById('publicUrl').value;
+                    break;
+                case 'private':
+                    url = document.getElementById('privateUrl').value;
+                    break;
+                case 'business':
+                    url = document.getElementById('businessUrl').value;
+                    break;
+                case 'markPriceCandle':
+                    url = document.getElementById('markPriceCandleUrl').value;
+                    break;
+                default:
+                    url = urls[currentMode][channel];
+            }
+            
+            const ws = new WebSocket(url);
+            
+            ws.onopen = function() {
+                console.log(`${channel}频道连接成功`);
+                document.getElementById(`${channel}Status`).textContent = '已连接';
+                document.getElementById(`${channel}Status`).className = 'status connected';
+                
+                // 发送订阅消息
+                if (channel === 'public') {
+                    const subscribeMsg = {
+                        op: 'subscribe',
+                        args: [
+                            {
+                                channel: 'tickers',
+                                instId: 'ETH-USDT'
+                            }
+                        ]
+                    };
+                    ws.send(JSON.stringify(subscribeMsg));
+                    
+                    // 初始化图表
+                    if (!ethUsdtChart) {
+                        initChart();
+                    }
+                } else if (channel === 'markPriceCandle') {
+                    // 订阅标记价格K线数据 (BTC-USD-190628, 1分钟K线)
+                    const subscribeMsg = {
+                        op: 'subscribe',
+                        args: [
+                            {
+                                channel: 'mark-price-candle1m',
+                                instId: 'ETH-USDT'
+                            }
+                        ]
+                    };
+                    ws.send(JSON.stringify(subscribeMsg));
+                }
+            };
+            
+            ws.onmessage = function(event) {
+                const message = event.data;
+                console.log(`${channel}频道收到消息:`, message);
+                
+                // 在页面上显示消息
+                const messagesDiv = document.getElementById(`${channel}Messages`);
+                const messageElement = document.createElement('div');
+                
+                // 尝试解析JSON消息并格式化显示
+                try {
+                    const jsonData = JSON.parse(message);
+                    
+                    // 检查是否为ETH-USDT的ticker数据
+                    if (jsonData.arg && jsonData.arg.instId === 'ETH-USDT' && jsonData.data && jsonData.data.length > 0) {
+                        const price = parseFloat(jsonData.data[0].last);
+                        const time = new Date();
+                        
+                        // 添加价格和时间到数组
+                        ethUsdtPrices.push(price);
+                        ethUsdtTimes.push(time);
+                        
+                        // 限制数据点数量,只保留最近的1000个
+                        // 为了保持图表连续性,我们采用滑动窗口的方式
+                        if (ethUsdtPrices.length > 1000) {
+                            // 移除最旧的数据点
+                            ethUsdtPrices.shift();
+                            ethUsdtTimes.shift();
+                            
+                            // 为了保持图表连续性,我们需要保留最后一个数据点作为下一个数据段的起始点
+                            // 这样可以避免图表出现断裂
+                            // 当数据点超过1000个时,我们重新构建数据集,确保连续性
+                            if (ethUsdtPrices.length > 1) {
+                                // 保留最后一个数据点作为新数据段的起始点
+                                const lastPrice = ethUsdtPrices[ethUsdtPrices.length - 1];
+                                const lastTime = ethUsdtTimes[ethUsdtTimes.length - 1];
+                                
+                                // 清空数组,但保留最后一个数据点
+                                ethUsdtPrices.length = 0;
+                                ethUsdtTimes.length = 0;
+                                
+                                // 将最后一个数据点作为新数据段的起始点
+                                ethUsdtPrices.push(lastPrice);
+                                ethUsdtTimes.push(lastTime);
+                            }
+                        }
+                        
+                        // 更新图表
+                        updateChart();
+                    }
+                    
+                    // 检查是否为标记价格K线数据
+                    if (jsonData.arg && jsonData.arg.channel && jsonData.arg.channel.startsWith('mark-price-candle') && 
+                        jsonData.arg.instId === 'BTC-USD-190628' && jsonData.data && jsonData.data.length > 0) {
+                        // 这里可以处理标记价格K线数据
+                        // 标记价格K线数据格式: [ts, o, h, l, c]
+                        // ts: 开始时间, o: 开盘价, h: 最高价, l: 最低价, c: 收盘价
+                        console.log('标记价格K线数据:', jsonData.data[0]);
+                    }
+                    
+                    messageElement.innerHTML = `<strong>[${new Date().toLocaleTimeString()}]</strong> ${JSON.stringify(jsonData, null, 2)}`;
+                } catch (e) {
+                    // 如果不是JSON格式,则直接显示
+                    messageElement.innerHTML = `<strong>[${new Date().toLocaleTimeString()}]</strong> ${message}`;
+                }
+                
+                messagesDiv.appendChild(messageElement);
+                messagesDiv.scrollTop = messagesDiv.scrollHeight;
+            };
+            
+            ws.onerror = function(error) {
+                console.error(`${channel}频道连接错误:`, error);
+                document.getElementById(`${channel}Status`).textContent = '连接错误';
+                document.getElementById(`${channel}Status`).className = 'status disconnected';
+            };
+            
+            ws.onclose = function() {
+                console.log(`${channel}频道连接已关闭`);
+                document.getElementById(`${channel}Status`).textContent = '连接已关闭';
+                document.getElementById(`${channel}Status`).className = 'status disconnected';
+                connections[channel] = null;
+            };
+            
+            connections[channel] = ws;
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/resources/static/febs/quant/okxWebsocketMonitor.html b/src/main/resources/static/febs/quant/okxWebsocketMonitor.html
new file mode 100644
index 0000000..0120c5f
--- /dev/null
+++ b/src/main/resources/static/febs/quant/okxWebsocketMonitor.html
@@ -0,0 +1,180 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>OKX WebSocket消息监控</title>
+    <style>
+        body {
+            font-family: Arial, sans-serif;
+            margin: 20px;
+            background-color: #f5f5f5;
+        }
+        .container {
+            max-width: 1200px;
+            margin: 0 auto;
+            background-color: white;
+            padding: 20px;
+            border-radius: 8px;
+            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+        }
+        h1 {
+            color: #333;
+            text-align: center;
+        }
+        .controls {
+            margin: 20px 0;
+            text-align: center;
+        }
+        .controls input, .controls button {
+            margin: 5px;
+            padding: 8px 15px;
+            border-radius: 4px;
+            border: 1px solid #ddd;
+        }
+        .controls button {
+            background-color: #007bff;
+            color: white;
+            cursor: pointer;
+        }
+        .controls button:hover {
+            background-color: #0056b3;
+        }
+        #messageDisplay {
+            background-color: #f8f9fa;
+            border: 1px solid #ddd;
+            border-radius: 4px;
+            padding: 15px;
+            min-height: 300px;
+            max-height: 600px;
+            overflow-y: auto;
+            white-space: pre-wrap;
+            font-family: monospace;
+        }
+        .message {
+            margin-bottom: 10px;
+            padding: 10px;
+            border-radius: 4px;
+            background-color: #e9ecef;
+        }
+        .timestamp {
+            font-size: 0.8em;
+            color: #6c757d;
+        }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <h1>OKX WebSocket消息监控</h1>
+        
+        <div class="controls">
+            <label for="refreshInterval">刷新间隔(秒):</label>
+            <input type="number" id="refreshInterval" min="1" max="60" value="5">
+            <button onclick="startAutoRefresh()">开始自动刷新</button>
+            <button onclick="stopAutoRefresh()">停止自动刷新</button>
+            <button onclick="refreshMessage()">手动刷新</button>
+            <button onclick="clearMessages()">清除消息</button>
+        </div>
+        
+        <div id="messageDisplay">
+            <p>等待接收消息...</p>
+        </div>
+    </div>
+
+    <script>
+        let refreshIntervalId;
+        let messageHistory = [];
+
+        // 获取最新消息
+        function refreshMessage() {
+            fetch('/quant/okx/latestMessage')
+                .then(response => response.json())
+                .then(data => {
+                    if (data.code === 200 && data.data) {
+                        displayMessage(data.data);
+                    }
+                })
+                .catch(error => {
+                    console.error('Error fetching message:', error);
+                    displayMessage('Error: ' + error.message);
+                });
+        }
+
+        // 显示消息
+        function displayMessage(message) {
+            const display = document.getElementById('messageDisplay');
+            const timestamp = new Date().toLocaleString();
+            
+            // 如果是新消息,添加到历史记录
+            if (!messageHistory.includes(message)) {
+                messageHistory.push({
+                    timestamp: timestamp,
+                    content: message
+                });
+                
+                // 限制历史记录数量
+                if (messageHistory.length > 100) {
+                    messageHistory.shift();
+                }
+            }
+            
+            // 更新显示
+            display.innerHTML = '';
+            messageHistory.forEach(msg => {
+                const messageElement = document.createElement('div');
+                messageElement.className = 'message';
+                messageElement.innerHTML = `
+                    <div class="timestamp">${msg.timestamp}</div>
+                    <div>${formatJson(msg.content)}</div>
+                `;
+                display.appendChild(messageElement);
+            });
+            
+            // 滚动到底部
+            display.scrollTop = display.scrollHeight;
+        }
+
+        // 格式化JSON
+        function formatJson(jsonString) {
+            try {
+                const obj = JSON.parse(jsonString);
+                return JSON.stringify(obj, null, 2);
+            } catch (e) {
+                return jsonString;
+            }
+        }
+
+        // 开始自动刷新
+        function startAutoRefresh() {
+            stopAutoRefresh(); // 先停止之前的定时器
+            const interval = document.getElementById('refreshInterval').value * 1000;
+            refreshIntervalId = setInterval(refreshMessage, interval);
+            refreshMessage(); // 立即获取一次消息
+        }
+
+        // 停止自动刷新
+        function stopAutoRefresh() {
+            if (refreshIntervalId) {
+                clearInterval(refreshIntervalId);
+                refreshIntervalId = null;
+            }
+        }
+
+        // 清除消息
+        function clearMessages() {
+            messageHistory = [];
+            document.getElementById('messageDisplay').innerHTML = '<p>消息已清除</p>';
+        }
+
+        // 页面加载完成后开始自动刷新
+        window.onload = function() {
+            startAutoRefresh();
+        };
+
+        // 页面关闭前停止定时器
+        window.onbeforeunload = function() {
+            stopAutoRefresh();
+        };
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/resources/templates/febs/views/modules/banner/platformBannerAdd.html b/src/main/resources/templates/febs/views/modules/banner/platformBannerAdd.html
index a78bb2a..074b274 100644
--- a/src/main/resources/templates/febs/views/modules/banner/platformBannerAdd.html
+++ b/src/main/resources/templates/febs/views/modules/banner/platformBannerAdd.html
@@ -47,6 +47,7 @@
                                                 <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
                                                     <div class="layui-upload-list" id="bannerImgUpload"></div>
                                                 </blockquote>
+                                                <div class="layui-word-aux">双击图片删除</div>
                                             </div>
                                         </div>
                                     </div>
@@ -60,27 +61,28 @@
                                     </div>
                                 </div>
 
-                                <div class="layui-row layui-col-space10 layui-form-item">
-                                    <div class="layui-col-lg6">
-                                        <label class="layui-form-label">背景图片:</label>
-                                        <div class="layui-input-block">
-                                            <div class="layui-upload">
-                                                <button type="button" class="layui-btn layui-btn-normal layui-btn" id="bannerImgUploadButtonBack">上传</button>
-                                                <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
-                                                    <div class="layui-upload-list" id="bannerImgUploadBack"></div>
-                                                </blockquote>
-                                            </div>
-                                        </div>
-                                    </div>
-                                </div>
-                                <div class="layui-row layui-col-space10 layui-form-item febs-hide">
-                                    <div class="layui-col-lg6">
-                                        <label class="layui-form-label">背景图片链接:</label>
-                                        <div class="layui-input-block">
-                                            <input type="text" id="imageBackUrl" name="imageBackUrl" autocomplete="off" class="layui-input" readonly>
-                                        </div>
-                                    </div>
-                                </div>
+<!--                                <div class="layui-row layui-col-space10 layui-form-item">-->
+<!--                                    <div class="layui-col-lg6">-->
+<!--                                        <label class="layui-form-label">背景图片:</label>-->
+<!--                                        <div class="layui-input-block">-->
+<!--                                            <div class="layui-upload">-->
+<!--                                                <button type="button" class="layui-btn layui-btn-normal layui-btn" id="bannerImgUploadButtonBack">上传</button>-->
+<!--                                                <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">-->
+<!--                                                    <div class="layui-upload-list" id="bannerImgUploadBack"></div>-->
+<!--                                                </blockquote>-->
+<!--                                                <div class="layui-word-aux">双击图片删除</div>-->
+<!--                                            </div>-->
+<!--                                        </div>-->
+<!--                                    </div>-->
+<!--                                </div>-->
+<!--                                <div class="layui-row layui-col-space10 layui-form-item febs-hide">-->
+<!--                                    <div class="layui-col-lg6">-->
+<!--                                        <label class="layui-form-label">背景图片链接:</label>-->
+<!--                                        <div class="layui-input-block">-->
+<!--                                            <input type="text" id="imageBackUrl" name="imageBackUrl" autocomplete="off" class="layui-input" readonly>-->
+<!--                                        </div>-->
+<!--                                    </div>-->
+<!--                                </div>-->
 
                                 <div class="layui-row layui-col-space10 layui-form-item">
                                     <div class="layui-col-lg6">
@@ -191,6 +193,9 @@
             }
             ,done: function(res){
                 $("#imageUrl").val(res.data.src);
+
+                imgUnBind(".single-image");
+                imgSingleBind("#imageUrl");
             }
         });
 
@@ -208,8 +213,30 @@
             }
             ,done: function(res){
                 $("#imageBackUrl").val(res.data.src);
+
+                imgUnBind(".single-image");
+                imgSingleBind("#imageBackUrl");
             }
         });
+
+        function imgSingleBind(idName) {
+            $(".single-image").each(function(index, element) {
+                $(this).on("dblclick", function() {
+                    var imgThumb = $(".single-image")[index];
+                    $(imgThumb).remove();
+                    $(idName).val("");
+
+                    imgUnBind(".single-image");
+                    imgSingleBind();
+                });
+            })
+        }
+        function imgUnBind(className) {
+            $(className).each(function() {
+                $(this).unbind('dblclick');
+            })
+        }
+
         formSelects.render();
         form.on('submit(banner-add-form-submit)', function (data) {
             febs.post(ctx + 'admin/banner/platformBannerAdds', data.field, function () {
diff --git a/src/main/resources/templates/febs/views/modules/banner/platformBannerDetail.html b/src/main/resources/templates/febs/views/modules/banner/platformBannerDetail.html
index 10156a1..9ab453c 100644
--- a/src/main/resources/templates/febs/views/modules/banner/platformBannerDetail.html
+++ b/src/main/resources/templates/febs/views/modules/banner/platformBannerDetail.html
@@ -49,6 +49,7 @@
                                                 <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
                                                     <div class="layui-upload-list" id="bannerImgUpload"></div>
                                                 </blockquote>
+                                                <div class="layui-word-aux">双击图片删除</div>
                                             </div>
                                         </div>
                                     </div>
@@ -62,27 +63,28 @@
                                     </div>
                                 </div>
 
-                                <div class="layui-row layui-col-space10 layui-form-item">
-                                    <div class="layui-col-lg6">
-                                        <label class="layui-form-label">背景图片:</label>
-                                        <div class="layui-input-block">
-                                            <div class="layui-upload">
-                                                <button type="button" class="layui-btn layui-btn-normal layui-btn" id="bannerImgUploadButtonBack">上传</button>
-                                                <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
-                                                    <div class="layui-upload-list" id="bannerImgUploadBack"></div>
-                                                </blockquote>
-                                            </div>
-                                        </div>
-                                    </div>
-                                </div>
-                                <div class="layui-row layui-col-space10 layui-form-item febs-hide">
-                                    <div class="layui-col-lg6">
-                                        <label class="layui-form-label">背景图片链接:</label>
-                                        <div class="layui-input-block">
-                                            <input type="text" id="imageBackUrl" name="imageBackUrl" autocomplete="off" class="layui-input" readonly>
-                                        </div>
-                                    </div>
-                                </div>
+<!--                                <div class="layui-row layui-col-space10 layui-form-item">-->
+<!--                                    <div class="layui-col-lg6">-->
+<!--                                        <label class="layui-form-label">背景图片:</label>-->
+<!--                                        <div class="layui-input-block">-->
+<!--                                            <div class="layui-upload">-->
+<!--                                                <button type="button" class="layui-btn layui-btn-normal layui-btn" id="bannerImgUploadButtonBack">上传</button>-->
+<!--                                                <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">-->
+<!--                                                    <div class="layui-upload-list" id="bannerImgUploadBack"></div>-->
+<!--                                                </blockquote>-->
+<!--                                                <div class="layui-word-aux">双击图片删除</div>-->
+<!--                                            </div>-->
+<!--                                        </div>-->
+<!--                                    </div>-->
+<!--                                </div>-->
+<!--                                <div class="layui-row layui-col-space10 layui-form-item febs-hide">-->
+<!--                                    <div class="layui-col-lg6">-->
+<!--                                        <label class="layui-form-label">背景图片链接:</label>-->
+<!--                                        <div class="layui-input-block">-->
+<!--                                            <input type="text" id="imageBackUrl" name="imageBackUrl" autocomplete="off" class="layui-input" readonly>-->
+<!--                                        </div>-->
+<!--                                    </div>-->
+<!--                                </div>-->
 
                                 <div class="layui-row layui-col-space10 layui-form-item">
                                     <div class="layui-col-lg6">
@@ -178,6 +180,9 @@
             }
             ,done: function(res){
                 $("#imageUrl").val(res.data.src);
+
+                imgUnBind(".single-image");
+                imgSingleBind("#imageUrl");
             }
         });
 
@@ -195,8 +200,29 @@
             }
             ,done: function(res){
                 $("#imageBackUrl").val(res.data.src);
+
+                imgUnBind(".single-image");
+                imgSingleBind("#imageBackUrl");
             }
         });
+
+        function imgSingleBind(idName) {
+            $(".single-image").each(function(index, element) {
+                $(this).on("dblclick", function() {
+                    var imgThumb = $(".single-image")[index];
+                    $(imgThumb).remove();
+                    $(idName).val("");
+
+                    imgUnBind(".single-image");
+                    imgSingleBind(idName);
+                });
+            })
+        }
+        function imgUnBind(className) {
+            $(className).each(function() {
+                $(this).unbind('dblclick');
+            })
+        }
 
         form.render();
         //(下拉框)
@@ -233,9 +259,11 @@
 
             $('#bannerImgUpload').append('<img src="' + banner.imageUrl + '" alt="" class="layui-upload-img single-image" style="width: 130px">');
             $("#imageUrl").val(banner.imageUrl);
+            imgSingleBind("#imageUrl");
 
             $('#bannerImgUploadBack').append('<img src="' + banner.imageBackUrl + '" alt="" class="layui-upload-img single-image" style="width: 130px">');
             $("#imageBackUrl").val(banner.imageBackUrl);
+            imgSingleBind("#imageBackUrl");
         }
 
         form.on('submit(banner-info-form-submit)', function (data) {

--
Gitblit v1.9.1