rank.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. "use strict";
  2. const common_vendor = require("../../common/vendor.js");
  3. const utils_auth = require("../../utils/auth.js");
  4. const utils_api = require("../../utils/api.js");
  5. if (!Math) {
  6. StockListItem();
  7. }
  8. const StockListItem = () => "../../components/StockListItem.js";
  9. const _sfc_main = {
  10. __name: "rank",
  11. setup(__props) {
  12. const isLoggedIn = common_vendor.ref(false);
  13. const myStocks = common_vendor.ref([]);
  14. const viewMode = common_vendor.ref("list");
  15. const isLoading = common_vendor.ref(false);
  16. const lastLoadTime = common_vendor.ref(0);
  17. const CACHE_DURATION = 5e3;
  18. const setViewMode = (mode) => {
  19. viewMode.value = mode;
  20. };
  21. const indexData = common_vendor.ref({
  22. stockCode: "000001",
  23. stockName: "上证指数",
  24. currentPrice: null,
  25. priceChange: null,
  26. changePercent: null
  27. });
  28. let refreshTimer = null;
  29. const fetchIndexData = async () => {
  30. try {
  31. const res = await utils_api.getIndexQuote("000001");
  32. if (res.code === 200 && res.data) {
  33. indexData.value = { ...indexData.value, ...res.data };
  34. }
  35. } catch (e) {
  36. console.error("[上证指数] 获取失败:", e.message);
  37. }
  38. };
  39. const formatIndexPrice = (price) => {
  40. if (!price)
  41. return "--";
  42. return parseFloat(price).toFixed(2);
  43. };
  44. const formatPrice = (price) => {
  45. if (!price)
  46. return "--";
  47. return parseFloat(price).toFixed(2);
  48. };
  49. const getIndexChangeClass = (changePercent) => {
  50. if (!changePercent)
  51. return "";
  52. const str = String(changePercent).replace("%", "").replace("+", "");
  53. const value = parseFloat(str);
  54. if (value > 0)
  55. return "index-up";
  56. if (value < 0)
  57. return "index-down";
  58. return "";
  59. };
  60. const getProfitClass = (profitPercent) => {
  61. if (!profitPercent)
  62. return "";
  63. const str = String(profitPercent).replace("%", "").replace("+", "");
  64. const value = parseFloat(str);
  65. if (value > 0)
  66. return "profit-up";
  67. if (value < 0)
  68. return "profit-down";
  69. return "";
  70. };
  71. const getMarketTag = (code) => {
  72. if (code.startsWith("6"))
  73. return "沪";
  74. if (code.startsWith("0"))
  75. return "深";
  76. if (code.startsWith("3"))
  77. return "创";
  78. return "沪";
  79. };
  80. const getMarketClass = (code) => {
  81. if (code.startsWith("6"))
  82. return "market-sh";
  83. if (code.startsWith("0"))
  84. return "market-sz";
  85. if (code.startsWith("3"))
  86. return "market-cy";
  87. return "market-sh";
  88. };
  89. const loadMyStocks = async (forceRefresh = false) => {
  90. console.log("[我的股票] loadMyStocks 开始执行, isLoggedIn=", isLoggedIn.value, "forceRefresh=", forceRefresh);
  91. if (!isLoggedIn.value) {
  92. myStocks.value = [];
  93. stopAutoRefresh();
  94. return;
  95. }
  96. if (isLoading.value) {
  97. console.log("[我的股票] 正在加载中,跳过");
  98. return;
  99. }
  100. const now = Date.now();
  101. if (!forceRefresh && myStocks.value.length > 0 && now - lastLoadTime.value < CACHE_DURATION) {
  102. console.log("[我的股票] 使用缓存数据,只刷新行情");
  103. await fetchIndexData();
  104. await refreshAllQuotes();
  105. startAutoRefresh();
  106. return;
  107. }
  108. try {
  109. isLoading.value = true;
  110. if (myStocks.value.length === 0 || forceRefresh) {
  111. common_vendor.index.showLoading({ title: "加载中..." });
  112. }
  113. console.log("[我的股票] 调用 getUserStocks 接口");
  114. const res = await utils_api.getUserStocks();
  115. console.log("[我的股票] 服务器返回:", JSON.stringify(res));
  116. common_vendor.index.hideLoading();
  117. if (res.code === 200 && res.data) {
  118. myStocks.value = res.data.map((item) => ({
  119. code: item.stockCode,
  120. name: item.stockName,
  121. addPrice: item.addPrice,
  122. addDate: item.addDate,
  123. currentPrice: item.currentPrice,
  124. profitPercent: item.profitPercent,
  125. priceChange: item.priceChange,
  126. changePercent: item.changePercent,
  127. trendData: item.trendData
  128. }));
  129. lastLoadTime.value = Date.now();
  130. console.log("[我的股票] 加载完成, 股票数量:", myStocks.value.length);
  131. } else {
  132. myStocks.value = [];
  133. console.log("[我的股票] 返回数据为空");
  134. }
  135. await fetchIndexData();
  136. if (myStocks.value.length > 0) {
  137. await refreshAllQuotes();
  138. }
  139. startAutoRefresh();
  140. } catch (e) {
  141. common_vendor.index.hideLoading();
  142. console.error("[我的股票] 加载失败:", e);
  143. if (myStocks.value.length === 0) {
  144. myStocks.value = [];
  145. }
  146. startAutoRefresh();
  147. } finally {
  148. isLoading.value = false;
  149. }
  150. };
  151. const refreshAllQuotes = async () => {
  152. if (myStocks.value.length === 0)
  153. return;
  154. try {
  155. const codes = myStocks.value.map((stock) => stock.code).join(",");
  156. const quoteRes = await utils_api.getStockQuotes(codes);
  157. if (quoteRes.code === 200 && quoteRes.data && quoteRes.data.length > 0) {
  158. quoteRes.data.forEach((quoteData) => {
  159. const index = myStocks.value.findIndex((stock) => stock.code === quoteData.stockCode);
  160. if (index !== -1) {
  161. const stock = myStocks.value[index];
  162. stock.priceChange = quoteData.priceChange;
  163. stock.changePercent = quoteData.changePercent;
  164. stock.currentPrice = quoteData.currentPrice;
  165. stock.name = quoteData.stockName || stock.name;
  166. stock.trendData = quoteData.trendData || null;
  167. if (stock.addPrice && quoteData.currentPrice) {
  168. const addPrice = parseFloat(stock.addPrice);
  169. const currentPrice = parseFloat(quoteData.currentPrice);
  170. if (addPrice > 0) {
  171. const profit = ((currentPrice - addPrice) / addPrice * 100).toFixed(2);
  172. stock.profitPercent = profit >= 0 ? `+${profit}%` : `${profit}%`;
  173. }
  174. }
  175. }
  176. });
  177. }
  178. } catch (e) {
  179. console.error("[我的股票] 刷新异常:", e.message);
  180. }
  181. };
  182. const startAutoRefresh = () => {
  183. if (!isLoggedIn.value)
  184. return;
  185. stopAutoRefresh();
  186. const scheduleNextRefresh = () => {
  187. const delay = 3e3 + Math.random() * 1e3;
  188. refreshTimer = setTimeout(async () => {
  189. await fetchIndexData();
  190. if (myStocks.value.length > 0) {
  191. await refreshAllQuotes();
  192. }
  193. scheduleNextRefresh();
  194. }, delay);
  195. };
  196. scheduleNextRefresh();
  197. };
  198. const stopAutoRefresh = () => {
  199. if (refreshTimer) {
  200. clearTimeout(refreshTimer);
  201. refreshTimer = null;
  202. }
  203. };
  204. const goToLogin = () => {
  205. common_vendor.index.navigateTo({ url: "/pages/login/login" });
  206. };
  207. const handleStockClick = async (stockItem, idx) => {
  208. console.log("点击股票:", stockItem.name, idx);
  209. try {
  210. const quoteRes = await utils_api.getStockQuotes(stockItem.code);
  211. if (quoteRes.code === 200 && quoteRes.data && quoteRes.data.length > 0) {
  212. const quoteData = quoteRes.data[0];
  213. const stock = myStocks.value[idx];
  214. if (stock) {
  215. stock.priceChange = quoteData.priceChange;
  216. stock.changePercent = quoteData.changePercent;
  217. stock.currentPrice = quoteData.currentPrice;
  218. stock.name = quoteData.stockName || stock.name;
  219. stock.trendData = quoteData.trendData || null;
  220. if (stock.addPrice && quoteData.currentPrice) {
  221. const addPrice = parseFloat(stock.addPrice);
  222. const currentPrice = parseFloat(quoteData.currentPrice);
  223. if (addPrice > 0) {
  224. const profit = ((currentPrice - addPrice) / addPrice * 100).toFixed(2);
  225. stock.profitPercent = profit >= 0 ? `+${profit}%` : `${profit}%`;
  226. }
  227. }
  228. }
  229. }
  230. } catch (e) {
  231. console.error("刷新股票行情失败:", e);
  232. }
  233. common_vendor.index.showToast({ title: "股票详情功能开发中", icon: "none" });
  234. };
  235. const removeStock = async (idx) => {
  236. const stock = myStocks.value[idx];
  237. common_vendor.index.showModal({
  238. title: "确认删除",
  239. content: `确定要删除 ${stock.name} 吗?`,
  240. confirmText: "删除",
  241. cancelText: "取消",
  242. success: async (res) => {
  243. if (res.confirm) {
  244. try {
  245. await utils_api.deleteUserStock(stock.code);
  246. myStocks.value.splice(idx, 1);
  247. common_vendor.index.showToast({ title: "删除成功", icon: "success" });
  248. if (myStocks.value.length === 0) {
  249. stopAutoRefresh();
  250. }
  251. } catch (e) {
  252. console.error("删除失败:", e);
  253. common_vendor.index.showToast({ title: "删除失败", icon: "none" });
  254. }
  255. }
  256. }
  257. });
  258. };
  259. common_vendor.onLoad(() => {
  260. console.log("[我的股票] onLoad 触发");
  261. isLoggedIn.value = utils_auth.isLoggedIn();
  262. loadMyStocks(true);
  263. });
  264. common_vendor.onShow(() => {
  265. console.log("[我的股票] onShow 触发");
  266. const wasLoggedIn = isLoggedIn.value;
  267. isLoggedIn.value = utils_auth.isLoggedIn();
  268. if (wasLoggedIn !== isLoggedIn.value) {
  269. loadMyStocks(true);
  270. } else {
  271. loadMyStocks(false);
  272. }
  273. common_vendor.index.setNavigationBarTitle({ title: "量化交易大师" });
  274. });
  275. common_vendor.onHide(() => {
  276. stopAutoRefresh();
  277. });
  278. common_vendor.onUnload(() => {
  279. stopAutoRefresh();
  280. });
  281. return (_ctx, _cache) => {
  282. return common_vendor.e({
  283. a: common_vendor.t(formatIndexPrice(indexData.value.currentPrice)),
  284. b: common_vendor.n(getIndexChangeClass(indexData.value.changePercent)),
  285. c: common_vendor.t(indexData.value.priceChange || "--"),
  286. d: common_vendor.n(getIndexChangeClass(indexData.value.changePercent)),
  287. e: common_vendor.t(indexData.value.stockName || "上证指数"),
  288. f: common_vendor.t(indexData.value.changePercent || "--"),
  289. g: common_vendor.n(getIndexChangeClass(indexData.value.changePercent)),
  290. h: viewMode.value === "table" ? 1 : "",
  291. i: viewMode.value === "list" ? 1 : "",
  292. j: common_vendor.o(($event) => setViewMode("list")),
  293. k: viewMode.value === "table" ? 1 : "",
  294. l: common_vendor.o(($event) => setViewMode("table")),
  295. m: common_vendor.f(myStocks.value, (stock, index, i0) => {
  296. return {
  297. a: stock.code,
  298. b: common_vendor.o(($event) => removeStock(index), stock.code),
  299. c: common_vendor.o(($event) => handleStockClick(stock, index), stock.code),
  300. d: "2482292d-0-" + i0,
  301. e: common_vendor.p({
  302. stock,
  303. ["show-delete"]: true
  304. })
  305. };
  306. }),
  307. n: viewMode.value === "list",
  308. o: myStocks.value.length === 0 ? 1 : "",
  309. p: common_vendor.f(myStocks.value, (stock, index, i0) => {
  310. return {
  311. a: common_vendor.t(stock.name),
  312. b: common_vendor.t(getMarketTag(stock.code)),
  313. c: common_vendor.n(getMarketClass(stock.code)),
  314. d: common_vendor.t(stock.code),
  315. e: common_vendor.t(stock.addDate || "--"),
  316. f: common_vendor.t(formatPrice(stock.addPrice)),
  317. g: common_vendor.t(stock.profitPercent || "--"),
  318. h: common_vendor.n(getProfitClass(stock.profitPercent)),
  319. i: stock.code,
  320. j: common_vendor.o(($event) => handleStockClick(stock, index), stock.code)
  321. };
  322. }),
  323. q: viewMode.value === "table",
  324. r: myStocks.value.length === 0 ? 1 : "",
  325. s: myStocks.value.length === 0
  326. }, myStocks.value.length === 0 ? {} : {}, {
  327. t: !isLoggedIn.value ? 1 : "",
  328. v: !isLoggedIn.value
  329. }, !isLoggedIn.value ? {
  330. w: common_vendor.o(goToLogin)
  331. } : {});
  332. };
  333. }
  334. };
  335. const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["__file", "D:/program/gupiao-wx/src/pages/rank/rank.vue"]]);
  336. wx.createPage(MiniProgramPage);