Feature/0723/zr #8

Merged
chenzhen merged 26 commits from feature/0723/ZR into release/0.01 2026-08-06 13:51:34 +08:00
3 changed files with 137 additions and 88 deletions
Showing only changes of commit 0a6d751e82 - Show all commits
+16 -88
View File
@@ -1,90 +1,22 @@
import { defineComponent, reactive } from 'vue';
import { useRoute } from 'vue-router';
import { Button, Checkbox, Form, FormItem, Input, message } from 'ant-design-vue';
import { defineComponent } from 'vue';
import { Button, Checkbox, Form, FormItem, Input } from 'ant-design-vue';
import { UserOutlined, LockOutlined } from '@ant-design/icons-vue';
import { auth } from '@/hooks/useAuth';
import { useEffect, useState } from '@/hooks';
import { useUserStore } from '@/stores/userStore';
import { login as loginApi } from '@/api/login';
import { loginFormRules } from './model/form';
import { useLoginModel } from './model/useLoginModel';
import styles from './index.module.less';
interface LoginForm {
phone: string;
password: string;
}
export default defineComponent({
name: 'LoginPage',
setup() {
const route = useRoute();
const [loading, setLoading] = useState(false);
const [rememberMe, setRememberMe] = useState(false);
const { setUser } = useUserStore();
const form = reactive<LoginForm>({
phone: '',
password: '',
});
useEffect(() => {
const saved = localStorage.getItem('cpms_login_remember');
if (saved) {
try {
const data = JSON.parse(saved);
form.phone = data.phone || '';
form.password = data.password || '';
setRememberMe(true);
} catch {
localStorage.removeItem('cpms_login_remember');
}
}
}, []);
const handleSubmit = async () => {
if (!form.phone || !form.password) {
message.warning('请输入用户名和密码');
return;
}
setLoading(true);
try {
const res = await loginApi({ phone: form.phone, password: form.password });
if (res.code != 200) {
message.error(res.msg || '登录失败');
return;
}
setUser({
phone: res.data.phone || form.phone,
nickname: res.data.nickName || '',
token: res.data.token,
});
if (rememberMe.value) {
localStorage.setItem(
'cpms_login_remember',
JSON.stringify({
phone: form.phone,
password: form.password,
}),
);
} else {
localStorage.removeItem('cpms_login_remember');
}
const redirect = Array.isArray(route.query.redirect)
? route.query.redirect[0]
: route.query.redirect;
await auth.login(res.data.token, redirect || undefined);
message.success('登录成功');
} catch (err) {
message.error('登录失败,请重试');
} finally {
setLoading(false);
}
};
const {
form,
setPhone,
setPassword,
rememberMe,
setRememberMe,
loading,
handleSubmit,
loginFormRules,
} = useLoginModel();
const particles = [
{ top: '8%', left: '15%', delay: '0s', duration: '8s' },
@@ -217,7 +149,7 @@ export default defineComponent({
<FormItem name="phone">
<Input
value={form.phone}
onUpdate:value={(val: string) => (form.phone = val)}
onUpdate:value={setPhone}
placeholder="请输入用户名"
size="large"
v-slots={{ prefix: () => <UserOutlined /> }}
@@ -226,7 +158,7 @@ export default defineComponent({
<FormItem name="password">
<Input
value={form.password}
onUpdate:value={(val: string) => (form.password = val)}
onUpdate:value={setPassword}
type="password"
placeholder="请输入密码"
size="large"
@@ -234,12 +166,8 @@ export default defineComponent({
/>
</FormItem>
{/* 记住密码 */}
<div class={styles.rememberRow}>
<Checkbox
checked={rememberMe.value}
onUpdate:checked={(val: boolean) => setRememberMe(val)}
>
<Checkbox checked={rememberMe.value} onUpdate:checked={setRememberMe}>
</Checkbox>
</div>
+4
View File
@@ -0,0 +1,4 @@
/**
* 登录页 - 接口服务
*/
export { login, type LoginResult } from '@/api/login';
+117
View File
@@ -0,0 +1,117 @@
import { reactive } from 'vue';
import { useRoute } from 'vue-router';
import { message } from 'ant-design-vue';
import { useEffect, useState } from '@/hooks';
import { auth } from '@/hooks/useAuth';
import { useUserStore } from '@/stores/userStore';
import { login } from './services';
import { loginFormRules } from './form';
// ============================================================
// 类型
// ============================================================
export interface LoginForm {
phone: string;
password: string;
}
// ============================================================
// 常量
// ============================================================
const REMEMBER_KEY = 'cpms_login_remember';
// ============================================================
// Model
// ============================================================
export function useLoginModel() {
const route = useRoute();
const { setUser } = useUserStore();
const [loading, setLoading] = useState(false);
const [rememberMe, setRememberMe] = useState(false);
const form = reactive<LoginForm>({
phone: '',
password: '',
});
useEffect(() => {
const saved = localStorage.getItem(REMEMBER_KEY);
if (!saved) return;
try {
const data = JSON.parse(saved);
form.phone = data.phone || '';
form.password = data.password || '';
setRememberMe(true);
} catch {
localStorage.removeItem(REMEMBER_KEY);
}
}, []);
const setPhone = (phone: string) => {
form.phone = phone;
};
const setPassword = (password: string) => {
form.password = password;
};
const handleSubmit = async () => {
if (!form.phone || !form.password) {
message.warning('请输入用户名和密码');
return;
}
setLoading(true);
try {
const res = await login({ phone: form.phone, password: form.password });
if (res.code != 200) {
message.error(res.msg || '登录失败');
return;
}
setUser({
phone: res.data.phone || form.phone,
nickname: res.data.nickName || '',
token: res.data.token,
});
if (rememberMe.value) {
localStorage.setItem(
REMEMBER_KEY,
JSON.stringify({
phone: form.phone,
password: form.password,
}),
);
} else {
localStorage.removeItem(REMEMBER_KEY);
}
const redirect = Array.isArray(route.query.redirect)
? route.query.redirect[0]
: route.query.redirect;
await auth.login(res.data.token, redirect || undefined);
message.success('登录成功');
} catch {
message.error('登录失败,请重试');
} finally {
setLoading(false);
}
};
return {
form,
setPhone,
setPassword,
rememberMe,
setRememberMe,
loading,
handleSubmit,
loginFormRules,
};
}