Browse Source

Merge branch 'milestone-20251031-简版功能开发' of http://39.101.133.168:8807/qimaohong/deepChartVueApp into wangyi/feature-20251026183100-deepmate王毅

lihuilin/feature-20251024095243-我的
wangyi 4 weeks ago
parent
commit
c57b7a27e3
  1. 8
      pages.json
  2. 655
      pages/marketSituation/chartExample.vue
  3. 446
      pages/marketSituation/marketCondition.vue
  4. 8
      pages/marketSituation/marketOverview.vue
  5. 33
      static/language/en.js
  6. 7
      static/language/ms.js
  7. 7
      static/language/th.js
  8. 7
      static/language/vi.js
  9. 33
      static/language/zh_CN.js
  10. 33
      static/language/zh_HK.js

8
pages.json

@ -97,14 +97,6 @@
} }
}, },
{ {
"path": "pages/marketSituation/chartExample",
"style": {
"navigationBarTitleText": "图表示例",
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black"
}
},
{
"path": "pages/marketSituation/globalIndex", "path": "pages/marketSituation/globalIndex",
"style": { "style": {
"navigationStyle": "custom", "navigationStyle": "custom",

655
pages/marketSituation/chartExample.vue

@ -1,655 +0,0 @@
<template>
<view style="width: 750rpx; height: 750rpx;">
<l-echart ref="chartRef" @finished="initChart"></l-echart>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
const chartRef = ref(null)
// window.innerWidth
const systemInfo = uni.getSystemInfoSync()
const screenWidth = ref(systemInfo.screenWidth || 375) // 375px
// 30
const generateAIGoldBullData = () => {
const data = []
for (let i = 0; i < 30; i++) {
// [, , , , , ]
const buySignal = Math.random() > 0.7 ? 1 : 0 // 30%
const sellSignal = Math.random() > 0.8 ? 1 : 0 // 20%
const holdSignal = Math.random() > 0.5 ? 1 : 0 // 50%
const strength = Math.floor(Math.random() * 3) + 1 // 1-3
const volume = Math.floor(Math.random() * 2000) + 500 // 500-2500
data.push([i, buySignal, sellSignal, holdSignal, strength, volume])
}
return data
}
//
var option
const AIGoldBull = ref({
JN: generateAIGoldBullData()
})
//
const t = ref({
suoxie: 'zh',
tianxian: '天线',
feixian: '飞线',
zhoongxian: '中线',
liuxian: '流线',
Klinetext_5: 'K线5',
Klinetext_6: 'K线6',
maipan: '买盘',
maipan1: '卖盘'
})
// 30K线 [, , , , ]
const generateKLineData = () => {
const data = []
let basePrice = 2450 //
for (let i = 0; i < 30; i++) {
const date = new Date(2024, 0, i + 1).toISOString().split('T')[0]
//
const volatility = (Math.random() - 0.5) * 50 // ±25
const open = basePrice + volatility
const highVolatility = Math.random() * 30 + 10 // 10-40
const lowVolatility = Math.random() * 30 + 10 // 10-40
const high = Math.max(open, open + highVolatility)
const low = Math.min(open, open - lowVolatility)
const closeVolatility = (Math.random() - 0.5) * 20
const close = Math.max(low, Math.min(high, open + closeVolatility))
data.push([date,
Math.round(open * 100) / 100,
Math.round(high * 100) / 100,
Math.round(low * 100) / 100,
Math.round(close * 100) / 100
])
basePrice = close //
}
return data
}
// 30 [, 1, 2, 1, 2, 3]
const generateWaveVolData = () => {
const data = []
for (let i = 0; i < 30; i++) {
const date = new Date(2024, 0, i + 1).toISOString().split('T')[0]
//
const vol1 = Math.floor(Math.random() * 2000) + 800 // 800-2800
const vol2 = Math.floor(Math.random() * 1500) + 600 // 600-2100
//
const indicator1 = Math.floor(Math.random() * 30) + 40 // 40-70
const indicator2 = Math.floor(Math.random() * 40) + 50 // 50-90
const indicator3 = Math.floor(Math.random() * 35) + 60 // 60-95
data.push([date, vol1, vol2, indicator1, indicator2, indicator3])
}
return data
}
// 30线 [MA5, MA10, MA20, MA30]
const generateFTLineData = () => {
const data = []
let ma5Base = 2450
let ma10Base = 2445
let ma20Base = 2440
let ma30Base = 2435
for (let i = 0; i < 30; i++) {
// 线
ma5Base += (Math.random() - 0.5) * 10
ma10Base += (Math.random() - 0.5) * 8
ma20Base += (Math.random() - 0.5) * 6
ma30Base += (Math.random() - 0.5) * 4
data.push([
Math.round(ma5Base * 100) / 100,
Math.round(ma10Base * 100) / 100,
Math.round(ma20Base * 100) / 100,
Math.round(ma30Base * 100) / 100
])
}
return data
}
//
const mockKLineData = generateKLineData()
const mockWaveVolData = generateWaveVolData()
const mockFTLineData = generateFTLineData()
// RSI ()
const generateRSIData = () => {
const data = []
for (let i = 0; i < 30; i++) {
const rsi = Math.random() * 60 + 20 // RSI20-80
data.push(Math.round(rsi * 100) / 100)
}
return data
}
// MACD
const generateMACDData = () => {
const data = []
for (let i = 0; i < 30; i++) {
const macd = (Math.random() - 0.5) * 20 // MACD-1010
const signal = (Math.random() - 0.5) * 15 // 线
const histogram = macd - signal //
data.push([
Math.round(macd * 100) / 100,
Math.round(signal * 100) / 100,
Math.round(histogram * 100) / 100
])
}
return data
}
//
const generateBollingerData = () => {
const data = []
let middleLine = 2450
for (let i = 0; i < 30; i++) {
middleLine += (Math.random() - 0.5) * 10
const upperBand = middleLine + Math.random() * 30 + 20 //
const lowerBand = middleLine - Math.random() * 30 - 20 //
data.push([
Math.round(upperBand * 100) / 100,
Math.round(middleLine * 100) / 100,
Math.round(lowerBand * 100) / 100
])
}
return data
}
//
const generateVolumeAnalysisData = () => {
const data = []
for (let i = 0; i < 30; i++) {
const buyVolume = Math.floor(Math.random() * 1500) + 500 //
const sellVolume = Math.floor(Math.random() * 1500) + 500 //
const netVolume = buyVolume - sellVolume //
data.push([buyVolume, sellVolume, netVolume])
}
return data
}
//
const generateMarketSentimentData = () => {
const sentiments = ['极度恐慌', '恐慌', '中性', '贪婪', '极度贪婪']
const data = []
for (let i = 0; i < 30; i++) {
const sentimentIndex = Math.floor(Math.random() * 100) // 0-100
const sentimentLabel = sentiments[Math.floor(sentimentIndex / 20)]
data.push({
date: new Date(2024, 0, i + 1).toISOString().split('T')[0],
index: sentimentIndex,
label: sentimentLabel,
fearGreedRatio: Math.random() * 100
})
}
return data
}
//
const generateNewsEventsData = () => {
const events = [
'美联储利率决议',
'非农就业数据发布',
'通胀数据公布',
'地缘政治紧张',
'央行政策变化',
'经济数据超预期',
'市场技术突破',
'大宗商品价格波动'
]
const data = []
for (let i = 0; i < 10; i++) { // 10
const randomDay = Math.floor(Math.random() * 30) + 1
const event = events[Math.floor(Math.random() * events.length)]
const impact = Math.floor(Math.random() * 5) + 1 // 1-5
data.push({
date: new Date(2024, 0, randomDay).toISOString().split('T')[0],
event: event,
impact: impact,
type: Math.random() > 0.5 ? 'positive' : 'negative'
})
}
return data.sort((a, b) => new Date(a.date) - new Date(b.date))
}
//
const generatePricePredictionData = () => {
const data = []
let currentPrice = 2450
for (let i = 0; i < 7; i++) { // 7
const date = new Date(2024, 1, i + 1).toISOString().split('T')[0] // 2
// AI
const prediction = currentPrice + (Math.random() - 0.5) * 100
const confidence = Math.random() * 40 + 60 // 60-100%
const upperBound = prediction + Math.random() * 50
const lowerBound = prediction - Math.random() * 50
data.push({
date: date,
predicted_price: Math.round(prediction * 100) / 100,
confidence: Math.round(confidence),
upper_bound: Math.round(upperBound * 100) / 100,
lower_bound: Math.round(lowerBound * 100) / 100
})
currentPrice = prediction
}
return data
}
//
const extractedDrawData = {
KLine20: mockKLineData,
WAVEVOL: mockWaveVolData,
FTLINE: mockFTLineData,
RSI: generateRSIData(),
MACD: generateMACDData(),
BOLLINGER: generateBollingerData(),
VOLUME_ANALYSIS: generateVolumeAnalysisData(),
MARKET_SENTIMENT: generateMarketSentimentData(),
NEWS_EVENTS: generateNewsEventsData(),
PRICE_PREDICTION: generatePricePredictionData()
}
const fnShowEcharts4 = (extractedDrawData) => {
const splitData = (b) => {
const a = JSON.parse(JSON.stringify(b))
let categoryData = []
let values = []
for (let i = 0; i < a.length; i++) {
categoryData.push(a[i].splice(0, 1)[0])
values.push(a[i])
}
return {
categoryData,
values
}
}
var bodongliang = splitData(extractedDrawData.WAVEVOL)
function bodongliangData(values, i) {
return values.map((subArray) => subArray[i])
}
function calculateMA(index, data) {
let result = []
if (data.FTLINE) {
data.FTLINE.forEach((item) => {
result.push(item[index])
})
}
return result
}
function vwToPx(vw) {
return (screenWidth.value * vw) / 100
}
var dealData = splitData(extractedDrawData.KLine20)
var dealGnBullData = AIGoldBull.value.JN
const textEcharts = t.value
const firstLegend = computed(() => {
if (screenWidth.value < 768) {
if (textEcharts.suoxie === 'en' || textEcharts.suoxie === 'th') {
return '2%'
} else if (textEcharts.suoxie === 'kr') {
return '2%'
} else {
return '2%'
}
} else {
return textEcharts.suoxie === 'en' ||
textEcharts.suoxie === 'th' ||
textEcharts.suoxie === 'kr'
? '9%'
: '9%'
}
})
const processBarData = (data) => {
const barData = []
data.forEach((item) => {
let color
switch (item[4]) {
case 1:
color = '#13E113'
break
case 2:
color = '#FF0E00'
break
case 3:
color = '#0000FE'
break
case 4:
color = '#1397FF'
break
}
barData.push({
value: item[5],
itemStyle: {
normal: {
color: color
}
}
})
})
return { barData }
}
const { barData } = processBarData(dealGnBullData)
option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
backgroundColor: 'rgba(119, 120, 125, 0.6)',
borderWidth: 1,
borderColor: '#77787D',
padding: 10,
textStyle: {
color: '#fff'
}
},
axisPointer: {
link: [
{
xAxisIndex: 'all'
}
],
label: {
backgroundColor: '#77787D'
}
},
toolbox: {
show: false
},
grid: [
{
left: screenWidth.value > 768 ? '10%' : '12%',
right: screenWidth.value > 768 ? '4%' : '6%',
top: screenWidth.value > 768 ? '10%' : '12%',
height: screenWidth.value > 768 ? '35%' : '34%',
containLabel: false
},
{
left: screenWidth.value > 768 ? '10%' : '12%',
right: screenWidth.value > 768 ? '4%' : '6%',
top: screenWidth.value > 768 ? '48%' : '48%',
height: screenWidth.value > 768 ? '19%' : '21%',
containLabel: false
},
{
left: screenWidth.value > 768 ? '10%' : '12%',
right: screenWidth.value > 768 ? '4%' : '6%',
top: screenWidth.value > 768 ? '70%' : '71%',
height: screenWidth.value > 768 ? '19%' : '21%',
containLabel: false
}
],
xAxis: [
{
type: 'category',
data: dealData.categoryData,
boundaryGap: true,
axisLine: { onZero: false },
splitLine: { show: false },
min: 'dataMin',
max: 'dataMax',
axisPointer: {
z: 100,
label: {
show: false //
}
},
axisLine: {
lineStyle: {
color: 'black'
}
}, //
axisLabel: { show: false },
axisTick: { show: false }
},
{
type: 'category',
gridIndex: 1,
data: dealData.categoryData,
boundaryGap: true,
axisPointer: {
z: 100,
label: {
show: false //
}
},
axisLine: { lineStyle: { color: 'black' } },
axisLabel: {
show: false,
interval: 'auto'
},
axisTick: { show: false }
},
{
type: 'category',
gridIndex: 2,
data: dealData.categoryData,
boundaryGap: true,
axisLine: { lineStyle: { color: 'black' } },
axisLabel: {
show: true,
interval: 'auto',
fontSize: screenWidth.value > 768 ? 15 : 9
},
axisTick: { show: false }
}
],
yAxis: [
{
scale: true,
gridIndex: 0,
position: 'left',
axisLabel: {
inside: false,
align: 'right',
fontSize: screenWidth.value > 768 ? 15 : 9
},
axisLine: {
show: true,
lineStyle: {
fontSize: '',
color: 'black'
}
},
axisTick: { show: false },
splitLine: { show: false }
},
{
scale: true,
gridIndex: 1,
splitNumber: 4,
min: 0,
minInterval: 1,
axisLabel: {
show: true,
fontSize: screenWidth.value > 768 ? 15 : 9,
margin: 8,
},
axisLine: { show: true, lineStyle: { color: 'black' } },
axisTick: { show: false },
splitLine: { show: true, lineStyle: { type: 'dashed' } },
boundaryGap: ['20%', '20%']
},
{
scale: true,
gridIndex: 2,
splitNumber: 2,
axisLabel: {
show: true,
fontSize: screenWidth.value > 768 ? 15 : 9
},
axisLine: { show: true, lineStyle: { color: 'black' } },
axisTick: { show: false },
splitLine: { show: false }
}
],
dataZoom: [
{
type: 'inside',
xAxisIndex: [0, 1, 2],
start: 50,
end: 100
},
{
show: true,
xAxisIndex: [0, 1, 2],
type: 'slider',
start: 50,
end: 100
}
],
series: [
{
type: 'candlestick',
name: '日K',
xAxisIndex: 0,
yAxisIndex: 0,
data: dealData.values,
itemStyle: {
normal: {
color0: 'red',
color: 'green',
borderColor0: 'red',
borderColor: 'green'
}
},
gridIndex: 1
},
{
name: '成交量',
type: 'bar',
barWidth: '70%',
xAxisIndex: 1,
yAxisIndex: 1,
data: barData,
},
// {
// name: textEcharts.feixian,
// type: 'line',
// data: calculateMA(1, extractedDrawData),
// smooth: true,
// symbol: 'none',
// xAxisIndex: 2,
// yAxisIndex: 2,
// itemStyle: {
// normal: {
// color: '#00a32e',
// lineStyle: {
// color: '#00a32e',
// width: 2,
// type: 'solid'
// }
// }
// }
// },
// {
// name: textEcharts.zhoongxian,
// type: 'line',
// data: calculateMA(2, extractedDrawData),
// smooth: true,
// symbol: 'none',
// xAxisIndex: 2,
// yAxisIndex: 2,
// itemStyle: {
// normal: {
// color: '#de0000',
// lineStyle: {
// color: '#de0000',
// width: 2,
// type: 'solid'
// }
// }
// }
// },
// {
// name: textEcharts.tianxian,
// type: 'line',
// data: calculateMA(3, extractedDrawData),
// smooth: true,
// symbol: 'none',
// xAxisIndex: 2,
// yAxisIndex: 2,
// itemStyle: {
// normal: {
// color: '#ffb300',
// lineStyle: {
// color: '#ffb300',
// width: 2,
// type: 'solid'
// }
// }
// }
// },
// {
// name: textEcharts.liuxian,
// type: 'line',
// data: calculateMA(4, extractedDrawData),
// smooth: true,
// symbol: 'none',
// xAxisIndex: 2,
// yAxisIndex: 2,
// itemStyle: {
// normal: {
// color: '#00c8ff',
// lineStyle: {
// color: '#00c8ff',
// width: 2,
// type: 'solid'
// }
// }
// }
// },
]
}
initChart()
}
//
onMounted(() => {
//
fnShowEcharts4(extractedDrawData)
})
//
const initChart = async () => {
if (!chartRef.value) return
try {
const chart = await chartRef.value.init(echarts)
chart.setOption(option)
} catch (error) {
console.error('图表初始化失败:', error)
}
}
</script>

446
pages/marketSituation/marketCondition.vue

@ -145,7 +145,7 @@
</view> </view>
</view> </view>
<view class="stock-kline"> <view class="stock-kline">
<view v-if="klineTab === 1 || klineTab === 2" class="time-chart-container" style="position: relative">
<view v-if="klineTab === 1 || klineTab === 2 || klineTab === 3 || klineTab === 4 || klineTab === 5 || klineTab === 6 || klineTab === 7 || klineTab === 8 || klineTab === 9" class="time-chart-container" style="position: relative">
<!-- 主图Canvas --> <!-- 主图Canvas -->
<canvas <canvas
canvas-id="stockChart" canvas-id="stockChart"
@ -195,15 +195,12 @@
></canvas> ></canvas>
</view> </view>
<!-- K线图区域 --> <!-- K线图区域 -->
<view class="test" v-else-if="klineTab === 3">
<view class="test" v-else-if="klineTab === 10">
<button @click="startTcp()">接收消息</button> <button @click="startTcp()">接收消息</button>
<button @click="sendStopTimeData()">停止消息</button> <button @click="sendStopTimeData()">停止消息</button>
<button @click="sendTcpMessage('real_time')">实时行情推送</button> <button @click="sendTcpMessage('real_time')">实时行情推送</button>
<button @click="sendTcpMessage('init_real_time')">初始化获取行情历史数据</button> <button @click="sendTcpMessage('init_real_time')">初始化获取行情历史数据</button>
<button @click="sendTcpMessage('stop_real_time')">停止实时推送</button> <button @click="sendTcpMessage('stop_real_time')">停止实时推送</button>
<view class="tcpMsg" v-for="item in tcpMessages" :key="item">
{{ item }}
</view>
</view> </view>
<view v-else class="kline-chart-container"> <view v-else class="kline-chart-container">
<text>K线图开发中...</text> <text>K线图开发中...</text>
@ -240,21 +237,6 @@ import tcpConnection, { TCPConnection, TCP_CONFIG } from "@/api/tcpConnection.js
// TCP // TCP
const tcpConnected = ref(false); 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 connectionListener = ref(null);
const messageListener = ref(null); const messageListener = ref(null);
@ -465,11 +447,54 @@ const confirmStockColor = (price, lastDayStockClosePrice) => {
// K线 // K线
const selectKlineTab = (tabId) => { const selectKlineTab = (tabId) => {
klineTab.value = tabId; klineTab.value = tabId;
if (klineTab.value == 1) {
sendTcpMessage("init_real_time");
if (klineTab.value) {
sendTcpMessage("stop_real_time");
}
switch (klineTab.value) {
case 1:
sendTcpMessage("init_real_time");
break;
case 2:
sendTcpMessage("daily_data");
break;
case 3:
sendTcpMessage("weekly_data");
break;
case 4:
sendTcpMessage("monthly_data");
break;
case 5:
sendTcpMessage("daily_one_minutes_data");
break;
case 6:
sendTcpMessage("daily_five_minutes_data");
break;
case 7:
sendTcpMessage("daily_fifteen_minutes_data");
break;
case 8:
sendTcpMessage("daily_thirty_minutes_data");
break;
case 9:
sendTcpMessage("daily_sixty_minutes_data");
break;
case 10:
uni.showToast({
title: "暂无季K数据",
icon: "none",
duration: 2000,
});
break;
case 11:
uni.showToast({
title: "暂无年K数据",
icon: "none",
duration: 2000,
});
break;
default:
break;
} }
initCanvas(); initCanvas();
// startAddDataTimer(); // startAddDataTimer();
}; };
@ -938,6 +963,7 @@ const drawChart = () => {
return; return;
} }
const data = klineTab.value == 1 ? timeData.value : klineData.value; const data = klineTab.value == 1 ? timeData.value : klineData.value;
console.log("data", data);
chartRange.value = []; chartRange.value = [];
// //
// HCharts.setCanvasColor(ctx.value, width, height, CANVAS_BACKGROUND_COLOR); // HCharts.setCanvasColor(ctx.value, width, height, CANVAS_BACKGROUND_COLOR);
@ -1246,6 +1272,7 @@ const touchMove = (e) => {
} }
} }
} else { } else {
return;
if (klineTab.value === 2) { if (klineTab.value === 2) {
// if(currentY) // if(currentY)
if (currentX < touchState.startX) { if (currentX < touchState.startX) {
@ -1413,10 +1440,6 @@ const initTcpListeners = () => {
timestamp: new Date().toLocaleTimeString(), timestamp: new Date().toLocaleTimeString(),
direction: "received", direction: "received",
}; };
console.log("0000");
tcpMessages.value.push(messageObj);
// console.log('TCP:', messageObj)
console.log("home开始调用parseStockData", messageObj);
// //
parseStockData(message); parseStockData(message);
@ -1469,6 +1492,7 @@ const sendTcpMessage = (command) => {
command: "stock_list", command: "stock_list",
}; };
break; break;
// 线
case "daily_data": case "daily_data":
messageData = { messageData = {
command: "daily_data", command: "daily_data",
@ -1477,38 +1501,53 @@ const sendTcpMessage = (command) => {
end_date: "20251023", end_date: "20251023",
}; };
break; break;
// 线
case "weekly_data": case "weekly_data":
messageData = { messageData = {
command: "weekly_data", command: "weekly_data",
stock_code: "000001.SZ", stock_code: "000001.SZ",
start_date: "20251001",
end_date: "20251023",
start_date: "2024912",
end_date: "20251029",
}; };
break; break;
// 线
case "monthly_data":
messageData = {
command: "monthly_data",
stock_code: "000001.SZ",
start_date: "2024912",
end_date: "20251029",
};
break;
// 1线
case "daily_one_minutes_data": case "daily_one_minutes_data":
messageData = { messageData = {
command: "daily_one_minutes_data", command: "daily_one_minutes_data",
stock_code: "000001.SZ", stock_code: "000001.SZ",
}; };
break; break;
// 5线
case "daily_five_minutes_data": case "daily_five_minutes_data":
messageData = { messageData = {
command: "daily_five_minutes_data", command: "daily_five_minutes_data",
stock_code: "000001.SZ", stock_code: "000001.SZ",
}; };
break; break;
// 15线
case "daily_fifteen_minutes_data": case "daily_fifteen_minutes_data":
messageData = { messageData = {
command: "daily_fifteen_minutes_data", command: "daily_fifteen_minutes_data",
stock_code: "000001.SZ", stock_code: "000001.SZ",
}; };
break; break;
// 30线
case "daily_thirty_minutes_data": case "daily_thirty_minutes_data":
messageData = { messageData = {
command: "daily_thirty_minutes_data", command: "daily_thirty_minutes_data",
stock_code: "000001.SZ", stock_code: "000001.SZ",
}; };
break; break;
// 60线
case "daily_sixty_minutes_data": case "daily_sixty_minutes_data":
messageData = { messageData = {
command: "daily_sixty_minutes_data", command: "daily_sixty_minutes_data",
@ -1531,7 +1570,7 @@ const sendTcpMessage = (command) => {
uni.showToast({ uni.showToast({
title: "命令不存在", title: "命令不存在",
icon: "none", icon: "none",
duration: 1500,
duration: 1000,
}); });
return; return;
} else { } else {
@ -1543,7 +1582,7 @@ const sendTcpMessage = (command) => {
uni.showToast({ uni.showToast({
title: "消息发送成功", title: "消息发送成功",
icon: "success", icon: "success",
duration: 1500,
duration: 1000,
}); });
} }
} catch (error) { } catch (error) {
@ -1551,34 +1590,102 @@ const sendTcpMessage = (command) => {
uni.showToast({ uni.showToast({
title: "消息发送失败", title: "消息发送失败",
icon: "none", icon: "none",
duration: 1500,
duration: 1000,
}); });
} }
} }
}; };
//
const clearTcpMessages = () => {
tcpMessages.value = [];
uni.showToast({
title: "消息记录已清空",
icon: "success",
duration: 1500,
});
};
// TCP // TCP
const getTcpStatus = () => { const getTcpStatus = () => {
const status = tcpConnection.getConnectionStatus(); const status = tcpConnection.getConnectionStatus();
uni.showModal({ uni.showModal({
title: "TCP连接状态", title: "TCP连接状态",
content: `当前状态: ${status ? "已连接" : "未连接"}\n消息数量: ${tcpMessages.value.length}`,
content: `当前状态: ${status ? "已连接" : "未连接"}`,
showCancel: false, showCancel: false,
}); });
}; };
let isMorePacket = false;
let isMorePacket = {
init_real_time: false,
daily_data: false,
weekly_data: false,
monthly_data: false,
daily_one_minutes_data: false,
daily_five_minutes_data: false,
daily_fifteen_minutes_data: false,
daily_thirty_minutes_data: false,
daily_sixty_minutes_data: false,
};
let receivedMessage; let receivedMessage;
const findJsonPacket = (message, command) => {
let jsonStartIndex = 0;
let jsonEndIndex = message.indexOf(command);
let jsonStartCount = 0;
let jsonEndCount = 0;
for (let i = 0; i < message.length - 1; ++i) {
if (message[i] == "{") {
jsonStartCount++;
if (jsonStartCount == 2) {
jsonStartIndex = i;
break;
}
}
}
for (let i = message.indexOf(command); i >= 0; --i) {
if (message[i] == "}" || i == jsonStartIndex) {
jsonEndCount++;
if (jsonEndCount == 1) {
jsonEndIndex = i;
break;
}
}
}
// JSON
if (jsonStartIndex >= jsonEndIndex) {
return { error: true };
}
return { json: JSON.parse(message.substring(jsonStartIndex, jsonEndIndex + 1)) };
};
// timeData
const generateNextTime = () => {
if (timeData.value.length === 0) {
return "09:30"; //
}
const lastTime = timeData.value[timeData.value.length - 1].time;
if (!lastTime) {
return "09:30";
}
// "HH:MM"
const [hours, minutes] = lastTime.split(":").map(Number);
//
let nextMinutes = minutes + 1;
let nextHours = hours;
//
if (nextMinutes >= 60) {
nextMinutes = 0;
nextHours += 1;
}
// 24
if (nextHours >= 24) {
nextHours = 0;
}
// "HH:MM"
const formattedHours = nextHours.toString().padStart(2, "0");
const formattedMinutes = nextMinutes.toString().padStart(2, "0");
return `${formattedHours}:${formattedMinutes}`;
};
// TCP // TCP
const parseStockData = (message) => { const parseStockData = (message) => {
try { try {
@ -1592,105 +1699,195 @@ const parseStockData = (message) => {
console.log("服务器命令列表,不予处理"); console.log("服务器命令列表,不予处理");
return; return;
} }
if ((typeof message === "string" && message.includes("init_real_data_start")) || isMorePacket) {
if (message.includes("real_time")) {
let startIndex = 0;
let endIndex = message.length;
for (let i = 0; i < message.length - 1; ++i) {
if (message[i] == "{") {
startIndex = i;
break;
}
}
for (let i = message.length - 1; i >= 0; --i) {
if (message[i] == "}") {
endIndex = i;
break;
}
}
parsedMessage = JSON.parse(message.substring(startIndex, endIndex + 1));
console.log("实时数据解析", parsedMessage);
//
timeData.value.push({
time: generateNextTime(),
price: parsedMessage.current_price,
volume: parsedMessage.volume,
amount: parsedMessage.amount,
});
//
stockInformation.value.currentPrice = parsedMessage.current_price;
stockInformation.value.openPrice = parsedMessage.open_price;
stockInformation.value.closePrice = parsedMessage.close_price;
stockInformation.value.highPrice = parsedMessage.high_price;
stockInformation.value.lowPrice = parsedMessage.low_price;
stockInformation.value.volume = parsedMessage.volume;
stockInformation.value.amount = parsedMessage.amount;
stockInformation.value.turnoverRatio = parsedMessage.turnover_ratio;
stockInformation.value.marketValue = parsedMessage.total_market_value;
stockInformation.value.currentValue = stockInformation.value.currentPrice - stockInformation.value.lastDayStockClosePrice;
stockInformation.value.currentRatio = ((stockInformation.value.currentPrice - stockInformation.value.lastDayStockClosePrice) / stockInformation.value.lastDayStockClosePrice) * 100;
console.log("重绘画面");
drawChart();
if (timeData.value.length >= 240) {
sendTcpMessage("stop_real_time");
}
return;
} else if ((typeof message === "string" && message.includes("init_real_data_start")) || isMorePacket.init_real_time) {
if (typeof message === "string" && message.includes("init_real_data_start")) { if (typeof message === "string" && message.includes("init_real_data_start")) {
console.log("开始接受分包数据"); console.log("开始接受分包数据");
receivedMessage = ""; receivedMessage = "";
} else { } else {
console.log("接收分包数据过程中"); console.log("接收分包数据过程中");
} }
isMorePacket = true;
isMorePacket.init_real_time = true;
receivedMessage += message; receivedMessage += message;
// }JSON // }JSON
if (receivedMessage.includes("init_real_data_complete")) { if (receivedMessage.includes("init_real_data_complete")) {
console.log("接受分包数据结束"); console.log("接受分包数据结束");
isMorePacket = false;
isMorePacket.init_real_time = false;
console.log("展示数据", receivedMessage); 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;
}
const result = findJsonPacket(receivedMessage, "init_real_data_complete");
if (result.error) {
throw new Error("解析JSON字符串失败");
} else {
parsedMessage = result.json;
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();
sendTcpMessage("stop_real_time");
sendTcpMessage("real_time");
} }
} }
}
} else if ((typeof message === "string" && message.includes("daily_data_start")) || isMorePacket.daily_data) {
if (typeof message === "string" && message.includes("daily_data_start")) {
console.log("开始接受分包数据");
receivedMessage = "";
} else {
console.log("接收分包数据过程中");
}
isMorePacket.daily_data = true;
receivedMessage += message;
// }JSON
if (receivedMessage.includes("daily_data_complete")) {
console.log("接受分包数据结束");
isMorePacket.daily_data = false;
for (let i = receivedMessage.indexOf("init_real_data_complete"); i >= 0; --i) {
if (receivedMessage[i] == "}" || i == jsonStartIndex) {
jsonEndCount++;
if (jsonEndCount == 1) {
jsonEndIndex = i;
break;
}
console.log("展示数据", receivedMessage);
const result = findJsonPacket(receivedMessage, "daily_data_complete");
if (result.error) {
throw new Error("解析JSON字符串失败");
} else {
parsedMessage = result.json;
console.log("JSON解析成功,解析后类型:", typeof parsedMessage, parsedMessage);
if (parsedMessage.type === "daily_data") {
klineData.value = parsedMessage.data.map((item) => ({
open: item.ask_open,
close: item.ask_close,
high: item.ask_high,
low: item.ask_low,
volume: item.tick_qty,
date: item.trade_date ? `${item.trade_date.slice(0, 4)}-${item.trade_date.slice(4, 6)}-${item.trade_date.slice(6, 8)}` : item.trade_date,
}));
stockInformation.value.lastDayStockClosePrice = klineData.value[klineData.value.length - 2].close;
touchState.offset = canvasWidth.value / klineData.value.length / 2;
console.log("lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice);
drawChart();
} }
} }
// JSON
if (jsonStartIndex >= jsonEndIndex) {
throw new Error("JSON字符串格式错误");
}
}
} else if ((typeof message === "string" && message.includes("weekly_data_start")) || isMorePacket.weekly_data) {
if (typeof message === "string" && message.includes("weekly_data_start")) {
console.log("开始接受分包数据");
receivedMessage = "";
} else {
console.log("接收分包数据过程中");
}
isMorePacket.weekly_data = true;
receivedMessage += message;
// }JSON
if (receivedMessage.includes("weekly_data_complete")) {
console.log("接受分包数据结束");
isMorePacket.weekly_data = false;
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();
console.log("展示数据", receivedMessage);
const result = findJsonPacket(receivedMessage, "weekly_data_complete");
if (result.error) {
throw new Error("解析JSON字符串失败");
} else {
parsedMessage = result.json;
console.log("JSON解析成功,解析后类型:", typeof parsedMessage, parsedMessage);
if (parsedMessage.type === "weekly_data") {
klineData.value = parsedMessage.data.map((item) => ({
open: item.bid_open,
close: item.bid_close,
high: item.bid_high,
low: item.bid_low,
volume: item.vol,
amount: item.amount,
date: item.trade_date ? `${item.trade_date.slice(0, 4)}-${item.trade_date.slice(4, 6)}-${item.trade_date.slice(6, 8)}` : item.trade_date,
}));
stockInformation.value.lastDayStockClosePrice = klineData.value[klineData.value.length - 2].close;
touchState.offset = canvasWidth.value / klineData.value.length / 2;
console.log("lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice);
drawChart();
}
} }
} }
// JSON
console.log("开始处理解析后的数据");
// batch_data_chunkbatch_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 || "",
};
} else if ((typeof message === "string" && message.includes("daily_one_minutes_data_start")) || isMorePacket.daily_one_minutes_data) {
if (typeof message === "string" && message.includes("daily_one_minutes_data_start")) {
console.log("开始接受分包数据");
receivedMessage = "";
} else {
console.log("接收分包数据过程中");
}
isMorePacket.daily_one_minutes_data = true;
receivedMessage += message;
// }JSON
if (receivedMessage.includes("daily_one_minutes_data_complete")) {
console.log("接受分包数据结束");
isMorePacket.daily_one_minutes_data = false;
console.log("展示数据", receivedMessage);
//
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);
}
const result = findJsonPacket(receivedMessage, "daily_one_minutes_data_complete");
if (result.error) {
throw new Error("解析JSON字符串失败");
} else {
parsedMessage = result.json;
console.log("JSON解析成功,解析后类型:", typeof parsedMessage, parsedMessage);
if (parsedMessage.type === "daily_one_minutes_data") {
// klineData.value = parsedMessage.data.map((item) => ({
// open: item.open,
// close: item.close,
// high: item.high,
// low: item.low,
// volume: item.volume,
// amount: item.amount,
// date: item.time,
// }));
stockInformation.value.lastDayStockClosePrice = klineData.value[klineData.value.length - 2].close;
touchState.offset = canvasWidth.value / klineData.value.length / 2;
console.log("lastDayStockClosePrice", stockInformation.value.lastDayStockClosePrice);
drawChart();
} }
} }
} else {
console.log("不是batch_data_chunk或batch_realtime_data类型的消息,跳过处理");
} }
} else { } else {
// JSON // JSON
@ -1789,7 +1986,8 @@ onLoad((options) => {
// //
onUnmounted(() => { onUnmounted(() => {
// disconnect();
removeTcpListeners();
disconnect();
if (timer) { if (timer) {
console.log("卸载定时器"); console.log("卸载定时器");
clearInterval(timer); clearInterval(timer);
@ -1829,7 +2027,9 @@ onMounted(async () => {
console.warn("没有时间数据,跳过股票信息计算"); console.warn("没有时间数据,跳过股票信息计算");
} }
await nextTick(); await nextTick();
initCanvas();
setTimeout(() => {
initCanvas();
}, 100);
console.log("所有初始化步骤完成"); console.log("所有初始化步骤完成");
} catch (error) { } catch (error) {
console.error("初始化过程中出现错误:", error); console.error("初始化过程中出现错误:", error);

8
pages/marketSituation/marketOverview.vue

@ -5,7 +5,6 @@
<!-- 可滚动内容区域 --> <!-- 可滚动内容区域 -->
<scroll-view class="content_scroll" scroll-y="true" :style="{ top: contentTopPosition + 'px' }"> <scroll-view class="content_scroll" scroll-y="true" :style="{ top: contentTopPosition + 'px' }">
<view class="content"> <view class="content">
<button @click="goToChartExample">图表</button>
<view class="map"> <view class="map">
<image src="/static/marketSituation-image/map.png" mode="widthFix"></image> <image src="/static/marketSituation-image/map.png" mode="widthFix"></image>
</view> </view>
@ -52,13 +51,6 @@ const isWarnTextOverflow = ref(false); // warn文字是否溢出
const pageIndex = ref(0); const pageIndex = ref(0);
const scrollToView = ref(""); const scrollToView = ref("");
//
const goToChartExample = () => {
uni.navigateTo({
url: "/pages/marketSituation/chartExample",
});
};
// contenttop // contenttop
const contentTopPosition = computed(() => { const contentTopPosition = computed(() => {
const statusBarHeight = iSMT.value || 0; const statusBarHeight = iSMT.value || 0;

33
static/language/en.js

@ -1,14 +1,21 @@
/** @format */
export default { export default {
language: {
"name": "Simplified Chinese"
},
components: {
footerBar: {
homepage: '首页',
marketSituation: '行情',
deepMate: 'DeepMate',
deepExploration: '深度探索',
member: '我的',
},
}
}
language: {
name: "Simplified Chinese",
},
components: {
footerBar: {
homepage: "首页",
marketSituation: "行情",
deepMate: "DeepMate",
deepExploration: "深度探索",
member: "我的",
},
},
marketSituation: {
globalIndex: "全球指数",
globalIndexMore:'查看更多',
warn:'全球指数为试运行,免费开放,有诸多不足请见谅'
},
};

7
static/language/ms.js

@ -10,5 +10,10 @@ export default {
deepExploration: '深度探索', deepExploration: '深度探索',
member: '我的', member: '我的',
}, },
}
},
marketSituation: {
globalIndex: "全球指数",
globalIndexMore:'查看更多',
warn:'全球指数为试运行,免费开放,有诸多不足请见谅'
},
} }

7
static/language/th.js

@ -10,5 +10,10 @@ export default {
deepExploration: '深度探索', deepExploration: '深度探索',
member: '我的', member: '我的',
}, },
}
},
marketSituation: {
globalIndex: "全球指数",
globalIndexMore:'查看更多',
warn:'全球指数为试运行,免费开放,有诸多不足请见谅'
},
} }

7
static/language/vi.js

@ -10,5 +10,10 @@ export default {
deepExploration: '深度探索', deepExploration: '深度探索',
member: '我的', member: '我的',
}, },
}
},
marketSituation: {
globalIndex: "全球指数",
globalIndexMore:'查看更多',
warn:'全球指数为试运行,免费开放,有诸多不足请见谅'
},
} }

