feat: add Login and fix res error
This commit is contained in:
@@ -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 = () => {
|
||||
|
||||
26
src/modules/redirect-to-login.ts
Normal file
26
src/modules/redirect-to-login.ts
Normal 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,
|
||||
});
|
||||
@@ -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');
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -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'>
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user