feat: add Login and fix res error

This commit is contained in:
2024-09-29 01:40:51 +08:00
parent 77485b34c0
commit 029710f31c
18 changed files with 178 additions and 118 deletions

View File

@@ -1,9 +1,28 @@
import { Query } from '@kevisual/query';
export const query = new Query({});
export const request = query.post;
export const ws = new WebSocket('ws://localhost:6010/api/router');
import { Query, QueryClient } from '@kevisual/query';
import { QueryWs } from '@kevisual/query/ws';
import { modal } from './redirect-to-login';
import { create } from 'zustand';
export const query = new Query();
query.beforeRequest = async (config) => {
if (config.headers) {
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] = 'Bearer ' + token;
}
}
return config;
};
query.afterResponse = async (res) => {
if (res.code === 401 || res.code === 403) {
modal.setOpen(true);
}
return res;
};
export const request = query.post;
export const queryWs = new QueryWs({
url: '/api/router',
});
export const ws = queryWs.ws;
type Store = {
connected: boolean;
setConnected: (connected: boolean) => void;
@@ -18,11 +37,6 @@ ws.onopen = () => {
console.log('Connected to WebSocket server');
useStore.getState().setConnected(true);
};
// 接收服务器的消息
ws.onmessage = (event) => {
// console.log('Received message:', event.data);
// const message = JSON.parse(event.data);
};
// 处理 WebSocket 关闭
ws.onclose = () => {

View File

@@ -0,0 +1,26 @@
import { DialogModal } from '@kevisual/ui';
import '@kevisual/ui/dist/index.css';
const content = document.createElement('div');
content.innerHTML = `
<div class="bg-white p-8 rounded shadow-md w-full max-w-md text-center">
<h2 class="text-2xl font-bold mb-4">Token 无效</h2>
<p class="mb-6">您的登录凭证已失效,请重新登录。</p>
<a href="/user/login" class="inline-block bg-red-500 text-white py-2 px-4 rounded hover:bg-red-600 transition duration-200">确定</a>
</div>
`;
export const modal = DialogModal.render(content, {
id: 'redirect-to-login',
contentStyle: {
width: 'unset',
},
dialogTitleStyle: {
display: 'none',
padding: '0',
},
dialogContentStyle: {
padding: '0',
},
mask: true,
open: false,
});

View File

@@ -34,7 +34,7 @@ export const useAgentStore = create<AgentStore>((set, get) => {
if (res.code === 200) {
set({ list: res.data });
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
updateData: async (data) => {
@@ -49,7 +49,7 @@ export const useAgentStore = create<AgentStore>((set, get) => {
set({ showEdit: false, formData: [] });
getList();
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
deleteData: async (id) => {
@@ -63,7 +63,7 @@ export const useAgentStore = create<AgentStore>((set, get) => {
getList();
message.success('Success');
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
publishData: async (data) => {
@@ -87,7 +87,7 @@ export const useAgentStore = create<AgentStore>((set, get) => {
if (res.code === 200) {
message.success('Success');
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
};

View File

@@ -1,6 +1,6 @@
import { useShallow } from 'zustand/react/shallow';
import { useAiStore } from './store/ai-store';
import { CloseOutlined } from '@ant-design/icons';
import { CloseOutlined, HistoryOutlined } from '@ant-design/icons';
import { Button, Form, Input } from 'antd';
import { useEffect } from 'react';
import { TextArea } from '../container/components/TextArea';
@@ -49,6 +49,9 @@ export const AiMoudle = () => {
<div className='flex gap-4 bg-slate-400 p-2'>
<Button className='position ml-4 !bg-slate-400 !border-black' onClick={() => aiStore.setOpen(false)} icon={<CloseOutlined />}></Button>
<h1 className='ml-10'>Ai Moudle</h1>
<div>
<HistoryOutlined />
</div>
</div>
<div className='flex-grow p-2 overflow-hidden h-full flex flex-col'>
<div className='flex flex-col'>
@@ -58,8 +61,9 @@ export const AiMoudle = () => {
return (
<div key={index} className=' justify-between px-4 w-full'>
<div className='h3 font-bold'>{message?.role}</div>
<div className='p-4 text-xs border shadow-sm rounded-sm scrollbar max-h-[200px] w-full overflow-scroll' dangerouslySetInnerHTML={{ __html: html }}>
</div>
<div
className='p-4 text-xs border shadow-sm rounded-sm scrollbar max-h-[200px] w-full overflow-scroll'
dangerouslySetInnerHTML={{ __html: html }}></div>
</div>
);
})}

View File

@@ -1,4 +1,4 @@
import { Button, Input, message, Modal, Table } from 'antd';
import { Button, Input, message, Modal, Select, Table, Tooltip } from 'antd';
import { Fragment, useEffect, useMemo, useState } from 'react';
import { TextArea } from '../components/TextArea';
import { useContainerStore } from '../store';
@@ -6,9 +6,10 @@ import { useShallow } from 'zustand/react/shallow';
import { Form } from 'antd';
import copy from 'copy-to-clipboard';
import { useNavigate } from 'react-router';
import { EditOutlined, SettingOutlined, LinkOutlined, SaveOutlined, DeleteOutlined, LeftOutlined } from '@ant-design/icons';
import { EditOutlined, SettingOutlined, LinkOutlined, SaveOutlined, DeleteOutlined, LeftOutlined, MessageOutlined } from '@ant-design/icons';
import clsx from 'clsx';
import { isObjectNull } from '@/utils/is-null';
import { CardBlank } from '@/components/card/CardBlank';
const FormModal = () => {
const [form] = Form.useForm();
const containerStore = useContainerStore(
@@ -67,6 +68,9 @@ const FormModal = () => {
<Form.Item name='description' label='description'>
<Input.TextArea rows={4} />
</Form.Item>
<Form.Item name='tags' label='tags'>
<Select mode='tags' />
</Form.Item>
<Form.Item name='code' label='code'>
<TextArea />
</Form.Item>
@@ -128,13 +132,14 @@ export const ContainerList = () => {
}}>
<div className='px-4 cursor-pointer'>
<div
className='font-bold'
className='font-bold flex items-center'
onClick={(e) => {
copy(item.code);
e.stopPropagation();
message.success('copy code success');
}}>
{item.title || '-'}
<div className='font-thin card-key ml-3 text-xs'>{item.tags ? item.tags.join(', ') : ''}</div>
</div>
<div className='font-light text-xs mt-2'>{item.description ? item.description : '-'}</div>
</div>
@@ -171,9 +176,7 @@ export const ContainerList = () => {
</Fragment>
);
})}
{new Array(4).fill(0).map((_, index) => {
return <div key={index} className='w-[400px]'></div>;
})}
<CardBlank className='w-[400px]' />
{containerStore.list.length == 0 && (
<div className='text-center' key={'no-data'}>
No Data
@@ -184,18 +187,33 @@ export const ContainerList = () => {
<div className={clsx('bg-gray-100 border-l border-bg-slate-300 w-[600px] flex-shrink-0', !codeEdit && 'hidden')}>
<div className='bg-white p-2'>
<div className='mt-2 ml-2 flex gap-2'>
<Button
onClick={() => {
setCodeEdit(false);
containerStore.setFormData({});
}}
icon={<LeftOutlined />}></Button>
<Button
onClick={() => {
console.log('save', containerStore.formData);
containerStore.updateData({ ...containerStore.formData, code });
}}
icon={<SaveOutlined />}></Button>
<Tooltip title='返回'>
<Button
onClick={() => {
setCodeEdit(false);
containerStore.setFormData({});
}}
icon={<LeftOutlined />}></Button>
</Tooltip>
<Tooltip title='保存'>
<Button
onClick={() => {
console.log('save', containerStore.formData);
containerStore.updateData({ ...containerStore.formData, code });
}}
icon={<SaveOutlined />}></Button>
</Tooltip>
<Tooltip title='预览'>
<Button
onClick={(e) => {
// navicate('/container/preview/' + item.id);
e.stopPropagation();
}}
icon={<LinkOutlined />}></Button>
</Tooltip>
<Tooltip title='ai编程'>
<Button onClick={(e) => {}} icon={<MessageOutlined />}></Button>
</Tooltip>
</div>
</div>
<div className='h-[94%] p-2 rounded-2 shadow-sm'>

View File

@@ -80,7 +80,7 @@ export const Preview = () => {
};
init([code]);
} else {
message.error(res.msg || 'Failed to fetch data');
message.error(res.message || 'Failed to fetch data');
}
};
const refresh = (data: any) => {
@@ -131,7 +131,7 @@ export const PreviewWrapper = () => {
fetch();
}, []);
const fetch = async () => {
const res = await query.post({
const res = await query.post<any, any>({
path: 'container',
key: 'get',
id,
@@ -149,7 +149,7 @@ export const PreviewWrapper = () => {
};
init([code]);
} else {
message.error(res.msg || 'Failed to fetch data');
message.error(res.message || 'Failed to fetch data');
}
};
const refresh = (data: any) => {

View File

@@ -34,7 +34,7 @@ export const useContainerStore = create<ContainerStore>((set, get) => {
if (res.code === 200) {
set({ list: res.data });
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
updateData: async (data) => {
@@ -49,7 +49,7 @@ export const useContainerStore = create<ContainerStore>((set, get) => {
set({ showEdit: false, formData: [] });
getList();
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
deleteData: async (id) => {
@@ -63,7 +63,7 @@ export const useContainerStore = create<ContainerStore>((set, get) => {
getList();
message.success('Success');
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
publishData: async (data) => {
@@ -87,7 +87,7 @@ export const useContainerStore = create<ContainerStore>((set, get) => {
if (res.code === 200) {
message.success('Success');
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
};

View File

@@ -31,8 +31,8 @@ const ServerPath = () => {
const navigate = useNavigate();
return (
<div className='p-2 w-full h-full bg-gray-200'>
<h1 className='p-4 w-1/2 m-auto h1'>Map</h1>
<div className='flex flex-col w-1/2 m-auto bg-white p-4 border rounded-md shadow-md'>
<h1 className='p-4 w-1/2 m-auto h1'>Site Map</h1>
<div className='flex flex-col w-1/2 m-auto bg-white p-4 border rounded-md shadow-md min-w-[600px]'>
{serverPath.map((item) => {
const links = item.links.map((link) => {
const hasId = link.includes(':id');

View File

@@ -31,7 +31,7 @@ export const useEditStore = create<EditStore>((set, get) => {
if (res.code === 200) {
set({ list: res.data });
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
updateData: async (data) => {
@@ -46,7 +46,7 @@ export const useEditStore = create<EditStore>((set, get) => {
set({ showEditModal: false, formData: [] });
getList();
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
deleteData: async (id) => {
@@ -60,7 +60,7 @@ export const useEditStore = create<EditStore>((set, get) => {
message.success('Success');
getList();
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
};

View File

@@ -50,7 +50,7 @@ export const usePanelStore = create<PanelStore>((set, get) => {
}),
);
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
saveNodesEdges: async ({ edges, nodes, viewport }) => {
@@ -77,7 +77,7 @@ export const usePanelStore = create<PanelStore>((set, get) => {
}),
);
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
updateNodeData: async (data) => {
@@ -95,7 +95,7 @@ export const usePanelStore = create<PanelStore>((set, get) => {
message.success('Success');
// getList();
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
updateNodeDataStyle: async (data) => {
@@ -118,7 +118,7 @@ export const usePanelStore = create<PanelStore>((set, get) => {
// getList();
return true;
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
return false;
},

View File

@@ -41,7 +41,7 @@ export const usePromptStore = create<PromptStore>((set, get) => {
if (res.code === 200) {
set({ list: res.data });
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
updateData: async (data) => {
@@ -56,7 +56,7 @@ export const usePromptStore = create<PromptStore>((set, get) => {
set({ showEdit: false, formData: [] });
getList();
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
deleteData: async (id) => {
@@ -70,7 +70,7 @@ export const usePromptStore = create<PromptStore>((set, get) => {
getList();
message.success('Success');
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
runAi: async () => {

View File

@@ -33,7 +33,7 @@ export const usePublishStore = create<Store>((set, get) => {
if (res.code === 200) {
set({ list: res.data });
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
updateData: async (data) => {
@@ -48,7 +48,7 @@ export const usePublishStore = create<Store>((set, get) => {
set({ showEdit: false, formData: [] });
getList();
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
deleteData: async (id) => {
@@ -62,7 +62,7 @@ export const usePublishStore = create<Store>((set, get) => {
getList();
message.success('Success');
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
};

View File

@@ -27,18 +27,23 @@ export const Login = () => {
loginStore.login();
};
return (
<div className='flex w-full h-full'>
<div className='w-[600px] mx-auto mt-[10%] '>
<div className='flex w-full h-full bg-slate-200'>
<div className='w-[600px] mx-auto mt-[10%] '>
<h1 className='mb-4 tracking-widest'>Login</h1>
<div className='card border-t-2'>
<Form form={form} onFinish={onFinish}>
<div className='card border-t-2 pt-8 px-8'>
<Form
form={form}
onFinish={onFinish}
labelCol={{
span: 4,
}}>
<Form.Item label='username' name='username'>
<Input />
</Form.Item>
<Form.Item label='password' name='password'>
<Input type='password' />
</Form.Item>
<Form.Item label=' ' noStyle colon={false}>
<Form.Item label=' ' colon={false}>
<div className='flex gap-2'>
<Button type='primary' htmlType='submit'>
Login

View File

@@ -33,7 +33,7 @@ export const useUserStore = create<UserStore>((set, get) => {
if (res.code === 200) {
set({ list: res.data });
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
updateData: async (data) => {
@@ -48,7 +48,7 @@ export const useUserStore = create<UserStore>((set, get) => {
set({ showEdit: false, formData: [] });
getList();
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
deleteData: async (id) => {
@@ -62,7 +62,7 @@ export const useUserStore = create<UserStore>((set, get) => {
getList();
message.success('Success');
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
};

View File

@@ -1,6 +1,7 @@
import { query } from '@/modules';
import { message } from 'antd';
import { create } from 'zustand';
import { history } from '@/utils/history';
type LoginStore = {
loading: boolean;
setLoading: (loading: boolean) => void;
@@ -29,11 +30,14 @@ export const useLoginStore = create<LoginStore>((set, get) => {
const res = await query.post({ path: 'user', key: 'login', username, password });
loaded();
if (res.code === 200) {
const { token } = res.data;
message.success('Success');
set({ isLogin: true });
localStorage.setItem('token', token);
// 跳到某一个页面更新localStorage
history.push('/map');
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
register: async () => {
@@ -44,8 +48,9 @@ export const useLoginStore = create<LoginStore>((set, get) => {
if (res.code === 200) {
message.success('Success');
// 跳到某一个页面
// history.push('/map', {}, true);
} else {
message.error(res.msg || 'Request failed');
message.error(res.message || 'Request failed');
}
},
isLogin: false,