33
static/language/zh_CN.js

@ -1,15 +1,22 @@
/** @format */
// 中文简体 // 中文简体
export default { export default {
language: {
name: '中文简体'
},
components: {
footerBar:{
homepage: '首页',
marketSituation: '行情',
deepMate: 'DeepMate',
deepExploration: '深度探索',
member: '我的',
},
},
}
language: {
name: "中文简体",
},
components: {
footerBar: {
homepage: "首页",
marketSituation: "行情",
deepMate: "DeepMate",
deepExploration: "深度探索",
member: "我的",
},
},
marketSituation: {
globalIndex: "全球指数",
globalIndexMore:'查看更多',
warn:'全球指数为试运行,免费开放,有诸多不足请见谅'
},
};

33
static/language/zh_HK.js

@ -1,15 +1,22 @@
/** @format */
// 中文繁体 // 中文繁体
export default { export default {
language: {
name: "中文繁体"
},
components: {
footerBar: {
homepage: '首页',
marketSituation: '行情',
deepMate: 'DeepMate',
deepExploration: '深度探索',
member: '我的',
},
},
}
language: {
name: "中文繁体",
},
components: {
footerBar: {
homepage: "首页",
marketSituation: "行情",
deepMate: "DeepMate",
deepExploration: "深度探索",
member: "我的",
},
},
marketSituation: {
globalIndex: "全球指数",
globalIndexMore:'查看更多',
warn:'全球指数为试运行,免费开放,有诸多不足请见谅'
},
};
Loading…
Cancel
Save