From 2d61bf689ce6c67bcced89d294ed3f88ef737d0d Mon Sep 17 00:00:00 2001 From: no99 <17663930442@163.com> Date: Tue, 28 Oct 2025 19:24:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=85=A5TCP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .hbuilderx/launch.json | 4 +- api/tcpConnection.js | 413 +++++++++++++------------- manifest.json | 22 +- pages/home/marketCondition.vue | 644 +++++++++++++++++++++++++++-------------- 4 files changed, 656 insertions(+), 427 deletions(-) diff --git a/.hbuilderx/launch.json b/.hbuilderx/launch.json index c4f1072..2a3f43d 100644 --- a/.hbuilderx/launch.json +++ b/.hbuilderx/launch.json @@ -2,8 +2,8 @@ "version" : "1.0", "configurations" : [ { - "customPlaygroundType" : "device", - "playground" : "standard", + "customPlaygroundType" : "local", + "playground" : "custom", "type" : "uni-app:app-android" // "playground" : "standard", // "type" : "uni-app:app-ios" diff --git a/api/tcpConnection.js b/api/tcpConnection.js index ffe9d88..c882f08 100644 --- a/api/tcpConnection.js +++ b/api/tcpConnection.js @@ -1,239 +1,238 @@ /** * TCP连接工具类 * 用于处理TCP连接、发送消息和断开连接 + * + * @format */ // 引用TCP插件 -const TCPSocket = uni.requireNativePlugin('Aimer-TCPPlugin'); +const TCPSocket = uni.requireNativePlugin("Aimer-TCPPlugin"); // TCP连接配置 const TCP_CONFIG = { - ip: '192.168.1.9', - port: '8080', - channel: '1', // 可选 1~20 - charsetname: 'UTF-8' // 默认UTF-8,可选GBK + ip: "192.168.1.9", + port: "8080", + channel: "1", // 可选 1~20 + charsetname: "UTF-8", // 默认UTF-8,可选GBK }; /** * TCP连接管理类 */ class TCPConnection { - constructor() { - this.isConnected = false; - this.connectionCallbacks = []; - this.messageCallbacks = []; - } - - /** - * TCP初始化连接 - * @param {Object} config - 连接配置 {ip, port, channel, charsetname} - * @param {Function} callback - 连接状态回调函数 - */ - connect(config = {}, callback = null) { - // 如果已经连接,先断开现有连接 - if (this.isConnected) { - console.log('检测到现有TCP连接,先断开...'); - this.disconnect(config); - // 等待断开完成后再连接 - setTimeout(() => { - this._performConnect(config, callback); - }, 300); - } else { - // 直接连接 - this._performConnect(config, callback); - } + constructor() { + this.isConnected = false; + this.connectionCallbacks = []; + this.messageCallbacks = []; + } + + /** + * TCP初始化连接 + * @param {Object} config - 连接配置 {ip, port, channel, charsetname} + * @param {Function} callback - 连接状态回调函数 + */ + connect(config = {}, callback = null) { + // 如果已经连接,先断开现有连接 + if (this.isConnected) { + console.log("检测到现有TCP连接,先断开..."); + this.disconnect(config); + // 等待断开完成后再连接 + setTimeout(() => { + this._performConnect(config, callback); + }, 300); + } else { + // 直接连接 + this._performConnect(config, callback); } - - /** - * 执行TCP连接 - * @param {Object} config - 连接配置 - * @param {Function} callback - 连接状态回调函数 - */ - _performConnect(config = {}, callback = null) { - const connectionConfig = { - channel: config.channel || TCP_CONFIG.channel, - ip: config.ip || TCP_CONFIG.ip, - port: config.port || TCP_CONFIG.port - }; - - // 如果指定了字符集,添加到配置中 - if (config.charsetname || TCP_CONFIG.charsetname) { - connectionConfig.charsetname = config.charsetname || TCP_CONFIG.charsetname; - } - - console.log('开始建立TCP连接:', connectionConfig); - TCPSocket.connect( - connectionConfig, - result => { - /** - * status : 0 连接成功 - * status : 1 断开连接 - * receivedMsg : 服务器返回字符串(普通的字符串交互) - * receivedHexMsg : 服务器返回字节数组(单片机、智能家居等硬件数据交互) - */ - if (result.status == '0') { - // TCP连接成功 - this.isConnected = true; - console.log('TCP连接成功'); - this._notifyConnectionCallbacks('connected', result); - } else if (result.status == '1') { - // TCP断开连接 - this.isConnected = false; - console.log('TCP断开连接'); - this._notifyConnectionCallbacks('disconnected', result); - } - - if (result.receivedMsg) { - // 服务器返回字符串 - console.log('收到字符串消息:', result.receivedMsg); - this._notifyMessageCallbacks('string', result.receivedMsg); - } - - // if (result.receivedHexMsg) { - // // 硬件服务器返回16进制数据 - // console.log('收到16进制消息:', result.receivedHexMsg); - // let msg = result.receivedHexMsg; - // let sum = msg.length / 2; - // let arr = []; - // for (let k = 0; k < sum; k++) { - // let i = msg.substring(k * 2, k * 2 + 2); - // arr.push(i); - // } - // console.log('解析后的16进制数组:', arr); - // this._notifyMessageCallbacks('hex', result.receivedHexMsg, arr); - // } - - // 执行回调函数 - if (callback && typeof callback === 'function') { - callback(result); - } - } - ); - } - - /** - * TCP发送消息(普通的字符串交互) - * @param {String|Object} message - 要发送的消息,如果是对象会自动转换为JSON字符串 - * @param {Object} config - 发送配置 {channel, charsetname} - */ - send(message, config = {}) { - if (!this.isConnected) { - console.warn('TCP未连接,无法发送消息'); - return false; - } - - // 如果message是对象,转换为JSON字符串 - let messageStr = message; - if (typeof message === 'object') { - messageStr = JSON.stringify(message) + '\n'; - } - - const sendConfig = { - channel: config.channel || '1', // 注意:channel应该是字符串 - message: messageStr - }; - - // 如果指定了字符编码,添加到配置中 - if (config.charsetname) { - sendConfig.charsetname = config.charsetname; - } - - TCPSocket.send(sendConfig); - console.log('js成功发送TCP消息:', messageStr); - return true; + } + + /** + * 执行TCP连接 + * @param {Object} config - 连接配置 + * @param {Function} callback - 连接状态回调函数 + */ + _performConnect(config = {}, callback = null) { + const connectionConfig = { + channel: config.channel || TCP_CONFIG.channel, + ip: config.ip || TCP_CONFIG.ip, + port: config.port || TCP_CONFIG.port, + }; + + // 如果指定了字符集,添加到配置中 + if (config.charsetname || TCP_CONFIG.charsetname) { + connectionConfig.charsetname = config.charsetname || TCP_CONFIG.charsetname; } - /** - * TCP断开连接 - * @param {Object} config - 断开配置 {channel} - */ - disconnect(config = {}) { - const disconnectConfig = { - channel: config.channel || TCP_CONFIG.channel - }; - - TCPSocket.disconnect(disconnectConfig); + console.log("开始建立TCP连接:", connectionConfig); + TCPSocket.connect(connectionConfig, (result) => { + /** + * status : 0 连接成功 + * status : 1 断开连接 + * receivedMsg : 服务器返回字符串(普通的字符串交互) + * receivedHexMsg : 服务器返回字节数组(单片机、智能家居等硬件数据交互) + */ + if (result.status == "0") { + // TCP连接成功 + this.isConnected = true; + console.log("TCP连接成功"); + this._notifyConnectionCallbacks("connected", result); + } else if (result.status == "1") { + // TCP断开连接 this.isConnected = false; - console.log('TCP连接已断开', disconnectConfig); + console.log("TCP断开连接"); + this._notifyConnectionCallbacks("disconnected", result); + } + + if (result.receivedMsg) { + // 服务器返回字符串 + console.log("收到字符串消息:", result.receivedMsg); + this._notifyMessageCallbacks("string", result.receivedMsg); + } + + // if (result.receivedHexMsg) { + // // 硬件服务器返回16进制数据 + // console.log('收到16进制消息:', result.receivedHexMsg); + // let msg = result.receivedHexMsg; + // let sum = msg.length / 2; + // let arr = []; + // for (let k = 0; k < sum; k++) { + // let i = msg.substring(k * 2, k * 2 + 2); + // arr.push(i); + // } + // console.log('解析后的16进制数组:', arr); + // this._notifyMessageCallbacks('hex', result.receivedHexMsg, arr); + // } + + // 执行回调函数 + if (callback && typeof callback === "function") { + callback(result); + } + }); + } + + /** + * TCP发送消息(普通的字符串交互) + * @param {String|Object} message - 要发送的消息,如果是对象会自动转换为JSON字符串 + * @param {Object} config - 发送配置 {channel, charsetname} + */ + send(message, config = {}) { + if (!this.isConnected) { + console.warn("TCP未连接,无法发送消息"); + return false; } - /** - * 添加连接状态监听器 - * @param {Function} callback - 回调函数 (status, result) => {} - */ - onConnectionChange(callback) { - if (typeof callback === 'function') { - this.connectionCallbacks.push(callback); - } + // 如果message是对象,转换为JSON字符串 + let messageStr = message; + if (typeof message === "object") { + messageStr = JSON.stringify(message) + "\n"; } - /** - * 添加消息监听器 - * @param {Function} callback - 回调函数 (type, message, parsedArray) => {} - */ - onMessage(callback) { - if (typeof callback === 'function') { - this.messageCallbacks.push(callback); - } - } + const sendConfig = { + channel: config.channel || "1", // 注意:channel应该是字符串 + message: messageStr, + }; - /** - * 移除连接状态监听器 - * @param {Function} callback - 要移除的回调函数 - */ - removeConnectionListener(callback) { - const index = this.connectionCallbacks.indexOf(callback); - if (index > -1) { - this.connectionCallbacks.splice(index, 1); - } + // 如果指定了字符编码,添加到配置中 + if (config.charsetname) { + sendConfig.charsetname = config.charsetname; } - /** - * 移除消息监听器 - * @param {Function} callback - 要移除的回调函数 - */ - removeMessageListener(callback) { - const index = this.messageCallbacks.indexOf(callback); - if (index > -1) { - this.messageCallbacks.splice(index, 1); - } + TCPSocket.send(sendConfig); + console.log("js成功发送TCP消息:", messageStr); + return true; + } + + /** + * TCP断开连接 + * @param {Object} config - 断开配置 {channel} + */ + disconnect(config = {}) { + const disconnectConfig = { + channel: config.channel || TCP_CONFIG.channel, + }; + + TCPSocket.disconnect(disconnectConfig); + this.isConnected = false; + console.log("TCP连接已断开", disconnectConfig); + } + + /** + * 添加连接状态监听器 + * @param {Function} callback - 回调函数 (status, result) => {} + */ + onConnectionChange(callback) { + if (typeof callback === "function") { + this.connectionCallbacks.push(callback); } - - /** - * 获取连接状态 - * @returns {Boolean} 连接状态 - */ - getConnectionStatus() { - return this.isConnected; + } + + /** + * 添加消息监听器 + * @param {Function} callback - 回调函数 (type, message, parsedArray) => {} + */ + onMessage(callback) { + if (typeof callback === "function") { + this.messageCallbacks.push(callback); } - - /** - * 通知连接状态回调 - * @private - */ - _notifyConnectionCallbacks(status, result) { - this.connectionCallbacks.forEach(callback => { - try { - callback(status, result); - } catch (error) { - console.error('连接状态回调执行错误:', error); - } - }); + } + + /** + * 移除连接状态监听器 + * @param {Function} callback - 要移除的回调函数 + */ + removeConnectionListener(callback) { + const index = this.connectionCallbacks.indexOf(callback); + if (index > -1) { + this.connectionCallbacks.splice(index, 1); } - - /** - * 通知消息回调 - * @private - */ - _notifyMessageCallbacks(type, message, parsedArray = null) { - this.messageCallbacks.forEach(callback => { - try { - callback(type, message, parsedArray); - } catch (error) { - console.error('消息回调执行错误:', error); - } - }); + } + + /** + * 移除消息监听器 + * @param {Function} callback - 要移除的回调函数 + */ + removeMessageListener(callback) { + const index = this.messageCallbacks.indexOf(callback); + if (index > -1) { + this.messageCallbacks.splice(index, 1); } + } + + /** + * 获取连接状态 + * @returns {Boolean} 连接状态 + */ + getConnectionStatus() { + return this.isConnected; + } + + /** + * 通知连接状态回调 + * @private + */ + _notifyConnectionCallbacks(status, result) { + this.connectionCallbacks.forEach((callback) => { + try { + callback(status, result); + } catch (error) { + console.error("连接状态回调执行错误:", error); + } + }); + } + + /** + * 通知消息回调 + * @private + */ + _notifyMessageCallbacks(type, message, parsedArray = null) { + this.messageCallbacks.forEach((callback) => { + try { + callback(type, message, parsedArray); + } catch (error) { + console.error("消息回调执行错误:", error); + } + }); + } } // 创建TCP连接实例 @@ -241,4 +240,4 @@ const tcpConnection = new TCPConnection(); // 导出TCP连接实例和类 export default tcpConnection; -export { TCPConnection, TCP_CONFIG }; \ No newline at end of file +export { TCPConnection, TCP_CONFIG }; diff --git a/manifest.json b/manifest.json index dd52cfc..5133cf6 100644 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "name" : "DeepChartApp", - "appid" : "__UNI__D8DF433", + "appid" : "__UNI__9C9AB28", "description" : "", "versionName" : "1.0.0", "versionCode" : "100", @@ -42,7 +42,9 @@ "" ] }, - "ios" : {}, + "ios" : { + "dSYMs" : false + }, /* ios打包配置 */ "sdkConfigs" : { "oauth" : { @@ -52,6 +54,22 @@ } } } + }, + "nativePlugins" : { + "Aimer-TCPPlugin" : { + "__plugin_info__" : { + "name" : "TCP-Socket原生插件(支持Android和IOS) - [试用版,仅用于自定义调试基座]", + "description" : "Uniapp实现基于TCP的数据通信,支持单片机、智能家居等硬件交互,联系QQ: 462108858", + "platforms" : "Android,iOS", + "url" : "https://ext.dcloud.net.cn/plugin?id=2029", + "android_package_name" : "", + "ios_bundle_id" : "", + "isCloud" : true, + "bought" : 0, + "pid" : "2029", + "parameters" : {} + } + } } }, /* SDK配置 */ diff --git a/pages/home/marketCondition.vue b/pages/home/marketCondition.vue index 413d700..e1f6696 100644 --- a/pages/home/marketCondition.vue +++ b/pages/home/marketCondition.vue @@ -15,8 +15,8 @@ - - ··· + + ··· @@ -196,8 +196,14 @@ - + + + + + + {{ item }} + K线图开发中... @@ -230,15 +236,27 @@ const instance = getCurrentInstance(); import { prevClosePrice, timeData as testTimeData, klineData as testKlineData } from "@/common/stockTimeInformation.js"; import { throttle } from "@/common/util.js"; import { HCharts } from "@/common/canvasMethod.js"; -// const TCPSocket = uni.requireNativePlugin("Aimer-TCPPlugin"); -const tcpObject = { - ip: "192.168.1.9", - port: 8080, - reconnectInterval: 3000, - isConnected: false, -}; -const TIME_OUT = 1000 * 5; -const resultR = ref([]); +import tcpConnection, { TCPConnection, TCP_CONFIG } from "@/api/tcpConnection.js"; + +// TCP相关响应式变量 +const tcpConnected = ref(false); +const tcpMessages = ref([]); +const tcpStockData = ref({ + count: 0, + data: {}, + stock_count: 0, + timestamp: "", + type: "", +}); +const currentStockInfo = ref({ + stock_name: "未知股票", + current_price: "0.00", + change: "0.00%", + change_value: 0, + change_percent: 0, +}); +const connectionListener = ref(null); +const messageListener = ref(null); // 股票信息栏变量 const stockInformation = ref({ @@ -401,29 +419,26 @@ const moreTabsData = ref([ // 股票当前选中的K线类型Tab // 1:分时 2:日K 3:周K 4:月K -const klineTab = ref(2); - -const sendGetTimeData = () => { - console.log("执行发送消息的方法"); +const klineTab = ref(1); +const startTcp = () => { try { - TCPSocket.send({ - channel: "1", - message: '{"command": "real_time", "stock_code": "SH.000001"}', + removeTcpListeners(); + disconnectTcp(); + initTcpListeners(); + connectTcp(); + } catch (error) { + console.error("建立连接并设置监听:", error); + uni.showToast({ + title: "建立连接并设置监听", + icon: "none", + duration: 1500, }); - } catch (e) { - console.log("error", e); } }; const sendStopTimeData = () => { - try { - TCPSocket.send({ - channel: "1", - message: '{"command": "stop_real_time"}', - }); - } catch (e) { - console.log("error", e); - } + disconnectTcp(); + removeTcpListeners(); }; // 确定股票数据的颜色方法 @@ -450,9 +465,11 @@ const confirmStockColor = (price, lastDayStockClosePrice) => { // 股票K线类型方法 const selectKlineTab = (tabId) => { klineTab.value = tabId; - if (tabId === 1) { - stockInformation.value.lastDayStockClosePrice = prevClosePrice; + + if (klineTab.value == 1) { + sendTcpMessage("init_real_time"); } + initCanvas(); // startAddDataTimer(); }; @@ -929,6 +946,7 @@ const drawChart = () => { // 根据当前标签绘制对应图表 if (klineTab.value == 1) { + console.log("stockInfomaton.lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice); // 设置标签样式 const label = [ { @@ -1364,151 +1382,341 @@ watch(klineTab, () => { console.log("标签页变化"); drawChart(); }); -/* - const connectTcp = (ip, port) => { - console.log(`🚀 正在连接TCP服务器 ${ip}:${port}...`); - TCPSocket.connect( - { - channel: "1", - ip: ip, - port: port, - }, - (result) => { - console.log(result); - if (result.status == 0) { - tcpObject.isConnected = true; - console.log("tcp连接成功"); - } else if (result.status == 1) { - tcpObject.isConnected = false; - console.log("tcp断开连接"); - } - if (result.receivedMsg) { - console.log("收到服务器发送的数据", result.receivedMsg); - if (result.receivedMsg.length == 0 || result.receivedMsg.includes("欢迎")) { - resultR.value = []; - } else { - const msgPacket = JSON.parse(result.receivedMsg); - resultR.value.push(msgPacket); - // 股票代码 - if (msgPacket.stock_code) { - stockInformation.value.stockCode = msgPacket.stock_code; - } - // 股票名称 - if (msgPacket.stock_name) { - stockInformation.value.stockName = msgPacket.stock_name; - } - // 前一日收盘价 - if (msgPacket.pre_close) { - stockInformation.value.lastDayStockClosePrice = msgPacket.pre_close; - } - // 当前股价(收盘价) - if (msgPacket.current_price) { - stockInformation.value.currentPrice = msgPacket.current_price; - } - // 涨跌额度 - if (msgPacket.current_price && msgPacket.pre_close) { - stockInformation.value.currentValue = msgPacket.current_price - msgPacket.pre_close; - stockInformation.value.currentRatio = ((msgPacket.current_price - msgPacket.pre_close) / msgPacket.pre_close) * 100; - } - - // 最高价 - if (msgPacket.high_price) { - stockInformation.value.highPrice = msgPacket.high_price; - } - // 最低价 - if (msgPacket.close_price) { - stockInformation.value.lowPrice = msgPacket.close_price; - } - // 开盘价 - if (msgPacket.open_price) { - stockInformation.value.openPrice = msgPacket.open_price; - } - // 开盘价 - if (msgPacket.low_price) { - stockInformation.value.lowPrice = msgPacket.low_price; - } - // 收盘价(当前股价) - if (msgPacket.current_price) { - stockInformation.value.closePrice = msgPacket.current_price; - } - // 成交量 - if (msgPacket.volume) { - stockInformation.value.volume = msgPacket.volume; - } - // 成交量比 - if (msgPacket.volume_ratio) { - stockInformation.value.volumeRatio = msgPacket.volume_ratio; - } - // 成交额 - if (msgPacket.amount) { - stockInformation.value.amount = msgPacket.amount; - } - // 市盈 - if (msgPacket.market_earn) { - stockInformation.value.marketEarn = msgPacket.market_earn; - } - // 换手率 - if (msgPacket.turnover_ratio) { - stockInformation.value.turnoverRatio = msgPacket.turnover_ratio; - } - // 市值 - if (msgPacket.total_market_value) { - stockInformation.value.marketValue = msgPacket.total_market_value; - } - } - } - // if (result.receivedHexMsg) { - // //服务器返回16进制数据 - // console.log("📥 收到16进制数据:", result.receivedHexMsg); - // let msg = result.receivedHexMsg; - // let sum = msg.length / 2; - // let arr = []; - // for (let k = 0; k < sum; k++) { - // let i = msg.substring(k * 2, k * 2 + 2); - // arr.push(i); - // } - // console.log("转换成16进制数组:", arr); - // if (tcpObject.responseCallback) { - // tcpObject.responseCallback({ - // data: arr, - // }); - // } - // } - - // 设置连接超时 - setTimeout(() => { - if (!tcpObject.isConnected) { - throw new Error("连接超时"); - return; - } - }, TIME_OUT); - } - ); - }; - // 断开连接 - const disconnect = () => { - try { - TCPSocket.disconnect({ - channel: "1", - }); - tcpObject.isConnected = false; - console.log("✅ 连接已关闭"); - } catch (e) { - console.log("⚠️ 断开连接时发生错误:", e.message); - } - }; - - const startTcp = async () => { - console.log("🚀 TCP客户端启动"); - console.log(`目标服务器: ${tcpObject.ip}:${tcpObject.port}`); - try { - // 连接服务器 - await connectTcp(tcpObject.ip, tcpObject.port); - } catch (e) { - console.log("error", e); - } - }; - */ + +// 初始化TCP监听器 +const initTcpListeners = () => { + // 创建连接状态监听器并保存引用 + connectionListener.value = (status, result) => { + tcpConnected.value = status === "connected"; + console.log("TCP连接状态变化:", status, tcpConnected.value); + + // 显示连接状态提示 + uni.showToast({ + title: status === "connected" ? "TCP连接成功" : "TCP连接断开", + icon: status === "connected" ? "success" : "none", + duration: 2000, + }); + + if (status === "connected") { + if (klineTab.value == 1) { + sendTcpMessage("init_real_time"); + } + } + }; + + // 创建消息监听器并保存引用 + messageListener.value = (type, message, parsedArray) => { + const messageObj = { + type: type, + content: message, + parsedArray: parsedArray, + timestamp: new Date().toLocaleTimeString(), + direction: "received", + }; + console.log("0000"); + tcpMessages.value.push(messageObj); + // console.log('收到TCP消息:', messageObj) + console.log("home开始调用parseStockData", messageObj); + + // 解析股票数据 + parseStockData(message); + }; + + // 注册监听器 + tcpConnection.onConnectionChange(connectionListener.value); + tcpConnection.onMessage(messageListener.value); +}; + +// 连接TCP服务器 +const connectTcp = () => { + console.log("开始连接TCP服务器..."); + tcpConnection.connect(); +}; + +// 断开TCP连接 +const disconnectTcp = () => { + console.log("断开TCP连接..."); + tcpConnection.disconnect(); + tcpConnected.value = false; +}; + +// 发送TCP消息 +const sendTcpMessage = (command) => { + let messageData; + switch (command) { + // 实时行情推送 + case "real_time": + messageData = { + command: "real_time", + stock_code: "SH.000001", + }; + break; + // 初始化获取行情历史数据 + case "init_real_time": + messageData = { + command: "init_real_time", + stock_code: "SH.000001", + }; + break; + case "stop_real_time": + messageData = { + command: "stop_real_time", + }; + break; + // 股票列表 + case "stock_list": + messageData = { + command: "stock_list", + }; + break; + case "daily_data": + messageData = { + command: "daily_data", + stock_code: "GBPAUD.FXCM", + start_date: "20251001", + end_date: "20251023", + }; + break; + case "weekly_data": + messageData = { + command: "weekly_data", + stock_code: "000001.SZ", + start_date: "20251001", + end_date: "20251023", + }; + break; + case "daily_one_minutes_data": + messageData = { + command: "daily_one_minutes_data", + stock_code: "000001.SZ", + }; + break; + case "daily_five_minutes_data": + messageData = { + command: "daily_five_minutes_data", + stock_code: "000001.SZ", + }; + break; + case "daily_fifteen_minutes_data": + messageData = { + command: "daily_fifteen_minutes_data", + stock_code: "000001.SZ", + }; + break; + case "daily_thirty_minutes_data": + messageData = { + command: "daily_thirty_minutes_data", + stock_code: "000001.SZ", + }; + break; + case "daily_sixty_minutes_data": + messageData = { + command: "daily_sixty_minutes_data", + stock_code: "000001.SZ", + }; + break; + case "batch_real_time": + messageData = { + command: "batch_real_time", + stock_codes: ["SH.000001", "SH.000002", "SH.000003", "SH.000004", "SH.000005"], + }; + break; + case "help": + messageData = { + command: "help", + }; + break; + } + if (!messageData) { + uni.showToast({ + title: "命令不存在", + icon: "none", + duration: 1500, + }); + return; + } else { + try { + // 发送消息 + const success = tcpConnection.send(messageData); + if (success) { + console.log("home发送TCP消息:", messageData); + uni.showToast({ + title: "消息发送成功", + icon: "success", + duration: 1500, + }); + } + } catch (error) { + console.error("发送TCP消息时出错:", error); + uni.showToast({ + title: "消息发送失败", + icon: "none", + duration: 1500, + }); + } + } +}; + +// 清空消息记录 +const clearTcpMessages = () => { + tcpMessages.value = []; + uni.showToast({ + title: "消息记录已清空", + icon: "success", + duration: 1500, + }); +}; + +// 获取TCP连接状态 +const getTcpStatus = () => { + const status = tcpConnection.getConnectionStatus(); + uni.showModal({ + title: "TCP连接状态", + content: `当前状态: ${status ? "已连接" : "未连接"}\n消息数量: ${tcpMessages.value.length}`, + showCancel: false, + }); +}; + +let isMorePacket = false; +let receivedMessage; +// 解析TCP股票数据 +const parseStockData = (message) => { + try { + console.log("进入parseStockData, message类型:", typeof message); + + let parsedMessage; + // 如果isMorePacket是true,说明正在接受分包数据,无条件接收 + // 如果message是字符串且以{开头,说明是JSON字符串,需要解析 + // 如果不属于以上两种情况,说明是普通字符串,不预解析 + if (message.includes("欢迎连接到股票数据服务器")) { + console.log("服务器命令列表,不予处理"); + return; + } + if ((typeof message === "string" && message.includes("init_real_data_start")) || isMorePacket) { + if (typeof message === "string" && message.includes("init_real_data_start")) { + console.log("开始接受分包数据"); + receivedMessage = ""; + } else { + console.log("接收分包数据过程中"); + } + isMorePacket = true; + receivedMessage += message; + // 如果当前消息包含},说明收到JSON字符串结尾,结束接收,开始解析 + if (receivedMessage.includes("init_real_data_complete")) { + console.log("接受分包数据结束"); + isMorePacket = false; + + console.log("展示数据", receivedMessage); + // 获取JSON字符串的开头和结尾的坐标 + let jsonStartIndex = 0; + let jsonEndIndex = receivedMessage.indexOf("init_real_data_complete"); + let jsonStartCount = 0; + let jsonEndCount = 0; + for (let i = 0; i < receivedMessage.length - 1; ++i) { + if (receivedMessage[i] == "{") { + jsonStartCount++; + if (jsonStartCount == 2) { + jsonStartIndex = i; + break; + } + } + } + + for (let i = receivedMessage.indexOf("init_real_data_complete"); i >= 0; --i) { + if (receivedMessage[i] == "}" || i == jsonStartIndex) { + jsonEndCount++; + if (jsonEndCount == 1) { + jsonEndIndex = i; + break; + } + } + } + // 检查JSON字符串是否有效 + if (jsonStartIndex >= jsonEndIndex) { + throw new Error("JSON字符串格式错误"); + } + + console.log("检测到JSON字符串,开始解析"); + parsedMessage = JSON.parse(receivedMessage.substring(jsonStartIndex, jsonEndIndex + 1)); + console.log("JSON解析成功,解析后类型:", typeof parsedMessage, parsedMessage); + if (parsedMessage.type === "daily_data") { + timeData.value = parsedMessage.data; + stockInformation.value.lastDayStockClosePrice = parsedMessage.pre_close; + console.log("lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice); + drawChart(); + } + } + // 通过了JSON解析判断,说明返回的数据是需要的正确数据,进行股票实时数据检查 + console.log("开始处理解析后的数据"); + + // 检查是否是股票数据(支持batch_data_chunk和batch_realtime_data两种类型) + if ((parsedMessage.type === "batch_data_chunk" || parsedMessage.type === "batch_realtime_data") && parsedMessage.data) { + console.log("开始更新TCP股票数据存储"); + // 更新TCP股票数据存储 + tcpStockData.value = { + count: parsedMessage.count || 0, + data: parsedMessage.data || {}, + stock_count: parsedMessage.stock_count || 0, + timestamp: parsedMessage.timestamp || "", + type: parsedMessage.type || "", + }; + + // 获取第一个股票的数据用于显示 + const stockCodes = Object.keys(parsedMessage.data); + if (stockCodes.length > 0) { + const firstStockCode = stockCodes[0]; + + // 检查数据结构 + if (parsedMessage.data[firstStockCode] && Array.isArray(parsedMessage.data[firstStockCode]) && parsedMessage.data[firstStockCode].length > 0) { + const stockData = parsedMessage.data[firstStockCode][0]; // 取第一条数据 + + if (stockData && stockData.current_price !== undefined && stockData.pre_close !== undefined) { + // 计算涨跌幅 + const changeValue = stockData.current_price - stockData.pre_close; + const changePercent = ((changeValue / stockData.pre_close) * 100).toFixed(2); + const changeSign = changeValue >= 0 ? "+" : ""; + + // 更新当前显示的股票信息 + currentStockInfo.value = { + stock_name: stockData.stock_name || "未知股票", + current_price: stockData.current_price ? stockData.current_price.toFixed(2) : "0.00", + change: `${changeSign}${changePercent}%`, + change_value: changeValue, + change_percent: parseFloat(changePercent), + }; + + console.log("股票数据更新成功:", currentStockInfo.value); + } + } + } + } else { + console.log("不是batch_data_chunk或batch_realtime_data类型的消息,跳过处理"); + } + } else { + // 没有通过JSON解析判断,说明不是需要的数据 + console.log("不是需要的数据,不做处理"); + } + } catch (error) { + console.error("解析TCP股票数据失败:", error.message); + console.error("错误详情:", error); + } +}; + +// 移除TCP监听器 +const removeTcpListeners = () => { + if (connectionListener.value) { + tcpConnection.removeConnectionListener(connectionListener.value); + connectionListener.value = null; + console.log("已移除TCP连接状态监听器"); + } + + if (messageListener.value) { + tcpConnection.removeMessageListener(messageListener.value); + messageListener.value = null; + console.log("已移除TCP消息监听器"); + } +}; + // 定时器标识(用于清除定时器) let timer = null; let index = 0; @@ -1535,41 +1743,41 @@ const startAddDataTimer = () => { onLoad((options) => { console.log("页面接收到的参数:", options); - + // 处理通过data参数传递的复杂对象 if (options.data) { try { const stockData = JSON.parse(decodeURIComponent(options.data)); console.log("解析的股票数据:", stockData); - + // 更新stockInformation if (stockData) { - stockInformation.value.stockName=stockData.stockName; - stockInformation.value.stockCode=stockData.stockCode; + stockInformation.value.stockName = stockData.stockName; + stockInformation.value.stockCode = stockData.stockCode; } } catch (error) { console.error("解析股票数据失败:", error); } } - + // 处理通过stockInformation参数传递的数据(兼容globalIndex.vue的传参方式) if (options.stockInformation) { try { const stockData = JSON.parse(decodeURIComponent(options.stockInformation)); console.log("解析的股票信息:", stockData); - + // 更新stockInformation if (stockData) { stockInformation.value = { ...stockInformation.value, - ...stockData + ...stockData, }; } } catch (error) { console.error("解析股票信息失败:", error); } } - + // 处理简单参数 if (options.stockCode) { stockInformation.value.stockCode = options.stockCode; @@ -1589,39 +1797,43 @@ onUnmounted(() => { }); onMounted(async () => { - // 获取系统信息,处理高清屏 - const systemInfo = uni.getSystemInfoSync(); - pixelRatio.value = systemInfo.pixelRatio; - // 设置Canvas实际像素(考虑pixelRatio以获得高清效果) - // 1rpx = 设备屏幕宽度 / 750 - const rpxToPx = systemInfo.windowWidth / 750; - const offsetHeight = (150 + 200 + 80 + 150 + 30) * rpxToPx; // 350rpx转换为px - const calculatedHeight = systemInfo.windowHeight - offsetHeight; - canvasWidth.value = systemInfo.windowWidth; - canvasHeight.value = Math.max(calculatedHeight, canvasHeight.value); - // startTcp(); - // timeData.value = testTimeData; - timeData.value = testTimeData.slice(0, 100); - klineData.value = testKlineData; - // klineData.value = testKlineData.slice(-touchState.baseVisibleCount); - // 前一日收盘价 - let prevClosePrice = timeData.value[timeData.value.length - 2].price || stockInformation.value.closePrice; - stockInformation.value.lastDayStockClosePrice = prevClosePrice; - // 当前股价 - stockInformation.value.currentPrice = timeData.value[timeData.value.length - 1].price; - // 涨跌额度 - stockInformation.value.currentValue = stockInformation.value.currentPrice - stockInformation.value.lastDayStockClosePrice; - // 涨跌幅度 - stockInformation.value.currentRatio = ((stockInformation.value.currentPrice - stockInformation.value.lastDayStockClosePrice) / stockInformation.value.lastDayStockClosePrice) * 100; - // 成交量 - stockInformation.value.volume = timeData.value[timeData.value.length - 1].volume; - text[0][1].value = utils.formatPrice(stockInformation.value.currentPrice); - text[1][0].value = utils.formatStockNumber(stockInformation.value.volume); - - await nextTick(); - setTimeout(() => { + try { + console.log("步骤1: 初始化系统信息"); + const systemInfo = uni.getSystemInfoSync(); + pixelRatio.value = systemInfo.pixelRatio; + // 设置Canvas实际像素(考虑pixelRatio以获得高清效果) + // 1rpx = 设备屏幕宽度 / 750 + const rpxToPx = systemInfo.windowWidth / 750; + const offsetHeight = (150 + 200 + 80 + 150 + 30) * rpxToPx; // 350rpx转换为px + const calculatedHeight = systemInfo.windowHeight - offsetHeight; + canvasWidth.value = systemInfo.windowWidth; + canvasHeight.value = Math.max(calculatedHeight, canvasHeight.value); + + initTcpListeners(); + await nextTick(); + // 开始连接 + startTcp(); + + if (timeData.value && timeData.value.length > 0) { + // 当前股价 + stockInformation.value.currentPrice = timeData.value[timeData.value.length - 1].price; + // 涨跌额度 + stockInformation.value.currentValue = stockInformation.value.currentPrice - stockInformation.value.lastDayStockClosePrice; + // 涨跌幅度 + stockInformation.value.currentRatio = ((stockInformation.value.currentPrice - stockInformation.value.lastDayStockClosePrice) / stockInformation.value.lastDayStockClosePrice) * 100; + // 成交量 + stockInformation.value.volume = timeData.value[timeData.value.length - 1].volume; + text[0][1].value = utils.formatPrice(stockInformation.value.currentPrice); + text[1][0].value = utils.formatStockNumber(stockInformation.value.volume); + } else { + console.warn("没有时间数据,跳过股票信息计算"); + } + await nextTick(); initCanvas(); - }, 200); + console.log("所有初始化步骤完成"); + } catch (error) { + console.error("初始化过程中出现错误:", error); + } });