|
|
@@ -5,7 +5,6 @@ const utils_api = require("../../utils/api.js");
|
|
|
const _sfc_main = {
|
|
|
__name: "rank",
|
|
|
setup(__props) {
|
|
|
- let componentInstance = null;
|
|
|
const isLoggedIn = common_vendor.ref(false);
|
|
|
const myStocks = common_vendor.ref([]);
|
|
|
const viewMode = common_vendor.ref("list");
|
|
|
@@ -62,6 +61,12 @@ const _sfc_main = {
|
|
|
};
|
|
|
const setViewMode = (mode) => {
|
|
|
viewMode.value = mode;
|
|
|
+ if (mode === "list" && myStocks.value.length > 0) {
|
|
|
+ common_vendor.nextTick$1(() => {
|
|
|
+ clearAllCanvases();
|
|
|
+ drawAllTrendCharts();
|
|
|
+ });
|
|
|
+ }
|
|
|
};
|
|
|
const indexData = common_vendor.ref({
|
|
|
stockCode: "000001",
|
|
|
@@ -131,63 +136,103 @@ const _sfc_main = {
|
|
|
return "market-cy";
|
|
|
return "market-sh";
|
|
|
};
|
|
|
+ const getDevicePixelRatio = () => {
|
|
|
+ try {
|
|
|
+ const windowInfo = common_vendor.wx$1.getWindowInfo();
|
|
|
+ return windowInfo.pixelRatio || 2;
|
|
|
+ } catch (e) {
|
|
|
+ return 2;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ const clearCanvas = (canvasId) => {
|
|
|
+ const query = common_vendor.index.createSelectorQuery();
|
|
|
+ query.select("#" + canvasId).fields({ node: true, size: true }).exec((res) => {
|
|
|
+ if (!res || !res[0] || !res[0].node)
|
|
|
+ return;
|
|
|
+ const canvas = res[0].node;
|
|
|
+ const ctx = canvas.getContext("2d");
|
|
|
+ const dpr = getDevicePixelRatio();
|
|
|
+ const width = res[0].width;
|
|
|
+ const height = res[0].height;
|
|
|
+ canvas.width = width * dpr;
|
|
|
+ canvas.height = height * dpr;
|
|
|
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
+ ctx.clearRect(0, 0, width * dpr, height * dpr);
|
|
|
+ });
|
|
|
+ };
|
|
|
+ const clearAllCanvases = () => {
|
|
|
+ myStocks.value.forEach((stock) => {
|
|
|
+ clearCanvas("chart-" + stock.code);
|
|
|
+ });
|
|
|
+ };
|
|
|
const drawTrendChart = (stock) => {
|
|
|
- if (!componentInstance)
|
|
|
- return;
|
|
|
const canvasId = "chart-" + stock.code;
|
|
|
let trendData = stock.trendData;
|
|
|
if (!trendData || !Array.isArray(trendData) || trendData.length === 0) {
|
|
|
trendData = generateMockTrendData(stock.changePercent);
|
|
|
}
|
|
|
- const ctx = common_vendor.index.createCanvasContext(canvasId, componentInstance);
|
|
|
- const width = 120;
|
|
|
- const height = 28;
|
|
|
- const padding = 1;
|
|
|
- const maxValue = Math.max(...trendData);
|
|
|
- const minValue = Math.min(...trendData);
|
|
|
- const dataRange = maxValue - minValue;
|
|
|
- const avgValue = (maxValue + minValue) / 2;
|
|
|
- const minRange = avgValue * 0.03 || 1;
|
|
|
- const range = Math.max(dataRange, minRange);
|
|
|
- const baseValue = trendData[0];
|
|
|
- const baseY = height - padding - (baseValue - minValue) / range * (height - padding * 2);
|
|
|
- const changePercent = parseFloat(String(stock.changePercent || "0").replace("%", "").replace("+", ""));
|
|
|
- const isUp = changePercent >= 0;
|
|
|
- const lineColor = isUp ? "#ef4444" : "#22c55e";
|
|
|
- const fillColor = isUp ? "rgba(239, 68, 68, 0.15)" : "rgba(34, 197, 94, 0.15)";
|
|
|
- ctx.beginPath();
|
|
|
- ctx.setStrokeStyle("#e5e7eb");
|
|
|
- ctx.setLineWidth(0.5);
|
|
|
- ctx.setLineDash([2, 2], 0);
|
|
|
- ctx.moveTo(padding, baseY);
|
|
|
- ctx.lineTo(width - padding, baseY);
|
|
|
- ctx.stroke();
|
|
|
- ctx.setLineDash([], 0);
|
|
|
- ctx.beginPath();
|
|
|
- ctx.moveTo(padding, baseY);
|
|
|
- trendData.forEach((value, index) => {
|
|
|
- const x = padding + index / (trendData.length - 1) * (width - padding * 2);
|
|
|
- const y = height - padding - (value - minValue) / range * (height - padding * 2);
|
|
|
- ctx.lineTo(x, y);
|
|
|
- });
|
|
|
- ctx.lineTo(width - padding, baseY);
|
|
|
- ctx.closePath();
|
|
|
- ctx.setFillStyle(fillColor);
|
|
|
- ctx.fill();
|
|
|
- ctx.beginPath();
|
|
|
- trendData.forEach((value, index) => {
|
|
|
- const x = padding + index / (trendData.length - 1) * (width - padding * 2);
|
|
|
- const y = height - padding - (value - minValue) / range * (height - padding * 2);
|
|
|
- if (index === 0) {
|
|
|
- ctx.moveTo(x, y);
|
|
|
- } else {
|
|
|
- ctx.lineTo(x, y);
|
|
|
+ const query = common_vendor.index.createSelectorQuery();
|
|
|
+ query.select("#" + canvasId).fields({ node: true, size: true }).exec((res) => {
|
|
|
+ if (!res || !res[0] || !res[0].node) {
|
|
|
+ console.warn("[趋势图] 获取canvas节点失败:", canvasId);
|
|
|
+ return;
|
|
|
}
|
|
|
+ const canvas = res[0].node;
|
|
|
+ const ctx = canvas.getContext("2d");
|
|
|
+ const dpr = getDevicePixelRatio();
|
|
|
+ const width = res[0].width;
|
|
|
+ const height = res[0].height;
|
|
|
+ canvas.width = width * dpr;
|
|
|
+ canvas.height = height * dpr;
|
|
|
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
+ ctx.scale(dpr, dpr);
|
|
|
+ const padding = 1;
|
|
|
+ const maxValue = Math.max(...trendData);
|
|
|
+ const minValue = Math.min(...trendData);
|
|
|
+ const dataRange = maxValue - minValue;
|
|
|
+ const avgValue = (maxValue + minValue) / 2;
|
|
|
+ const minRange = avgValue * 0.03 || 1;
|
|
|
+ const range = Math.max(dataRange, minRange);
|
|
|
+ const baseValue = trendData[0];
|
|
|
+ const baseY = height - padding - (baseValue - minValue) / range * (height - padding * 2);
|
|
|
+ const changePercent = parseFloat(String(stock.changePercent || "0").replace("%", "").replace("+", ""));
|
|
|
+ const isUp = changePercent >= 0;
|
|
|
+ const lineColor = isUp ? "#ef4444" : "#22c55e";
|
|
|
+ const fillColor = isUp ? "rgba(239, 68, 68, 0.15)" : "rgba(34, 197, 94, 0.15)";
|
|
|
+ ctx.clearRect(0, 0, width, height);
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.strokeStyle = "#e5e7eb";
|
|
|
+ ctx.lineWidth = 0.5;
|
|
|
+ ctx.setLineDash([2, 2]);
|
|
|
+ ctx.moveTo(padding, baseY);
|
|
|
+ ctx.lineTo(width - padding, baseY);
|
|
|
+ ctx.stroke();
|
|
|
+ ctx.setLineDash([]);
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.moveTo(padding, baseY);
|
|
|
+ trendData.forEach((value, index) => {
|
|
|
+ const x = padding + index / (trendData.length - 1) * (width - padding * 2);
|
|
|
+ const y = height - padding - (value - minValue) / range * (height - padding * 2);
|
|
|
+ ctx.lineTo(x, y);
|
|
|
+ });
|
|
|
+ ctx.lineTo(width - padding, baseY);
|
|
|
+ ctx.closePath();
|
|
|
+ ctx.fillStyle = fillColor;
|
|
|
+ ctx.fill();
|
|
|
+ ctx.beginPath();
|
|
|
+ trendData.forEach((value, index) => {
|
|
|
+ const x = padding + index / (trendData.length - 1) * (width - padding * 2);
|
|
|
+ const y = height - padding - (value - minValue) / range * (height - padding * 2);
|
|
|
+ if (index === 0) {
|
|
|
+ ctx.moveTo(x, y);
|
|
|
+ } else {
|
|
|
+ ctx.lineTo(x, y);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ ctx.strokeStyle = lineColor;
|
|
|
+ ctx.lineWidth = 1.5;
|
|
|
+ ctx.stroke();
|
|
|
});
|
|
|
- ctx.setStrokeStyle(lineColor);
|
|
|
- ctx.setLineWidth(1.5);
|
|
|
- ctx.stroke();
|
|
|
- ctx.draw();
|
|
|
};
|
|
|
const generateMockTrendData = (changePercent) => {
|
|
|
const change = parseFloat(String(changePercent || "0").replace("%", "").replace("+", ""));
|
|
|
@@ -206,12 +251,20 @@ const _sfc_main = {
|
|
|
const drawAllTrendCharts = () => {
|
|
|
if (myStocks.value.length === 0)
|
|
|
return;
|
|
|
+ if (!isPageVisible.value)
|
|
|
+ return;
|
|
|
common_vendor.nextTick$1(() => {
|
|
|
setTimeout(() => {
|
|
|
- myStocks.value.forEach((stock) => {
|
|
|
- drawTrendChart(stock);
|
|
|
+ if (!isPageVisible.value)
|
|
|
+ return;
|
|
|
+ myStocks.value.forEach((stock, index) => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (isPageVisible.value) {
|
|
|
+ drawTrendChart(stock);
|
|
|
+ }
|
|
|
+ }, index * 30);
|
|
|
});
|
|
|
- }, 300);
|
|
|
+ }, 350);
|
|
|
});
|
|
|
};
|
|
|
const loadMyStocks = async (forceRefresh = false) => {
|
|
|
@@ -230,18 +283,23 @@ const _sfc_main = {
|
|
|
console.log("[我的股票] 使用缓存数据,只刷新行情");
|
|
|
await fetchIndexData();
|
|
|
await refreshAllQuotes();
|
|
|
+ drawAllTrendCharts();
|
|
|
startAutoRefresh();
|
|
|
return;
|
|
|
}
|
|
|
try {
|
|
|
isLoading.value = true;
|
|
|
+ let showedLoading = false;
|
|
|
if (myStocks.value.length === 0 || forceRefresh) {
|
|
|
common_vendor.index.showLoading({ title: "加载中..." });
|
|
|
+ showedLoading = true;
|
|
|
}
|
|
|
console.log("[我的股票] 调用 getUserStocks 接口");
|
|
|
const res = await utils_api.getUserStocks();
|
|
|
console.log("[我的股票] 服务器返回:", JSON.stringify(res));
|
|
|
- common_vendor.index.hideLoading();
|
|
|
+ if (showedLoading) {
|
|
|
+ common_vendor.index.hideLoading();
|
|
|
+ }
|
|
|
if (res.code === 200 && res.data) {
|
|
|
myStocks.value = res.data.map((item) => ({
|
|
|
code: item.stockCode,
|
|
|
@@ -267,7 +325,10 @@ const _sfc_main = {
|
|
|
}
|
|
|
startAutoRefresh();
|
|
|
} catch (e) {
|
|
|
- common_vendor.index.hideLoading();
|
|
|
+ try {
|
|
|
+ common_vendor.index.hideLoading();
|
|
|
+ } catch (err) {
|
|
|
+ }
|
|
|
console.error("[我的股票] 加载失败:", e);
|
|
|
if (myStocks.value.length === 0) {
|
|
|
myStocks.value = [];
|
|
|
@@ -317,7 +378,7 @@ const _sfc_main = {
|
|
|
stopAutoRefresh();
|
|
|
return;
|
|
|
}
|
|
|
- const delay = 3e3 + Math.random() * 1e3;
|
|
|
+ const delay = 1e4;
|
|
|
refreshTimer = setTimeout(async () => {
|
|
|
if (!isPageVisible.value) {
|
|
|
stopAutoRefresh();
|
|
|
@@ -326,6 +387,7 @@ const _sfc_main = {
|
|
|
await fetchIndexData();
|
|
|
if (myStocks.value.length > 0) {
|
|
|
await refreshAllQuotes();
|
|
|
+ drawAllTrendCharts();
|
|
|
}
|
|
|
scheduleNextRefresh();
|
|
|
}, delay);
|
|
|
@@ -370,7 +432,6 @@ const _sfc_main = {
|
|
|
};
|
|
|
common_vendor.onLoad(() => {
|
|
|
console.log("[我的股票] onLoad 触发");
|
|
|
- componentInstance = common_vendor.getCurrentInstance();
|
|
|
isLoggedIn.value = utils_auth.isLoggedIn();
|
|
|
isPageVisible.value = true;
|
|
|
loadMyStocks(true);
|
|
|
@@ -378,6 +439,9 @@ const _sfc_main = {
|
|
|
common_vendor.onShow(() => {
|
|
|
console.log("[我的股票] onShow 触发");
|
|
|
isPageVisible.value = true;
|
|
|
+ if (myStocks.value.length > 0) {
|
|
|
+ clearAllCanvases();
|
|
|
+ }
|
|
|
const wasLoggedIn = isLoggedIn.value;
|
|
|
isLoggedIn.value = utils_auth.isLoggedIn();
|
|
|
if (wasLoggedIn !== isLoggedIn.value) {
|
|
|
@@ -421,15 +485,14 @@ const _sfc_main = {
|
|
|
c: common_vendor.n(getMarketClass(stock.code)),
|
|
|
d: common_vendor.t(stock.code),
|
|
|
e: "chart-" + stock.code,
|
|
|
- f: "chart-" + stock.code,
|
|
|
- g: common_vendor.t(stock.currentPrice || "-"),
|
|
|
- h: common_vendor.t(stock.changePercent || "-"),
|
|
|
- i: common_vendor.n(getProfitClass(stock.changePercent)),
|
|
|
- j: common_vendor.o(($event) => removeStock(index), stock.code),
|
|
|
- k: ((_a = slideStates[stock.code]) == null ? void 0 : _a.x) || 0,
|
|
|
- l: common_vendor.o((e) => handleSlideChange(e, stock.code), stock.code),
|
|
|
- m: common_vendor.o(() => handleSlideEnd(stock.code), stock.code),
|
|
|
- n: stock.code
|
|
|
+ f: common_vendor.t(stock.currentPrice || "-"),
|
|
|
+ g: common_vendor.t(stock.changePercent || "-"),
|
|
|
+ h: common_vendor.n(getProfitClass(stock.changePercent)),
|
|
|
+ i: common_vendor.o(($event) => removeStock(index), stock.code),
|
|
|
+ j: ((_a = slideStates[stock.code]) == null ? void 0 : _a.x) || 0,
|
|
|
+ k: common_vendor.o((e) => handleSlideChange(e, stock.code), stock.code),
|
|
|
+ l: common_vendor.o(() => handleSlideEnd(stock.code), stock.code),
|
|
|
+ m: stock.code
|
|
|
};
|
|
|
}),
|
|
|
o: viewMode.value === "list",
|