From c976333b7244d47d53970920e0e23f92ba9d87b0 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 7 Apr 2026 10:58:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9Amarket=E5=85=B3?= =?UTF-8?q?=E9=97=AD=E6=97=B6=E5=80=99=E7=9A=84=E9=A1=B5=E9=9D=A2=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=EF=BC=8C=E4=BC=98=E5=8C=96=E4=BC=A0=E5=8F=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- design/pencil-new.pen | 1758 ++++++++++++++++++++++++++++++++- src/api/event.ts | 68 +- src/components/MarketCard.vue | 21 +- src/locales/en.json | 7 +- src/locales/ja.json | 7 +- src/locales/ko.json | 7 +- src/locales/zh-CN.json | 7 +- src/locales/zh-TW.json | 7 +- src/router/index.ts | 19 + src/router/scrollKeys.ts | 2 + src/views/EventMarkets.vue | 210 +++- src/views/Home.vue | 9 + src/views/Search.vue | 22 +- src/views/TradeDetail.vue | 149 ++- src/views/Wallet.vue | 15 +- 15 files changed, 2162 insertions(+), 146 deletions(-) create mode 100644 src/router/scrollKeys.ts diff --git a/design/pencil-new.pen b/design/pencil-new.pen index bf9b3fa..3ef8f85 100644 --- a/design/pencil-new.pen +++ b/design/pencil-new.pen @@ -1,5 +1,5 @@ { - "version": "2.9", + "version": "2.10", "children": [ { "type": "frame", @@ -6491,7 +6491,8 @@ "fill": "$--text-primary", "content": "←", "fontFamily": "Inter", - "fontSize": 22 + "fontSize": 22, + "fontWeight": "normal" }, { "type": "text", @@ -6842,6 +6843,1759 @@ "fontWeight": "normal" } ] + }, + { + "type": "frame", + "id": "8RaDm", + "x": 4260, + "y": 0, + "name": "Trade Detail — Mobile", + "clip": true, + "width": 402, + "fill": "$--bg-page", + "layout": "vertical", + "gap": 16, + "padding": 16, + "children": [ + { + "type": "frame", + "id": "lNCLc", + "name": "Chart", + "width": "fill_container", + "fill": "#FFFFFF", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E7E7E7" + }, + "layout": "vertical", + "gap": 10, + "padding": 16, + "children": [ + { + "type": "text", + "id": "r9yEE", + "fill": "$--text-primary", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Will Candidate X win the 2028 election?", + "lineHeight": 1.35, + "fontFamily": "Inter", + "fontSize": 18, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "w7e5x", + "name": "ctrl", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "Mwpmo", + "name": "pill", + "fill": "$--bg-dark", + "cornerRadius": 999, + "padding": [ + 6, + 12 + ], + "children": [ + { + "type": "text", + "id": "yn2AB", + "fill": "#FFFFFF", + "content": "Dec 31, 2028", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "juXtR", + "width": "fill_container", + "height": 1 + }, + { + "type": "frame", + "id": "kSiMv", + "name": "tog", + "height": 26, + "cornerRadius": 6, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border-color" + }, + "children": [ + { + "type": "frame", + "id": "N1cXW", + "name": "tA", + "fill": "$--primary", + "cornerRadius": 4, + "padding": [ + 4, + 8 + ], + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "QNgEi", + "width": 18, + "height": 18, + "iconFontName": "show_chart", + "iconFontFamily": "Material Symbols Outlined", + "fill": "#FFFFFF" + } + ] + }, + { + "type": "frame", + "id": "UxemX", + "name": "tB", + "padding": [ + 4, + 10 + ], + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "iQ8zF", + "fill": "$--text-secondary", + "content": "BTC", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "700" + } + ] + } + ] + } + ] + }, + { + "type": "text", + "id": "RSUew", + "fill": "#2563EB", + "content": "62% Chance", + "fontFamily": "Inter", + "fontSize": 22, + "fontWeight": "700" + }, + { + "type": "frame", + "id": "5W1aW", + "name": "area", + "clip": true, + "width": "fill_container", + "height": 260, + "fill": "#F9FAFB", + "cornerRadius": 8, + "layout": "none", + "children": [ + { + "type": "rectangle", + "id": "Csb1Q", + "x": 0, + "y": 65, + "fill": "#E5E7EB", + "width": 330, + "height": 1 + }, + { + "type": "rectangle", + "id": "Q6K8y", + "x": 0, + "y": 130, + "fill": "#E5E7EB", + "width": 330, + "height": 1 + }, + { + "type": "rectangle", + "id": "O3RER", + "x": 0, + "y": 195, + "fill": "#E5E7EB", + "width": 330, + "height": 1 + }, + { + "type": "path", + "id": "wiQaQ", + "x": 12, + "y": 36, + "geometry": "M0 110l70-15 70 30 70-55 70 30 34-45 0 145-314 0z", + "fill": { + "type": "gradient", + "gradientType": "linear", + "enabled": true, + "rotation": 180, + "size": { + "height": 1 + }, + "colors": [ + { + "color": "#2563EB33", + "position": 0 + }, + { + "color": "#2563EB00", + "position": 1 + } + ] + }, + "width": 338, + "height": 200 + }, + { + "type": "path", + "id": "d6dVi", + "x": 12, + "y": 36, + "geometry": "M0 110l70-15 70 30 70-55 70 30 34-45", + "fill": "#00000000", + "width": 338, + "height": 200, + "stroke": { + "align": "center", + "thickness": 2.5, + "fill": "#2563EB" + } + } + ] + }, + { + "type": "frame", + "id": "7tpap", + "name": "foot", + "width": "fill_container", + "stroke": { + "align": "inside", + "thickness": { + "top": 1 + }, + "fill": "$--border-light" + }, + "padding": [ + 10, + 0, + 0, + 0 + ], + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "SKQX5", + "fill": "$--text-secondary", + "textGrowth": "fixed-width", + "width": 200, + "content": "$1.2M Vol. | Jan 20, 2029", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "DCb8Y", + "name": "tr", + "gap": 4, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "r9kIn", + "fill": "$--text-secondary", + "content": "1H", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "0pkTv", + "fill": "$--text-primary", + "content": "1D", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "600" + }, + { + "type": "text", + "id": "9UJdE", + "fill": "$--text-secondary", + "content": "1W", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "sS7Za", + "fill": "$--text-secondary", + "content": "ALL", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "3M8Lt", + "name": "pos", + "clip": true, + "width": "fill_container", + "fill": "#FFFFFF", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border-color" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "grJKR", + "name": "tabs", + "width": "fill_container", + "height": 46, + "stroke": { + "align": "inside", + "thickness": { + "bottom": 1 + }, + "fill": "$--border-color" + }, + "gap": 20, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "8lvlx", + "fill": "$--text-primary", + "content": "我的持仓", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "600" + }, + { + "type": "text", + "id": "CmiIn", + "fill": "$--text-secondary", + "content": "未成交订单", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "sfbVq", + "name": "pane", + "width": "fill_container", + "layout": "vertical", + "gap": 10, + "padding": 12, + "children": [ + { + "type": "frame", + "id": "NmErT", + "name": "row", + "stroke": { + "align": "inside", + "thickness": { + "bottom": 1 + }, + "fill": "#F0F0F0" + }, + "layout": "vertical", + "gap": 6, + "padding": [ + 10, + 0 + ], + "children": [ + { + "type": "frame", + "id": "eHTV5", + "name": "h", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "xbkHd", + "name": "ic", + "width": 28, + "height": 28, + "fill": { + "type": "gradient", + "gradientType": "linear", + "enabled": true, + "rotation": 135, + "size": { + "height": 1 + }, + "colors": [ + { + "color": "#22C55E", + "position": 0 + }, + { + "color": "#16A34A", + "position": 1 + } + ] + }, + "cornerRadius": 8, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "M4d8p", + "fill": "#FFFFFF", + "content": "Y", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "700" + } + ] + }, + { + "type": "text", + "id": "QCSjJ", + "fill": "$--text-primary", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "Market title…", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + } + ] + }, + { + "type": "frame", + "id": "AkRgi", + "name": "m", + "width": "fill_container", + "gap": 6, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "GdDrn", + "name": "yp", + "fill": "#DCFCE7", + "cornerRadius": 4, + "padding": [ + 2, + 8 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "4EljD", + "fill": "#166534", + "content": "Yes", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "600" + } + ] + }, + { + "type": "text", + "id": "qO52h", + "fill": "$--text-primary", + "content": "120 份额", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "j0s8i", + "fill": "$--text-primary", + "content": "$72", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "vv6La", + "width": "fill_container", + "height": 1 + }, + { + "type": "frame", + "id": "CKgH5", + "name": "sb", + "cornerRadius": 6, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--primary" + }, + "padding": [ + 5, + 10 + ], + "children": [ + { + "type": "text", + "id": "xwgol", + "fill": "$--primary", + "content": "卖出", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "500" + } + ] + } + ] + }, + { + "type": "text", + "id": "jHETu", + "fill": "$--text-secondary", + "content": "花费 $60 → 可赢 $120", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "Xrg6V", + "name": "ob", + "clip": true, + "width": "fill_container", + "fill": "#FFFFFF", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border-color" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "ZZy3J", + "name": "h0", + "width": "fill_container", + "padding": 12, + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "RibpR", + "fill": "$--text-primary", + "content": "订单簿", + "fontFamily": "Inter", + "fontSize": 15, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "0gPwS", + "name": "live", + "gap": 6, + "alignItems": "center", + "children": [ + { + "type": "ellipse", + "id": "20fCw", + "fill": "#DC2626", + "width": 8, + "height": 8 + }, + { + "type": "text", + "id": "WNzjA", + "fill": "$--text-secondary", + "content": "实时", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "BsYX8", + "name": "tb", + "stroke": { + "align": "inside", + "thickness": { + "bottom": 1 + }, + "fill": "$--border-color" + }, + "gap": 8, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "y8Kd2", + "name": "ty", + "padding": [ + 10, + 12 + ], + "children": [ + { + "type": "text", + "id": "NbknN", + "fill": "$--text-primary", + "content": "买入 Yes", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "600" + } + ] + }, + { + "type": "frame", + "id": "kiiqS", + "name": "tn", + "padding": [ + 10, + 12 + ], + "children": [ + { + "type": "text", + "id": "jCdL2", + "fill": "$--text-secondary", + "content": "买入 No", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "nNNCL", + "name": "hd", + "gap": 6, + "padding": [ + 6, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "ZcUGr", + "width": 80, + "height": 1 + }, + { + "type": "text", + "id": "PwAlt", + "fill": "$--text-tertiary", + "textGrowth": "fixed-width", + "width": 56, + "content": "价格", + "textAlign": "right", + "fontFamily": "Inter", + "fontSize": 10, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "WMEKt", + "fill": "$--text-tertiary", + "textGrowth": "fixed-width", + "width": 64, + "content": "份额", + "textAlign": "right", + "fontFamily": "Inter", + "fontSize": 10, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "0T5UR", + "fill": "$--text-tertiary", + "textGrowth": "fixed-width", + "width": 56, + "content": "合计", + "textAlign": "right", + "fontFamily": "Inter", + "fontSize": 10, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "FLoJS", + "name": "r1", + "height": 32, + "gap": 6, + "padding": [ + 0, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "rectangle", + "cornerRadius": 3, + "id": "9U4qp", + "fill": "#E8959522", + "width": 72, + "height": 20 + }, + { + "type": "text", + "id": "eSmGk", + "fill": "#991B1B", + "textGrowth": "fixed-width", + "width": 56, + "content": "64¢", + "textAlign": "right", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "600" + }, + { + "type": "text", + "id": "FvcbT", + "fill": "$--text-primary", + "textGrowth": "fixed-width", + "width": 64, + "content": "1.2k", + "textAlign": "right", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "FsWfg", + "fill": "$--text-primary", + "textGrowth": "fixed-width", + "width": 56, + "content": "768", + "textAlign": "right", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "Twfgb", + "name": "lbl", + "gap": 6, + "padding": [ + 2, + 12 + ], + "justifyContent": "center", + "children": [ + { + "type": "text", + "id": "D6xu5", + "fill": "#991B1B", + "content": "卖单", + "fontFamily": "Inter", + "fontSize": 10, + "fontWeight": "600" + }, + { + "type": "text", + "id": "eRa7G", + "fill": "$--text-tertiary", + "content": "·", + "fontFamily": "Inter", + "fontSize": 10, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "Zl06G", + "fill": "#166534", + "content": "买单", + "fontFamily": "Inter", + "fontSize": 10, + "fontWeight": "600" + } + ] + }, + { + "type": "frame", + "id": "HaHOc", + "name": "r2", + "height": 32, + "gap": 6, + "padding": [ + 0, + 12, + 8, + 12 + ], + "alignItems": "center", + "children": [ + { + "type": "rectangle", + "cornerRadius": 3, + "id": "zdvnt", + "fill": "#7ACC7A33", + "width": 60, + "height": 20 + }, + { + "type": "text", + "id": "qyCzy", + "fill": "#166534", + "textGrowth": "fixed-width", + "width": 56, + "content": "61¢", + "textAlign": "right", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "600" + }, + { + "type": "text", + "id": "Mh6dW", + "fill": "$--text-primary", + "textGrowth": "fixed-width", + "width": 64, + "content": "2.4k", + "textAlign": "right", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "kzFqJ", + "fill": "$--text-primary", + "textGrowth": "fixed-width", + "width": 56, + "content": "1464", + "textAlign": "right", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "SPI4X", + "name": "ft", + "width": "fill_container", + "padding": [ + 8, + 12 + ], + "justifyContent": "space_between", + "children": [ + { + "type": "text", + "id": "PiMS9", + "fill": "$--text-secondary", + "content": "最新 62¢", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "P8dGX", + "fill": "$--text-secondary", + "content": "价差 1¢", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "3lFid", + "name": "rules", + "width": "fill_container", + "fill": "#FFFFFF", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border-color" + }, + "layout": "vertical", + "gap": 10, + "padding": 14, + "children": [ + { + "type": "text", + "id": "NEtgM", + "fill": "$--text-secondary", + "content": "规则说明", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "600", + "letterSpacing": 0.5 + }, + { + "type": "text", + "id": "kCHD4", + "fill": "#374151", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "本市场在正式结果公布并按规则结算后关闭。Yes 则 Yes 份额 $1 兑付;否则 No 份额兑付。", + "lineHeight": 1.45, + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "A2B1k", + "fill": "$--text-secondary", + "content": "信息来源", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "600" + }, + { + "type": "text", + "id": "MNpBf", + "fill": "#2563EB", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "https://example.com/source", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "c6Fwf", + "name": "sp", + "width": "fill_container", + "height": 88, + "fill": "#00000000" + }, + { + "type": "frame", + "id": "0NXrY", + "name": "bar", + "width": "fill_container", + "height": 76, + "fill": "#FFFFFF", + "stroke": { + "align": "inside", + "thickness": { + "top": 1 + }, + "fill": "#EEEEEE" + }, + "gap": 10, + "padding": 12, + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "VYzNT", + "name": "yBar", + "width": "fill_container", + "height": 50, + "fill": "#B8E0B8", + "cornerRadius": 6, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "VAFRq", + "fill": "#006600", + "content": "Yes 62¢", + "fontFamily": "Inter", + "fontSize": 15, + "fontWeight": "600" + } + ] + }, + { + "type": "frame", + "id": "Hcq6p", + "name": "nBar", + "width": "fill_container", + "height": 50, + "fill": "#F0B8B8", + "cornerRadius": 6, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "qIHNe", + "fill": "#CC0000", + "content": "No 38¢", + "fontFamily": "Inter", + "fontSize": 15, + "fontWeight": "600" + } + ] + }, + { + "type": "frame", + "id": "qb8vO", + "name": "more", + "width": 50, + "height": 50, + "fill": "#E5E7EB", + "cornerRadius": 999, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "icon_font", + "id": "3diW2", + "width": 22, + "height": 22, + "iconFontName": "more_horiz", + "iconFontFamily": "Material Symbols Outlined", + "fill": "$--text-secondary" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "P4mwJ", + "x": 4686, + "y": 0, + "name": "Trade Detail — Resolved (Mobile)", + "clip": true, + "width": 402, + "fill": "$--bg-page", + "layout": "vertical", + "gap": 16, + "padding": 16, + "children": [ + { + "type": "frame", + "id": "Nbj9r", + "name": "stat", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "z3L74", + "name": "p", + "fill": "#E5E7EB", + "cornerRadius": 999, + "padding": [ + 4, + 10 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "m15x0", + "fill": "#4B5563", + "content": "已结算", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "600" + } + ] + }, + { + "type": "text", + "id": "2m6XZ", + "fill": "$--text-secondary", + "content": "2025-11-06 · 官方结果已公布", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "text", + "id": "PriFq", + "fill": "$--text-primary", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "2024 年美国总统大选:民主党候选人会赢吗?", + "lineHeight": 1.35, + "fontFamily": "Inter", + "fontSize": 18, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "2BWsE", + "name": "hero", + "width": "fill_container", + "fill": "#FFFFFF", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border-color" + }, + "layout": "vertical", + "gap": 12, + "padding": 16, + "children": [ + { + "type": "text", + "id": "pN70W", + "fill": "$--text-secondary", + "content": "最终结果", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "600", + "letterSpacing": 0.4 + }, + { + "type": "frame", + "id": "MqHrB", + "name": "out", + "gap": 10, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "UoVmW", + "fill": "#DCFCE7", + "cornerRadius": 8, + "padding": [ + 6, + 14 + ], + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "VFp1w", + "fill": "#166534", + "content": "Yes", + "fontFamily": "Inter", + "fontSize": 20, + "fontWeight": "700" + } + ] + } + ] + }, + { + "type": "text", + "id": "9YkzI", + "fill": "#374151", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "胜出方按 $1 / 份兑付;另一方归零。", + "lineHeight": 1.4, + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "s17po", + "name": "ch", + "width": "fill_container", + "fill": "#FFFFFF", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "#E7E7E7" + }, + "layout": "vertical", + "gap": 10, + "padding": 16, + "children": [ + { + "type": "frame", + "id": "EGEzG", + "name": "chH", + "width": "fill_container", + "justifyContent": "space_between", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "zUSBv", + "fill": "$--text-primary", + "content": "历史概率(已收盘)", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "600" + }, + { + "type": "text", + "id": "virhJ", + "fill": "#166534", + "content": "100%", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "700" + } + ] + }, + { + "type": "frame", + "id": "kRpo9", + "name": "area", + "clip": true, + "width": "fill_container", + "height": 200, + "fill": "#F9FAFB", + "cornerRadius": 8, + "layout": "none", + "children": [ + { + "type": "rectangle", + "id": "3848B", + "x": 0, + "y": 50, + "fill": "#E5E7EB", + "width": 330, + "height": 1 + }, + { + "type": "rectangle", + "id": "L5ZBf", + "x": 0, + "y": 100, + "fill": "#E5E7EB", + "width": 330, + "height": 1 + }, + { + "type": "rectangle", + "id": "O2tLC", + "x": 0, + "y": 150, + "fill": "#E5E7EB", + "width": 330, + "height": 1 + }, + { + "type": "path", + "id": "hfhMU", + "x": 10, + "y": 30, + "geometry": "M0 130l40-5 50-25 50 10 60-40 60-20 40-30 20-15 10 0 0 155-330 0z", + "fill": { + "type": "gradient", + "gradientType": "linear", + "enabled": true, + "rotation": 180, + "size": { + "height": 1 + }, + "colors": [ + { + "color": "#16653422", + "position": 0 + }, + { + "color": "#16653400", + "position": 1 + } + ] + }, + "width": 350, + "height": 150 + }, + { + "type": "path", + "id": "S0Um8", + "x": 10, + "y": 30, + "geometry": "M0 130l40-5 50-25 50 10 60-40 60-20 40-30 20-15 10 0", + "fill": "#00000000", + "width": 350, + "height": 150, + "stroke": { + "align": "center", + "thickness": 2, + "fill": "#16A34A" + } + }, + { + "type": "text", + "id": "rEszp", + "x": 8, + "y": 178, + "fill": "$--text-tertiary", + "content": "起点", + "fontFamily": "Inter", + "fontSize": 9, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "5bLUS", + "x": 298, + "y": 178, + "fill": "$--text-tertiary", + "content": "结算", + "fontFamily": "Inter", + "fontSize": 9, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "11czT", + "name": "settle", + "width": "fill_container", + "fill": "#FFFFFF", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border-color" + }, + "layout": "vertical", + "gap": 12, + "padding": 16, + "children": [ + { + "type": "text", + "id": "SpiqQ", + "fill": "$--text-primary", + "content": "结算信息", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "600" + }, + { + "type": "frame", + "id": "I1S7t", + "name": "r1", + "width": "fill_container", + "justifyContent": "space_between", + "children": [ + { + "type": "text", + "id": "h5DFN", + "fill": "$--text-secondary", + "content": "Yes 最终价", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "mY31G", + "fill": "#166534", + "content": "100.0¢", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "600" + } + ] + }, + { + "type": "frame", + "id": "etX2u", + "name": "r2", + "width": "fill_container", + "justifyContent": "space_between", + "children": [ + { + "type": "text", + "id": "6eUnN", + "fill": "$--text-secondary", + "content": "No 最终价", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "ZM7Xs", + "fill": "$--text-tertiary", + "content": "—", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "saEnz", + "name": "r3", + "width": "fill_container", + "justifyContent": "space_between", + "children": [ + { + "type": "text", + "id": "JQ1dZ", + "fill": "$--text-secondary", + "content": "投票结束", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "DHqmz", + "fill": "$--text-primary", + "content": "2025-11-05", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + } + ] + }, + { + "type": "text", + "id": "RlzjI", + "fill": "#6B7280", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "结果依据:Associated Press 官宣 + UMA Oracle", + "lineHeight": 1.4, + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "2d5YO", + "name": "pos", + "clip": true, + "width": "fill_container", + "fill": "#FFFFFF", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border-color" + }, + "layout": "vertical", + "children": [ + { + "type": "frame", + "id": "ViYxh", + "name": "pt", + "width": "fill_container", + "stroke": { + "align": "inside", + "thickness": { + "bottom": 1 + }, + "fill": "$--border-color" + }, + "gap": 8, + "padding": [ + 12, + 14 + ], + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "CkrGn", + "fill": "$--text-primary", + "content": "我的持仓", + "fontFamily": "Inter", + "fontSize": 14, + "fontWeight": "600" + }, + { + "type": "text", + "id": "8pYEb", + "fill": "#4B5563", + "content": "已结算", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "600" + } + ] + }, + { + "type": "frame", + "id": "to6Jy", + "name": "body", + "width": "fill_container", + "layout": "vertical", + "gap": 8, + "padding": 14, + "children": [ + { + "type": "frame", + "id": "pjqDk", + "name": "row", + "width": "fill_container", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "frame", + "id": "t5qRl", + "fill": "#DCFCE7", + "cornerRadius": 4, + "padding": [ + 2, + 8 + ], + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "tR6vx", + "fill": "#166534", + "content": "Yes", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "600" + } + ] + }, + { + "type": "text", + "id": "WaUuJ", + "fill": "$--text-primary", + "content": "80 份", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "frame", + "id": "hdPK6", + "width": "fill_container", + "height": 1 + }, + { + "type": "text", + "id": "ovgnn", + "fill": "#166534", + "content": "已兑付 $80", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "600" + } + ] + }, + { + "type": "text", + "id": "NMZuB", + "fill": "$--text-secondary", + "content": "成本约 $48 · 已计入钱包余额", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "normal" + } + ] + } + ] + }, + { + "type": "frame", + "id": "8seBc", + "name": "arch", + "width": "fill_container", + "fill": "#F9FAFB", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border-color" + }, + "layout": "vertical", + "gap": 8, + "padding": 14, + "children": [ + { + "type": "text", + "id": "O4zOo", + "fill": "$--text-secondary", + "content": "订单簿", + "fontFamily": "Inter", + "fontSize": 12, + "fontWeight": "600" + }, + { + "type": "text", + "id": "4W0dk", + "fill": "#4B5563", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "市场已关闭 · 不再更新。收盘前最后成交约 62¢(Yes)。", + "lineHeight": 1.45, + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "icon_font", + "id": "RclST", + "layoutPosition": "absolute", + "x": 350, + "y": 20, + "width": 18, + "height": 18, + "iconFontName": "chevron_right", + "iconFontFamily": "Material Symbols Outlined", + "fill": "$--text-tertiary" + } + ] + }, + { + "type": "frame", + "id": "La88r", + "name": "rules", + "width": "fill_container", + "fill": "#FFFFFF", + "cornerRadius": 12, + "stroke": { + "align": "inside", + "thickness": 1, + "fill": "$--border-color" + }, + "layout": "vertical", + "gap": 10, + "padding": 14, + "children": [ + { + "type": "text", + "id": "b00NP", + "fill": "$--text-secondary", + "content": "规则说明", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "600", + "letterSpacing": 0.5 + }, + { + "type": "text", + "id": "4ufVi", + "fill": "#374151", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "若官方结果表明民主党候选人获胜,本市场解析为 Yes;否则为 No。争议期已过,结果不可复议。", + "lineHeight": 1.45, + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + }, + { + "type": "text", + "id": "ajtlR", + "fill": "$--text-secondary", + "content": "信息来源", + "fontFamily": "Inter", + "fontSize": 11, + "fontWeight": "600" + }, + { + "type": "text", + "id": "4LOYl", + "fill": "#2563EB", + "textGrowth": "fixed-width", + "width": "fill_container", + "content": "https://elections.ap.org / uma.xyz", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "normal" + } + ] + }, + { + "type": "frame", + "id": "L8b2d", + "name": "endBar", + "width": "fill_container", + "fill": "#F3F4F6", + "cornerRadius": 10, + "padding": 14, + "justifyContent": "center", + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "mLrt4", + "fill": "#6B7280", + "content": "该市场已结束,无法继续交易", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500" + } + ] + } + ] } ], "variables": { diff --git a/src/api/event.ts b/src/api/event.ts index 37282f3..cfbbbb2 100644 --- a/src/api/event.ts +++ b/src/api/event.ts @@ -64,9 +64,49 @@ export interface PmEventMarketItem { clobTokenIds?: string[] endDate?: string volume?: number + /** 为 true 时表示市场已关闭/已结算,不再交易 */ + closed?: boolean [key: string]: unknown } +/** 市场是否已关闭(不再接受下单) */ +export function isPmMarketClosed(m: PmEventMarketItem | null | undefined): boolean { + return m?.closed === true +} + +/** + * 已结算市场的结果角标:取 outcomePrices 中概率最高项对应 outcomes 文案(兼容 0–1 或 1–100)。 + */ +export function getPmMarketSettledWinner(m: PmEventMarketItem): { + label: string + winnerIndex: number +} | null { + if (!isPmMarketClosed(m)) return null + const prices = m.outcomePrices + const outcomes = m.outcomes + if (!prices?.length) { + return { label: outcomes?.[0] ?? '—', winnerIndex: 0 } + } + let bestIdx = 0 + let bestProb = -1 + for (let i = 0; i < prices.length; i++) { + const p = parseFloat(String(prices[i])) + if (!Number.isFinite(p)) continue + const prob = p > 1 ? Math.min(1, p / 100) : p + if (prob > bestProb) { + bestProb = prob + bestIdx = i + } + } + if (bestProb < 0) { + return { label: outcomes?.[0] ?? '—', winnerIndex: 0 } + } + const label = + outcomes?.[bestIdx] ?? + (bestIdx === 0 ? 'Yes' : bestIdx === 1 ? 'No' : `#${bestIdx + 1}`) + return { label, winnerIndex: bestIdx } +} + /** 从市场项取 marketId,兼容 ID / id */ export function getMarketId(m: PmEventMarketItem | null | undefined): string | undefined { if (!m) return undefined @@ -237,36 +277,24 @@ export function readTradeRouteEventSlug(obj: unknown): string | undefined { } export interface TradeDetailRouteInput { - /** 事件数字 ID(与首页 MarketCard :id 一致),优先用于路径参数 */ + /** 事件数字 ID;无 slug 时用作路径段 */ eventId?: string | number | null - /** 事件 slug;无 eventId 时用作路径;路径为数字 ID 时可作为 query.slug 传给 findPmEvent */ + /** 事件 slug,优先作为路径参数(详情页仅用其请求 findPmEvent) */ eventSlug?: string | null - /** 市场行 ID,对应详情页 query.marketId */ - marketId?: string | null - /** 详情页标题回显 query.title */ - title?: string | null } /** - * 构造与 MarketCard、EventMarkets → trade-detail 一致的 router.push 参数。 - * 路径:`/trade-detail/:id`,id 为事件数字 ID 或事件 slug。 + * 跳转详情:`/trade-detail/:id` 仅传路径参数,无 query;优先 slug,否则数字 ID。 */ export function buildTradeDetailPushOptions( input: TradeDetailRouteInput, -): { name: 'trade-detail'; params: { id: string }; query: Record } | null { +): { name: 'trade-detail'; params: { id: string } } | null { + const slug = input.eventSlug?.trim() || '' const eid = input.eventId != null && String(input.eventId).trim() !== '' ? String(input.eventId).trim() : '' - const slugOnly = input.eventSlug?.trim() || '' - if (!eid && !slugOnly) return null - const pathId = eid || slugOnly - const numId = parseInt(eid, 10) - const isNumericEventPath = - eid !== '' && Number.isFinite(numId) && String(numId) === eid && numId >= 1 - const query: Record = {} - if (input.title?.trim()) query.title = input.title.trim() - if (input.marketId?.trim()) query.marketId = input.marketId.trim() - if (isNumericEventPath && slugOnly) query.slug = slugOnly - return { name: 'trade-detail', params: { id: pathId }, query } + const pathId = slug || eid + if (!pathId) return null + return { name: 'trade-detail', params: { id: pathId } } } /** 多选项卡片中单个选项(用于左右滑动切换) */ diff --git a/src/components/MarketCard.vue b/src/components/MarketCard.vue index 7d1b9b7..8c7aa1b 100644 --- a/src/components/MarketCard.vue +++ b/src/components/MarketCard.vue @@ -232,26 +232,13 @@ const semiProgressColor = computed(() => { }) const navigateToDetail = () => { + const segment = (props.slug?.trim() || props.id || '').trim() + if (!segment) return if (props.displayType === 'multi' && (props.outcomes?.length ?? 0) > 1) { - router.push({ - path: `/event/${props.id}/markets`, - query: { ...(props.slug && { slug: props.slug }) }, - }) + router.push({ name: 'event-markets', params: { id: segment } }) return } - router.push({ - path: `/trade-detail/${props.id}`, - query: { - title: props.marketTitle, - imageUrl: props.imageUrl || undefined, - category: props.category || undefined, - marketInfo: props.marketInfo || undefined, - expiresAt: props.expiresAt || undefined, - chance: String(props.chanceValue), - ...(props.marketId && { marketId: props.marketId }), - ...(props.slug && { slug: props.slug }), - }, - }) + router.push({ name: 'trade-detail', params: { id: segment } }) } function openTradeSingle(side: 'yes' | 'no') { diff --git a/src/locales/en.json b/src/locales/en.json index b834d89..0ddc35b 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -77,6 +77,10 @@ "pleaseSelectMarket": "Please select a market (with clobTokenIds)", "userError": "User info error", "orderFailed": "Order failed", + "marketClosedTitle": "Market is closed", + "marketClosedDesc": "This market has settled. Trading and new orders are not available.", + "marketClosedOutcome": "Outcome: {outcome}", + "marketClosedBanner": "This market is closed and has settled.", "expiration": { "5m": "5m", "15m": "15m", @@ -106,7 +110,8 @@ "yes": "Yes", "no": "No", "priceZero": "0¢", - "moreActions": "More actions" + "moreActions": "More actions", + "settledSubMarketsTitle": "Sub-markets (settled)" }, "searchPage": { "title": "Search", diff --git a/src/locales/ja.json b/src/locales/ja.json index c2666ae..40c48ef 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -77,6 +77,10 @@ "pleaseSelectMarket": "市場を選択してください(clobTokenIds が必要)", "userError": "ユーザー情報エラー", "orderFailed": "注文に失敗しました", + "marketClosedTitle": "マーケットは閉鎖されています", + "marketClosedDesc": "このマーケットは決済済みです。取引や新規注文はできません。", + "marketClosedOutcome": "結果:{outcome}", + "marketClosedBanner": "このマーケットは閉鎖され決済されています。", "expiration": { "5m": "5分", "15m": "15分", @@ -106,7 +110,8 @@ "yes": "Yes", "no": "No", "priceZero": "0¢", - "moreActions": "その他の操作" + "moreActions": "その他の操作", + "settledSubMarketsTitle": "サブマーケット(決済済み)" }, "searchPage": { "title": "検索", diff --git a/src/locales/ko.json b/src/locales/ko.json index 9566188..b24de40 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -77,6 +77,10 @@ "pleaseSelectMarket": "시장을 선택하세요 (clobTokenIds 필요)", "userError": "사용자 정보 오류", "orderFailed": "주문 실패", + "marketClosedTitle": "마켓이 종료되었습니다", + "marketClosedDesc": "이 마켓은 정산되었으며 거래와 신규 주문을 받지 않습니다.", + "marketClosedOutcome": "결과: {outcome}", + "marketClosedBanner": "이 마켓은 종료되어 정산되었습니다.", "expiration": { "5m": "5분", "15m": "15분", @@ -106,7 +110,8 @@ "yes": "Yes", "no": "No", "priceZero": "0¢", - "moreActions": "더보기" + "moreActions": "더보기", + "settledSubMarketsTitle": "하위 마켓(정산 완료)" }, "searchPage": { "title": "검색", diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index f406459..0ac2ccc 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -77,6 +77,10 @@ "pleaseSelectMarket": "请先选择市场(需包含 clobTokenIds)", "userError": "用户信息异常", "orderFailed": "下单失败", + "marketClosedTitle": "市场已关闭", + "marketClosedDesc": "本市场已结算,不再接受交易与下单。", + "marketClosedOutcome": "结果:{outcome}", + "marketClosedBanner": "该市场已关闭并完成结算。", "expiration": { "5m": "5分钟", "15m": "15分钟", @@ -106,7 +110,8 @@ "yes": "是", "no": "否", "priceZero": "0¢", - "moreActions": "更多操作" + "moreActions": "更多操作", + "settledSubMarketsTitle": "子市场(已结算)" }, "searchPage": { "title": "搜索", diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index 72be553..04ed69e 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -77,6 +77,10 @@ "pleaseSelectMarket": "請先選擇市場(需包含 clobTokenIds)", "userError": "用戶資訊異常", "orderFailed": "下單失敗", + "marketClosedTitle": "市場已關閉", + "marketClosedDesc": "本市場已結算,不再接受交易與下單。", + "marketClosedOutcome": "結果:{outcome}", + "marketClosedBanner": "該市場已關閉並完成結算。", "expiration": { "5m": "5分鐘", "15m": "15分鐘", @@ -106,7 +110,8 @@ "yes": "是", "no": "否", "priceZero": "0¢", - "moreActions": "更多操作" + "moreActions": "更多操作", + "settledSubMarketsTitle": "子市場(已結算)" }, "searchPage": { "title": "搜尋", diff --git a/src/router/index.ts b/src/router/index.ts index 4875f10..9a69b54 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,4 +1,5 @@ import { createRouter, createWebHistory } from 'vue-router' +import { HOME_MAIN_SCROLL_STORAGE_KEY } from './scrollKeys' import Home from '../views/Home.vue' import Trade from '../views/Trade.vue' import Login from '../views/Login.vue' @@ -67,6 +68,24 @@ const router = createRouter({ scrollBehavior(to, from, savedPosition) { const el = document.querySelector('[data-main-scroll]') if (el) { + const shouldRestoreHomeScroll = + to.name === 'home' && + from?.name != null && + (from.name === 'trade-detail' || from.name === 'event-markets') + + if (shouldRestoreHomeScroll) { + const raw = sessionStorage.getItem(HOME_MAIN_SCROLL_STORAGE_KEY) + const top = raw != null ? parseInt(raw, 10) : NaN + if (Number.isFinite(top) && top >= 0) { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + el.scrollTo({ top, left: 0 }) + }) + }) + return + } + } + if (savedPosition && from?.name) { el.scrollTo({ top: savedPosition.top, left: savedPosition.left ?? 0 }) return diff --git a/src/router/scrollKeys.ts b/src/router/scrollKeys.ts new file mode 100644 index 0000000..846f722 --- /dev/null +++ b/src/router/scrollKeys.ts @@ -0,0 +1,2 @@ +/** 离开首页时写入 [data-main-scroll].scrollTop,从详情/多市场返回首页时恢复 */ +export const HOME_MAIN_SCROLL_STORAGE_KEY = 'pcv-home-main-scroll-top' diff --git a/src/views/EventMarkets.vue b/src/views/EventMarkets.vue index 085b89a..ddc1c22 100644 --- a/src/views/EventMarkets.vue +++ b/src/views/EventMarkets.vue @@ -94,12 +94,17 @@ - - + +
+ + + +
+ {{ t('eventMarkets.settledSubMarketsTitle') }} +
+
+
+
+ {{ + market.question || t('eventMarkets.marketPlaceholder') + }} + {{ formatVolumeLine(market.volume) }} +
+ + {{ settledWinnerPill(market)!.label }} + + mdi-chevron-right +
+
+
-
+
-