更新索引文档,新增2026-04-23的全屏直播与点卡商城及直播房间详情联调记录,同时在会议记录中添加相关会议主题,确保文档内容的完整性与一致性。

This commit is contained in:
乘风
2026-04-23 14:23:00 +08:00
parent 086099af3e
commit 18c645a3f8
13 changed files with 104 additions and 8 deletions

View File

@@ -0,0 +1,8 @@
# 开发助理 - 2026-04-23
## 跨端摘要
- **玩值** 直播App 全屏页对接既有 `/api/app/live/*`**点卡**:新增 App 只读目录 + 下单写 `pointCardOrders`,管理端仍管 SKU/福禄;**管理端** 直播详情节省列表全量拉取。
- 文档与索引:`开发文档/玩值/迁移-API对照表.md``进度-看板.md`、项目索引、会议纪要已同步。
详见各 `agent/玩值*/evolution/2026-04-23-*.md`

View File

@@ -2,6 +2,7 @@
| 日期 | 主题 |
|------|------|
| 2026-04-23 | [全屏直播与点卡商城](2026-04-23-全屏直播与点卡商城.md) |
| 2026-04-22 | [wz-app Uno 与 custom-tabbar](2026-04-22-wz-app-Uno与custom-tabbar.md) |
| 2026-04-22 | [TS原生编译跨平台吸收Perry](2026-04-22-TS原生编译跨平台吸收.md) |
| 2026-04-20 | [玩值迁移-吸收](2026-04-20-玩值迁移-吸收.md) |

View File

@@ -2,5 +2,6 @@
| 日期 | 主题 |
|------|------|
| 2026-04-23 | [直播房间详情联调](2026-04-23-直播房间详情联调.md) |
| 2026-04-22 | [TS原生编译跨平台吸收Perry](2026-04-22-TS原生编译跨平台吸收.md) |
| 2026-04-20 | [玩值迁移-吸收](2026-04-20-玩值迁移-吸收.md) |

View File

@@ -0,0 +1,31 @@
# 会议纪要 - 2026-04-23 | 玩值三端:直播 + 点卡 接口与功能打通
## 基本信息
- **时间**2026-04-23
- **议题**wz-api 补 C 端点卡与订单、管理端直播房间详情wz-app 全屏直播页与商城点卡;三端与《迁移-API对照表》同步
- **参与角色**:产品(验收口径)、玩值 API、玩值管理端、玩值移动端、测试联调项
## 会议决议
1. C 端点卡仅走 **`/api/app/mall/*`** 与 **`/api/app/orders/point-card`**,与 admin 的 `/api/admin/wz/points/*` 分离;订单首版 `pending`、不接支付。
2. 观众侧直播使用 **`/live/:streamerId`24 位 hex**,与 `GET /api/app/live/*` 对齐;动态页用 API 主播列表映射,避免假 `roomId` 直跳。
3. 管理端直播详情优先 **`GET /api/admin/wz/live/rooms/:roomId`**,无则列表兜底。
## 问题与作答区
| 问题 | 责任角色 | 作答 |
|------|----------|------|
| 点卡支付何时接入? | 产品 / API | (待排期,当前仅建单) |
| 库存是否下单后扣减? | API | 首版不扣,避免与支付未闭环冲突 |
## 实现摘要(会后落地)
- wz-api`playhub_wz_app_mall.go``RegisterPlayhubWzAdminRoutes` 增加 `GET .../live/rooms/:roomId`
- wz-app`LivePage``MallPointsPage``api/live.ts``api/mall.ts`、路由结构调整
- wz-admin`fetchLiveRoomById``LiveDetailPage` 优先直查
- 文档:`开发文档/玩值/迁移-API对照表.md``进度-看板.md` 更新
---
各角色经验见 `agent/玩值*/evolution/2026-04-23-*.md`

View File

@@ -58,6 +58,7 @@ YYYY-MM-DD_会议主题.md
| 日期 | 主题 | 参与角色 | 文件 |
|------|------|---------|------|
| 2026-04-23 | 玩值三端:直播 + 点卡 接口与功能打通 | 玩值 API、管理端、移动端、产品 | [2026-04-23_玩值三端直播点卡打通.md](2026-04-23_玩值三端直播点卡打通.md) |
| 2026-02-27 | 开发进度同步会议 | 产品、后端、管理端、小程序 | [2026-02-27_开发进度同步会议.md](2026-02-27_开发进度同步会议.md) |
| 2026-02-28 | 临时需求池 stitch_soul 需求评审含页面重构专项·10 张图全覆盖) | 产品、后端、管理端、小程序、测试 | [2026-02-28_临时需求池stitch_soul需求评审.md](2026-02-28_临时需求池stitch_soul需求评审.md) |
| 2026-02-28 | 个人资料页实现评估profile-show / profile-edit | 产品、后端、管理端、小程序、测试 | [2026-02-28_个人资料页实现评估.md](2026-02-28_个人资料页实现评估.md) |

View File

@@ -6,6 +6,10 @@
---
## 2026-04-23
- 玩值三端直播+点卡打通:纪要 `meeting/2026-04-23_玩值三端直播点卡打通.md`;经验入库玩值 API/管理端/移动端;项目索引玩值.md、迁移对照表、进度看板、会议 README 索引
## 2026-04-21
- wz-app 迁移计划续:`src/` 目录、Vite 脚本、路由映射与 tabBar+占位页、鉴权与首页/我的对接;看板、真源 README、2026-04-21 日志、项目索引/玩值.md

