feat: 实现首次登录功能,添加用户名和密码输入,更新状态管理
This commit is contained in:
@@ -1,22 +1,20 @@
|
||||
import { useEffect } from "react";
|
||||
import { use, useEffect, useState } from "react";
|
||||
import { Layout } from "./layout"
|
||||
import { useStore } from "./store";
|
||||
export const FirstLogin = () => {
|
||||
const store = useStore();
|
||||
const [username, setUsername] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
useEffect(() => {
|
||||
store.initAdmin();
|
||||
}, []);
|
||||
const onClickLogin = async () => {
|
||||
const accountInput = document.getElementById('account') as HTMLInputElement;
|
||||
const passwordInput = document.getElementById('password') as HTMLInputElement;
|
||||
const username = accountInput.value;
|
||||
const password = passwordInput.value;
|
||||
const res = await store.login(username, password);
|
||||
if (res.code === 200) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert(res.message || '登录失败');
|
||||
useEffect(() => {
|
||||
if (store.username) {
|
||||
setUsername(store.username);
|
||||
}
|
||||
}, [store.username]);
|
||||
const onClickLogin = async () => {
|
||||
await store.login(username, password);
|
||||
}
|
||||
return (
|
||||
<Layout>
|
||||
@@ -27,12 +25,14 @@ export const FirstLogin = () => {
|
||||
第一次登录的<a className="text-gray-700 mx-1" href="https://kevisual.cn">kevisual</a> 用户为当前设备管理员。如果已经存在管理员账号,管理员可在"全局设置"中设置。
|
||||
<a className="text-gray-700 mx-1 underline" href="../docs/01-login-first/">文档</a>
|
||||
</blockquote>
|
||||
<div className='space-y-4 mt-8'>
|
||||
<form className='space-y-4 mt-8'>
|
||||
<div>
|
||||
<label htmlFor='account' className='block text-sm font-medium text-gray-900 mb-2'> 账号 </label>
|
||||
<input
|
||||
type='text'
|
||||
id='account'
|
||||
onChange={e => setUsername(e.target.value)}
|
||||
value={username}
|
||||
placeholder='请输入账号'
|
||||
className='w-full px-4 py-2 border-2 border-black bg-white text-black placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-black focus:border-transparent'
|
||||
/>
|
||||
@@ -42,6 +42,8 @@ export const FirstLogin = () => {
|
||||
<input
|
||||
type='password'
|
||||
id='password'
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
value={password}
|
||||
placeholder='请输入密码'
|
||||
className='w-full px-4 py-2 border-2 border-black bg-white text-black placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-black focus:border-transparent'
|
||||
/>
|
||||
@@ -52,9 +54,25 @@ export const FirstLogin = () => {
|
||||
className='w-full px-4 py-2 bg-black text-white font-medium hover:bg-gray-800 active:bg-gray-900 transition-colors focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2'>
|
||||
确定
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export const Config = () => {
|
||||
const store = useStore();
|
||||
useEffect(() => {
|
||||
store.initAdmin();
|
||||
}, []);
|
||||
return (
|
||||
<Layout>
|
||||
<div className="p-4">
|
||||
<pre className="bg-gray-100 p-4 rounded-lg overflow-x-auto">
|
||||
{JSON.stringify(store.config, null, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
@@ -1,31 +1,42 @@
|
||||
import { query } from '@/modules/query';
|
||||
import { query, queryLogin } from '@/modules/query';
|
||||
import { create } from 'zustand';
|
||||
|
||||
type SettingState = {
|
||||
username?: string;
|
||||
initAdmin: () => any;
|
||||
login: (username: string, password: string) => any;
|
||||
config?: any;
|
||||
}
|
||||
export const useStore = create<SettingState>((set => ({
|
||||
username: undefined,
|
||||
config: undefined,
|
||||
initAdmin: async () => {
|
||||
const res = await query.post({
|
||||
path: 'config'
|
||||
})
|
||||
console.log('initAdmin', res);
|
||||
if (res.code === 200) {
|
||||
const auth = res.data.auth || {}
|
||||
if (auth.username) {
|
||||
set({ username: auth.username });
|
||||
}
|
||||
set({ config: res.data });
|
||||
}
|
||||
},
|
||||
login: async (username: string, password: string) => {
|
||||
const res = await query.post({
|
||||
path: 'admin',
|
||||
key: 'login',
|
||||
data: {
|
||||
username,
|
||||
password
|
||||
}
|
||||
});
|
||||
if (res.code === 200) {
|
||||
set({ username });
|
||||
const setToken = await queryLogin.setLoginToken(res.data)
|
||||
console.log('setToken', setToken);
|
||||
}
|
||||
console.log('login res', res);
|
||||
|
||||
return res;
|
||||
}
|
||||
})));
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Query } from '@kevisual/query'
|
||||
|
||||
import { QueryClient, Query } from '@kevisual/query'
|
||||
import { QueryLoginBrowser } from '@kevisual/query-login'
|
||||
const getUrl = () => {
|
||||
const host = window.location.host
|
||||
const isKevisual = host.includes('kevisual');
|
||||
@@ -10,6 +10,14 @@ const getUrl = () => {
|
||||
return '/client/router'
|
||||
}
|
||||
|
||||
export const query = new Query({
|
||||
export const query = new QueryClient({
|
||||
url: getUrl()
|
||||
});
|
||||
|
||||
export const remoteQuery = new Query({
|
||||
url: '/api/router'
|
||||
});
|
||||
|
||||
export const queryLogin = new QueryLoginBrowser({
|
||||
query: remoteQuery
|
||||
});
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
import Html from '@/components/html.astro';
|
||||
import { FirstLogin } from '@/apps/setting/index.tsx';
|
||||
import { Config } from '@/apps/setting/index.tsx';
|
||||
---
|
||||
|
||||
<Html>
|
||||
<FirstLogin client:only />
|
||||
<Config client:only />
|
||||
</Html>
|
||||
|
||||
Reference in New Issue
Block a user