StockListItem.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. "use strict";
  2. const common_vendor = require("../common/vendor.js");
  3. const _sfc_main = {
  4. __name: "StockListItem",
  5. props: {
  6. stock: {
  7. type: Object,
  8. required: true
  9. },
  10. showDelete: {
  11. type: Boolean,
  12. default: false
  13. }
  14. },
  15. emits: ["delete"],
  16. setup(__props, { emit }) {
  17. const props = __props;
  18. let componentInstance = null;
  19. const deleteWidth = 60;
  20. const moveX = common_vendor.ref(0);
  21. let currentX = 0;
  22. let autoResetTimer = null;
  23. const AUTO_RESET_DELAY = 2e3;
  24. const startAutoResetTimer = () => {
  25. clearAutoResetTimer();
  26. autoResetTimer = setTimeout(() => {
  27. moveX.value = 0;
  28. currentX = 0;
  29. }, AUTO_RESET_DELAY);
  30. };
  31. const clearAutoResetTimer = () => {
  32. if (autoResetTimer) {
  33. clearTimeout(autoResetTimer);
  34. autoResetTimer = null;
  35. }
  36. };
  37. const canvasId = common_vendor.ref(`chart-${props.stock.code}-${Math.random().toString(36).slice(2, 11)}`);
  38. const getMarketTag = (code) => {
  39. if (code.startsWith("6"))
  40. return "沪";
  41. if (code.startsWith("0"))
  42. return "深";
  43. if (code.startsWith("3"))
  44. return "创";
  45. return "沪";
  46. };
  47. const getMarketClass = (code) => {
  48. if (code.startsWith("6"))
  49. return "market-sh";
  50. if (code.startsWith("0"))
  51. return "market-sz";
  52. if (code.startsWith("3"))
  53. return "market-cy";
  54. return "market-sh";
  55. };
  56. const getChangeClass = (changePercent) => {
  57. if (!changePercent)
  58. return "";
  59. const str = String(changePercent).replace("%", "").replace("+", "");
  60. const value = parseFloat(str);
  61. if (value > 0)
  62. return "change-up";
  63. if (value < 0)
  64. return "change-down";
  65. return "";
  66. };
  67. const formatChangePercent = (changePercent) => {
  68. if (!changePercent)
  69. return "--";
  70. return String(changePercent);
  71. };
  72. const formatPrice = (price) => {
  73. if (!price)
  74. return "--";
  75. return parseFloat(price).toFixed(2);
  76. };
  77. const hasValidChange = (changePercent) => {
  78. if (!changePercent)
  79. return false;
  80. const str = String(changePercent).replace("%", "").replace("+", "");
  81. const value = parseFloat(str);
  82. return value !== 0 && !isNaN(value);
  83. };
  84. const drawTrendChart = (instance) => {
  85. let trendData = props.stock.trendData;
  86. if (!trendData || !Array.isArray(trendData) || trendData.length === 0) {
  87. trendData = generateMockTrendData();
  88. }
  89. const ctx = common_vendor.index.createCanvasContext(canvasId.value, instance);
  90. const width = 100;
  91. const height = 30;
  92. const padding = 2;
  93. const maxValue = Math.max(...trendData);
  94. const minValue = Math.min(...trendData);
  95. const dataRange = maxValue - minValue;
  96. const avgValue = (maxValue + minValue) / 2;
  97. const minRange = avgValue * 0.03 || 1;
  98. const range = Math.max(dataRange, minRange);
  99. const baseValue = trendData[0];
  100. const baseY = height - padding - (baseValue - minValue) / range * (height - padding * 2);
  101. const changePercent = parseFloat(String(props.stock.changePercent || "0").replace("%", "").replace("+", ""));
  102. const isUp = changePercent >= 0;
  103. const lineColor = isUp ? "#FF3B30" : "#34C759";
  104. const fillColor = isUp ? "rgba(255, 59, 48, 0.15)" : "rgba(52, 199, 89, 0.15)";
  105. ctx.beginPath();
  106. ctx.setStrokeStyle("#e0e0e0");
  107. ctx.setLineWidth(0.5);
  108. ctx.setLineDash([2, 2], 0);
  109. ctx.moveTo(padding, baseY);
  110. ctx.lineTo(width - padding, baseY);
  111. ctx.stroke();
  112. ctx.setLineDash([], 0);
  113. ctx.beginPath();
  114. ctx.moveTo(padding, baseY);
  115. trendData.forEach((value, index) => {
  116. const x = padding + index / (trendData.length - 1) * (width - padding * 2);
  117. const y = height - padding - (value - minValue) / range * (height - padding * 2);
  118. ctx.lineTo(x, y);
  119. });
  120. ctx.lineTo(width - padding, baseY);
  121. ctx.closePath();
  122. ctx.setFillStyle(fillColor);
  123. ctx.fill();
  124. ctx.beginPath();
  125. trendData.forEach((value, index) => {
  126. const x = padding + index / (trendData.length - 1) * (width - padding * 2);
  127. const y = height - padding - (value - minValue) / range * (height - padding * 2);
  128. if (index === 0) {
  129. ctx.moveTo(x, y);
  130. } else {
  131. ctx.lineTo(x, y);
  132. }
  133. });
  134. ctx.setStrokeStyle(lineColor);
  135. ctx.setLineWidth(1.5);
  136. ctx.stroke();
  137. ctx.draw();
  138. };
  139. const generateMockTrendData = () => {
  140. const changePercent = parseFloat(String(props.stock.changePercent || "0").replace("%", "").replace("+", ""));
  141. const points = 15;
  142. const data = [];
  143. let baseValue = 100;
  144. const trend = changePercent / 100;
  145. for (let i = 0; i < points; i++) {
  146. const randomChange = (Math.random() - 0.5) * 6;
  147. const trendChange = i / points * trend * 100;
  148. baseValue = baseValue + randomChange + trendChange / points;
  149. data.push(baseValue);
  150. }
  151. return data;
  152. };
  153. const handleMoveChange = (e) => {
  154. currentX = e.detail.x;
  155. if (props.showDelete && currentX <= -deleteWidth / 2) {
  156. startAutoResetTimer();
  157. }
  158. };
  159. const handleMoveEnd = () => {
  160. if (!props.showDelete)
  161. return;
  162. if (currentX < -deleteWidth / 3) {
  163. moveX.value = -deleteWidth;
  164. startAutoResetTimer();
  165. } else {
  166. moveX.value = 0;
  167. currentX = 0;
  168. clearAutoResetTimer();
  169. }
  170. };
  171. const handleDelete = () => {
  172. clearAutoResetTimer();
  173. moveX.value = 0;
  174. emit("delete");
  175. };
  176. common_vendor.onMounted(() => {
  177. componentInstance = common_vendor.getCurrentInstance();
  178. common_vendor.nextTick$1(() => {
  179. setTimeout(() => {
  180. drawTrendChart(componentInstance);
  181. }, 300);
  182. });
  183. });
  184. common_vendor.watch(() => props.stock.trendData, (newData) => {
  185. if (newData && componentInstance) {
  186. common_vendor.nextTick$1(() => {
  187. drawTrendChart(componentInstance);
  188. });
  189. }
  190. }, { deep: true });
  191. common_vendor.watch(() => props.stock.changePercent, () => {
  192. if (componentInstance) {
  193. common_vendor.nextTick$1(() => {
  194. drawTrendChart(componentInstance);
  195. });
  196. }
  197. });
  198. common_vendor.watch(moveX, (newVal) => {
  199. if (newVal < 0 && props.showDelete) {
  200. if (!autoResetTimer) {
  201. startAutoResetTimer();
  202. }
  203. } else if (newVal === 0) {
  204. clearAutoResetTimer();
  205. }
  206. });
  207. common_vendor.onUnmounted(() => {
  208. clearAutoResetTimer();
  209. });
  210. return (_ctx, _cache) => {
  211. return common_vendor.e({
  212. a: common_vendor.t(__props.stock.name),
  213. b: common_vendor.t(getMarketTag(__props.stock.code)),
  214. c: common_vendor.n(getMarketClass(__props.stock.code)),
  215. d: common_vendor.t(__props.stock.code),
  216. e: canvasId.value,
  217. f: canvasId.value,
  218. g: hasValidChange(__props.stock.changePercent)
  219. }, hasValidChange(__props.stock.changePercent) ? {
  220. h: common_vendor.t(formatChangePercent(__props.stock.changePercent)),
  221. i: common_vendor.n(getChangeClass(__props.stock.changePercent))
  222. } : {}, {
  223. j: common_vendor.t(formatPrice(__props.stock.currentPrice)),
  224. k: __props.showDelete
  225. }, __props.showDelete ? {
  226. l: common_vendor.o(handleDelete)
  227. } : {}, {
  228. m: moveX.value,
  229. n: common_vendor.o(handleMoveChange),
  230. o: common_vendor.o(handleMoveEnd)
  231. });
  232. };
  233. }
  234. };
  235. const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["__scopeId", "data-v-29af7fd7"], ["__file", "D:/program/gupiao-wx/src/components/StockListItem.vue"]]);
  236. wx.createComponent(Component);