View File

@@ -1,5 +1,8 @@
# 生产/预览:填写 wz 网关根地址,无尾斜杠
# VITE_API_BASE_URL=https://你的域名
#
# 开发:可留空,使用 Vite 代理到 http://localhost:48080
# 开发:可留空,使用 Vite 代理到 http://localhost:48080(见 vite.config.ts → /api
# 鉴权:登录成功后 token 存 localStoragewz_app_token请求头 Authorization: Bearer
VITE_API_BASE_URL=
# 可选别名,与 VITE_API_BASE_URL 二选一
# VITE_WZ_API_BASE=

View File

@@ -11,8 +11,8 @@
rel="stylesheet"
/>
<title>玩值电竞 - WanZhi Esports</title>
<script type="module" crossorigin src="/assets/index-Xl-bD0z5.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BAB65AsD.css">
<script type="module" crossorigin src="/assets/index-B7BS2MS9.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CxS0zmvh.css">
</head>
<body class="min-h-screen antialiased">
<div id="root"></div>

View File

@@ -12,6 +12,7 @@ import { MallPointsPage } from "@/pages/MallPointsPage"
import { ProfilePage } from "@/pages/ProfilePage"
import { NotFoundPage } from "@/pages/NotFoundPage"
import { LivePage } from "@/pages/LivePage"
import { AuthSessionListener } from "@/components/auth/AuthSessionListener"
/** 带底栏 Tab 的主区(与全屏直播页互斥,避免底栏与输入条叠层) */
function TabLayout() {
@@ -26,6 +27,7 @@ export default function App() {
return (
<BrowserRouter>
<AppProvider>
<AuthSessionListener />
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route

View File

@@ -0,0 +1,26 @@
import { useEffect } from "react"
import { useNavigate } from "react-router-dom"
import { useAppContext } from "@/components/providers/app-provider"
/**
* 与 `request.ts` 中 401 时派发的 `wz:auth-lost` 联动:清空上下文并回登录页(避免仅清 token 但 UI 仍显示已登录)。
*/
export function AuthSessionListener() {
const navigate = useNavigate()
const { logout } = useAppContext()
useEffect(() => {
const onLost = () => {
void (async () => {
await logout()
if (window.location.pathname !== "/login") {
navigate("/login", { replace: true })
}
})()
}
window.addEventListener("wz:auth-lost", onLost)
return () => window.removeEventListener("wz:auth-lost", onLost)
}, [logout, navigate])
return null
}

View File

@@ -60,6 +60,11 @@ export async function request<T = unknown>(path: string, options: RequestOptions
if (res.status === 401) {
clearToken()
try {
window.dispatchEvent(new CustomEvent("wz:auth-lost"))
} catch {
/* ignore */
}
throw new Error(typeof json.message === "string" ? json.message : "未登录")
}
if (!res.ok) {

View File

@@ -1,4 +1,4 @@
import { useState } from "react"
import { useState, useEffect } from "react"
import { useNavigate } from "react-router-dom"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
@@ -10,7 +10,7 @@ import { setToken } from "@/lib/token"
export function LoginPage() {
const navigate = useNavigate()
const { login, syncFromDatabase } = useAppContext()
const { login, syncFromDatabase, isLoggedIn, authChecked } = useAppContext()
const [phone, setPhone] = useState("")
const [name, setName] = useState("")
const [password, setPassword] = useState("")
@@ -20,6 +20,12 @@ export function LoginPage() {
const [agreed, setAgreed] = useState(false)
const [error, setError] = useState("")
useEffect(() => {
if (authChecked && isLoggedIn) {
navigate("/", { replace: true })
}
}, [authChecked, isLoggedIn, navigate])
const handleSubmit = async () => {
if (!agreed) {
setError("请先阅读并同意用户协议与隐私政策")
@@ -188,12 +194,15 @@ export function LoginPage() {
<span className="text-foreground/30 text-xs"></span>
<div className="bg-foreground/10 h-px flex-1" />
</div>
<div className="flex justify-center gap-8">
<p className="text-foreground/40 mb-2 text-center text-xs"></p>
<div className="flex justify-center gap-8 opacity-50">
{["微信", "QQ", "微博"].map((n) => (
<button
key={n}
type="button"
className="text-foreground/50 flex h-12 w-12 items-center justify-center rounded-full bg-foreground/5 text-xs"
disabled
title="暂未接入"
className="text-foreground/50 flex h-12 w-12 cursor-not-allowed items-center justify-center rounded-full bg-foreground/5 text-xs"
>
{n}
</button>

View File

@@ -22,6 +22,11 @@ import { Button } from "@/components/ui/button"
import { useAppContext } from "@/components/providers/app-provider"
import { useState } from "react"
function maskPhone(p?: string): string {
if (!p || p.length < 7) return p || "—"
return `${p.slice(0, 3)}****${p.slice(-4)}`
}
export function ProfilePage() {
const { user, wallet, logout } = useAppContext()
const navigate = useNavigate()
@@ -100,7 +105,7 @@ export function ProfilePage() {
</Link>
</div>
<p className="text-xs text-foreground/60 bg-foreground/10 px-2 py-0.5 rounded-full inline-block mb-2 truncate max-w-full">
ID: {user.odlId || "888888"}
ID: {user.id || user.odlId || "—"} · {user.phone ? maskPhone(user.phone) : "手机未绑定"}
</p>
<p className="text-xs text-foreground/40 truncate"> | 耀</p>
</div>