docs: add pagewise ui test checklist
This commit is contained in:
@@ -1,58 +1,97 @@
|
||||
# Seed Verification & UI Test Guide (Staging)
|
||||
# UI Page Testing Checklist (By Page → Actions → Data Validation)
|
||||
|
||||
## Service Startup (Local)
|
||||
- Backend: `go run ./backend/main.go serve` (default `http://localhost:8080`).
|
||||
- Portal: `npm -C frontend/portal install && npm -C frontend/portal run dev` (default `http://localhost:5174`, remote `http://10.1.1.104:5174`).
|
||||
- Superadmin: `npm -C frontend/superadmin install && npm -C frontend/superadmin run dev` (default `http://localhost:5173`, remote `http://10.1.1.104:5173`).
|
||||
- Proxies: portal `/v1` → backend `8080`; superadmin `/super/v1` & `/v1` → backend `8080`.
|
||||
## Prereqs
|
||||
- Seed: `go run ./backend/main.go seed`(会 TRUNCATE 并重建种子数据)。
|
||||
- tenantCode: `SELECT code FROM tenants ORDER BY id DESC LIMIT 1;`(示例:`meipai_768`)。
|
||||
- Portal base: `http://10.1.1.104:5174`,Superadmin base: `http://10.1.1.104:5173`。
|
||||
- Login creds: Portal OTP 固定 `1234`(手机号 `13800138000`),Superadmin `superadmin/superadmin123`。
|
||||
|
||||
## Chrome DevTools MCP
|
||||
- Remote Chrome 已启动;连接 `http://10.1.1.104:9222`。
|
||||
- 仅页面操作,无需 API 直接调用。
|
||||
## Portal(/t/:tenantCode/...)
|
||||
- **Login** `/auth/login`
|
||||
- 操作:填手机号 `13800138000` + 勾条款 → 获取验证码 → 输入 `1234` → 登录。
|
||||
- 数据验证:登录态写入 token;后续接口 200;用户信息显示 “戏迷小张(ID:2)”。
|
||||
- DB 验证:`users` 中 phone 唯一;登录命中最新用户(ID 最大)。
|
||||
|
||||
## AI Auto-Handling Prereqs
|
||||
- Seed 检查:`SELECT COUNT(*) FROM tenants;` 为 0 则 `go run ./backend/main.go seed`。
|
||||
- tenantCode:`SELECT code FROM tenants ORDER BY id DESC LIMIT 1;` → `/t/:tenantCode`。
|
||||
- 清理存储:`localStorage.clear(); sessionStorage.clear();` + 清除 cookies。
|
||||
- **Home** `/t/:tenantCode`
|
||||
- 操作:页面加载、点击内容卡片进入详情。
|
||||
- 数据验证:内容列表非空;跳转到对应 contentId。
|
||||
- DB 验证:`contents` 至少 10 条,tenant_id 为当前租户。
|
||||
|
||||
## Portal Test Checklist (tenantCode from DB)
|
||||
1) **Login** `/auth/login` → 手机 `13800138000` + OTP `1234`,勾选条款;断言“登录成功”。
|
||||
2) **Home** `/t/:tenantCode` → 有内容/导航无报错。
|
||||
3) **Content Detail** `/t/:tenantCode/contents/1` → 封面/正文/评论可见。
|
||||
4) **Orders** `/t/:tenantCode/me/orders` → 列表非空。
|
||||
5) **Library** `/t/:tenantCode/me/library` → 列表非空。
|
||||
6) **Favorites** `/t/:tenantCode/me/favorites` → 列表非空,可见“取消收藏”。
|
||||
7) **Likes** `/t/:tenantCode/me/likes` → 列表非空,可见“取消点赞”。
|
||||
8) **Notifications** `/t/:tenantCode/me/notifications` → 页面无错误。
|
||||
9) **Creator entry** `/t/:tenantCode/creator` → 页面可加载。
|
||||
- 每页:调用 `chrome-devtools_list_console_messages` 无 `error`。
|
||||
- **Content Detail** `/t/:tenantCode/contents/:id`
|
||||
- 操作:查看封面/正文,点赞/收藏按钮可用。
|
||||
- 数据验证:点赞/收藏后,列表页/我的点赞/收藏同步变化。
|
||||
- DB 验证:`content_assets` 绑定封面/主资产;`user_content_actions` 写入 like/favorite。
|
||||
|
||||
## Superadmin Test Checklist
|
||||
1) **Login** `/super/auth/login` → `superadmin/superadmin123`,成功进入 Dashboard。
|
||||
2) **Orders** `/super/superadmin/orders` → 有标记/对账数据。
|
||||
3) **Finance** `/super/superadmin/finance` → 提现审核/流水/异常标签有数据。
|
||||
4) **Users** `/super/superadmin/users` → 列表可见。
|
||||
5) **Tenants** `/super/superadmin/tenants` → 列表可见。
|
||||
6) **Notifications** `/super/superadmin/notifications` → 模板列表可见。
|
||||
7) **System Configs** `/super/superadmin/system-configs` → `site_name/support_email` 可见。
|
||||
8) **Audit Logs** `/super/superadmin/audit-logs` → 列表可见。
|
||||
- 每页:检查 console 无 `error`;必要时截图。
|
||||
- **Orders** `/t/:tenantCode/me/orders`
|
||||
- 操作:查看订单列表,点击“查看详情”。
|
||||
- 数据验证:列表非空;详情金额/状态与列表一致。
|
||||
- DB 验证:`orders`、`order_items`、`content_access` 状态/金额匹配。
|
||||
|
||||
## Manual-Only Coverage
|
||||
- 上传链路(init/part/complete)需真实存储;seed 仅提供素材记录。
|
||||
- **Order Detail** `/t/:tenantCode/me/orders/:id`
|
||||
- 操作:查看订单状态、商品信息,复制订单号。
|
||||
- 数据验证:金额/状态显示正确;“已支付/已退款”等标签与订单一致。
|
||||
- DB 验证:`orders.status`、`order_items.amount_paid` 与页面一致。
|
||||
|
||||
## Seed Notes
|
||||
- 执行 `go run ./backend/main.go seed` 会 TRUNCATE 全部业务表后重建。
|
||||
- 用户:`creator(13800000001)`, `test(13800138000)`, `superadmin(13800009999)`, `negative(13800009998)`。
|
||||
- 租户:`meipai_<rand>`(DB 查询获取)。
|
||||
- Orders/likes/favorites/notifications 已预置示例数据。
|
||||
- **Checkout** `/t/:tenantCode/checkout?contentId=:id`(半成品)
|
||||
- 操作:加载内容 → 点击“提交订单”→ 跳转 Payment。
|
||||
- 数据验证:显示商品标题/价格(取 `price_amount` 等);创建订单成功跳转。
|
||||
- DB 验证:`orders` 新增一条(tenant_id、user_id、content_id 匹配)。
|
||||
|
||||
## MCP Steps (Example)
|
||||
- `chrome-devtools_new_page http://10.1.1.104:5174/auth/login`
|
||||
- 填手机号+勾条款 → 获取验证码 → 填 `1234` → 登录
|
||||
- 导航并断言:
|
||||
- `/t/:tenantCode/me/orders` 有行
|
||||
- `/t/:tenantCode/me/library` 有行
|
||||
- `/t/:tenantCode/me/favorites` 有行
|
||||
- `/t/:tenantCode/me/likes` 有行
|
||||
- Superadmin:打开登录 → 填账号密码 → 断言 Dashboard → 进入 Orders/Finance/Notifications/System Configs/Audit Logs;每页检查 console `error`。
|
||||
- **Payment** `/t/:tenantCode/payment/:orderId`(半成品)
|
||||
- 操作:轮询 `/status`,点击“立即支付”(调用 `/pay`),或“模拟支付成功”。
|
||||
- 数据验证:状态变为 paid/completed 后跳转订单详情;金额显示来自订单。
|
||||
- DB 验证:`orders.status` 更新;若 pay 未实现,可用模拟成功代替。
|
||||
|
||||
- **Library** `/t/:tenantCode/me/library`
|
||||
- 操作:查看已购列表。
|
||||
- 数据验证:非空;点击内容可播放/查看。
|
||||
- DB 验证:`content_access` 记录存在且 status=active。
|
||||
|
||||
- **Favorites / Likes** `/t/:tenantCode/me/favorites` `/likes`
|
||||
- 操作:列表展示,取消收藏/点赞。
|
||||
- 数据验证:取消后列表减少;详情页同步。
|
||||
- DB 验证:`user_content_actions` 删除/新增对应记录。
|
||||
|
||||
- **Coupons** `/t/:tenantCode/me/coupons`
|
||||
- 操作:查看可用/已用/已过期;新人券应可见。
|
||||
- 数据验证:金额/门槛显示正确。
|
||||
- DB 验证:`user_coupons.status`、`coupons` 配置匹配。
|
||||
|
||||
- **Wallet** `/t/:tenantCode/me/wallet`
|
||||
- 操作:查看余额、交易明细;(如有)充值入口。
|
||||
- 数据验证:余额 50 元(seed);交易明细含购买/充值记录。
|
||||
- DB 验证:`users.balance`、`tenant_ledgers`/交易记录一致。
|
||||
|
||||
- **Notifications** `/t/:tenantCode/me/notifications`
|
||||
- 操作:查看列表。
|
||||
- 数据验证:种子“欢迎注册”可见;群发暂未落库(已知缺口)。
|
||||
- DB 验证:`notifications` 当前仅种子数据;群发功能待修复。
|
||||
|
||||
- **Creator** `/t/:tenantCode/creator/*`
|
||||
- 操作:Dashboard/内容/订单/成员/设置页面可打开。
|
||||
- 数据验证:种子内容/订单/成员可见。
|
||||
- DB 验证:`contents`、`tenant_users`、`orders` 等与租户匹配。
|
||||
|
||||
## Superadmin
|
||||
- **Login** `/super/auth/login`
|
||||
- 操作:账号 `superadmin/superadmin123` 登录。
|
||||
- 数据验证:进入 Dashboard;后续接口 200。
|
||||
|
||||
- **Dashboard/Orders/Finance/Users/Tenants/Reports/Health/Contents/Assets/System Configs/Audit Logs**
|
||||
- 操作:打开页面,查看列表/统计。
|
||||
- 数据验证:列表有种子数据;console 无 error。
|
||||
- DB 验证:对应表数据与显示一致(如 `orders`、`tenant_ledgers`、`contents`、`media_assets` 等)。
|
||||
|
||||
- **Notifications (模板管理)** `/super/superadmin/notifications`
|
||||
- 操作:编辑模板并保存。
|
||||
- 数据验证:保存成功提示;模板列表更新。
|
||||
- DB 验证:`notification_templates` 记录更新。
|
||||
|
||||
- **Broadcast (已知缺口)** `/super/v1/notifications/broadcast`
|
||||
- API 返回 200 但 DB 无新增通知,说明 Notification provider 未落库;群发暂不可用。
|
||||
|
||||
## 已知缺口 / 注意事项
|
||||
- 群发通知未写入 DB(待修复 provider)。
|
||||
- 支付流半成品:需要后端 `/orders`、`/pay`、`/status` 字段/逻辑配合;前端已添加提交/轮询/支付按钮及模拟成功。
|
||||
- 上传链路未验证(需真实存储)。
|
||||
- 使用最新 seed 后再测,避免重复用户/数据污染。
|
||||
|
||||
@@ -28,7 +28,6 @@ onMounted(() => {
|
||||
checkAuth();
|
||||
});
|
||||
|
||||
|
||||
const logout = () => {
|
||||
localStorage.removeItem("token");
|
||||
localStorage.removeItem("user");
|
||||
@@ -95,10 +94,10 @@ const logout = () => {
|
||||
<div class="flex items-center gap-4">
|
||||
<template v-if="isLoggedIn">
|
||||
<!-- Notification -->
|
||||
<router-link
|
||||
:to="tenantRoute('/me/notifications')"
|
||||
class="relative w-10 h-10 flex items-center justify-center rounded-full hover:bg-slate-50 text-slate-600"
|
||||
>
|
||||
<router-link
|
||||
:to="tenantRoute('/me/notifications')"
|
||||
class="relative w-10 h-10 flex items-center justify-center rounded-full hover:bg-slate-50 text-slate-600"
|
||||
>
|
||||
<i class="pi pi-bell text-xl"></i>
|
||||
<span
|
||||
class="absolute top-2 right-2 w-2 h-2 bg-red-500 rounded-full border border-white"
|
||||
@@ -106,10 +105,10 @@ const logout = () => {
|
||||
</router-link>
|
||||
|
||||
<!-- Creator Entry -->
|
||||
<router-link
|
||||
:to="tenantRoute('/creator/apply')"
|
||||
class="hidden sm:flex items-center gap-1 px-3 py-1.5 text-sm font-medium text-slate-600 hover:bg-slate-50 rounded-lg border border-slate-200"
|
||||
>
|
||||
<router-link
|
||||
:to="tenantRoute('/creator/apply')"
|
||||
class="hidden sm:flex items-center gap-1 px-3 py-1.5 text-sm font-medium text-slate-600 hover:bg-slate-50 rounded-lg border border-slate-200"
|
||||
>
|
||||
<i class="pi pi-pencil"></i>
|
||||
<span>创作</span>
|
||||
</router-link>
|
||||
@@ -143,16 +142,16 @@ const logout = () => {
|
||||
{{ user.phone }}
|
||||
</p>
|
||||
</div>
|
||||
<router-link
|
||||
:to="tenantRoute('/me')"
|
||||
class="block px-4 py-2 text-sm text-slate-700 hover:bg-slate-50"
|
||||
>个人中心</router-link
|
||||
>
|
||||
<router-link
|
||||
:to="tenantRoute('/creator')"
|
||||
class="block px-4 py-2 text-sm text-slate-700 hover:bg-slate-50"
|
||||
>创作者中心</router-link
|
||||
>
|
||||
<router-link
|
||||
:to="tenantRoute('/me')"
|
||||
class="block px-4 py-2 text-sm text-slate-700 hover:bg-slate-50"
|
||||
>个人中心</router-link
|
||||
>
|
||||
<router-link
|
||||
:to="tenantRoute('/creator')"
|
||||
class="block px-4 py-2 text-sm text-slate-700 hover:bg-slate-50"
|
||||
>创作者中心</router-link
|
||||
>
|
||||
<div class="border-t border-slate-50 mt-1"></div>
|
||||
<button
|
||||
@click="logout"
|
||||
@@ -166,11 +165,11 @@ const logout = () => {
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<router-link
|
||||
:to="'/auth/login'"
|
||||
class="bg-primary-600 text-white px-6 py-2 rounded-full font-medium hover:bg-primary-700 transition-all shadow-sm shadow-primary-100 active:scale-95"
|
||||
>登录 / 注册</router-link
|
||||
>
|
||||
<router-link
|
||||
:to="'/auth/login'"
|
||||
class="bg-primary-600 text-white px-6 py-2 rounded-full font-medium hover:bg-primary-700 transition-all shadow-sm shadow-primary-100 active:scale-95"
|
||||
>登录 / 注册</router-link
|
||||
>
|
||||
</template>
|
||||
|
||||
<!-- Mobile Menu Button -->
|
||||
|
||||
@@ -4,7 +4,11 @@ import { getTenantCode } from "./tenant";
|
||||
export async function request(endpoint, options = {}) {
|
||||
const tenantCode = getTenantCode();
|
||||
const isAuthRequest = endpoint.startsWith("/auth/");
|
||||
const baseUrl = isAuthRequest ? "/v1" : tenantCode ? `/v1/t/${tenantCode}` : "/v1";
|
||||
const baseUrl = isAuthRequest
|
||||
? "/v1"
|
||||
: tenantCode
|
||||
? `/v1/t/${tenantCode}`
|
||||
: "/v1";
|
||||
|
||||
if (!tenantCode && !isAuthRequest && !endpoint.startsWith("/tenants")) {
|
||||
// 无租户时仍允许访问公共入口,避免全局页面 404
|
||||
|
||||
@@ -248,7 +248,7 @@ onMounted(fetchData);
|
||||
v-for="creator in matchedCreators"
|
||||
:key="creator.id"
|
||||
class="flex items-center gap-3 p-3 rounded-xl hover:bg-slate-50 transition-colors cursor-pointer border border-transparent hover:border-slate-200"
|
||||
@click="$router.push(`/t/${creator.id}`)"
|
||||
@click="$router.push(`/t/${creator.id}`)"
|
||||
>
|
||||
<img
|
||||
:src="
|
||||
@@ -402,7 +402,7 @@ onMounted(fetchData);
|
||||
<div class="flex-1 min-w-0">
|
||||
<div
|
||||
class="font-bold text-slate-900 text-sm truncate hover:text-primary-600 cursor-pointer"
|
||||
@click="$router.push(`/t/${creator.id}`)"
|
||||
@click="$router.push(`/t/${creator.id}`)"
|
||||
>
|
||||
{{ creator.name }}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,94 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { contentApi } from "../../api/content";
|
||||
import { orderApi } from "../../api/order";
|
||||
import { tenantPath } from "../../utils/tenant";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const tenantRoute = (path) => tenantPath(path, route);
|
||||
|
||||
const contentId = route.query.contentId || route.query.content_id;
|
||||
const loading = ref(false);
|
||||
const errorMsg = ref("");
|
||||
const content = ref(null);
|
||||
const price = ref("0.00");
|
||||
|
||||
const loadContent = async () => {
|
||||
if (!contentId) {
|
||||
errorMsg.value = "缺少 contentId";
|
||||
return;
|
||||
}
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await contentApi.get(contentId);
|
||||
content.value = res;
|
||||
if (res?.prices?.length) {
|
||||
price.value = (res.prices[0].price_amount / 100).toFixed(2);
|
||||
} else if (res?.price_amount !== undefined) {
|
||||
price.value = (res.price_amount / 100).toFixed(2);
|
||||
} else if (res?.price !== undefined) {
|
||||
price.value = Number(res.price).toFixed(2);
|
||||
}
|
||||
} catch (e) {
|
||||
errorMsg.value = "加载内容失败";
|
||||
console.error(e);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const createOrder = async () => {
|
||||
if (!contentId) return;
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await orderApi.create({ content_id: Number(contentId) });
|
||||
const orderID = res?.id || res?.order_id || res?.orderID;
|
||||
if (!orderID) {
|
||||
throw new Error("未返回订单ID");
|
||||
}
|
||||
router.push(tenantRoute(`/payment/${orderID}`));
|
||||
} catch (e) {
|
||||
errorMsg.value = "创建订单失败";
|
||||
console.error(e);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(loadContent);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mx-auto max-w-screen-xl my-8 p-8 bg-white rounded-xl shadow-sm">
|
||||
<h1 class="text-2xl font-bold mb-4">Checkout</h1>
|
||||
<p class="text-slate-400">(Checkout flow)</p>
|
||||
<h1 class="text-2xl font-bold mb-4">结算</h1>
|
||||
<p v-if="loading" class="text-slate-400">加载中...</p>
|
||||
<p v-else-if="errorMsg" class="text-red-500 text-sm">{{ errorMsg }}</p>
|
||||
<div v-else class="space-y-6">
|
||||
<div class="border rounded-lg p-4 bg-slate-50">
|
||||
<div class="text-lg font-semibold text-slate-900">
|
||||
{{ content?.title }}
|
||||
</div>
|
||||
<div class="text-slate-500 text-sm">{{ content?.description }}</div>
|
||||
<div class="text-2xl font-bold text-primary-600 mt-2">
|
||||
¥ {{ price }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<button
|
||||
class="px-5 py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700"
|
||||
@click="createOrder"
|
||||
>
|
||||
提交订单
|
||||
</button>
|
||||
<button
|
||||
class="px-4 py-2 rounded-lg border border-slate-200 text-slate-600"
|
||||
@click="router.back()"
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -8,9 +8,10 @@ const route = useRoute();
|
||||
const router = useRouter();
|
||||
const tenantRoute = (path) => tenantPath(path, route);
|
||||
|
||||
const orderId = route.params.id || "82934712";
|
||||
const amount = "9.90"; // Should fetch order details first
|
||||
const productName = "《霸王别姬》全本实录珍藏版";
|
||||
const orderId = route.params.id;
|
||||
const amount = ref("0.00");
|
||||
const productName = ref("");
|
||||
const orderStatus = ref("");
|
||||
|
||||
const paymentMethod = ref("alipay");
|
||||
const timeLeft = ref(900); // 15 minutes
|
||||
@@ -29,6 +30,38 @@ const formatTime = (seconds) => {
|
||||
return `${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
|
||||
};
|
||||
|
||||
const loadOrder = async () => {
|
||||
try {
|
||||
const res = await orderApi.status(orderId);
|
||||
orderStatus.value = res?.status || "";
|
||||
if (res?.amount_paid !== undefined) {
|
||||
amount.value = (res.amount_paid / 100).toFixed(2);
|
||||
} else if (res?.amount_original !== undefined) {
|
||||
amount.value = (res.amount_original / 100).toFixed(2);
|
||||
}
|
||||
if (res?.content_title) {
|
||||
productName.value = res.content_title;
|
||||
}
|
||||
if (orderStatus.value === "paid" || orderStatus.value === "completed") {
|
||||
isSuccess.value = true;
|
||||
isScanning.value = false;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Load order failed", e);
|
||||
}
|
||||
};
|
||||
|
||||
const payOrder = async () => {
|
||||
try {
|
||||
isScanning.value = true;
|
||||
await orderApi.pay(orderId, { method: paymentMethod.value });
|
||||
// 支付接口若未立即更新状态,将继续依赖轮询
|
||||
} catch (e) {
|
||||
console.error("Pay order failed", e);
|
||||
isScanning.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const simulateSuccess = () => {
|
||||
isScanning.value = true;
|
||||
setTimeout(() => {
|
||||
@@ -45,11 +78,20 @@ onMounted(() => {
|
||||
if (timeLeft.value > 0) timeLeft.value--;
|
||||
}, 1000);
|
||||
|
||||
loadOrder();
|
||||
|
||||
// Poll Status
|
||||
pollTimer = setInterval(async () => {
|
||||
try {
|
||||
const res = await orderApi.status(orderId);
|
||||
if (res.status === "paid" || res.status === "completed") {
|
||||
orderStatus.value = res?.status || "";
|
||||
if (res?.amount_paid !== undefined) {
|
||||
amount.value = (res.amount_paid / 100).toFixed(2);
|
||||
}
|
||||
if (res?.content_title) {
|
||||
productName.value = res.content_title;
|
||||
}
|
||||
if (orderStatus.value === "paid" || orderStatus.value === "completed") {
|
||||
isScanning.value = false;
|
||||
isSuccess.value = true;
|
||||
clearInterval(pollTimer);
|
||||
@@ -105,7 +147,10 @@ onUnmounted(() => {
|
||||
<p class="text-slate-500 mb-2">订单提交成功,请尽快支付</p>
|
||||
<div class="text-4xl font-bold text-slate-900">¥ {{ amount }}</div>
|
||||
<div class="text-sm text-slate-500 mt-2">
|
||||
商品:{{ productName }}
|
||||
商品:{{ productName || "加载中..." }}
|
||||
</div>
|
||||
<div class="text-xs text-slate-400 mt-1">
|
||||
状态:{{ orderStatus || "pending" }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -193,12 +238,20 @@ onUnmounted(() => {
|
||||
</div>
|
||||
|
||||
<!-- Dev Tool -->
|
||||
<button
|
||||
@click="simulateSuccess"
|
||||
class="mt-8 text-xs text-slate-300 hover:text-slate-500 underline"
|
||||
>
|
||||
[开发调试] 模拟支付成功
|
||||
</button>
|
||||
<div class="flex flex-col items-center gap-3 mt-6">
|
||||
<button
|
||||
@click="payOrder"
|
||||
class="px-4 py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700"
|
||||
>
|
||||
立即支付
|
||||
</button>
|
||||
<button
|
||||
@click="simulateSuccess"
|
||||
class="text-xs text-slate-300 hover:text-slate-500 underline"
|
||||
>
|
||||
[开发调试] 模拟支付成功
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user