初始化足球投注平台 MVP Monorepo

包含 NestJS 后端、三端前端、Prisma 数据模型、结算引擎测试与 PRD 文档。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-02 14:35:48 +08:00
commit 14e49374ac
118 changed files with 15944 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useAuthStore } from '../stores/auth';
const { t } = useI18n();
const auth = useAuthStore();
const router = useRouter();
const username = ref('player1');
const password = ref('Player@123');
const error = ref('');
const loading = ref(false);
async function submit() {
loading.value = true;
error.value = '';
try {
await auth.login(username.value, password.value);
router.push('/');
} catch (e: unknown) {
error.value = (e as { response?: { data?: { error?: string } } })?.response?.data?.error || 'Login failed';
} finally {
loading.value = false;
}
}
</script>
<template>
<div class="login-page">
<h1 class="logo">TheBet365</h1>
<form @submit.prevent="submit" class="login-form">
<label>{{ t('auth.username') }}</label>
<input v-model="username" required />
<label>{{ t('auth.password') }}</label>
<input v-model="password" type="password" required />
<p v-if="error" class="error">{{ error }}</p>
<button type="submit" class="btn-primary" :disabled="loading">
{{ t('auth.login') }}
</button>
</form>
</div>
</template>
<style scoped>
.login-page {
min-height: 100vh; display: flex; flex-direction: column;
align-items: center; justify-content: center; padding: 24px;
}
.logo { color: var(--primary); font-size: 32px; margin-bottom: 32px; }
.login-form { width: 100%; max-width: 320px; display: flex; flex-direction: column; gap: 12px; }
label { font-size: 13px; color: var(--text-muted); }
.error { color: var(--danger); font-size: 13px; }
</style>