From 91fc37a0ee828d2b03c51d5bafedc303721a0e99 Mon Sep 17 00:00:00 2001 From: hzj <1304805162@qq.com> Date: Mon, 8 Jun 2026 17:30:42 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E4=B8=96=E7=95=8C=E6=9D=AF=E6=B4=BB?= =?UTF-8?q?=E5=8A=A8):=20=E5=AF=B9=E6=8E=A5=E6=8E=A5=E5=8F=A3=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E5=AE=8C=E6=88=90=E4=B8=A4=E4=B8=AA=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E7=9A=84=E5=9F=BA=E6=9C=AC=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/worldCup.js | 65 + src/config/security.js | 1 + src/router/index.js | 6 + src/utils/permissionManager.js | 1 + .../Activities/WorldCup/EventDetail/index.vue | 827 +++++++++ .../WorldCup/EventDetail/页面创建信息.md | 97 ++ .../WorldCup/components/topUser.vue | 18 +- src/views/Activities/WorldCup/index.vue | 1523 ++++++++++++++--- src/views/Activities/WorldCup/page.config.js | 68 +- .../Activities/WorldCup/世界杯接口说明.md | 358 ++++ src/views/Activities/WorldCup/页面创建信息.md | 407 ++--- 11 files changed, 2892 insertions(+), 479 deletions(-) create mode 100644 src/api/worldCup.js create mode 100644 src/views/Activities/WorldCup/EventDetail/index.vue create mode 100644 src/views/Activities/WorldCup/EventDetail/页面创建信息.md create mode 100644 src/views/Activities/WorldCup/世界杯接口说明.md diff --git a/src/api/worldCup.js b/src/api/worldCup.js new file mode 100644 index 0000000..62c53a3 --- /dev/null +++ b/src/api/worldCup.js @@ -0,0 +1,65 @@ +import { get, post } from '../utils/http.js' + +const WORLD_CUP_API_PREFIX = '/activity/worldcup' + +const logWorldCupApiError = (message, error) => { + console.error(message, error) + console.error('error:' + (error.response?.errorMsg || error.errorMsg || error.message || '')) +} + +// 获取世界杯比赛列表:tab 为 0 时返回进行中/可投注,tab 为 1 时返回已结束。 +export const apiPostWorldCupMatchList = async (data) => { + try { + const response = await post(`${WORLD_CUP_API_PREFIX}/match/list`, data) + return response + } catch (error) { + logWorldCupApiError('Failed to get world cup match list:', error) + throw error + } +} + +// 提交世界杯比赛押注:betOption 为 1 主胜、2 平局、3 客胜。 +export const apiPostWorldCupBet = async (data) => { + try { + const response = await post(`${WORLD_CUP_API_PREFIX}/bet`, data) + return response + } catch (error) { + logWorldCupApiError('Failed to submit world cup bet:', error) + throw error + } +} + +// 获取我的世界杯竞猜记录:matchId 为空时查询全部比赛记录。 +export const apiPostWorldCupMyBetList = async (data) => { + try { + const response = await post(`${WORLD_CUP_API_PREFIX}/my/bet/list`, data) + return response + } catch (error) { + logWorldCupApiError('Failed to get world cup my bet list:', error) + throw error + } +} + +// 获取世界杯排行榜:接口没有业务参数,POST 请求仍传空对象。 +export const apiPostWorldCupRankList = async () => { + try { + const response = await post(`${WORLD_CUP_API_PREFIX}/rank/list`, {}) + return response + } catch (error) { + logWorldCupApiError('Failed to get world cup rank list:', error) + throw error + } +} + +// 获取世界杯比赛详情,同时返回当前用户本场竞猜记录。 +export const apiGetWorldCupMatchDetail = async (matchId) => { + try { + const response = await get( + `${WORLD_CUP_API_PREFIX}/match/detail?matchId=${encodeURIComponent(matchId)}`, + ) + return response + } catch (error) { + logWorldCupApiError('Failed to get world cup match detail:', error) + throw error + } +} diff --git a/src/config/security.js b/src/config/security.js index 8e4db63..26a348d 100644 --- a/src/config/security.js +++ b/src/config/security.js @@ -23,6 +23,7 @@ export const PUBLIC_PATHS = Object.freeze([ '/activities/gulben-festival', '/activities/bounty-football', '/activities/world-cup', + '/activities/world-cup/event-detail', '/activities/lucky-dollars-season5', '/activities/lucky-dollars-season4', '/activities/lesser-bairam', diff --git a/src/router/index.js b/src/router/index.js index 2ab8c0c..43f034c 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -452,6 +452,12 @@ const router = createRouter({ component: () => import('../views/Activities/WorldCup/index.vue'), meta: { requiresAuth: false }, }, // WorldCup + { + path: '/activities/world-cup/event-detail', + name: 'world-cup-event-detail', + component: () => import('../views/Activities/WorldCup/EventDetail/index.vue'), + meta: { requiresAuth: false }, + }, // WorldCup EventDetail { path: '/activities/games/the-greedy-king', name: 'games-the-greedy-king', diff --git a/src/utils/permissionManager.js b/src/utils/permissionManager.js index 6506027..a48f43d 100644 --- a/src/utils/permissionManager.js +++ b/src/utils/permissionManager.js @@ -69,6 +69,7 @@ const ACTIVITIES = [ '/activities/spring-festival', // 春节打榜 '/activities/world-cup', // WorldCup + '/activities/world-cup/event-detail', // WorldCup EventDetail '/activities/games/the-greedy-king', //贪金王游戏排行榜 '/activities/bounty-football', // BountyFootball '/activities/poker-ace', // 扑克王牌排行榜 diff --git a/src/views/Activities/WorldCup/EventDetail/index.vue b/src/views/Activities/WorldCup/EventDetail/index.vue new file mode 100644 index 0000000..f686389 --- /dev/null +++ b/src/views/Activities/WorldCup/EventDetail/index.vue @@ -0,0 +1,827 @@ + + + + + diff --git a/src/views/Activities/WorldCup/EventDetail/页面创建信息.md b/src/views/Activities/WorldCup/EventDetail/页面创建信息.md new file mode 100644 index 0000000..f389482 --- /dev/null +++ b/src/views/Activities/WorldCup/EventDetail/页面创建信息.md @@ -0,0 +1,97 @@ +# 页面创建信息 + +## 0. 建页规则关联 + +- 页面改动、模块补充、接口对接、样式同步和文档同步,都需要先联系 `docs/活动页/建页/` 下的建页规则执行。 +- 本页面为 `WorldCup` 的赛事详情页,后续生成或更新时需要同步回 `src/views/Activities/WorldCup/页面创建信息.md` 的入口说明。 +- 页面模块、div 结构、方法、接口处理都需要补充中文注释。 +- 页面根容器使用 `100vh` 方案,内部滚动并隐藏滚动条,不展示可见滚动条。 +- 能使用内联样式处理的页面样式,优先使用内联样式。 +- 新建或更新 `index.vue` 时必须使用统一加载动画:`isLoading` 阶段只渲染 `LoadingContent`,关键图片和初始化接口完成后再渲染正式背景图与业务节点。 +- 普通业务模块不提前设置 `min-height` 和 `line-height`;`min-height` 只在基础页面容器按需使用,`itemCenter` 的 `min-height` 只在页面开发完成后确实需要稳定图片容器高度时再补。 + +## 1. 基础信息 + +- 页面类型:Activities +- 页面名称:WorldCup EventDetail +- 页面目录:`src/views/Activities/WorldCup/EventDetail` +- 页面入口:`src/views/Activities/WorldCup/EventDetail/index.vue` +- 路由 path:`/activities/world-cup/event-detail` +- 路由 name:`world-cup-event-detail` +- 进入来源:WorldCup 首页赛事列表项下方的 `TOTAL PRIZE POOL` 模块。 +- Query 参数:`matchId`,来自比赛列表接口返回的 `matchId`。 + +## 2. 业务规则 + +- 本页面用于展示世界杯赛事详情,并给用户提供押注服务。 +- 押注只允许在赛事未开始时进行。 +- 只要赛事开始,用户就不能再押注,只展示赛事状态和用户押注状态。 +- 页面详情接口使用 `apiGetWorldCupMatchDetail(matchId)`。 +- 押注接口使用 `apiPostWorldCupBet(data)`。 +- 我的本场竞猜记录优先使用详情接口返回的 `myBets`。 +- 页面进入参数为 `matchId`,由首页赛事列表总奖池入口跳转时通过 query 传入。 + +## 3. 页面结构 + +- 根容器固定 `100vw * 100vh`,背景色为 `#101E14`。 +- 最底层背景图使用 `detailPageBg`,宽度设置为 `100vw`,高度按图片自身比例展示,不强制拉伸到页面高度。 +- 顶部使用公共组件 `src/components/GeneralHeader.vue`,标题为 `World Cup`,非首页,使用组件默认返回键。 +- `GeneralHeader` 返回键图片通过 `backImg` 指定为 `src/assets/icon/Azizi/arrowBack.png`,只影响当前详情页。 +- 主内容区为内部滚动区域,使用 column 布局,`gap: 2vw`,隐藏可见滚动条。 +- 第一模块为赛事结果模块,使用 `itemCenter` 组件承载不同状态背景图。 +- 第二模块为押注模块,负责展示押注对象、押注状态和未开赛时的押注金额入口。 +- 第三模块为押注记录模块,负责展示当前赛事内用户押注对象、金额和押注时间。 + +## 4. 赛事结果模块 + +- 未开始状态使用 `statusNotStarted`,角标文案为 `Not Started`,主文案根据 `kickoffTime` 展示倒计时,例如 `2D 18 : 59 : 59`。 +- 正在进行状态使用 `statusInProgress`,角标文案为 `In Progress`,主文案展示 `The match is underway`。 +- 已结束且至少有一个中奖押注时使用 `statusEndedWin`,角标文案为 `Ended`,主文案展示 `+ coin + payout合计`。 +- 已结束且未中奖或未参与时使用 `statusEndedfail`,角标文案为 `Ended`,主文案展示 `Better luck next time!`。 +- 第(2)行主文案只按状态切换展示内容,字体样式固定一致:`color: #F8E89A`、`font-size: 2em`、`font-weight: 500`。 +- 开赛时间文案在所有状态下固定展示,文案根据 `kickoffTime` 格式化,例如 `Kick-off is at 18:00:00 on 12 June 2026.`。 +- 分割线和底部信息行在所有状态下固定展示;底部信息行左侧展示 `total prize pool:`、coin 图片和 `totalPool`,右侧展示 `numPeopleGold` 图片和 `joinCount`。 +- 中奖判断来自 `myBets`,`betStatus === 1` 或 `payout > 0` 都视为中奖。 +- 当前页面会预加载 `detailPageBg`、`statusNotStarted`、`statusInProgress`、`statusEndedWin`、`statusEndedfail`、`numPeopleGold`。 + +## 5. 押注模块 + +- 押注模块使用普通 `section`,整体样式为绿色渐变背景、`12px` 圆角、`#5D6948` 边框和 `backdrop-filter`。 +- 模块内部从上往下分为押注对象和押注金额两个小模块。 +- 押注对象结构对齐首页 `Ended` 列表项中的三列押注选项:主胜、平局、客胜。 +- 押注对象上方金额展示用户在当前选项的累计下注额:`myHomeBetFormat` / `myDrawBetFormat` / `myAwayBetFormat`,详情接口缺失时按 `myBets` 中 `betOption` 汇总兜底。 +- 押注对象下方金额展示当前选项奖池:`homePoolFormat` / `drawPoolFormat` / `awayPoolFormat`,没有格式化字段时回退 `homePool` / `drawPool` / `awayPool`。 +- 未开始赛事中,押注对象允许点击选择,默认不选中任何项;选中的押注项使用首页 `Ended` 选中态样式。 +- 已开始或已结束赛事中,押注对象不可点击,选中态用于展示用户已押注过的选项。 +- 押注金额模块只在未开始赛事展示,金额选项为 `100`、`1000`、`10000`、`100000`,每个金额左侧展示 coin 图片。 +- 押注流程为:先选择押注对象,再点击押注金额;点击金额时调用 `apiPostWorldCupBet({ matchId, betOption, betAmount })`。 +- 押注成功后清空当前选中押注对象,并重新拉取 `apiGetWorldCupMatchDetail` 和 `apiPostWorldCupMyBetList` 刷新页面状态。 + +## 6. 押注记录模块 + +- 押注记录模块使用普通 `section`,整体样式为绿色渐变背景、`12px` 圆角、`#5D6948` 边框和 `backdrop-filter`。 +- 数据接口使用 `apiPostWorldCupMyBetList({ size: 100, current: 1, matchId })`,只获取一次,不做上拉加载。 +- 模块内部从上往下分为固定标题和竞猜记录两个小模块。 +- 固定标题为 `My prediction for this game:`,样式为 `color: #FFE083`、`font-weight: 500`。 +- 竞猜记录为空时居中展示两行:第一行为 `footballSign` 图片,宽度暂定 `30vw`;第二行为 `No records yet.`,样式为 `color: #FFE083`、`font-size: 1.5em`、`font-weight: 500`。 +- 竞猜记录不为空时,记录区域内部滚动并隐藏可见滚动条。 +- 单条记录样式为金色描边渐变背景,内部左右 `space-between` 布局。 +- 记录左侧展示两行:`Bets placed:` + `betOptionName`,以及格式化后的 `betTime`,时间格式为 `MM-DD-YYYY HH:mm:ss`。 +- 记录右侧展示 coin 图片和 `betAmount`,金额文字为白色、`font-weight: 500`。 + +## 7. 路由代码片段 + +```js +{ + path: '/activities/world-cup/event-detail', + name: 'world-cup-event-detail', + component: () => import('../views/Activities/WorldCup/EventDetail/index.vue'), + meta: { requiresAuth: false }, +} +``` + +## 8. 验证记录 + +- `npm run build`:已通过。 +- 当前已完成赛事结果模块、押注模块和押注记录模块。 +- 本次已按 `docs/活动页/建页/` 规则调整详情页底座:loading/v-else 分离、中文注释、内部滚动隐藏滚动条、`