"use strict"; const common_vendor = require("../../common/vendor.js"); const utils_auth = require("../../utils/auth.js"); 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"); const isLoading = common_vendor.ref(false); const lastLoadTime = common_vendor.ref(0); const CACHE_DURATION = 5e3; const isPageVisible = common_vendor.ref(false); const SLIDE_WIDTH = 100; const slideStates = common_vendor.reactive({}); let slideTimers = {}; const AUTO_RESET_DELAY = 2e3; const initSlideState = (code) => { if (!slideStates[code]) { slideStates[code] = { x: 0, currentX: 0 }; } }; const handleSlideChange = (e, code) => { initSlideState(code); slideStates[code].currentX = e.detail.x; }; const handleSlideEnd = (code) => { initSlideState(code); const state = slideStates[code]; if (state.currentX < -20) { state.x = -SLIDE_WIDTH; startAutoResetTimer(code); } else { resetSlide(code); } }; const resetSlide = (code) => { if (slideStates[code]) { slideStates[code].x = 0; slideStates[code].currentX = 0; } clearSlideTimer(code); }; const startAutoResetTimer = (code) => { clearSlideTimer(code); slideTimers[code] = setTimeout(() => { resetSlide(code); }, AUTO_RESET_DELAY); }; const clearSlideTimer = (code) => { if (slideTimers[code]) { clearTimeout(slideTimers[code]); delete slideTimers[code]; } }; const clearAllSlideTimers = () => { Object.keys(slideTimers).forEach((code) => { clearSlideTimer(code); }); }; const setViewMode = (mode) => { viewMode.value = mode; }; const indexData = common_vendor.ref({ stockCode: "000001", stockName: "上证指数", currentPrice: null, priceChange: null, changePercent: null }); let refreshTimer = null; const fetchIndexData = async () => { try { const res = await utils_api.getIndexQuote("000001"); if (res.code === 200 && res.data) { indexData.value = { ...indexData.value, ...res.data }; } } catch (e) { console.error("[上证指数] 获取失败:", e.message); } }; const formatIndexPrice = (price) => { if (!price) return "--"; return parseFloat(price).toFixed(2); }; const formatPrice = (price) => { if (!price) return "--"; return parseFloat(price).toFixed(2); }; const getIndexChangeClass = (changePercent) => { if (!changePercent) return ""; const str = String(changePercent).replace("%", "").replace("+", ""); const value = parseFloat(str); if (value > 0) return "index-up"; if (value < 0) return "index-down"; return ""; }; const getProfitClass = (profitPercent) => { if (!profitPercent) return ""; const str = String(profitPercent).replace("%", "").replace("+", ""); const value = parseFloat(str); if (value > 0) return "profit-up"; if (value < 0) return "profit-down"; return ""; }; const getMarketTag = (code) => { if (code.startsWith("6")) return "沪"; if (code.startsWith("0")) return "深"; if (code.startsWith("3")) return "创"; return "沪"; }; const getMarketClass = (code) => { if (code.startsWith("6")) return "market-sh"; if (code.startsWith("0")) return "market-sz"; if (code.startsWith("3")) return "market-cy"; return "market-sh"; }; 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); } }); ctx.setStrokeStyle(lineColor); ctx.setLineWidth(1.5); ctx.stroke(); ctx.draw(); }; const generateMockTrendData = (changePercent) => { const change = parseFloat(String(changePercent || "0").replace("%", "").replace("+", "")); const points = 15; const data = []; let baseValue = 100; const trend = change / 100; for (let i = 0; i < points; i++) { const randomChange = (Math.random() - 0.5) * 6; const trendChange = i / points * trend * 100; baseValue = baseValue + randomChange + trendChange / points; data.push(baseValue); } return data; }; const drawAllTrendCharts = () => { if (myStocks.value.length === 0) return; common_vendor.nextTick$1(() => { setTimeout(() => { myStocks.value.forEach((stock) => { drawTrendChart(stock); }); }, 300); }); }; const loadMyStocks = async (forceRefresh = false) => { console.log("[我的股票] loadMyStocks 开始执行, isLoggedIn=", isLoggedIn.value, "forceRefresh=", forceRefresh); if (!isLoggedIn.value) { myStocks.value = []; stopAutoRefresh(); return; } if (isLoading.value) { console.log("[我的股票] 正在加载中,跳过"); return; } const now = Date.now(); if (!forceRefresh && myStocks.value.length > 0 && now - lastLoadTime.value < CACHE_DURATION) { console.log("[我的股票] 使用缓存数据,只刷新行情"); await fetchIndexData(); await refreshAllQuotes(); startAutoRefresh(); return; } try { isLoading.value = true; if (myStocks.value.length === 0 || forceRefresh) { common_vendor.index.showLoading({ title: "加载中..." }); } console.log("[我的股票] 调用 getUserStocks 接口"); const res = await utils_api.getUserStocks(); console.log("[我的股票] 服务器返回:", JSON.stringify(res)); common_vendor.index.hideLoading(); if (res.code === 200 && res.data) { myStocks.value = res.data.map((item) => ({ code: item.stockCode, name: item.stockName, addPrice: item.addPrice, addDate: item.addDate, currentPrice: item.currentPrice, profitPercent: item.profitPercent, priceChange: item.priceChange, changePercent: item.changePercent, trendData: item.trendData })); lastLoadTime.value = Date.now(); console.log("[我的股票] 加载完成, 股票数量:", myStocks.value.length); } else { myStocks.value = []; console.log("[我的股票] 返回数据为空"); } await fetchIndexData(); if (myStocks.value.length > 0) { await refreshAllQuotes(); drawAllTrendCharts(); } startAutoRefresh(); } catch (e) { common_vendor.index.hideLoading(); console.error("[我的股票] 加载失败:", e); if (myStocks.value.length === 0) { myStocks.value = []; } startAutoRefresh(); } finally { isLoading.value = false; } }; const refreshAllQuotes = async () => { if (myStocks.value.length === 0) return; try { const codes = myStocks.value.map((stock) => stock.code).join(","); const quoteRes = await utils_api.getStockQuotes(codes); if (quoteRes.code === 200 && quoteRes.data && quoteRes.data.length > 0) { quoteRes.data.forEach((quoteData) => { const index = myStocks.value.findIndex((stock) => stock.code === quoteData.stockCode); if (index !== -1) { const stock = myStocks.value[index]; stock.priceChange = quoteData.priceChange; stock.changePercent = quoteData.changePercent; stock.currentPrice = quoteData.currentPrice; stock.name = quoteData.stockName || stock.name; stock.trendData = quoteData.trendData || null; if (stock.addPrice && quoteData.currentPrice) { const addPrice = parseFloat(stock.addPrice); const currentPrice = parseFloat(quoteData.currentPrice); if (addPrice > 0) { const profit = ((currentPrice - addPrice) / addPrice * 100).toFixed(2); stock.profitPercent = profit >= 0 ? `+${profit}%` : `${profit}%`; } } } }); } } catch (e) { console.error("[我的股票] 刷新异常:", e.message); } }; const startAutoRefresh = () => { if (!isLoggedIn.value || !isPageVisible.value) return; stopAutoRefresh(); const scheduleNextRefresh = () => { if (!isPageVisible.value) { stopAutoRefresh(); return; } const delay = 3e3 + Math.random() * 1e3; refreshTimer = setTimeout(async () => { if (!isPageVisible.value) { stopAutoRefresh(); return; } await fetchIndexData(); if (myStocks.value.length > 0) { await refreshAllQuotes(); } scheduleNextRefresh(); }, delay); }; scheduleNextRefresh(); }; const stopAutoRefresh = () => { if (refreshTimer) { clearTimeout(refreshTimer); refreshTimer = null; } }; const goToLogin = () => { common_vendor.index.navigateTo({ url: "/pages/login/login" }); }; const removeStock = async (idx) => { const stock = myStocks.value[idx]; resetSlide(stock.code); common_vendor.index.showModal({ title: "确认删除", content: `确定要删除 ${stock.name} 吗?`, confirmText: "删除", cancelText: "取消", success: async (res) => { if (res.confirm) { try { await utils_api.deleteUserStock(stock.code); delete slideStates[stock.code]; clearSlideTimer(stock.code); myStocks.value.splice(idx, 1); common_vendor.index.showToast({ title: "删除成功", icon: "success" }); if (myStocks.value.length === 0) { stopAutoRefresh(); } } catch (e) { console.error("删除失败:", e); common_vendor.index.showToast({ title: "删除失败", icon: "none" }); } } } }); }; common_vendor.onLoad(() => { console.log("[我的股票] onLoad 触发"); componentInstance = common_vendor.getCurrentInstance(); isLoggedIn.value = utils_auth.isLoggedIn(); isPageVisible.value = true; loadMyStocks(true); }); common_vendor.onShow(() => { console.log("[我的股票] onShow 触发"); isPageVisible.value = true; const wasLoggedIn = isLoggedIn.value; isLoggedIn.value = utils_auth.isLoggedIn(); if (wasLoggedIn !== isLoggedIn.value) { loadMyStocks(true); } else { loadMyStocks(false); } common_vendor.index.setNavigationBarTitle({ title: "量化交易大师" }); }); common_vendor.onHide(() => { console.log("[我的股票] onHide 触发"); isPageVisible.value = false; stopAutoRefresh(); }); common_vendor.onUnload(() => { console.log("[我的股票] onUnload 触发"); isPageVisible.value = false; stopAutoRefresh(); clearAllSlideTimers(); }); return (_ctx, _cache) => { return common_vendor.e({ a: common_vendor.t(formatIndexPrice(indexData.value.currentPrice)), b: common_vendor.n(getIndexChangeClass(indexData.value.changePercent)), c: common_vendor.t(indexData.value.priceChange || "--"), d: common_vendor.n(getIndexChangeClass(indexData.value.changePercent)), e: common_vendor.t(indexData.value.stockName || "上证指数"), f: common_vendor.t(indexData.value.changePercent || "--"), g: common_vendor.n(getIndexChangeClass(indexData.value.changePercent)), h: viewMode.value === "table" ? 1 : "", i: viewMode.value === "list" ? 1 : "", j: common_vendor.o(($event) => setViewMode("list")), k: viewMode.value === "table" ? 1 : "", l: common_vendor.o(($event) => setViewMode("table")), m: common_vendor.t(myStocks.value.length), n: common_vendor.f(myStocks.value, (stock, index, i0) => { var _a; return { a: common_vendor.t(stock.name), b: common_vendor.t(getMarketTag(stock.code)), 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 }; }), o: viewMode.value === "list", p: myStocks.value.length === 0 ? 1 : "", q: common_vendor.f(myStocks.value, (stock, index, i0) => { return { a: common_vendor.t(stock.name), b: common_vendor.t(getMarketTag(stock.code)), c: common_vendor.n(getMarketClass(stock.code)), d: common_vendor.t(stock.code), e: common_vendor.t(stock.addDate || "--"), f: common_vendor.t(formatPrice(stock.addPrice)), g: common_vendor.t(stock.profitPercent || "--"), h: common_vendor.n(getProfitClass(stock.profitPercent)), i: stock.code }; }), r: viewMode.value === "table", s: myStocks.value.length === 0 ? 1 : "", t: myStocks.value.length === 0 }, myStocks.value.length === 0 ? {} : {}, { v: !isLoggedIn.value ? 1 : "", w: !isLoggedIn.value }, !isLoggedIn.value ? { x: common_vendor.o(goToLogin) } : {}); }; } }; const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["__file", "D:/program/gupiao-wx/src/pages/rank/rank.vue"]]); wx.createPage(MiniProgramPage);