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 6dcc539..ffe9d88 100644
--- a/api/tcpConnection.js
+++ b/api/tcpConnection.js
@@ -30,6 +30,26 @@ class TCPConnection {
* @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,
@@ -41,6 +61,7 @@ class TCPConnection {
connectionConfig.charsetname = config.charsetname || TCP_CONFIG.charsetname;
}
+ console.log('开始建立TCP连接:', connectionConfig);
TCPSocket.connect(
connectionConfig,
result => {
diff --git a/common/util.js b/common/util.js
index 0058c56..3fbc198 100644
--- a/common/util.js
+++ b/common/util.js
@@ -1,6 +1,6 @@
var util = {}
util.data = {}
-util.data.base_url = 'https://dbqb.nfdxy.net/devApi'
+util.data.base_url = 'https://hwjb.homilychart.com/testApi'
// util.data.base_url = 'https://dbqb.nfdxy.net/prodApi'
// AJAX 请求方法
@@ -15,7 +15,8 @@ util.request = (url, callback, data = {}, failCallback) => {
'content-type': 'application/json',
'version': uni.getSystemInfoSync().appVersion,
'client': uni.getSystemInfoSync().platform == 'ios' ? 'ios' : 'android',
- 'token': uni.getStorageSync('token')
+ 'token': uni.getStorageSync('token'),
+ 'deviceId': uni.getSystemInfoSync().deviceId
},
sslVerify: false,
success: callback,
diff --git a/components/MarketOverview.vue b/components/MarketOverview.vue
index 743b365..c5f56a1 100644
--- a/components/MarketOverview.vue
+++ b/components/MarketOverview.vue
@@ -18,20 +18,13 @@
-
- 美元/日元
- 151.13
- +1.62%
-
-
- 美元/韩元
- 1424.900
- -2.92%
-
-
- 美元/英镑
- 0.730
- +2.92%
+
+ {{ stock.stock_name }}
+ {{ stock.current_price }}
+ {{ stock.change }}
@@ -94,6 +87,35 @@
-
-
\ No newline at end of file
diff --git a/pages/blank/institutionalTrendsBriefing.vue b/pages/blank/institutionalTrendsBriefing.vue
new file mode 100644
index 0000000..d78c5b0
--- /dev/null
+++ b/pages/blank/institutionalTrendsBriefing.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
+暂无内容~
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/blank/notice.vue b/pages/blank/notice.vue
new file mode 100644
index 0000000..713de07
--- /dev/null
+++ b/pages/blank/notice.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
+暂无内容~
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/deepMate/deepMate.vue b/pages/deepMate/deepMate.vue
index 622aa30..7ca432a 100644
--- a/pages/deepMate/deepMate.vue
+++ b/pages/deepMate/deepMate.vue
@@ -6,6 +6,7 @@
@@ -18,6 +19,7 @@
@@ -78,7 +80,7 @@
@@ -418,12 +420,29 @@ const newChat = () => {
};
// 跳转到空白页
-const goBlank = () => {
+const goinstitutionalTrendsBriefing = () => {
uni.navigateTo({
- url: "/pages/blank/blank",
+ url: "/pages/blank/institutionalTrendsBriefing",
});
};
+// 跳转到客户服务平台首页
+const goToCustomerService = () => {
+ uni.navigateTo({
+ url: "/pages/customerServicePlatform/csPlatformIndex",
+ });
+};
+// 跳转到通知页
+function goToNotice() {
+ try {
+ console.log("goToNotice: navigating to /pages/blank/notice");
+ uni.navigateTo({ url: "/pages/blank/notice" });
+ } catch (e) {
+ console.error("goToNotice navigateTo failed, fallback to redirect:", e);
+ uni.redirectTo({ url: "/pages/blank/notice" });
+ }
+}
+
// 历史记录
const openHistoryDrawer = async () => {
const res = await postHistory({
diff --git a/pages/home/globalIndex.vue b/pages/home/globalIndex.vue
deleted file mode 100644
index f624da9..0000000
--- a/pages/home/globalIndex.vue
+++ /dev/null
@@ -1,579 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pages/home/home.vue b/pages/home/home.vue
index 3e0d7ff..bd32e6b 100644
--- a/pages/home/home.vue
+++ b/pages/home/home.vue
@@ -17,7 +17,7 @@
-
+
@@ -121,7 +121,43 @@
-
+
+
+
+
+
+
+
+
+
+
@@ -142,6 +178,8 @@
import footerBar from '../../components/footerBar.vue'
import MarketOverview from '../../components/MarketOverview.vue'
import DeepMate from '../../components/DeepMate.vue'
+import tcpConnection from '../../api/tcpConnection.js'
+import th from '../../static/language/th'
export default {
components: {
@@ -177,7 +215,62 @@ export default {
],
// 防抖定时器
- debounceTimer: null
+ debounceTimer: null,
+
+ // TCP连接相关状态
+ tcpConnected: false,
+ tcpMessages: [],
+ lastSentMessage: '',
+
+ // TCP监听器引用,用于移除监听器
+ connectionListener: null,
+ messageListener: null,
+
+ // TCP股票数据存储
+ tcpStockData: {
+ count: 0,
+ data: {},
+ stock_count: 0,
+ timestamp: '',
+ type: ''
+ },
+
+ // TCP数据缓存机制,用于处理分片数据
+ tcpDataCache: {
+ isCollecting: false, // 是否正在收集数据片段
+ expectedCount: 0, // 期望的数据总数
+ collectedData: {}, // 已收集的数据对象(用于对象级拼接)
+ timestamp: '', // 数据时间戳
+ type: '', // 数据类型
+ // 新增:字符串片段缓存
+ firstPartData: '', // 前半部分数据字符串
+ isWaitingSecondPart: false // 是否正在等待后半部分数据
+ },
+
+ // 当前显示的3个股票数据(用于MarketOverview组件)
+ currentStockInfoList: [
+ {
+ stock_name: '美元/日元',
+ current_price: '151.13',
+ change: '+1.62%',
+ change_value: 0,
+ change_percent: 0
+ },
+ {
+ stock_name: '美元/韩元',
+ current_price: '1424.900',
+ change: '-2.92%',
+ change_value: 0,
+ change_percent: 0
+ },
+ {
+ stock_name: '美元/英镑',
+ current_price: '0.730',
+ change: '+2.92%',
+ change_value: 0,
+ change_percent: 0
+ }
+ ]
}
},
@@ -200,6 +293,34 @@ export default {
}
})
})
+
+ // 初始化TCP连接监听器
+ this.initTcpListeners()
+
+ // 页面渲染完成后自动连接TCP
+ this.$nextTick(() => {
+ console.log('页面渲染完成,开始自动连接TCP服务器...')
+ this.connectTcp()
+ })
+ },
+
+ // 页面销毁前的清理工作
+ onUnload() {
+ // 自动关闭TCP连接
+ if (this.tcpConnected) {
+ console.log('页面销毁,自动关闭TCP连接')
+ tcpConnection.disconnect()
+ this.tcpConnected = false
+ }
+
+ // 清理防抖定时器
+ if (this.debounceTimer) {
+ clearTimeout(this.debounceTimer)
+ this.debounceTimer = null
+ }
+
+ // 移除TCP监听器,防止内存泄漏
+ this.removeTcpListeners()
},
methods: {
@@ -210,6 +331,433 @@ export default {
fn()
this.debounceTimer = null
}, delay)
+ },
+
+ // TCP连接相关方法
+
+ // 初始化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.messageListener = (type, message, parsedArray) => {
+ const messageObj = {
+ type: type,
+ content: message,
+ parsedArray: parsedArray,
+ 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)
+ }
+
+ // 注册监听器
+ tcpConnection.onConnectionChange(this.connectionListener)
+ tcpConnection.onMessage(this.messageListener)
+ },
+
+ // 连接TCP服务器
+ connectTcp() {
+ console.log('开始连接TCP服务器...')
+
+ // 先断开现有连接(如果存在)
+ if (this.tcpConnected) {
+ console.log('检测到现有连接,先断开...')
+ this.disconnectTcp()
+ // 等待断开完成后再连接
+ setTimeout(() => {
+ this.performTcpConnect()
+ }, 500)
+ } else {
+ // 直接连接
+ this.performTcpConnect()
+ }
+ },
+
+ // 执行TCP连接
+ performTcpConnect() {
+ console.log('执行TCP连接...')
+ tcpConnection.connect(
+ {
+ ip: '192.168.1.9',
+ port: '8080',
+ channel: '1', // 可选 1~20
+ charsetname: 'UTF-8' // 默认UTF-8,可选GBK
+ }
+ )
+ },
+
+ // 断开TCP连接
+ disconnectTcp() {
+ console.log('断开TCP连接...')
+ tcpConnection.disconnect(
+ {
+ ip: '192.168.1.9',
+ port: '8080',
+ channel: '1', // 可选 1~20
+ charsetname: 'UTF-8' // 默认UTF-8,可选GBK
+ }
+ )
+ this.tcpConnected = false
+ },
+
+ // 发送TCP消息
+ sendTcpMessage() {
+ // 构造要发送的消息对象
+ const messageData =
+ // {
+ // command: "real_time",
+ // stock_code: "SH.000001"
+ // }
+ // {"command": "stock_list"}
+ // {"command": "batch_real_time", "stock_codes": ["SH.000001"]}
+ {"command": "batch_real_time", "stock_codes": ["SH.000001","SH.000002","SH.000003"]}
+
+ // 发送消息
+ const success = tcpConnection.send(messageData)
+ if (success) {
+ console.log('home发送TCP消息:', messageData)
+ uni.showToast({
+ title: '服务器连接成功',
+ icon: 'success',
+ duration: 1500
+ })
+ }
+ },
+
+
+ // 清空消息记录
+ clearTcpMessages() {
+ this.tcpMessages = []
+ uni.showToast({
+ title: '消息记录已清空',
+ icon: 'success',
+ duration: 1500
+ })
+ },
+
+ // 获取TCP连接状态
+ getTcpStatus() {
+ const status = tcpConnection.getConnectionStatus()
+ uni.showModal({
+ title: 'TCP连接状态',
+ content: `当前状态: ${status ? '已连接' : '未连接'}\n消息数量: ${this.tcpMessages.length}`,
+ showCancel: false
+ })
+ },
+
+ // 验证数据完整性(检查count值与data对象个数是否相等)
+ validateDataIntegrity(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
+ },
+
+ // 检查数据状态(完整数据、前半部分数据、后半部分数据)
+ getDataStatus(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'
+
+ }
+ },
+
+ // 缓存前半部分数据
+ cacheFirstPartData(message) {
+ this.tcpDataCache.firstPartData = message.trim()
+ this.tcpDataCache.isWaitingSecondPart = true
+ console.log('已缓存前半部分数据,长度:', this.tcpDataCache.firstPartData.length)
+ },
+
+ // 拼接前后两部分数据
+ concatenateDataParts(secondPartMessage) {
+ const completeMessage = this.tcpDataCache.firstPartData + secondPartMessage.trim()
+ console.log('数据拼接完成,完整数据长度:', completeMessage.length)
+
+ // 清空缓存
+ this.clearStringFragmentCache()
+
+ return completeMessage
+ },
+
+ // 清空字符串片段缓存
+ clearStringFragmentCache() {
+ this.tcpDataCache.firstPartData = ''
+ this.tcpDataCache.isWaitingSecondPart = false
+ console.log('字符串片段缓存已清空')
+ },
+
+ // 合并数据到缓存中
+ mergeDataToCache(parsedMessage) {
+ // 如果是第一次收集数据,初始化缓存
+ if (!this.tcpDataCache.isCollecting) {
+ this.tcpDataCache.isCollecting = true
+ this.tcpDataCache.expectedCount = parsedMessage.count
+ this.tcpDataCache.collectedData = {}
+ this.tcpDataCache.timestamp = parsedMessage.timestamp
+ this.tcpDataCache.type = parsedMessage.type
+ console.log('开始收集数据片段,期望总数:', parsedMessage.count)
+ }
+
+ // 合并新数据到缓存中
+ if (parsedMessage.data) {
+ Object.assign(this.tcpDataCache.collectedData, parsedMessage.data)
+ console.log('数据片段已合并,当前已收集:', Object.keys(this.tcpDataCache.collectedData).length, '个对象')
+ }
+ },
+
+ // 检查缓存数据是否完整
+ isCacheDataComplete() {
+ const collectedCount = Object.keys(this.tcpDataCache.collectedData).length
+ const expectedCount = this.tcpDataCache.expectedCount
+
+ console.log(`缓存数据检查: 已收集${collectedCount}个,期望${expectedCount}个`)
+ return collectedCount === expectedCount && collectedCount > 0
+ },
+
+ // 获取完整的缓存数据并清空缓存
+ getCompleteDataFromCache() {
+ const completeData = {
+ count: this.tcpDataCache.expectedCount,
+ data: { ...this.tcpDataCache.collectedData },
+ stock_count: this.tcpDataCache.expectedCount,
+ timestamp: this.tcpDataCache.timestamp,
+ type: this.tcpDataCache.type
+ }
+
+ // 清空缓存
+ this.tcpDataCache.isCollecting = false
+ this.tcpDataCache.expectedCount = 0
+ this.tcpDataCache.collectedData = {}
+ this.tcpDataCache.timestamp = ''
+ this.tcpDataCache.type = ''
+
+ console.log('获取完整数据并清空缓存,数据对象数:', Object.keys(completeData.data).length)
+ return completeData
+ },
+
+ // 解析TCP股票数据
+ parseStockData(message) {
+ try {
+ console.log('进入parseStockData, message类型:', typeof message, '长度:', message.length)
+
+ // 第一步:检查数据状态(完整、前半部分、后半部分)
+ const dataStatus = this.getDataStatus(message)
+
+ let completeMessage = ''
+
+ switch (dataStatus) {
+ case 'complete':
+ // 完整数据,直接处理
+ console.log('检测到完整数据,直接处理')
+ completeMessage = message
+ break
+
+ case 'first_part':
+ // 前半部分数据,缓存并等待后半部分
+ console.log('检测到前半部分数据,开始缓存')
+ this.cacheFirstPartData(message)
+ return // 等待后半部分数据
+
+ case 'second_part':
+ // 后半部分数据,检查是否有缓存的前半部分
+ if (this.tcpDataCache.isWaitingSecondPart) {
+ console.log('检测到后半部分数据,开始拼接')
+ completeMessage = this.concatenateDataParts(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.clearStringFragmentCache()
+ 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.processCompleteStockData(parsedMessage)
+ } else {
+ const isDataComplete = this.validateDataIntegrity(parsedMessage)
+
+ if (isDataComplete) {
+ // 数据完整,直接处理
+ console.log('对象级数据完整,直接处理')
+ this.processCompleteStockData(parsedMessage)
+ } else {
+ // 数据不完整,需要拼接(对象级别的拼接)
+ console.log('对象级数据不完整,开始拼接处理')
+
+ // 将当前数据合并到缓存中
+ this.mergeDataToCache(parsedMessage)
+
+ // 检查缓存中的数据是否已经完整
+ if (this.isCacheDataComplete()) {
+ console.log('缓存数据已完整,开始处理')
+ const completeData = this.getCompleteDataFromCache()
+ this.processCompleteStockData(completeData)
+ } else {
+ console.log('缓存数据仍不完整,等待更多数据片段')
+ }
+ }
+ }
+ } catch (error) {
+ console.error('解析TCP股票数据失败:', error.message)
+ console.error('错误详情:', error)
+ // 发生错误时清空所有缓存
+ this.clearStringFragmentCache()
+ if (this.tcpDataCache.isCollecting) {
+ console.log('发生错误,清空对象级数据缓存')
+ this.tcpDataCache.isCollecting = false
+ this.tcpDataCache.expectedCount = 0
+ this.tcpDataCache.collectedData = {}
+ this.tcpDataCache.timestamp = ''
+ this.tcpDataCache.type = ''
+ }
+ }
+ },
+
+ // 处理完整的股票数据
+ processCompleteStockData(completeData) {
+ console.log("开始更新TCP股票数据存储")
+
+ // 更新TCP股票数据存储
+ this.tcpStockData = {
+ count: completeData.count || 0,
+ data: completeData.data || {},
+ stock_count: completeData.stock_count || 0,
+ timestamp: completeData.timestamp || '',
+ type: completeData.type || ''
+ }
+
+ // 获取所有股票的数据用于显示(最多3个)
+ const stockCodes = Object.keys(completeData.data)
+ const newStockInfoList = []
+
+ // 处理最多3个股票数据
+ for (let i = 0; i < Math.min(stockCodes.length, 3); 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] // 取第一条数据
+
+ 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 ? '+' : ''
+
+ // 添加到股票信息列表
+ newStockInfoList.push({
+ 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)
+ })
+ }
+ }
+ }
+
+ // 更新当前显示的股票信息列表
+ if (newStockInfoList.length > 0) {
+ this.currentStockInfoList = newStockInfoList
+ console.log('股票数据更新成功,共', newStockInfoList.length, '个股票:', this.currentStockInfoList)
+ }
+ },
+
+ // 移除TCP监听器
+ removeTcpListeners() {
+ if (this.connectionListener) {
+ tcpConnection.removeConnectionListener(this.connectionListener)
+ this.connectionListener = null
+ console.log('已移除TCP连接状态监听器')
+ }
+
+ if (this.messageListener) {
+ tcpConnection.removeMessageListener(this.messageListener)
+ this.messageListener = null
+ console.log('已移除TCP消息监听器')
+ }
}
}
}
@@ -706,4 +1254,155 @@ export default {
bottom: 0;
width: 100%;
}
+
+/* TCP测试区域样式 */
+.tcp-test-section {
+ border: 1px solid #e0e0e0;
+ background-color: #f9f9f9;
+}
+
+.tcp-status {
+ padding: 4px 12px;
+ border-radius: 12px;
+ font-size: 12px;
+}
+
+.tcp-status.connected {
+ background-color: #e8f5e8;
+ color: #4caf50;
+ border: 1px solid #4caf50;
+}
+
+.tcp-status.disconnected {
+ background-color: #ffeaea;
+ color: #f44336;
+ border: 1px solid #f44336;
+}
+
+.status-text {
+ font-size: 12px;
+ font-weight: bold;
+}
+
+.tcp-controls {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin-bottom: 15px;
+}
+
+.tcp-btn {
+ flex: 1;
+ min-width: 80px;
+ height: 36px;
+ border-radius: 6px;
+ font-size: 12px;
+ border: none;
+ color: white;
+ font-weight: bold;
+}
+
+.connect-btn {
+ background-color: #4caf50;
+}
+
+.connect-btn:disabled {
+ background-color: #cccccc;
+}
+
+.disconnect-btn {
+ background-color: #f44336;
+}
+
+.disconnect-btn:disabled {
+ background-color: #cccccc;
+}
+
+.send-btn {
+ background-color: #2196f3;
+}
+
+.send-btn:disabled {
+ background-color: #cccccc;
+}
+
+.status-btn {
+ background-color: #ff9800;
+}
+
+.tcp-messages {
+ margin-top: 15px;
+ border-top: 1px solid #e0e0e0;
+ padding-top: 15px;
+}
+
+.messages-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 10px;
+}
+
+.messages-title {
+ font-size: 14px;
+ font-weight: bold;
+ color: #333;
+}
+
+.clear-btn {
+ padding: 4px 8px;
+ background-color: #f44336;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ font-size: 10px;
+}
+
+.messages-list {
+ max-height: 200px;
+ border: 1px solid #e0e0e0;
+ border-radius: 6px;
+ padding: 8px;
+ background-color: white;
+}
+
+.message-item {
+ margin-bottom: 8px;
+ padding: 8px;
+ border-radius: 6px;
+ border-left: 3px solid #ccc;
+}
+
+.message-item.sent {
+ background-color: #e3f2fd;
+ border-left-color: #2196f3;
+}
+
+.message-item.received {
+ background-color: #f1f8e9;
+ border-left-color: #4caf50;
+}
+
+.message-info {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 4px;
+}
+
+.message-direction {
+ font-size: 10px;
+ font-weight: bold;
+ color: #666;
+}
+
+.message-time {
+ font-size: 10px;
+ color: #999;
+}
+
+.message-content {
+ font-size: 12px;
+ color: #333;
+ word-break: break-all;
+}
\ No newline at end of file
diff --git a/pages/home/marketDetail.vue b/pages/home/marketDetail.vue
deleted file mode 100644
index d3acf86..0000000
--- a/pages/home/marketDetail.vue
+++ /dev/null
@@ -1,488 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ stock.stockName }}
- {{ stock.stockCode }}
-
-
-
- {{ typeof stock.price === "number" ? stock.price.toFixed(2) : stock.price }}
-
-
-
-
- {{ stock.change || stock.changePercent }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pages/home/marketSituation.vue b/pages/home/marketSituation.vue
deleted file mode 100644
index 14f8b75..0000000
--- a/pages/home/marketSituation.vue
+++ /dev/null
@@ -1,920 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ $t("marketSituation.globalIndex") }}
-
-
- {{ $t("marketSituation.globalIndexMore") }}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ $t("marketSituation.warn") }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ country }}
-
-
-
-
-
-
-
-
-
-
diff --git a/pages/marketSituation/chartExample.vue b/pages/marketSituation/chartExample.vue
new file mode 100644
index 0000000..47ab2a3
--- /dev/null
+++ b/pages/marketSituation/chartExample.vue
@@ -0,0 +1,655 @@
+
+
+
+
+
+
diff --git a/pages/marketSituation/countryMarket.vue b/pages/marketSituation/countryMarket.vue
new file mode 100644
index 0000000..9bb0a30
--- /dev/null
+++ b/pages/marketSituation/countryMarket.vue
@@ -0,0 +1,493 @@
+
+
+
+
+
+ {{ tab }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 今日市场情绪温度
+
+
+
+
+
+ {{ m.value }}°C
+ {{ m.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ sec.price }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ stk.name }}
+ {{ stk.code }}
+
+
+ {{ stk.price }}
+
+
+
+ {{ stk.change }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/marketSituation/forexMetals.vue b/pages/marketSituation/forexMetals.vue
new file mode 100644
index 0000000..c002ed7
--- /dev/null
+++ b/pages/marketSituation/forexMetals.vue
@@ -0,0 +1,301 @@
+
+
+
+
+ 💱
+ 外汇市场
+
+
+
+
+ {{ item.base }}
+ /
+ {{ item.quote }}
+
+
+ {{ item.price }}
+
+ {{ item.change }}
+
+
+
+
+
+
+
+
+ 🥇
+ 贵金属
+
+
+
+
+ {{ item.icon }}
+ {{ item.name }}
+
+
+ {{ item.price }}
+ {{ item.unit }}
+
+ {{ item.change }}
+
+
+
+
+
+
+
+
+
+ 📰
+ 市场动态
+
+
+
+
+ {{ news.title }}
+ {{ news.time }}
+
+
+ {{ news.impactText }}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/marketSituation/globalIndex.vue b/pages/marketSituation/globalIndex.vue
new file mode 100644
index 0000000..2a2ed7d
--- /dev/null
+++ b/pages/marketSituation/globalIndex.vue
@@ -0,0 +1,574 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/home/marketCondition.vue b/pages/marketSituation/marketCondition.vue
similarity index 100%
rename from pages/home/marketCondition.vue
rename to pages/marketSituation/marketCondition.vue
diff --git a/pages/marketSituation/marketDetail.vue b/pages/marketSituation/marketDetail.vue
new file mode 100644
index 0000000..f349d6f
--- /dev/null
+++ b/pages/marketSituation/marketDetail.vue
@@ -0,0 +1,485 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ stock.name }}
+ {{ stock.code }}
+
+
+
+ {{ typeof stock.price === 'number' ? stock.price.toFixed(2) : stock.price }}
+
+
+
+
+ {{ stock.change || stock.changePercent }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/marketSituation/marketOverview.vue b/pages/marketSituation/marketOverview.vue
new file mode 100644
index 0000000..db1ad11
--- /dev/null
+++ b/pages/marketSituation/marketOverview.vue
@@ -0,0 +1,733 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('marketSituation.globalIndex') }}
+
+
+ {{ $t('marketSituation.globalIndexMore') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('marketSituation.warn') }}
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/marketSituation/marketSituation.vue b/pages/marketSituation/marketSituation.vue
new file mode 100644
index 0000000..e76aa2d
--- /dev/null
+++ b/pages/marketSituation/marketSituation.vue
@@ -0,0 +1,593 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ country }}
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/static/icons/Left_(左).png b/static/icons/Left_(左).png
new file mode 100644
index 0000000..4af54c5
Binary files /dev/null and b/static/icons/Left_(左).png differ
diff --git a/static/images/缺省.png b/static/images/缺省.png
new file mode 100644
index 0000000..a4f9ac4
Binary files /dev/null and b/static/images/缺省.png differ
diff --git a/static/marketSituation-image/cool.png b/static/marketSituation-image/cool.png
new file mode 100644
index 0000000..16ba272
Binary files /dev/null and b/static/marketSituation-image/cool.png differ
diff --git a/static/marketSituation-image/hot.png b/static/marketSituation-image/hot.png
new file mode 100644
index 0000000..e8f7360
Binary files /dev/null and b/static/marketSituation-image/hot.png differ
diff --git a/static/marketSituation-image/warm.png b/static/marketSituation-image/warm.png
new file mode 100644
index 0000000..1338a2a
Binary files /dev/null and b/static/marketSituation-image/warm.png differ