|
|
|
@ -82,24 +82,37 @@ |
|
|
|
<text class="section-title">我的自选</text> |
|
|
|
<text class="more-btn">添加自选股</text> |
|
|
|
</view> |
|
|
|
<!-- 我的自选TCP连接状态和控制 --> |
|
|
|
<!-- <view class="my-stocks-tcp-control"> |
|
|
|
<view class="tcp-status" :class="{'connected': myStocksTcpConnected, 'disconnected': !myStocksTcpConnected}"> |
|
|
|
<text class="status-text">{{myStocksTcpConnected ? '自选已连接' : '自选未连接'}}</text> |
|
|
|
</view> |
|
|
|
<view class="tcp-buttons"> |
|
|
|
<button class="tcp-btn connect-btn" @click="connectMyStocksTcp" :disabled="myStocksTcpConnected">连接</button> |
|
|
|
<button class="tcp-btn disconnect-btn" @click="disconnectMyStocksTcp" :disabled="!myStocksTcpConnected">断开</button> |
|
|
|
</view> |
|
|
|
</view> --> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 下部分:股票列表 --> |
|
|
|
<view class="stock-container"> |
|
|
|
<view class="stock-list"> |
|
|
|
<view class="stock-item" v-for="(item, index) in myStocks" :key="item.code"> |
|
|
|
<!-- 如果有TCP数据,显示实时数据;否则显示静态数据 --> |
|
|
|
<view class="stock-item" v-for="(item, index) in (myStocksInfoList.length > 0 ? myStocksInfoList : myStocks)" :key="item.code || item.stock_code"> |
|
|
|
<view class="stock-info"> |
|
|
|
<view class="name-container"> |
|
|
|
<text class="stock-name">{{item.name}}</text> |
|
|
|
<text class="stock-code-label">{{item.code}}</text> |
|
|
|
<text class="stock-name">{{item.name || item.stock_name}}</text> |
|
|
|
<text class="stock-code-label">{{item.code || item.stock_code}}</text> |
|
|
|
</view> |
|
|
|
<view class="price-container"> |
|
|
|
<text class="stock-price">{{item.price}}</text> |
|
|
|
<text class="stock-change" :class="{'stock-up': item.change > 0, 'stock-down': item.change < 0}">{{item.change > 0 ? '+' : ''}}{{item.change}}%</text> |
|
|
|
<text class="stock-price">{{item.price || item.current_price}}</text> |
|
|
|
<text class="stock-change" :class="{'stock-up': (item.change_percent || item.change || item.change_amount || 0) > 0, 'stock-down': (item.change_percent || item.change || item.change_amount || 0) < 0}"> |
|
|
|
{{(item.change_percent || item.change || item.change_amount || 0) > 0 ? '+' : ''}}{{(parseFloat(item.change_percent || item.change || item.change_amount || 0)).toFixed(2)}}% |
|
|
|
</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<view class="stock-chart"> |
|
|
|
<image :src="item.chartImg" mode="aspectFit" class="chart-image"></image> |
|
|
|
<image :src="item.chartImg || '/static/c5.png'" mode="aspectFit" class="chart-image"></image> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
@ -222,6 +235,9 @@ export default { |
|
|
|
tcpMessages: [], |
|
|
|
lastSentMessage: '', |
|
|
|
|
|
|
|
// 我的自选TCP连接状态 |
|
|
|
myStocksTcpConnected: false, |
|
|
|
|
|
|
|
// TCP监听器引用,用于移除监听器 |
|
|
|
connectionListener: null, |
|
|
|
messageListener: null, |
|
|
|
@ -235,6 +251,15 @@ export default { |
|
|
|
type: '' |
|
|
|
}, |
|
|
|
|
|
|
|
// 我的自选TCP股票数据存储 |
|
|
|
myStocksTcpData: { |
|
|
|
count: 0, |
|
|
|
data: {}, |
|
|
|
stock_count: 0, |
|
|
|
timestamp: '', |
|
|
|
type: '' |
|
|
|
}, |
|
|
|
|
|
|
|
// TCP数据缓存机制,用于处理分片数据 |
|
|
|
tcpDataCache: { |
|
|
|
isCollecting: false, // 是否正在收集数据片段 |
|
|
|
@ -247,6 +272,18 @@ export default { |
|
|
|
isWaitingSecondPart: false // 是否正在等待后半部分数据 |
|
|
|
}, |
|
|
|
|
|
|
|
// 我的自选TCP数据缓存机制,用于处理分片数据 |
|
|
|
myStocksTcpDataCache: { |
|
|
|
isCollecting: false, // 是否正在收集数据片段 |
|
|
|
expectedCount: 0, // 期望的数据总数 |
|
|
|
collectedData: {}, // 已收集的数据对象(用于对象级拼接) |
|
|
|
timestamp: '', // 数据时间戳 |
|
|
|
type: '', // 数据类型 |
|
|
|
// 字符串片段缓存 |
|
|
|
firstPartData: '', // 前半部分数据字符串 |
|
|
|
isWaitingSecondPart: false // 是否正在等待后半部分数据 |
|
|
|
}, |
|
|
|
|
|
|
|
// 当前显示的3个股票数据(用于MarketOverview组件) |
|
|
|
currentStockInfoList: [ |
|
|
|
{ |
|
|
|
@ -270,7 +307,10 @@ export default { |
|
|
|
change_value: 0, |
|
|
|
change_percent: 0 |
|
|
|
} |
|
|
|
] |
|
|
|
], |
|
|
|
|
|
|
|
// 我的自选处理后的股票信息列表 |
|
|
|
myStocksInfoList: [] |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
@ -297,22 +337,50 @@ export default { |
|
|
|
// 初始化TCP连接监听器 |
|
|
|
this.initTcpListeners() |
|
|
|
|
|
|
|
// 页面渲染完成后自动连接TCP |
|
|
|
// 页面渲染完成后自动连接两个TCP连接 |
|
|
|
this.$nextTick(() => { |
|
|
|
console.log('页面渲染完成,开始自动连接TCP服务器...') |
|
|
|
this.connectTcp() |
|
|
|
// 延迟一小段时间确保页面完全加载后再连接 |
|
|
|
setTimeout(() => { |
|
|
|
// 连接今日市场概览TCP(channel 1) |
|
|
|
console.log('连接今日市场概览TCP(channel 1)...') |
|
|
|
this.connectTcp() |
|
|
|
|
|
|
|
// 稍微延迟后连接我的自选TCP(channel 2) |
|
|
|
setTimeout(() => { |
|
|
|
console.log('连接我的自选TCP(channel 2)...') |
|
|
|
this.connectMyStocksTcp() |
|
|
|
}, 500) |
|
|
|
}, 1000) |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
// 页面销毁前的清理工作 |
|
|
|
onUnload() { |
|
|
|
// 自动关闭TCP连接 |
|
|
|
// 自动关闭主TCP连接 |
|
|
|
if (this.tcpConnected) { |
|
|
|
console.log('页面销毁,自动关闭TCP连接') |
|
|
|
tcpConnection.disconnect() |
|
|
|
console.log('页面销毁,自动关闭主TCP连接') |
|
|
|
tcpConnection.disconnect({ |
|
|
|
ip: '192.168.1.9', |
|
|
|
port: '8080', |
|
|
|
channel: '1', |
|
|
|
charsetname: 'UTF-8' |
|
|
|
}) |
|
|
|
this.tcpConnected = false |
|
|
|
} |
|
|
|
|
|
|
|
// 自动关闭我的自选TCP连接 |
|
|
|
if (this.myStocksTcpConnected) { |
|
|
|
console.log('页面销毁,自动关闭我的自选TCP连接') |
|
|
|
tcpConnection.disconnect({ |
|
|
|
ip: '192.168.1.9', |
|
|
|
port: '8080', |
|
|
|
channel: '2', |
|
|
|
charsetname: 'UTF-8' |
|
|
|
}) |
|
|
|
this.myStocksTcpConnected = false |
|
|
|
} |
|
|
|
|
|
|
|
// 清理防抖定时器 |
|
|
|
if (this.debounceTimer) { |
|
|
|
clearTimeout(this.debounceTimer) |
|
|
|
@ -338,43 +406,79 @@ export default { |
|
|
|
// 初始化TCP监听器 |
|
|
|
initTcpListeners() { |
|
|
|
// 创建连接状态监听器并保存引用 |
|
|
|
this.connectionListener = (status, result) => { |
|
|
|
this.tcpConnected = (status === 'connected') |
|
|
|
console.log('TCP连接状态变化:', status, this.tcpConnected) |
|
|
|
|
|
|
|
// 显示连接状态提示 |
|
|
|
uni.showToast({ |
|
|
|
title: status === 'connected' ? '连接服务器成功' : '服务器连接断开', |
|
|
|
icon: status === 'connected' ? 'success' : 'none', |
|
|
|
duration: 1000 |
|
|
|
}) |
|
|
|
|
|
|
|
// 连接成功后自动发送股票数据请求命令 |
|
|
|
if (status === 'connected') { |
|
|
|
console.log('TCP连接成功,自动发送股票数据请求...') |
|
|
|
// 延迟一小段时间确保连接稳定后再发送命令 |
|
|
|
setTimeout(() => { |
|
|
|
this.sendTcpMessage() |
|
|
|
}, 500) |
|
|
|
this.connectionListener = (status, result, channel) => { |
|
|
|
console.log('TCP连接状态变化:', status, 'channel:', channel) |
|
|
|
|
|
|
|
// 根据channel更新对应的连接状态 |
|
|
|
if (channel === '1') { |
|
|
|
// 主TCP连接 |
|
|
|
this.tcpConnected = (status === 'connected') |
|
|
|
console.log('主TCP连接状态:', this.tcpConnected) |
|
|
|
|
|
|
|
// 显示连接状态提示 |
|
|
|
uni.showToast({ |
|
|
|
title: status === 'connected' ? '主连接服务器成功' : '主服务器连接断开', |
|
|
|
icon: status === 'connected' ? 'success' : 'none', |
|
|
|
duration: 1000 |
|
|
|
}) |
|
|
|
|
|
|
|
// 连接成功后自动发送股票数据请求命令 |
|
|
|
if (status === 'connected') { |
|
|
|
console.log('主TCP连接成功,自动发送股票数据请求...') |
|
|
|
// 延迟一小段时间确保连接稳定后再发送命令 |
|
|
|
setTimeout(() => { |
|
|
|
this.sendTcpMessage() |
|
|
|
}, 500) |
|
|
|
} |
|
|
|
} else if (channel === '2') { |
|
|
|
// 我的自选TCP连接 |
|
|
|
this.myStocksTcpConnected = (status === 'connected') |
|
|
|
console.log('我的自选TCP连接状态:', this.myStocksTcpConnected) |
|
|
|
|
|
|
|
// 显示连接状态提示 |
|
|
|
uni.showToast({ |
|
|
|
title: status === 'connected' ? '我的自选连接成功' : '我的自选连接断开', |
|
|
|
icon: status === 'connected' ? 'success' : 'none', |
|
|
|
duration: 1000 |
|
|
|
}) |
|
|
|
|
|
|
|
// 连接成功后自动发送我的自选股票数据请求 |
|
|
|
if (status === 'connected') { |
|
|
|
console.log('我的自选TCP连接成功,自动发送自选股票数据请求...') |
|
|
|
// 延迟一小段时间确保连接稳定后再发送命令 |
|
|
|
setTimeout(() => { |
|
|
|
this.sendMyStocksTcpMessage() |
|
|
|
}, 500) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 创建消息监听器并保存引用 |
|
|
|
this.messageListener = (type, message, parsedArray) => { |
|
|
|
this.messageListener = (type, message, parsedArray, channel) => { |
|
|
|
const messageObj = { |
|
|
|
type: type, |
|
|
|
content: message, |
|
|
|
parsedArray: parsedArray, |
|
|
|
channel: channel, |
|
|
|
timestamp: new Date().toLocaleTimeString(), |
|
|
|
direction: 'received' |
|
|
|
} |
|
|
|
console.log("0000") |
|
|
|
this.tcpMessages.push(messageObj) |
|
|
|
// console.log('收到TCP消息:', messageObj) |
|
|
|
console.log('home开始调用parseStockData',messageObj) |
|
|
|
|
|
|
|
// 解析股票数据 |
|
|
|
this.parseStockData(message) |
|
|
|
console.log('收到TCP消息:', messageObj) |
|
|
|
console.log('消息来源channel:', channel) |
|
|
|
|
|
|
|
// 根据channel调用相应的数据处理方法 |
|
|
|
if (channel === '1') { |
|
|
|
// 主TCP连接 - 今日市场概览数据 |
|
|
|
// console.log('处理今日市场概览数据') |
|
|
|
this.parseStockData(message) |
|
|
|
} else if (channel === '2') { |
|
|
|
// 我的自选TCP连接 - 我的自选数据 |
|
|
|
console.log('处理我的自选数据') |
|
|
|
this.parseMyStocksData(message) |
|
|
|
} else { |
|
|
|
console.warn('未知的channel:', channel) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 注册监听器 |
|
|
|
@ -384,11 +488,11 @@ export default { |
|
|
|
|
|
|
|
// 连接TCP服务器 |
|
|
|
connectTcp() { |
|
|
|
console.log('开始连接TCP服务器...') |
|
|
|
// console.log('开始连接TCP服务器...') |
|
|
|
|
|
|
|
// 先断开现有连接(如果存在) |
|
|
|
if (this.tcpConnected) { |
|
|
|
console.log('检测到现有连接,先断开...') |
|
|
|
// console.log('检测到现有连接,先断开...') |
|
|
|
this.disconnectTcp() |
|
|
|
// 等待断开完成后再连接 |
|
|
|
setTimeout(() => { |
|
|
|
@ -402,7 +506,7 @@ export default { |
|
|
|
|
|
|
|
// 执行TCP连接 |
|
|
|
performTcpConnect() { |
|
|
|
console.log('执行TCP连接...') |
|
|
|
// console.log('执行TCP连接...') |
|
|
|
tcpConnection.connect( |
|
|
|
{ |
|
|
|
ip: '192.168.1.9', |
|
|
|
@ -415,7 +519,7 @@ export default { |
|
|
|
|
|
|
|
// 断开TCP连接 |
|
|
|
disconnectTcp() { |
|
|
|
console.log('断开TCP连接...') |
|
|
|
// console.log('断开TCP连接...') |
|
|
|
tcpConnection.disconnect( |
|
|
|
{ |
|
|
|
ip: '192.168.1.9', |
|
|
|
@ -427,6 +531,321 @@ export default { |
|
|
|
this.tcpConnected = false |
|
|
|
}, |
|
|
|
|
|
|
|
// 连接我的自选TCP服务器 |
|
|
|
connectMyStocksTcp() { |
|
|
|
console.log('开始连接我的自选TCP服务器...') |
|
|
|
|
|
|
|
// 先断开现有连接(如果存在) |
|
|
|
if (this.myStocksTcpConnected) { |
|
|
|
console.log('检测到我的自选现有连接,先断开...') |
|
|
|
this.disconnectMyStocksTcp() |
|
|
|
// 等待断开完成后再连接 |
|
|
|
setTimeout(() => { |
|
|
|
this.performMyStocksTcpConnect() |
|
|
|
}, 500) |
|
|
|
} else { |
|
|
|
// 直接连接 |
|
|
|
this.performMyStocksTcpConnect() |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 执行我的自选TCP连接 |
|
|
|
performMyStocksTcpConnect() { |
|
|
|
console.log('执行我的自选TCP连接...') |
|
|
|
tcpConnection.connect( |
|
|
|
{ |
|
|
|
ip: '192.168.1.9', |
|
|
|
port: '8080', |
|
|
|
channel: '2', // 我的自选使用channel 2 |
|
|
|
charsetname: 'UTF-8' // 默认UTF-8,可选GBK |
|
|
|
} |
|
|
|
) |
|
|
|
}, |
|
|
|
|
|
|
|
// 断开我的自选TCP连接 |
|
|
|
disconnectMyStocksTcp() { |
|
|
|
console.log('断开我的自选TCP连接...') |
|
|
|
tcpConnection.disconnect( |
|
|
|
{ |
|
|
|
ip: '192.168.1.9', |
|
|
|
port: '8080', |
|
|
|
channel: '2', // 我的自选使用channel 2 |
|
|
|
charsetname: 'UTF-8' // 默认UTF-8,可选GBK |
|
|
|
} |
|
|
|
) |
|
|
|
this.myStocksTcpConnected = false |
|
|
|
}, |
|
|
|
|
|
|
|
// 解析我的自选TCP股票数据 |
|
|
|
parseMyStocksData(message) { |
|
|
|
try { |
|
|
|
console.log('进入parseMyStocksData, message类型:', typeof message, '长度:', message.length) |
|
|
|
|
|
|
|
// 第一步:检查数据状态(完整、前半部分、后半部分) |
|
|
|
const dataStatus = this.getMyStocksDataStatus(message) |
|
|
|
|
|
|
|
let completeMessage = '' |
|
|
|
|
|
|
|
switch (dataStatus) { |
|
|
|
case 'complete': |
|
|
|
// 完整数据,直接处理 |
|
|
|
console.log('我的自选:检测到完整数据,直接处理') |
|
|
|
completeMessage = message |
|
|
|
break |
|
|
|
|
|
|
|
case 'first_part': |
|
|
|
// 前半部分数据,缓存并等待后半部分 |
|
|
|
console.log('我的自选:检测到前半部分数据,开始缓存') |
|
|
|
this.cacheMyStocksFirstPartData(message) |
|
|
|
return // 等待后半部分数据 |
|
|
|
|
|
|
|
case 'second_part': |
|
|
|
// 后半部分数据,检查是否有缓存的前半部分 |
|
|
|
if (this.myStocksTcpDataCache.isWaitingSecondPart) { |
|
|
|
console.log('我的自选:检测到后半部分数据,开始拼接') |
|
|
|
completeMessage = this.concatenateMyStocksDataParts(message) |
|
|
|
} else { |
|
|
|
console.log('我的自选:收到后半部分数据,但没有缓存的前半部分,跳过处理') |
|
|
|
return |
|
|
|
} |
|
|
|
break |
|
|
|
|
|
|
|
case 'invalid': |
|
|
|
default: |
|
|
|
console.log('我的自选:数据格式无效,跳过处理') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 第二步:解析完整的JSON数据 |
|
|
|
let parsedMessage |
|
|
|
try { |
|
|
|
console.log('我的自选:开始解析完整JSON数据,长度:', completeMessage.length) |
|
|
|
parsedMessage = JSON.parse(completeMessage) |
|
|
|
console.log('我的自选:JSON解析成功,解析后类型:', typeof parsedMessage, parsedMessage) |
|
|
|
} catch (parseError) { |
|
|
|
console.error('我的自选:JSON解析失败:', parseError.message) |
|
|
|
// 清空字符串片段缓存 |
|
|
|
this.clearMyStocksStringFragmentCache() |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 第三步:检查是否是股票数据类型 |
|
|
|
if (!((parsedMessage.type === 'batch_data_chunk' || parsedMessage.type === 'batch_realtime_data') && parsedMessage.data)) { |
|
|
|
console.log('我的自选:不是batch_data_chunk或batch_realtime_data类型的消息,跳过处理') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
console.log('我的自选:开始处理股票数据') |
|
|
|
|
|
|
|
// 第四步:验证数据完整性(对象级别的完整性检查) |
|
|
|
// 注意:batch_data_chunk类型的数据不需要验证完整性,直接处理 |
|
|
|
if (parsedMessage.type === 'batch_data_chunk') { |
|
|
|
console.log('我的自选:batch_data_chunk类型数据,跳过完整性验证,直接处理') |
|
|
|
this.processCompleteMyStocksData(parsedMessage) |
|
|
|
} else { |
|
|
|
const isDataComplete = this.validateMyStocksDataIntegrity(parsedMessage) |
|
|
|
|
|
|
|
if (isDataComplete) { |
|
|
|
// 数据完整,直接处理 |
|
|
|
console.log('我的自选:对象级数据完整,直接处理') |
|
|
|
this.processCompleteMyStocksData(parsedMessage) |
|
|
|
} else { |
|
|
|
// 数据不完整,需要拼接(对象级别的拼接) |
|
|
|
console.log('我的自选:对象级数据不完整,开始拼接处理') |
|
|
|
|
|
|
|
// 将当前数据合并到缓存中 |
|
|
|
this.mergeMyStocksDataToCache(parsedMessage) |
|
|
|
|
|
|
|
// 检查缓存中的数据是否已经完整 |
|
|
|
if (this.isMyStocksCacheDataComplete()) { |
|
|
|
console.log('我的自选:缓存数据已完整,开始处理') |
|
|
|
const completeData = this.getCompleteMyStocksDataFromCache() |
|
|
|
this.processCompleteMyStocksData(completeData) |
|
|
|
} else { |
|
|
|
console.log('我的自选:缓存数据仍不完整,等待更多数据片段') |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('我的自选:解析TCP股票数据失败:', error.message) |
|
|
|
console.error('我的自选:错误详情:', error) |
|
|
|
// 发生错误时清空所有缓存 |
|
|
|
this.clearMyStocksStringFragmentCache() |
|
|
|
if (this.myStocksTcpDataCache.isCollecting) { |
|
|
|
console.log('我的自选:发生错误,清空对象级数据缓存') |
|
|
|
this.myStocksTcpDataCache.isCollecting = false |
|
|
|
this.myStocksTcpDataCache.expectedCount = 0 |
|
|
|
this.myStocksTcpDataCache.collectedData = {} |
|
|
|
this.myStocksTcpDataCache.timestamp = '' |
|
|
|
this.myStocksTcpDataCache.type = '' |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 验证我的自选数据完整性 |
|
|
|
validateMyStocksDataIntegrity(parsedMessage) { |
|
|
|
if (!parsedMessage.count || !parsedMessage.data) { |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
const dataObjectCount = Object.keys(parsedMessage.data).length |
|
|
|
const expectedCount = parsedMessage.count |
|
|
|
|
|
|
|
console.log(`我的自选数据完整性验证: 期望${expectedCount}个对象,实际${dataObjectCount}个对象`) |
|
|
|
return dataObjectCount === expectedCount |
|
|
|
}, |
|
|
|
|
|
|
|
// 检查我的自选数据状态(完整数据、前半部分数据、后半部分数据) |
|
|
|
getMyStocksDataStatus(message) { |
|
|
|
if (typeof message !== 'string') { |
|
|
|
return 'invalid' |
|
|
|
} |
|
|
|
|
|
|
|
const trimmedMessage = message.trim() |
|
|
|
const startsWithBrace = trimmedMessage.startsWith('{') |
|
|
|
const endsWithBrace = trimmedMessage.endsWith('}') |
|
|
|
|
|
|
|
if (startsWithBrace && endsWithBrace) { |
|
|
|
// 以{开头,以}结尾 - 完整数据 |
|
|
|
console.log('我的自选:检测到完整数据格式') |
|
|
|
return 'complete' |
|
|
|
} else if (startsWithBrace && !endsWithBrace) { |
|
|
|
// 以{开头,不以}结尾 - 前半部分数据 |
|
|
|
console.log('我的自选:检测到前半部分数据') |
|
|
|
return 'first_part' |
|
|
|
} else if (!startsWithBrace && endsWithBrace) { |
|
|
|
// 不以{开头,以}结尾 - 后半部分数据 |
|
|
|
console.log('我的自选:检测到后半部分数据') |
|
|
|
return 'second_part' |
|
|
|
} else { |
|
|
|
// 其他情况 - 无效数据 |
|
|
|
console.log('我的自选:检测到无效数据格式') |
|
|
|
return 'invalid' |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 缓存我的自选前半部分数据 |
|
|
|
cacheMyStocksFirstPartData(message) { |
|
|
|
this.myStocksTcpDataCache.firstPartData = message.trim() |
|
|
|
this.myStocksTcpDataCache.isWaitingSecondPart = true |
|
|
|
console.log('我的自选:已缓存前半部分数据,长度:', this.myStocksTcpDataCache.firstPartData.length) |
|
|
|
}, |
|
|
|
|
|
|
|
// 拼接我的自选前后两部分数据 |
|
|
|
concatenateMyStocksDataParts(secondPartMessage) { |
|
|
|
const completeMessage = this.myStocksTcpDataCache.firstPartData + secondPartMessage.trim() |
|
|
|
console.log('我的自选:数据拼接完成,完整数据长度:', completeMessage.length) |
|
|
|
|
|
|
|
// 清空缓存 |
|
|
|
this.clearMyStocksStringFragmentCache() |
|
|
|
|
|
|
|
return completeMessage |
|
|
|
}, |
|
|
|
|
|
|
|
// 清空我的自选字符串片段缓存 |
|
|
|
clearMyStocksStringFragmentCache() { |
|
|
|
this.myStocksTcpDataCache.firstPartData = '' |
|
|
|
this.myStocksTcpDataCache.isWaitingSecondPart = false |
|
|
|
console.log('我的自选:字符串片段缓存已清空') |
|
|
|
}, |
|
|
|
|
|
|
|
// 合并我的自选数据到缓存中 |
|
|
|
mergeMyStocksDataToCache(parsedMessage) { |
|
|
|
// 如果是第一次收集数据,初始化缓存 |
|
|
|
if (!this.myStocksTcpDataCache.isCollecting) { |
|
|
|
this.myStocksTcpDataCache.isCollecting = true |
|
|
|
this.myStocksTcpDataCache.expectedCount = parsedMessage.count |
|
|
|
this.myStocksTcpDataCache.collectedData = {} |
|
|
|
this.myStocksTcpDataCache.timestamp = parsedMessage.timestamp |
|
|
|
this.myStocksTcpDataCache.type = parsedMessage.type |
|
|
|
console.log('我的自选:开始收集数据片段,期望总数:', parsedMessage.count) |
|
|
|
} |
|
|
|
|
|
|
|
// 合并新数据到缓存中 |
|
|
|
if (parsedMessage.data) { |
|
|
|
Object.assign(this.myStocksTcpDataCache.collectedData, parsedMessage.data) |
|
|
|
console.log('我的自选:数据片段已合并,当前已收集:', Object.keys(this.myStocksTcpDataCache.collectedData).length, '个对象') |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 检查我的自选缓存数据是否完整 |
|
|
|
isMyStocksCacheDataComplete() { |
|
|
|
const collectedCount = Object.keys(this.myStocksTcpDataCache.collectedData).length |
|
|
|
const expectedCount = this.myStocksTcpDataCache.expectedCount |
|
|
|
|
|
|
|
console.log(`我的自选缓存数据检查: 已收集${collectedCount}个,期望${expectedCount}个`) |
|
|
|
return collectedCount === expectedCount && collectedCount > 0 |
|
|
|
}, |
|
|
|
|
|
|
|
// 获取我的自选完整的缓存数据并清空缓存 |
|
|
|
getCompleteMyStocksDataFromCache() { |
|
|
|
const completeData = { |
|
|
|
count: this.myStocksTcpDataCache.expectedCount, |
|
|
|
data: { ...this.myStocksTcpDataCache.collectedData }, |
|
|
|
stock_count: this.myStocksTcpDataCache.expectedCount, |
|
|
|
timestamp: this.myStocksTcpDataCache.timestamp, |
|
|
|
type: this.myStocksTcpDataCache.type |
|
|
|
} |
|
|
|
|
|
|
|
// 清空缓存 |
|
|
|
this.myStocksTcpDataCache.isCollecting = false |
|
|
|
this.myStocksTcpDataCache.expectedCount = 0 |
|
|
|
this.myStocksTcpDataCache.collectedData = {} |
|
|
|
this.myStocksTcpDataCache.timestamp = '' |
|
|
|
this.myStocksTcpDataCache.type = '' |
|
|
|
|
|
|
|
console.log('我的自选:获取完整数据并清空缓存,数据对象数:', Object.keys(completeData.data).length) |
|
|
|
return completeData |
|
|
|
}, |
|
|
|
|
|
|
|
// 处理我的自选完整的股票数据 |
|
|
|
processCompleteMyStocksData(completeData) { |
|
|
|
console.log("我的自选:开始更新我的自选TCP股票数据存储") |
|
|
|
|
|
|
|
// 更新我的自选TCP股票数据存储 |
|
|
|
this.myStocksTcpData = { |
|
|
|
count: completeData.count || 0, |
|
|
|
data: completeData.data || {}, |
|
|
|
stock_count: completeData.stock_count || 0, |
|
|
|
timestamp: completeData.timestamp || '', |
|
|
|
type: completeData.type || '' |
|
|
|
} |
|
|
|
|
|
|
|
// 获取所有股票的数据用于显示 |
|
|
|
const stockCodes = Object.keys(completeData.data) |
|
|
|
const newMyStocksInfoList = [] |
|
|
|
|
|
|
|
// 只处理前3条股票数据 |
|
|
|
const maxStocks = Math.min(3, stockCodes.length) |
|
|
|
for (let i = 0; i < maxStocks; i++) { |
|
|
|
const stockCode = stockCodes[i] |
|
|
|
|
|
|
|
// 检查数据结构 |
|
|
|
if (completeData.data[stockCode] && Array.isArray(completeData.data[stockCode]) && completeData.data[stockCode].length > 0) { |
|
|
|
const stockData = completeData.data[stockCode][0] // 取第一条数据 |
|
|
|
console.log('遍历的数据:', stockCode, stockData) |
|
|
|
|
|
|
|
if (stockData && stockData.current_price !== undefined) { |
|
|
|
// 直接使用返回的数据,不重新计算 |
|
|
|
newMyStocksInfoList.push({ |
|
|
|
stock_code: stockCode, |
|
|
|
stock_name: stockData.stock_name || '未知股票', |
|
|
|
current_price: parseFloat(stockData.current_price).toFixed(2), |
|
|
|
change: stockData.change || '0.00%', |
|
|
|
change_value: stockData.change_value || 0, |
|
|
|
change_percent: parseFloat(stockData.change) || 0 |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 更新我的自选股票信息列表 |
|
|
|
if (newMyStocksInfoList.length > 0) { |
|
|
|
this.myStocksInfoList = newMyStocksInfoList |
|
|
|
console.log('我的自选:股票数据更新成功,共', newMyStocksInfoList.length, '个股票:', this.myStocksInfoList) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 发送TCP消息 |
|
|
|
sendTcpMessage() { |
|
|
|
// 构造要发送的消息对象 |
|
|
|
@ -442,7 +861,7 @@ export default { |
|
|
|
// 发送消息 |
|
|
|
const success = tcpConnection.send(messageData) |
|
|
|
if (success) { |
|
|
|
console.log('home发送TCP消息:', messageData) |
|
|
|
// console.log('home发送TCP消息:', messageData) |
|
|
|
uni.showToast({ |
|
|
|
title: '服务器连接成功', |
|
|
|
icon: 'success', |
|
|
|
@ -451,6 +870,30 @@ export default { |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 发送我的自选TCP消息 |
|
|
|
sendMyStocksTcpMessage() { |
|
|
|
// 构造要发送的消息对象 - 我的自选股票数据请求 |
|
|
|
const messageData = {"command": "batch_real_time", "stock_codes": ["SH.000001","SH.000002","SH.000003"]} |
|
|
|
|
|
|
|
// 发送消息到channel 2(我的自选TCP连接) |
|
|
|
const success = tcpConnection.send(messageData, { channel: '2' }) |
|
|
|
if (success) { |
|
|
|
console.log('我的自选:发送TCP消息成功:', messageData) |
|
|
|
uni.showToast({ |
|
|
|
title: '我的自选数据请求已发送', |
|
|
|
icon: 'success', |
|
|
|
duration: 1500 |
|
|
|
}) |
|
|
|
} else { |
|
|
|
console.error('我的自选:发送TCP消息失败') |
|
|
|
uni.showToast({ |
|
|
|
title: '我的自选连接失败', |
|
|
|
icon: 'error', |
|
|
|
duration: 1500 |
|
|
|
}) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
// 清空消息记录 |
|
|
|
clearTcpMessages() { |
|
|
|
@ -481,7 +924,7 @@ export default { |
|
|
|
const dataObjectCount = Object.keys(parsedMessage.data).length |
|
|
|
const expectedCount = parsedMessage.count |
|
|
|
|
|
|
|
console.log(`数据完整性验证: 期望${expectedCount}个对象,实际${dataObjectCount}个对象`) |
|
|
|
// console.log(`数据完整性验证: 期望${expectedCount}个对象,实际${dataObjectCount}个对象`) |
|
|
|
return dataObjectCount === expectedCount |
|
|
|
}, |
|
|
|
|
|
|
|
@ -497,19 +940,19 @@ export default { |
|
|
|
|
|
|
|
if (startsWithBrace && endsWithBrace) { |
|
|
|
// 以{开头,以}结尾 - 完整数据 |
|
|
|
console.log('检测到完整数据格式') |
|
|
|
// console.log('检测到完整数据格式') |
|
|
|
return 'complete' |
|
|
|
} else if (startsWithBrace && !endsWithBrace) { |
|
|
|
// 以{开头,不以}结尾 - 前半部分数据 |
|
|
|
console.log('检测到前半部分数据') |
|
|
|
// console.log('检测到前半部分数据') |
|
|
|
return 'first_part' |
|
|
|
} else if (!startsWithBrace && endsWithBrace) { |
|
|
|
// 不以{开头,以}结尾 - 后半部分数据 |
|
|
|
console.log('检测到后半部分数据') |
|
|
|
// console.log('检测到后半部分数据') |
|
|
|
return 'second_part' |
|
|
|
} else { |
|
|
|
// 其他情况 - 无效数据 |
|
|
|
console.log('检测到无效数据格式') |
|
|
|
// console.log('检测到无效数据格式') |
|
|
|
return 'invalid' |
|
|
|
|
|
|
|
} |
|
|
|
@ -519,13 +962,13 @@ export default { |
|
|
|
cacheFirstPartData(message) { |
|
|
|
this.tcpDataCache.firstPartData = message.trim() |
|
|
|
this.tcpDataCache.isWaitingSecondPart = true |
|
|
|
console.log('已缓存前半部分数据,长度:', this.tcpDataCache.firstPartData.length) |
|
|
|
// console.log('已缓存前半部分数据,长度:', this.tcpDataCache.firstPartData.length) |
|
|
|
}, |
|
|
|
|
|
|
|
// 拼接前后两部分数据 |
|
|
|
concatenateDataParts(secondPartMessage) { |
|
|
|
const completeMessage = this.tcpDataCache.firstPartData + secondPartMessage.trim() |
|
|
|
console.log('数据拼接完成,完整数据长度:', completeMessage.length) |
|
|
|
// console.log('数据拼接完成,完整数据长度:', completeMessage.length) |
|
|
|
|
|
|
|
// 清空缓存 |
|
|
|
this.clearStringFragmentCache() |
|
|
|
@ -537,7 +980,7 @@ export default { |
|
|
|
clearStringFragmentCache() { |
|
|
|
this.tcpDataCache.firstPartData = '' |
|
|
|
this.tcpDataCache.isWaitingSecondPart = false |
|
|
|
console.log('字符串片段缓存已清空') |
|
|
|
// console.log('字符串片段缓存已清空') |
|
|
|
}, |
|
|
|
|
|
|
|
// 合并数据到缓存中 |
|
|
|
@ -549,13 +992,13 @@ export default { |
|
|
|
this.tcpDataCache.collectedData = {} |
|
|
|
this.tcpDataCache.timestamp = parsedMessage.timestamp |
|
|
|
this.tcpDataCache.type = parsedMessage.type |
|
|
|
console.log('开始收集数据片段,期望总数:', parsedMessage.count) |
|
|
|
// console.log('开始收集数据片段,期望总数:', parsedMessage.count) |
|
|
|
} |
|
|
|
|
|
|
|
// 合并新数据到缓存中 |
|
|
|
if (parsedMessage.data) { |
|
|
|
Object.assign(this.tcpDataCache.collectedData, parsedMessage.data) |
|
|
|
console.log('数据片段已合并,当前已收集:', Object.keys(this.tcpDataCache.collectedData).length, '个对象') |
|
|
|
// console.log('数据片段已合并,当前已收集:', Object.keys(this.tcpDataCache.collectedData).length, '个对象') |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
@ -564,7 +1007,7 @@ export default { |
|
|
|
const collectedCount = Object.keys(this.tcpDataCache.collectedData).length |
|
|
|
const expectedCount = this.tcpDataCache.expectedCount |
|
|
|
|
|
|
|
console.log(`缓存数据检查: 已收集${collectedCount}个,期望${expectedCount}个`) |
|
|
|
// console.log(`缓存数据检查: 已收集${collectedCount}个,期望${expectedCount}个`) |
|
|
|
return collectedCount === expectedCount && collectedCount > 0 |
|
|
|
}, |
|
|
|
|
|
|
|
@ -585,14 +1028,14 @@ export default { |
|
|
|
this.tcpDataCache.timestamp = '' |
|
|
|
this.tcpDataCache.type = '' |
|
|
|
|
|
|
|
console.log('获取完整数据并清空缓存,数据对象数:', Object.keys(completeData.data).length) |
|
|
|
// console.log('获取完整数据并清空缓存,数据对象数:', Object.keys(completeData.data).length) |
|
|
|
return completeData |
|
|
|
}, |
|
|
|
|
|
|
|
// 解析TCP股票数据 |
|
|
|
parseStockData(message) { |
|
|
|
try { |
|
|
|
console.log('进入parseStockData, message类型:', typeof message, '长度:', message.length) |
|
|
|
// console.log('进入parseStockData, message类型:', typeof message, '长度:', message.length) |
|
|
|
|
|
|
|
// 第一步:检查数据状态(完整、前半部分、后半部分) |
|
|
|
const dataStatus = this.getDataStatus(message) |
|
|
|
@ -602,41 +1045,41 @@ export default { |
|
|
|
switch (dataStatus) { |
|
|
|
case 'complete': |
|
|
|
// 完整数据,直接处理 |
|
|
|
console.log('检测到完整数据,直接处理') |
|
|
|
// console.log('检测到完整数据,直接处理') |
|
|
|
completeMessage = message |
|
|
|
break |
|
|
|
|
|
|
|
case 'first_part': |
|
|
|
// 前半部分数据,缓存并等待后半部分 |
|
|
|
console.log('检测到前半部分数据,开始缓存') |
|
|
|
// console.log('检测到前半部分数据,开始缓存') |
|
|
|
this.cacheFirstPartData(message) |
|
|
|
return // 等待后半部分数据 |
|
|
|
|
|
|
|
case 'second_part': |
|
|
|
// 后半部分数据,检查是否有缓存的前半部分 |
|
|
|
if (this.tcpDataCache.isWaitingSecondPart) { |
|
|
|
console.log('检测到后半部分数据,开始拼接') |
|
|
|
// console.log('检测到后半部分数据,开始拼接') |
|
|
|
completeMessage = this.concatenateDataParts(message) |
|
|
|
} else { |
|
|
|
console.log('收到后半部分数据,但没有缓存的前半部分,跳过处理') |
|
|
|
// console.log('收到后半部分数据,但没有缓存的前半部分,跳过处理') |
|
|
|
return |
|
|
|
} |
|
|
|
break |
|
|
|
|
|
|
|
case 'invalid': |
|
|
|
default: |
|
|
|
console.log('数据格式无效,跳过处理') |
|
|
|
// console.log('数据格式无效,跳过处理') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 第二步:解析完整的JSON数据 |
|
|
|
let parsedMessage |
|
|
|
try { |
|
|
|
console.log('开始解析完整JSON数据,长度:', completeMessage.length) |
|
|
|
// console.log('开始解析完整JSON数据,长度:', completeMessage.length) |
|
|
|
parsedMessage = JSON.parse(completeMessage) |
|
|
|
console.log('JSON解析成功,解析后类型:', typeof parsedMessage, parsedMessage) |
|
|
|
// console.log('JSON解析成功,解析后类型:', typeof parsedMessage, parsedMessage) |
|
|
|
} catch (parseError) { |
|
|
|
console.error('JSON解析失败:', parseError.message) |
|
|
|
// console.error('JSON解析失败:', parseError.message) |
|
|
|
// 清空字符串片段缓存 |
|
|
|
this.clearStringFragmentCache() |
|
|
|
return |
|
|
|
@ -644,48 +1087,48 @@ export default { |
|
|
|
|
|
|
|
// 第三步:检查是否是股票数据类型 |
|
|
|
if (!((parsedMessage.type === 'batch_data_chunk' || parsedMessage.type === 'batch_realtime_data') && parsedMessage.data)) { |
|
|
|
console.log('不是batch_data_chunk或batch_realtime_data类型的消息,跳过处理') |
|
|
|
// console.log('不是batch_data_chunk或batch_realtime_data类型的消息,跳过处理') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
console.log('开始处理股票数据') |
|
|
|
// console.log('开始处理股票数据') |
|
|
|
|
|
|
|
// 第四步:验证数据完整性(对象级别的完整性检查) |
|
|
|
// 注意:batch_data_chunk类型的数据不需要验证完整性,直接处理 |
|
|
|
if (parsedMessage.type === 'batch_data_chunk') { |
|
|
|
console.log('batch_data_chunk类型数据,跳过完整性验证,直接处理') |
|
|
|
// console.log('batch_data_chunk类型数据,跳过完整性验证,直接处理') |
|
|
|
this.processCompleteStockData(parsedMessage) |
|
|
|
} else { |
|
|
|
const isDataComplete = this.validateDataIntegrity(parsedMessage) |
|
|
|
|
|
|
|
if (isDataComplete) { |
|
|
|
// 数据完整,直接处理 |
|
|
|
console.log('对象级数据完整,直接处理') |
|
|
|
// console.log('对象级数据完整,直接处理') |
|
|
|
this.processCompleteStockData(parsedMessage) |
|
|
|
} else { |
|
|
|
// 数据不完整,需要拼接(对象级别的拼接) |
|
|
|
console.log('对象级数据不完整,开始拼接处理') |
|
|
|
// console.log('对象级数据不完整,开始拼接处理') |
|
|
|
|
|
|
|
// 将当前数据合并到缓存中 |
|
|
|
this.mergeDataToCache(parsedMessage) |
|
|
|
|
|
|
|
// 检查缓存中的数据是否已经完整 |
|
|
|
if (this.isCacheDataComplete()) { |
|
|
|
console.log('缓存数据已完整,开始处理') |
|
|
|
// console.log('缓存数据已完整,开始处理') |
|
|
|
const completeData = this.getCompleteDataFromCache() |
|
|
|
this.processCompleteStockData(completeData) |
|
|
|
} else { |
|
|
|
console.log('缓存数据仍不完整,等待更多数据片段') |
|
|
|
// console.log('缓存数据仍不完整,等待更多数据片段') |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('解析TCP股票数据失败:', error.message) |
|
|
|
console.error('错误详情:', error) |
|
|
|
// console.error('解析TCP股票数据失败:', error.message) |
|
|
|
// console.error('错误详情:', error) |
|
|
|
// 发生错误时清空所有缓存 |
|
|
|
this.clearStringFragmentCache() |
|
|
|
if (this.tcpDataCache.isCollecting) { |
|
|
|
console.log('发生错误,清空对象级数据缓存') |
|
|
|
// console.log('发生错误,清空对象级数据缓存') |
|
|
|
this.tcpDataCache.isCollecting = false |
|
|
|
this.tcpDataCache.expectedCount = 0 |
|
|
|
this.tcpDataCache.collectedData = {} |
|
|
|
@ -697,7 +1140,7 @@ export default { |
|
|
|
|
|
|
|
// 处理完整的股票数据 |
|
|
|
processCompleteStockData(completeData) { |
|
|
|
console.log("开始更新TCP股票数据存储") |
|
|
|
// console.log("开始更新TCP股票数据存储") |
|
|
|
|
|
|
|
// 更新TCP股票数据存储 |
|
|
|
this.tcpStockData = { |
|
|
|
@ -741,7 +1184,7 @@ export default { |
|
|
|
// 更新当前显示的股票信息列表 |
|
|
|
if (newStockInfoList.length > 0) { |
|
|
|
this.currentStockInfoList = newStockInfoList |
|
|
|
console.log('股票数据更新成功,共', newStockInfoList.length, '个股票:', this.currentStockInfoList) |
|
|
|
// console.log('股票数据更新成功,共', newStockInfoList.length, '个股票:', this.currentStockInfoList) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
@ -750,13 +1193,13 @@ export default { |
|
|
|
if (this.connectionListener) { |
|
|
|
tcpConnection.removeConnectionListener(this.connectionListener) |
|
|
|
this.connectionListener = null |
|
|
|
console.log('已移除TCP连接状态监听器') |
|
|
|
// console.log('已移除TCP连接状态监听器') |
|
|
|
} |
|
|
|
|
|
|
|
if (this.messageListener) { |
|
|
|
tcpConnection.removeMessageListener(this.messageListener) |
|
|
|
this.messageListener = null |
|
|
|
console.log('已移除TCP消息监听器') |
|
|
|
// console.log('已移除TCP消息监听器') |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -1405,4 +1848,32 @@ export default { |
|
|
|
color: #333; |
|
|
|
word-break: break-all; |
|
|
|
} |
|
|
|
|
|
|
|
/* 我的自选TCP控制样式 */ |
|
|
|
.my-stocks-tcp-control { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
margin-top: 8px; |
|
|
|
padding: 8px 12px; |
|
|
|
background-color: #f8f9fa; |
|
|
|
border-radius: 8px; |
|
|
|
border: 1px solid #e9ecef; |
|
|
|
} |
|
|
|
|
|
|
|
.tcp-buttons { |
|
|
|
display: flex; |
|
|
|
gap: 6px; |
|
|
|
} |
|
|
|
|
|
|
|
.my-stocks-tcp-control .tcp-btn { |
|
|
|
flex: none; |
|
|
|
min-width: 50px; |
|
|
|
height: 28px; |
|
|
|
border-radius: 4px; |
|
|
|
font-size: 11px; |
|
|
|
border: none; |
|
|
|
color: white; |
|
|
|
font-weight: bold; |
|
|
|
} |
|
|
|
</style> |