feat: 运营平台基建 搭建
This commit is contained in:
+196
-37
@@ -1,7 +1,8 @@
|
||||
import { defineComponent, reactive, ref } from 'vue';
|
||||
import { Button, Card, Form, FormItem, Input, message } from 'ant-design-vue';
|
||||
import { Button, Checkbox, Form, FormItem, Input, message } from 'ant-design-vue';
|
||||
import { UserOutlined, LockOutlined } from '@ant-design/icons-vue';
|
||||
import { auth } from '@/hooks/useAuth';
|
||||
import { useEffect } from '@/hooks/useEffect';
|
||||
import styles from './index.module.less';
|
||||
|
||||
interface LoginForm {
|
||||
@@ -9,20 +10,31 @@ interface LoginForm {
|
||||
password: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录页
|
||||
* auth.login() 内部会自动:保存 token → 拉取菜单+权限 → 动态注册路由 → 跳转首页
|
||||
*/
|
||||
export default defineComponent({
|
||||
name: 'LoginPage',
|
||||
setup() {
|
||||
const loading = ref(false);
|
||||
const rememberMe = ref(false);
|
||||
|
||||
const form = reactive<LoginForm>({
|
||||
username: 'admin',
|
||||
password: '123456',
|
||||
username: '',
|
||||
password: '',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const saved = localStorage.getItem('cpms_login_remember');
|
||||
if (saved) {
|
||||
try {
|
||||
const data = JSON.parse(saved);
|
||||
form.username = data.username || '';
|
||||
form.password = data.password || '';
|
||||
rememberMe.value = true;
|
||||
} catch {
|
||||
localStorage.removeItem('cpms_login_remember');
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
const rules = {
|
||||
username: [{ required: true, message: '请输入用户名' }],
|
||||
password: [{ required: true, message: '请输入密码' }],
|
||||
@@ -37,14 +49,21 @@ export default defineComponent({
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
// TODO: 替换为真实登录接口
|
||||
// const res = await post<LoginResult>('/auth/login', { username: form.username, password: form.password });
|
||||
// await auth.login(res.token);
|
||||
|
||||
// Mock:模拟登录
|
||||
await new Promise((r) => setTimeout(r, 600));
|
||||
await auth.login('mock_token_' + Date.now());
|
||||
message.success('登录成功');
|
||||
|
||||
if (rememberMe.value) {
|
||||
localStorage.setItem(
|
||||
'cpms_login_remember',
|
||||
JSON.stringify({
|
||||
username: form.username,
|
||||
password: form.password,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
localStorage.removeItem('cpms_login_remember');
|
||||
}
|
||||
} catch (err) {
|
||||
message.error('登录失败,请重试');
|
||||
} finally {
|
||||
@@ -52,34 +71,174 @@ export default defineComponent({
|
||||
}
|
||||
};
|
||||
|
||||
const particles = [
|
||||
{ top: '8%', left: '15%', delay: '0s', duration: '8s' },
|
||||
{ top: '22%', left: '65%', delay: '1.5s', duration: '7s' },
|
||||
{ top: '45%', left: '25%', delay: '0.8s', duration: '9s' },
|
||||
{ top: '60%', left: '75%', delay: '2s', duration: '6.5s' },
|
||||
{ top: '75%', left: '40%', delay: '3s', duration: '8.5s' },
|
||||
{ top: '15%', left: '80%', delay: '1s', duration: '7.5s' },
|
||||
{ top: '35%', left: '50%', delay: '2.5s', duration: '6s' },
|
||||
{ top: '85%', left: '20%', delay: '0.5s', duration: '9.5s' },
|
||||
{ top: '50%', left: '90%', delay: '3.5s', duration: '8s' },
|
||||
{ top: '92%', left: '55%', delay: '1.2s', duration: '7s' },
|
||||
];
|
||||
|
||||
return () => (
|
||||
<div class={styles.container}>
|
||||
<Card class={styles.card} title="CPMS 运营平台">
|
||||
<Form model={form} rules={rules} layout="vertical" onFinish={handleSubmit}>
|
||||
<FormItem name="username">
|
||||
<Input
|
||||
v-model={[form.username, 'value']}
|
||||
placeholder="用户名"
|
||||
size="large"
|
||||
v-slots={{ prefix: () => <UserOutlined /> }}
|
||||
<div class={styles.brand}>
|
||||
<div class={styles.orb1} />
|
||||
<div class={styles.orb2} />
|
||||
<div class={styles.orb3} />
|
||||
<div class={styles.pulse} />
|
||||
<div class={styles.brandGrid} />
|
||||
<div class={styles.scanLine} />
|
||||
<div class={styles.particles}>
|
||||
{particles.map((p, i) => (
|
||||
<div
|
||||
key={i}
|
||||
class={styles.particle}
|
||||
style={{
|
||||
top: p.top,
|
||||
left: p.left,
|
||||
animationDelay: p.delay,
|
||||
animationDuration: p.duration,
|
||||
}}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem name="password">
|
||||
<Input
|
||||
v-model={[form.password, 'value']}
|
||||
type="password"
|
||||
placeholder="密码"
|
||||
size="large"
|
||||
v-slots={{ prefix: () => <LockOutlined /> }}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button type="primary" htmlType="submit" size="large" block loading={loading.value}>
|
||||
登录
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div class={styles.brandInner}>
|
||||
<div class={styles.logoRow}>
|
||||
<div class={styles.logoMark}>6</div>
|
||||
<span class={styles.logoText}>羽友赛事</span>
|
||||
</div>
|
||||
<h1 class={styles.brandTitle}>六个羽友赛事运营平台</h1>
|
||||
<p class={styles.brandSubtitle}>
|
||||
专业的赛事管理、报名运营与数据分析一站式解决方案,助力每一场精彩赛事
|
||||
</p>
|
||||
<div class={styles.statsRow}>
|
||||
<div class={styles.statItem}>
|
||||
<span class={styles.statValue}>
|
||||
<span class={styles.statHighlight}>1,200</span>+
|
||||
</span>
|
||||
<span class={styles.statLabel}>累计赛事场次</span>
|
||||
</div>
|
||||
<div class={styles.statItem}>
|
||||
<span class={styles.statValue}>
|
||||
<span class={styles.statHighlight}>50,000</span>+
|
||||
</span>
|
||||
<span class={styles.statLabel}>参赛选手</span>
|
||||
</div>
|
||||
<div class={styles.statItem}>
|
||||
<span class={styles.statValue}>
|
||||
<span class={styles.statHighlight}>100</span>%
|
||||
</span>
|
||||
<span class={styles.statLabel}>运营满意度</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class={styles.eventCards}>
|
||||
<div class={styles.eventCard}>
|
||||
<div class={[styles.eventIcon, styles.blue]}>📋</div>
|
||||
<div class={styles.eventTitle}>赛事管理</div>
|
||||
<div class={styles.eventDesc}>创建发布、赛事审核、赛程编排全流程在线化</div>
|
||||
</div>
|
||||
<div class={styles.eventCard}>
|
||||
<div class={[styles.eventIcon, styles.green]}>🏆</div>
|
||||
<div class={styles.eventTitle}>对阵分组</div>
|
||||
<div class={styles.eventDesc}>智能分组算法、自动生成对阵表与淘汰树</div>
|
||||
</div>
|
||||
<div class={styles.eventCard}>
|
||||
<div class={[styles.eventIcon, styles.orange]}>📊</div>
|
||||
<div class={styles.eventTitle}>数据看板</div>
|
||||
<div class={styles.eventDesc}>参赛统计、实时进度、成绩排名可视化呈现</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class={styles.flowSteps}>
|
||||
<div class={styles.step}>
|
||||
<span class={styles.stepDot} />
|
||||
<span class={styles.stepLabel}>创建赛事</span>
|
||||
</div>
|
||||
<div class={styles.stepLine} />
|
||||
<div class={styles.step}>
|
||||
<span class={styles.stepDot} />
|
||||
<span class={styles.stepLabel}>赛事审核</span>
|
||||
</div>
|
||||
<div class={styles.stepLine} />
|
||||
<div class={styles.step}>
|
||||
<span class={styles.stepDot} />
|
||||
<span class={styles.stepLabel}>分组对阵</span>
|
||||
</div>
|
||||
<div class={styles.stepLine} />
|
||||
<div class={styles.step}>
|
||||
<span class={styles.stepDot} />
|
||||
<span class={styles.stepLabel}>成绩录入</span>
|
||||
</div>
|
||||
<div class={styles.stepLine} />
|
||||
<div class={styles.step}>
|
||||
<span class={styles.stepDot} />
|
||||
<span class={styles.stepLabel}>数据复盘</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class={styles.brandFooter}>六个羽友赛事运营平台 ©{new Date().getFullYear()}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class={styles.loginSide}>
|
||||
<div class={styles.loginWrapper}>
|
||||
<h2 class={styles.loginTitle}>欢迎回来</h2>
|
||||
<p class={styles.loginDesc}>登录六个羽友赛事运营平台</p>
|
||||
|
||||
<Form
|
||||
class={styles.loginForm}
|
||||
model={form}
|
||||
rules={rules}
|
||||
layout="vertical"
|
||||
onFinish={handleSubmit}
|
||||
>
|
||||
<FormItem name="username">
|
||||
<Input
|
||||
v-model={[form.username, 'value']}
|
||||
placeholder="请输入用户名"
|
||||
size="large"
|
||||
v-slots={{ prefix: () => <UserOutlined /> }}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem name="password">
|
||||
<Input
|
||||
v-model={[form.password, 'value']}
|
||||
type="password"
|
||||
placeholder="请输入密码"
|
||||
size="large"
|
||||
v-slots={{ prefix: () => <LockOutlined /> }}
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
{/* 记住密码 */}
|
||||
<div class={styles.rememberRow}>
|
||||
<Checkbox v-model={[rememberMe.value, 'checked']}>记住密码</Checkbox>
|
||||
</div>
|
||||
|
||||
<FormItem>
|
||||
<Button
|
||||
class={styles.loginBtn}
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
size="large"
|
||||
block
|
||||
loading={loading.value}
|
||||
>
|
||||
登 录
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
|
||||
<div class={styles.loginFooter}>六个羽友赛事运营平台 ©{new Date().getFullYear()}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user