feat: prevent the user from entering the knowledge base if he is not logged in (#45)

This commit is contained in:
balibabu 2024-01-29 19:28:39 +08:00 committed by GitHub
parent e1bc1d46e6
commit 04aba1bb65
20 changed files with 700 additions and 591 deletions

View File

@ -1,22 +1,20 @@
import { defineConfig } from "umi"; import { defineConfig } from 'umi';
import routes from './routes' import routes from './src/routes';
export default defineConfig({ export default defineConfig({
outputPath: 'dist', outputPath: 'dist',
// alias: { '@': './src' }, // alias: { '@': './src' },
routes,
npmClient: 'npm', npmClient: 'npm',
base: '/', base: '/',
routes,
publicPath: '/web/dist/', publicPath: '/web/dist/',
esbuildMinifyIIFE: true, esbuildMinifyIIFE: true,
icons: { icons: {},
},
hash: true, hash: true,
history: { history: {
type: 'browser', type: 'browser',
}, },
plugins: ['@react-dev-inspector/umi4-plugin','@umijs/plugins/dist/dva',], plugins: ['@react-dev-inspector/umi4-plugin', '@umijs/plugins/dist/dva'],
dva: {}, dva: {},
// proxy: { // proxy: {
// '/v1': { // '/v1': {
@ -26,4 +24,3 @@ export default defineConfig({
// }, // },
// }, // },
}); });

View File

@ -1,89 +0,0 @@
const routes = [
{
path: '/login',
component: '@/pages/login',
layout: false
},
{
path: '/',
component: '@/layouts', // 默认页面
redirect: '/knowledge',
// wrappers: [
// '@/wrappers/auth',
// ]
},
{
id: 2,
name: '知识库',
icon: 'home',
auth: [3, 4, 100],
path: '/knowledge',
component: '@/pages/knowledge',
pathname: 'knowledge'
},
{
id: 2,
name: '知识库',
icon: 'home',
auth: [3, 4, 100],
path: '/knowledge/add/*',
component: '@/pages/add-knowledge',
pathname: 'knowledge',
// routes: [{
// id: 3,
// name: '设置',
// icon: 'home',
// auth: [3, 4, 100],
// path: '/knowledge/add/setting',
// component: '@/pages/setting',
// pathname: "setting"
// }, {
// id: 1,
// name: '文件',
// icon: 'file',
// auth: [3, 4, 100],
// path: '/knowledge/add/file',
// component: '@/pages/file',
// pathname: 'file'
// },]
},
{
id: 3,
name: '聊天',
icon: 'home',
auth: [3, 4, 100],
path: '/chat',
component: '@/pages/chat',
pathname: "chat"
},
{
id: 3,
name: '设置',
icon: 'home',
auth: [3, 4, 100],
path: '/setting',
component: '@/pages/setting',
pathname: "setting"
},
{
id: 1,
name: '文件',
icon: 'file',
auth: [3, 4, 100],
path: '/file',
component: '@/pages/file',
pathname: 'file'
},
{
path: '/*',
component: '@/pages/404',
layout: false
}
];
module.exports = routes;

View File

@ -0,0 +1,3 @@
export const Authorization = 'Authorization';
export const Token = 'token';
export const UserInfo = 'userInfo';

View File

10
web/src/hooks/authHook.ts Normal file
View File

@ -0,0 +1,10 @@
import authorizationUtil from '@/utils/authorizationUtil';
import { useState } from 'react';
export const useAuth = () => {
const [isLogin, setIsLogin] = useState(
() => !!authorizationUtil.getAuthorization(),
);
return { isLogin };
};

View File

@ -1,38 +1,53 @@
import React, { useMemo } from 'react'; import authorizationUtil from '@/utils/authorizationUtil';
import type { MenuProps } from 'antd'; import type { MenuProps } from 'antd';
import { Button, Dropdown, } from 'antd'; import { Button, Dropdown } from 'antd';
import { history } from 'umi' import React, { useMemo } from 'react';
import { useTranslation, Trans } from 'react-i18next' import { useTranslation } from 'react-i18next';
import { history } from 'umi';
const App: React.FC = () => { const App: React.FC = () => {
const { t } = useTranslation() const { t } = useTranslation();
const logout = () => { history.push('/login') }
const toSetting = () => { history.push('/setting') }
const items: MenuProps['items'] = useMemo(() => {
return [
{
key: '1',
label: (
<Button type="text" onClick={logout}>{t('header.logout')}</Button>
),
},
{
key: '2',
label: (
<Button type="text" onClick={toSetting}>{t('header.setting')}</Button>
),
},
]
}, []);
return (<> const logout = () => {
<Dropdown menu={{ items }} placement="bottomLeft" arrow> authorizationUtil.removeAll();
<img history.push('/login');
style={{ width: '50px', height: '50px', borderRadius: '25px' }} };
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
/>
</Dropdown>
</>)
}
export default App; const toSetting = () => {
history.push('/setting');
};
const items: MenuProps['items'] = useMemo(() => {
return [
{
key: '1',
label: (
<Button type="text" onClick={logout}>
{t('header.logout')}
</Button>
),
},
{
key: '2',
label: (
<Button type="text" onClick={toSetting}>
{t('header.setting')}
</Button>
),
},
];
}, []);
return (
<>
<Dropdown menu={{ items }} placement="bottomLeft" arrow>
<img
style={{ width: '50px', height: '50px', borderRadius: '25px' }}
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
/>
</Dropdown>
</>
);
};
export default App;

View File

@ -1,22 +1,18 @@
import logo from '@/assets/logo.png';
import { Layout, Space, theme } from 'antd';
import classnames from 'classnames';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { history, Outlet, useLocation, useNavigate } from 'umi'; import { useTranslation } from 'react-i18next';
import { useTranslation, Trans } from 'react-i18next' import { Outlet, useLocation, useNavigate } from 'umi';
import classnames from 'classnames'
import '../locales/config'; import '../locales/config';
import logo from '@/assets/logo.png' import User from './components/user';
import { import styles from './index.less';
RedditOutlined
} from '@ant-design/icons';
import { Layout, Button, theme, Space, } from 'antd';
import styles from './index.less'
import User from './components/user'
import { head } from 'lodash';
const { Header, Content } = Layout; const { Header, Content } = Layout;
const App: React.FC = (props) => { const App: React.FC = (props) => {
const { t } = useTranslation() const { t } = useTranslation();
const navigate = useNavigate() const navigate = useNavigate();
const { const {
token: { colorBgContainer, borderRadiusLG }, token: { colorBgContainer, borderRadiusLG },
} = theme.useToken(); } = theme.useToken();
@ -25,34 +21,49 @@ const App: React.FC = (props) => {
const location = useLocation(); const location = useLocation();
useEffect(() => { useEffect(() => {
if (location.pathname !== '/') { if (location.pathname !== '/') {
const path = location.pathname.split('/') const path = location.pathname.split('/');
setCurrent(path[1]); // setCurrent(path[1]);
} }
console.log(location.pathname.split('/')) console.log(location.pathname.split('/'));
}, [location.pathname]) }, [location.pathname]);
const handleChange = (path: string) => { const handleChange = (path: string) => {
setCurrent(path) // setCurrent(path)
navigate(path); navigate(path);
}; };
const tagsData = [{ path: '/knowledge', name: 'knowledge' }, { path: '/chat', name: 'chat' }, { path: '/file', name: 'file' }]; const tagsData = [
{ path: '/knowledge', name: 'knowledge' },
{ path: '/chat', name: 'chat' },
{ path: '/file', name: 'file' },
];
return ( return (
<Layout className={styles.layout} > <Layout className={styles.layout}>
<Layout> <Layout>
<Header style={{ padding: '0 8px', background: colorBgContainer, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> <Header
style={{
padding: '0 8px',
background: colorBgContainer,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<img src={logo} alt="" style={{ height: 30, width: 30 }} /> <img src={logo} alt="" style={{ height: 30, width: 30 }} />
<Space size={[0, 8]} wrap> <Space size={[0, 8]} wrap>
{tagsData.map((item) => {tagsData.map((item) => (
(<span key={item.name} className={classnames(styles['tag'], { <span
[styles['checked']]: current === item.name key={item.name}
})} onClick={() => handleChange(item.path)}> className={classnames(styles['tag'], {
{item.name} [styles['checked']]: current === item.name,
</span>) })}
)} onClick={() => handleChange(item.path)}
>
{item.name}
</span>
))}
</Space> </Space>
<User ></User> <User></User>
</Header> </Header>
<Content <Content
style={{ style={{
@ -61,14 +72,14 @@ const App: React.FC = (props) => {
minHeight: 280, minHeight: 280,
background: colorBgContainer, background: colorBgContainer,
borderRadius: borderRadiusLG, borderRadius: borderRadiusLG,
overflow: 'auto' overflow: 'auto',
}} }}
> >
<Outlet /> <Outlet />
</Content> </Content>
</Layout> </Layout>
</Layout > </Layout>
); );
}; };
export default App; export default App;

View File

@ -1,6 +1,5 @@
import { Effect, Reducer, Subscription } from 'umi'
import { message } from 'antd';
import kbService from '@/services/kbService'; import kbService from '@/services/kbService';
import { Effect, Reducer } from 'umi';
export interface chunkModelState { export interface chunkModelState {
loading: boolean; loading: boolean;
@ -9,7 +8,7 @@ export interface chunkModelState {
isShowCreateModal: boolean; isShowCreateModal: boolean;
chunk_id: string; chunk_id: string;
doc_id: string; doc_id: string;
chunkInfo: any chunkInfo: any;
} }
export interface chunkgModelType { export interface chunkgModelType {
namespace: 'chunkModel'; namespace: 'chunkModel';
@ -24,7 +23,7 @@ export interface chunkgModelType {
reducers: { reducers: {
updateState: Reducer<chunkModelState>; updateState: Reducer<chunkModelState>;
}; };
subscriptions: { setup: Subscription }; // subscriptions: { setup: Subscription };
} }
const Model: chunkgModelType = { const Model: chunkgModelType = {
namespace: 'chunkModel', namespace: 'chunkModel',
@ -35,91 +34,86 @@ const Model: chunkgModelType = {
isShowCreateModal: false, isShowCreateModal: false,
chunk_id: '', chunk_id: '',
doc_id: '', doc_id: '',
chunkInfo: {} chunkInfo: {},
},
subscriptions: {
setup({ dispatch, history }) {
history.listen(location => {
console.log(location)
});
}
}, },
// subscriptions: {
// setup({ dispatch, history }) {
// history.listen(location => {
// console.log(location)
// });
// }
// },
effects: { effects: {
* chunk_list({ payload = {}, callback }, { call, put }) { *chunk_list({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.chunk_list, payload); const { data, response } = yield call(kbService.chunk_list, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
console.log(res) console.log(res);
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
data: res.chunks, data: res.chunks,
total: res.total, total: res.total,
loading: false loading: false,
} },
}); });
callback && callback() callback && callback();
} }
}, },
*switch_chunk({ payload = {}, callback }, { call, put }) { *switch_chunk({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.switch_chunk, payload); const { data, response } = yield call(kbService.switch_chunk, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
callback && callback() callback && callback();
} }
}, },
*rm_chunk({ payload = {}, callback }, { call, put }) { *rm_chunk({ payload = {}, callback }, { call, put }) {
console.log('shanchu') console.log('shanchu');
const { data, response } = yield call(kbService.rm_chunk, payload); const { data, response } = yield call(kbService.rm_chunk, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
callback && callback() callback && callback();
} }
}, },
* get_chunk({ payload = {}, callback }, { call, put }) { *get_chunk({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.get_chunk, payload); const { data, response } = yield call(kbService.get_chunk, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
chunkInfo: res chunkInfo: res,
} },
}); });
callback && callback(res) callback && callback(res);
} }
}, },
*create_hunk({ payload = {} }, { call, put }) { *create_hunk({ payload = {} }, { call, put }) {
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
loading: true loading: true,
} },
}); });
let service = kbService.create_chunk let service = kbService.create_chunk;
if (payload.chunk_id) { if (payload.chunk_id) {
service = kbService.set_chunk service = kbService.set_chunk;
} }
const { data, response } = yield call(service, payload); const { data, response } = yield call(service, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
loading: false loading: false,
} },
}); });
if (retcode === 0) { if (retcode === 0) {
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
isShowCreateModal: false isShowCreateModal: false,
} },
}); });
} }
}, },
@ -128,9 +122,9 @@ const Model: chunkgModelType = {
updateState(state, { payload }) { updateState(state, { payload }) {
return { return {
...state, ...state,
...payload ...payload,
}; };
} },
} },
}; };
export default Model; export default Model;

View File

@ -1,6 +1,6 @@
import { message } from 'antd';
import { Effect, Reducer, Subscription } from 'umi'
import kbService from '@/services/kbService'; import kbService from '@/services/kbService';
import { message } from 'antd';
import { Effect, Reducer, Subscription } from 'umi';
export interface kFModelState { export interface kFModelState {
isShowCEFwModal: boolean; isShowCEFwModal: boolean;
@ -8,7 +8,7 @@ export interface kFModelState {
isShowSegmentSetModal: boolean; isShowSegmentSetModal: boolean;
loading: boolean; loading: boolean;
tenantIfo: any; tenantIfo: any;
data: any[] data: any[];
} }
export interface kFModelType { export interface kFModelType {
namespace: 'kFModel'; namespace: 'kFModel';
@ -36,60 +36,60 @@ const Model: kFModelType = {
isShowSegmentSetModal: false, isShowSegmentSetModal: false,
loading: false, loading: false,
tenantIfo: {}, tenantIfo: {},
data: [] data: [],
}, },
subscriptions: { subscriptions: {
setup({ dispatch, history }) { setup({ dispatch, history }) {
history.listen(location => { history.listen((location) => {});
}); },
}
}, },
effects: { effects: {
* createKf({ payload = {}, callback }, { call, put }) { *createKf({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.createKb, payload); const { data, response } = yield call(kbService.createKb, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
message.success('创建成功!'); message.success('创建成功!');
} }
}, },
* updateKf({ payload = {}, callback }, { call, put }) { *updateKf({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.updateKb, payload); const { data, response } = yield call(kbService.updateKb, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
message.success('修改成功!'); message.success('修改成功!');
} }
}, },
*getKfDetail({ payload = {}, callback }, { call, put }) { *getKfDetail({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.get_kb_detail, payload); const { data, response } = yield call(kbService.get_kb_detail, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
// localStorage.setItem('userInfo',res.) // localStorage.setItem('userInfo',res.)
callback && callback(res) callback && callback(res);
} }
}, },
*getKfList({ payload = {} }, { call, put }) { *getKfList({ payload = {} }, { call, put }) {
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
loading: true loading: true,
} },
}); });
const { data, response } = yield call(kbService.get_document_list, payload); const { data, response } = yield call(
const { retcode, data: res, retmsg } = data kbService.get_document_list,
payload,
);
const { retcode, data: res, retmsg } = data;
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
loading: false loading: false,
} },
}); });
if (retcode === 0) { if (retcode === 0) {
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
data: res data: res,
} },
}); });
} }
}, },
@ -97,58 +97,60 @@ const Model: kFModelType = {
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
loading: true loading: true,
} },
}); });
const { data, response } = yield call(kbService.document_change_status, payload); const { data, response } = yield call(
const { retcode, data: res, retmsg } = data kbService.document_change_status,
payload,
);
const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
message.success('修改成功!'); message.success('修改成功!');
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
loading: false loading: false,
} },
}); });
callback && callback() callback && callback();
} }
}, },
*document_rm({ payload = {}, callback }, { call, put }) { *document_rm({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.document_rm, payload); const { data, response } = yield call(kbService.document_rm, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
message.success('删除成功!'); message.success('删除成功!');
callback && callback() callback && callback();
} }
}, },
*document_create({ payload = {}, callback }, { call, put }) { *document_create({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.document_create, payload); const { data, response } = yield call(kbService.document_create, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
message.success('创建成功!'); message.success('创建成功!');
callback && callback() callback && callback();
} }
}, },
*document_change_parser({ payload = {}, callback }, { call, put }) { *document_change_parser({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.document_change_parser, payload); const { data, response } = yield call(
const { retcode, data: res, retmsg } = data kbService.document_change_parser,
payload,
);
const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
message.success('修改成功!'); message.success('修改成功!');
callback && callback() callback && callback();
} }
}, },
}, },
reducers: { reducers: {
updateState(state, { payload }) { updateState(state, { payload }) {
return { return {
...state, ...state,
...payload ...payload,
}; };
} },
} },
}; };
export default Model; export default Model;

View File

@ -1,109 +1,131 @@
import React, { useEffect, useState, } from 'react'; import { formatDate } from '@/utils/date';
import { useNavigate, connect, Dispatch } from 'umi' import {
import { Card, List, Popconfirm, message, FloatButton, Row, Col } from 'antd'; DeleteOutlined,
import { MinusSquareOutlined, DeleteOutlined, PlusOutlined } from '@ant-design/icons'; MinusSquareOutlined,
import styles from './index.less' PlusOutlined,
import { formatDate } from '@/utils/date' } from '@ant-design/icons';
import type { knowledgeModelState } from './model' import { Card, Col, FloatButton, Popconfirm, Row } from 'antd';
import React, { useEffect } from 'react';
import { Dispatch, connect, useNavigate } from 'umi';
import styles from './index.less';
import type { knowledgeModelState } from './model';
interface KnowledgeProps { interface KnowledgeProps {
dispatch: Dispatch; dispatch: Dispatch;
knowledgeModel: knowledgeModelState knowledgeModel: knowledgeModelState;
} }
const Index: React.FC<KnowledgeProps> = ({ knowledgeModel, dispatch }) => { const Index: React.FC<KnowledgeProps> = ({ knowledgeModel, dispatch }) => {
const navigate = useNavigate() const navigate = useNavigate();
// const [datas, setDatas] = useState(data) // const [datas, setDatas] = useState(data)
const { data = [] } = knowledgeModel const { data = [] } = knowledgeModel;
console.log(knowledgeModel) console.log(knowledgeModel);
// const x = useSelector((state) => state.knowledgeModel);
const confirm = (id: string) => { const confirm = (id: string) => {
dispatch({ dispatch({
type: 'knowledgeModel/rmKb', type: 'knowledgeModel/rmKb',
payload: { payload: {
kb_id: id kb_id: id,
}, },
callback: () => { callback: () => {
dispatch({ dispatch({
type: 'knowledgeModel/getList', type: 'knowledgeModel/getList',
payload: { payload: {},
}
}); });
} },
}); });
}; };
const handleAddKnowledge = () => { const handleAddKnowledge = () => {
navigate(`add/setting?activeKey=setting`); navigate(`add/setting?activeKey=setting`);
} };
const handleEditKnowledge = (id: string) => { const handleEditKnowledge = (id: string) => {
navigate(`add/setting?activeKey=file&id=${id}`); navigate(`add/setting?activeKey=file&id=${id}`);
} };
useEffect(() => { useEffect(() => {
dispatch({ dispatch({
type: 'knowledgeModel/getList', type: 'knowledgeModel/getList',
payload: { payload: {},
}
}); });
}, []) }, []);
return (<> return (
<div className={styles.knowledge}> <>
<FloatButton onClick={handleAddKnowledge} icon={<PlusOutlined />} type="primary" style={{ right: 24, top: 100 }} /> <div className={styles.knowledge}>
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}> <FloatButton
{ onClick={handleAddKnowledge}
data.map((item: any) => { icon={<PlusOutlined />}
return (<Col className="gutter-row" key={item.name} xs={24} sm={12} md={8} lg={6}> type="primary"
<Card className={styles.card} style={{ right: 24, top: 100 }}
onClick={() => { handleEditKnowledge(item.id) }} />
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}>
{data.map((item: any) => {
return (
<Col
className="gutter-row"
key={item.name}
xs={24}
sm={12}
md={8}
lg={6}
> >
<div className={styles.container}> <Card
<div className={styles.content}> className={styles.card}
<span className={styles.context}> onClick={() => {
{item.name} handleEditKnowledge(item.id);
</span> }}
<span className={styles.delete}> >
<Popconfirm <div className={styles.container}>
title="Delete the task" <div className={styles.content}>
description="Are you sure to delete this task?" <span className={styles.context}>{item.name}</span>
onConfirm={(e: any) => { <span className={styles.delete}>
e.stopPropagation(); <Popconfirm
e.nativeEvent.stopImmediatePropagation() title="Delete the task"
confirm(item.id) description="Are you sure to delete this task?"
onConfirm={(e: any) => {
}} e.stopPropagation();
okText="Yes" e.nativeEvent.stopImmediatePropagation();
cancelText="No" confirm(item.id);
> }}
<DeleteOutlined onClick={(e) => { okText="Yes"
e.stopPropagation(); cancelText="No"
e.nativeEvent.stopImmediatePropagation() >
}} /> <DeleteOutlined
</Popconfirm> onClick={(e) => {
e.stopPropagation();
</span> e.nativeEvent.stopImmediatePropagation();
}}
/>
</Popconfirm>
</span>
</div>
<div className={styles.footer}>
<span className={styles.text}>
<MinusSquareOutlined />
{item.doc_num}
</span>
<span className={styles.text}>
<MinusSquareOutlined />
{item.chunk_num}
</span>
<span className={styles.text}>
<MinusSquareOutlined />
{item.token_num}
</span>
<span style={{ float: 'right' }}>
{formatDate(item.update_date)}
</span>
</div>
</div> </div>
<div className={styles.footer}> </Card>
<span className={styles.text}> </Col>
<MinusSquareOutlined />{item.doc_num} );
</span> })}
<span className={styles.text}> </Row>
<MinusSquareOutlined />{item.chunk_num} </div>
</span> </>
<span className={styles.text}> );
<MinusSquareOutlined />{item.token_num}
</span>
<span style={{ float: 'right' }}>
{formatDate(item.update_date)}
</span>
</div>
</div>
</Card>
</Col>)
})
}
</Row>
</div>
</>
)
}; };
export default connect(({ knowledgeModel, loading }) => ({ knowledgeModel, loading }))(Index); export default connect(({ knowledgeModel, loading }) => ({
knowledgeModel,
loading,
}))(Index);

View File

@ -1,5 +1,5 @@
import kbService from '@/services/kbService'; import kbService from '@/services/kbService';
import { Effect, Reducer, Subscription } from 'umi'; import { Effect, Reducer } from 'umi';
export interface knowledgeModelState { export interface knowledgeModelState {
loading: boolean; loading: boolean;
@ -15,7 +15,7 @@ export interface knowledgegModelType {
reducers: { reducers: {
updateState: Reducer<knowledgeModelState>; updateState: Reducer<knowledgeModelState>;
}; };
subscriptions: { setup: Subscription }; // subscriptions: { setup: Subscription };
} }
const Model: knowledgegModelType = { const Model: knowledgegModelType = {
namespace: 'knowledgeModel', namespace: 'knowledgeModel',
@ -23,13 +23,13 @@ const Model: knowledgegModelType = {
loading: false, loading: false,
data: [], data: [],
}, },
subscriptions: { // subscriptions: {
setup({ dispatch, history }) { // setup({ dispatch, history }) {
history.listen((location) => { // history.listen((location) => {
console.log(location); // console.log(location);
}); // });
}, // },
}, // },
effects: { effects: {
*rmKb({ payload = {}, callback }, { call, put }) { *rmKb({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.rmKb, payload); const { data, response } = yield call(kbService.rmKb, payload);

View File

@ -1,19 +1,18 @@
import { connect, Icon, Dispatch } from 'umi'; import { rsaPsw } from '@/utils';
import { Input, Form, Button, Checkbox } from 'antd'; import { Button, Checkbox, Form, Input } from 'antd';
import { FC, useEffect, useState } from 'react';
import { Dispatch, Icon, connect, useNavigate } from 'umi';
import styles from './index.less'; import styles from './index.less';
import { rsaPsw } from '@/utils'
import { useState, useEffect, FC } from 'react';
interface LoginProps { interface LoginProps {
dispatch: Dispatch; dispatch: Dispatch;
} }
const View: FC<LoginProps> = ({ const View: FC<LoginProps> = ({ dispatch }) => {
dispatch, let navigate = useNavigate();
}) => { const [title, setTitle] = useState('login');
const [title, setTitle] = useState('login')
const changeTitle = () => { const changeTitle = () => {
setTitle((title) => title === 'login' ? 'register' : 'login') setTitle((title) => (title === 'login' ? 'register' : 'login'));
} };
const [form] = Form.useForm(); const [form] = Form.useForm();
const [checkNick, setCheckNick] = useState(false); const [checkNick, setCheckNick] = useState(false);
@ -25,15 +24,17 @@ const View: FC<LoginProps> = ({
try { try {
const params = await form.validateFields(); const params = await form.validateFields();
var rsaPassWord = rsaPsw(params.password) var rsaPassWord = rsaPsw(params.password);
if (title === 'login') { if (title === 'login') {
dispatch({ const ret = await dispatch({
type: 'loginModel/login', type: 'loginModel/login',
payload: { payload: {
email: params.email, email: params.email,
password: rsaPassWord password: rsaPassWord,
} },
}); });
console.info(ret);
navigate('/knowledge');
} else { } else {
dispatch({ dispatch({
type: 'loginModel/register', type: 'loginModel/register',
@ -43,8 +44,8 @@ const View: FC<LoginProps> = ({
password: rsaPassWord, password: rsaPassWord,
}, },
callback() { callback() {
setTitle('login') setTitle('login');
} },
}); });
} }
} catch (errorInfo) { } catch (errorInfo) {
@ -56,103 +57,124 @@ const View: FC<LoginProps> = ({
// wrapperCol: { span: 8 }, // wrapperCol: { span: 8 },
}; };
const toGoogle = () => { const toGoogle = () => {
window.location.href = "https://github.com/login/oauth/authorize?scope=user:email&client_id=302129228f0d96055bee" window.location.href =
} 'https://github.com/login/oauth/authorize?scope=user:email&client_id=302129228f0d96055bee';
};
return ( return (
<div className={styles.loginPage}> <div className={styles.loginPage}>
<div className={styles.loginLeft}> <div className={styles.loginLeft}>
<div className={styles.modal}> <div className={styles.modal}>
<div className={styles.loginTitle}> <div className={styles.loginTitle}>
<div> <div>{title === 'login' ? 'Sign in' : 'Create an account'}</div>
{title === 'login' ? 'Sign in' : 'Create an account'} <span>
</div> {title === 'login'
<span > ? 'Were so excited to see you again!'
{title === 'login' ? 'Were so excited to see you again!' : 'Glad to have you on board!'} : 'Glad to have you on board!'}
</span> </span>
</div> </div>
<Form form={form} layout="vertical" name="dynamic_rule" style={{ maxWidth: 600 }}> <Form
form={form}
layout="vertical"
name="dynamic_rule"
style={{ maxWidth: 600 }}
>
<Form.Item <Form.Item
{...formItemLayout} {...formItemLayout}
name="email" name="email"
label="Email" label="Email"
rules={[{ required: true, message: 'Please input value' }]} rules={[{ required: true, message: 'Please input value' }]}
> >
<Input size='large' placeholder="Please input value" /> <Input size="large" placeholder="Please input value" />
</Form.Item> </Form.Item>
{ {title === 'register' && (
title === 'register' && <Form.Item <Form.Item
{...formItemLayout} {...formItemLayout}
name="nickname" name="nickname"
label="Nickname" label="Nickname"
rules={[{ required: true, message: 'Please input your nickname' }]} rules={[
{ required: true, message: 'Please input your nickname' },
]}
> >
<Input size='large' placeholder="Please input your nickname" /> <Input size="large" placeholder="Please input your nickname" />
</Form.Item> </Form.Item>
} )}
<Form.Item <Form.Item
{...formItemLayout} {...formItemLayout}
name="password" name="password"
label="Password" label="Password"
rules={[{ required: true, message: 'Please input value' }]} rules={[{ required: true, message: 'Please input value' }]}
> >
<Input size='large' placeholder="Please input value" /> <Input size="large" placeholder="Please input value" />
</Form.Item> </Form.Item>
{ {title === 'login' && (
title === 'login' && <Form.Item <Form.Item name="remember" valuePropName="checked">
name="remember"
valuePropName="checked"
>
<Checkbox> Remember me</Checkbox> <Checkbox> Remember me</Checkbox>
</Form.Item> </Form.Item>
} )}
<div> { <div>
title === 'login' && (<div> {' '}
Dont have an account? {title === 'login' && (
<Button type="link" onClick={changeTitle}> <div>
Sign up Dont have an account?
</Button> <Button type="link" onClick={changeTitle}>
</div>) Sign up
} </Button>
{ </div>
title === 'register' && (<div> )}
{title === 'register' && (
<div>
Already have an account? Already have an account?
<Button type="link" onClick={changeTitle}> <Button type="link" onClick={changeTitle}>
Sign in Sign in
</Button> </Button>
</div>) </div>
} )}
</div> </div>
<Button type="primary" block size='large' onClick={onCheck}> <Button type="primary" block size="large" onClick={onCheck}>
{title === 'login' ? 'Sign in' : 'Continue'} {title === 'login' ? 'Sign in' : 'Continue'}
</Button> </Button>
{ {title === 'login' && (
title === 'login' && (<><Button block size='large' onClick={toGoogle} style={{ marginTop: 15 }}> <>
<div > <Button
<Icon icon="local:google" style={{ verticalAlign: 'middle', marginRight: 5 }} /> block
Sign in with Google size="large"
</div> onClick={toGoogle}
</Button> style={{ marginTop: 15 }}
<Button block size='large' onClick={toGoogle} style={{ marginTop: 15 }}> >
<div > <div>
<Icon icon="local:github" style={{ verticalAlign: 'middle', marginRight: 5 }} /> <Icon
icon="local:google"
style={{ verticalAlign: 'middle', marginRight: 5 }}
/>
Sign in with Google
</div>
</Button>
<Button
block
size="large"
onClick={toGoogle}
style={{ marginTop: 15 }}
>
<div>
<Icon
icon="local:github"
style={{ verticalAlign: 'middle', marginRight: 5 }}
/>
Sign in with Github Sign in with Github
</div> </div>
</Button></>) </Button>
} </>
)}
</Form> </Form>
</div> </div>
</div> </div>
<div className={styles.loginRight}> <div className={styles.loginRight}></div>
</div>
</div> </div>
); );
}; };
export default connect(({ loginModel, loading }) => ({ loginModel, loading }))(View); export default connect(({ loginModel, loading }) => ({ loginModel, loading }))(
View,
);

View File

@ -1,6 +1,8 @@
import { Effect, Reducer, Subscription } from 'umi' import { Authorization } from '@/constants/authorization';
import { message } from 'antd';
import userService from '@/services/userService'; import userService from '@/services/userService';
import authorizationUtil from '@/utils/authorizationUtil';
import { message } from 'antd';
import { Effect, Reducer, Subscription } from 'umi';
export interface loginModelState { export interface loginModelState {
list: any[]; list: any[];
@ -28,49 +30,52 @@ const Model: logingModelType = {
}, },
subscriptions: { subscriptions: {
setup({ dispatch, history }) { setup({ dispatch, history }) {
history.listen(location => { }); history.listen((location) => {});
} },
}, },
effects: { effects: {
*login({ payload = {} }, { call, put }) { *login({ payload = {} }, { call, put }) {
console.log(111, payload) console.log(111, payload);
const { data, response } = yield call(userService.login, payload); const { data, response } = yield call(userService.login, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
console.log() console.log();
const Authorization = response.headers.get('Authorization') const authorization = response.headers.get(Authorization);
if (retcode === 0) { if (retcode === 0) {
message.success('登录成功!'); message.success('登录成功!');
const token = res.access_token; const token = res.access_token;
const userInfo = { const userInfo = {
avatar: res.avatar, avatar: res.avatar,
name: res.nickname, name: res.nickname,
email: res.email email: res.email,
}; };
localStorage.setItem('token', token) authorizationUtil.setItems({
localStorage.setItem('userInfo', JSON.stringify(userInfo)) Authorization: authorization,
localStorage.setItem('Authorization', Authorization) userInfo: JSON.stringify(userInfo),
setTimeout(() => { Token: token,
window.location.href = '/file'; });
}, 300); // setTimeout(() => {
// window.location.href = '/file';
// }, 300);
} }
return data;
}, },
*register({ payload = {}, callback }, { call, put }) { *register({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(userService.register, payload); const { data, response } = yield call(userService.register, payload);
console.log() console.log();
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
message.success('注册成功!'); message.success('注册成功!');
callback && callback() callback && callback();
} }
} },
}, },
reducers: { reducers: {
updateState(state, { payload }) { updateState(state, { payload }) {
return { return {
...state, ...state,
...payload ...payload,
}; };
} },
} },
}; };
export default Model; export default Model;

View File

@ -1,90 +1,105 @@
import { connect, Dispatch } from 'umi'; import { Button, FloatButton } from 'antd';
import i18n from 'i18next'; import i18n from 'i18next';
import { useTranslation, Trans } from 'react-i18next' import { useTranslation } from 'react-i18next';
import { Button, FloatButton } from 'antd' import { Dispatch, connect } from 'umi';
import authorizationUtil from '@/utils/authorizationUtil';
import { FC, useEffect } from 'react';
import CPwModal from './CPwModal';
import List from './List';
import SAKModal from './SAKModal';
import SSModal from './SSModal';
import TntModal from './TntModal';
import styles from './index.less'; import styles from './index.less';
import CPwModal from './CPwModal'
import SAKModal from './SAKModal'
import TntModal from './TntModal'
import SSModal from './SSModal'
import List from './List'
import { useEffect, useState, FC } from 'react';
interface CPwModalProps { interface CPwModalProps {
dispatch: Dispatch; dispatch: Dispatch;
settingModel: any settingModel: any;
} }
const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => { const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => {
// const [llm_factory, set_llm_factory] = useState('') // const [llm_factory, set_llm_factory] = useState('')
const { t } = useTranslation() const { t } = useTranslation();
const userInfo = JSON.parse(localStorage.getItem('userInfo') || '') const userInfo = authorizationUtil.getUserInfoObject();
const changeLang = (val: string) => { // 改变状态里的 语言 进行切换 const changeLang = (val: string) => {
i18n.changeLanguage(val); // 改变状态里的 语言 进行切换
} i18n.changeLanguage(val);
useEffect(() => { };
dispatch({ useEffect(() => {
type: 'settingModel/getTenantInfo', dispatch({
payload: { type: 'settingModel/getTenantInfo',
} payload: {},
}); });
}, []) }, []);
const showCPwModal = () => { const showCPwModal = () => {
dispatch({ dispatch({
type: 'settingModel/updateState', type: 'settingModel/updateState',
payload: { payload: {
isShowPSwModal: true isShowPSwModal: true,
} },
}); });
}; };
const showTntModal = () => { const showTntModal = () => {
dispatch({ dispatch({
type: 'settingModel/updateState', type: 'settingModel/updateState',
payload: { payload: {
isShowTntModal: true isShowTntModal: true,
} },
}); });
}; };
const showSSModal = () => { const showSSModal = () => {
dispatch({ dispatch({
type: 'settingModel/updateState', type: 'settingModel/updateState',
payload: { payload: {
isShowSSModal: true isShowSSModal: true,
} },
}); });
// dispatch({ // dispatch({
// type: 'settingModel/getTenantInfo', // type: 'settingModel/getTenantInfo',
// payload: { // payload: {
// } // }
// }); // });
}; };
return ( return (
<div className={styles.settingPage}> <div className={styles.settingPage}>
<div className={styles.avatar}> <div className={styles.avatar}>
<img style={{ width: 50, marginRight: 5 }} src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png" alt="" /> <img
<div> style={{ width: 50, marginRight: 5 }}
<div>{userInfo.name}</div> src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png"
<div><span>******</span><Button type='link' onClick={showCPwModal}></Button></div> alt=""
/>
</div> <div>
</div > <div>{userInfo.name}</div>
<div> <div>
<Button type="link" onClick={showTntModal}> <span>******</span>
<Button type="link" onClick={showCPwModal}>
</Button>
<Button type="link" onClick={showSSModal}> </Button>
</div>
</Button> </div>
<List /> </div>
</div> <div>
<CPwModal /> <Button type="link" onClick={showTntModal}>
<SAKModal />
<SSModal /> </Button>
<TntModal /> <Button type="link" onClick={showSSModal}>
<FloatButton shape='square' description={t('setting.btn')} onClick={() => i18n.changeLanguage(i18n.language == 'en' ? 'zh' : 'en')} type="default" style={{ right: 94, fontSize: 14 }} />
</div > </Button>
<List />
</div>
); <CPwModal />
} <SAKModal />
export default connect(({ settingModel, loading }) => ({ settingModel, loading }))(Index); <SSModal />
<TntModal />
<FloatButton
shape="square"
description={t('setting.btn')}
onClick={() => i18n.changeLanguage(i18n.language == 'en' ? 'zh' : 'en')}
type="default"
style={{ right: 94, fontSize: 14 }}
/>
</div>
);
};
export default connect(({ settingModel, loading }) => ({
settingModel,
loading,
}))(Index);

View File

@ -1,6 +1,7 @@
import { Effect, Reducer, Subscription } from 'umi';
import { message } from 'antd';
import userService from '@/services/userService'; import userService from '@/services/userService';
import authorizationUtil from '@/utils/authorizationUtil';
import { message } from 'antd';
import { Effect, Reducer, Subscription } from 'umi';
export interface settingModelState { export interface settingModelState {
isShowPSwModal: boolean; isShowPSwModal: boolean;
@ -9,10 +10,10 @@ export interface settingModelState {
isShowSSModal: boolean; isShowSSModal: boolean;
llm_factory: string; llm_factory: string;
loading: boolean; loading: boolean;
tenantIfo: any, tenantIfo: any;
llmInfo: any, llmInfo: any;
myLlm: any[], myLlm: any[];
factoriesList: any[] factoriesList: any[];
} }
export interface settingModelType { export interface settingModelType {
@ -45,32 +46,31 @@ const Model: settingModelType = {
tenantIfo: {}, tenantIfo: {},
llmInfo: {}, llmInfo: {},
myLlm: [], myLlm: [],
factoriesList: [] factoriesList: [],
}, },
subscriptions: { subscriptions: {
setup({ dispatch, history }) { setup({ dispatch, history }) {
history.listen(location => { history.listen((location) => {});
}); },
}
}, },
effects: { effects: {
*setting({ payload = {}, callback }, { call, put }) { *setting({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(userService.setting, payload); const { data, response } = yield call(userService.setting, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
message.success('密码修改成功!'); message.success('密码修改成功!');
callback && callback() callback && callback();
} }
}, },
*getUserInfo({ payload = {} }, { call, put }) { *getUserInfo({ payload = {} }, { call, put }) {
const { data, response } = yield call(userService.user_info, payload); const { data, response } = yield call(userService.user_info, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
const userInfo = { const userInfo = {
avatar: res.avatar, avatar: res.avatar,
name: res.nickname, name: res.nickname,
email: res.email email: res.email,
}; };
localStorage.setItem('userInfo', JSON.stringify(userInfo)) authorizationUtil.setUserInfo(userInfo);
if (retcode === 0) { if (retcode === 0) {
// localStorage.setItem('userInfo',res.) // localStorage.setItem('userInfo',res.)
} }
@ -79,91 +79,100 @@ const Model: settingModelType = {
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
loading: true loading: true,
} },
}); });
const { data, response } = yield call(userService.get_tenant_info, payload); const { data, response } = yield call(
const { retcode, data: res, retmsg } = data userService.get_tenant_info,
payload,
);
const { retcode, data: res, retmsg } = data;
// llm_id 对应chat_id // llm_id 对应chat_id
// asr_id 对应speech2txt // asr_id 对应speech2txt
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
loading: false loading: false,
} },
}); });
if (retcode === 0) { if (retcode === 0) {
res.chat_id = res.llm_id res.chat_id = res.llm_id;
res.speech2text_id = res.asr_id res.speech2text_id = res.asr_id;
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
tenantIfo: res tenantIfo: res,
} },
}); });
} }
}, },
*set_tenant_info({ payload = {} }, { call, put }) { *set_tenant_info({ payload = {} }, { call, put }) {
const { data, response } = yield call(userService.set_tenant_info, payload); const { data, response } = yield call(
const { retcode, data: res, retmsg } = data userService.set_tenant_info,
payload,
);
const { retcode, data: res, retmsg } = data;
// llm_id 对应chat_id // llm_id 对应chat_id
// asr_id 对应speech2txt // asr_id 对应speech2txt
if (retcode === 0) { if (retcode === 0) {
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
isShowSSModal: false isShowSSModal: false,
} },
}); });
yield put({ yield put({
type: 'getTenantInfo' type: 'getTenantInfo',
}) });
} }
}, },
*factories_list({ payload = {} }, { call, put }) { *factories_list({ payload = {} }, { call, put }) {
const { data, response } = yield call(userService.factories_list, payload); const { data, response } = yield call(
const { retcode, data: res, retmsg } = data userService.factories_list,
payload,
);
const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
factoriesList: res factoriesList: res,
} },
}); });
} }
}, },
*llm_list({ payload = {} }, { call, put }) { *llm_list({ payload = {} }, { call, put }) {
const { data, response } = yield call(userService.llm_list, payload); const { data, response } = yield call(userService.llm_list, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
llmInfo: res llmInfo: res,
} },
}); });
} }
}, },
*my_llm({ payload = {} }, { call, put }) { *my_llm({ payload = {} }, { call, put }) {
const { data, response } = yield call(userService.my_llm, payload); const { data, response } = yield call(userService.my_llm, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
yield put({ yield put({
type: 'updateState', type: 'updateState',
payload: { payload: {
myLlm: res myLlm: res,
} },
}); });
} }
}, },
*set_api_key({ payload = {}, callback }, { call, put }) { *set_api_key({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(userService.set_api_key, payload); const { data, response } = yield call(userService.set_api_key, payload);
const { retcode, data: res, retmsg } = data const { retcode, data: res, retmsg } = data;
if (retcode === 0) { if (retcode === 0) {
message.success('设置API KEY成功'); message.success('设置API KEY成功');
callback && callback() callback && callback();
} }
}, },
}, },
@ -171,9 +180,9 @@ const Model: settingModelType = {
updateState(state, { payload }) { updateState(state, { payload }) {
return { return {
...state, ...state,
...payload ...payload,
}; };
} },
} },
}; };
export default Model; export default Model;

43
web/src/routes.ts Normal file
View File

@ -0,0 +1,43 @@
const routes = [
{
path: '/login',
component: '@/pages/login',
layout: false,
},
{
path: '/',
component: '@/layouts',
layout: false,
wrappers: ['@/wrappers/auth'],
routes: [
{ path: '/', redirect: '/knowledge' },
{
path: '/knowledge',
component: '@/pages/knowledge',
},
{
path: '/knowledge/add/*',
component: '@/pages/add-knowledge',
},
{
path: '/chat',
component: '@/pages/chat',
},
{
path: '/setting',
component: '@/pages/setting',
},
{
path: '/file',
component: '@/pages/file',
},
],
},
{
path: '/*',
component: '@/pages/404',
layout: false,
},
];
export default routes;

View File

@ -0,0 +1,43 @@
import { Authorization, Token, UserInfo } from '@/constants/authorization';
const KeySet = [Authorization, Token, UserInfo];
const storage = {
getAuthorization: () => {
return localStorage.getItem(Authorization);
},
getToken: () => {
return localStorage.getItem(Token);
},
getUserInfo: () => {
return localStorage.getItem(UserInfo);
},
getUserInfoObject: () => {
return JSON.parse(localStorage.getItem('userInfo') || '');
},
setAuthorization: (value: string) => {
localStorage.setItem(Authorization, value);
},
setToken: (value: string) => {
localStorage.setItem(Token, value);
},
setUserInfo: (value: string | Object) => {
let valueStr = typeof value !== 'string' ? JSON.stringify(value) : value;
localStorage.setItem(UserInfo, valueStr);
},
setItems: (pairs: Record<string, string>) => {
Object.entries(pairs).forEach(([key, value]) => {
localStorage.setItem(key, value);
});
},
removeAuthorization: () => {
localStorage.removeItem(Authorization);
},
removeAll: () => {
KeySet.forEach((x) => {
localStorage.removeItem(x);
});
},
};
export default storage;

3
web/src/utils/history.ts Normal file
View File

@ -0,0 +1,3 @@
import { createBrowserHistory } from 'history';
export const history = createBrowserHistory();

View File

@ -1,14 +1,14 @@
import { message, notification } from 'antd';
import { extend } from 'umi-request'; import { extend } from 'umi-request';
import { notification, message } from 'antd';
import { Authorization } from '@/constants/authorization';
import api from '@/utils/api'; import api from '@/utils/api';
import authorizationUtil from '@/utils/authorizationUtil';
const { login } = api; const { login } = api;
const ABORT_REQUEST_ERR_MESSAGE = 'The user aborted a request.'; // 手动中断请求。errorHandler 抛出的error message const ABORT_REQUEST_ERR_MESSAGE = 'The user aborted a request.'; // 手动中断请求。errorHandler 抛出的error message
const retcodeMessage = { const retcodeMessage = {
200: '服务器成功返回请求的数据。', 200: '服务器成功返回请求的数据。',
201: '新建或修改数据成功。', 201: '新建或修改数据成功。',
@ -24,7 +24,7 @@ const retcodeMessage = {
500: '服务器发生错误,请检查服务器。', 500: '服务器发生错误,请检查服务器。',
502: '网关错误。', 502: '网关错误。',
503: '服务不可用,服务器暂时过载或维护。', 503: '服务不可用,服务器暂时过载或维护。',
504: '网关超时。' 504: '网关超时。',
}; };
type retcode = type retcode =
| 200 | 200
@ -49,16 +49,20 @@ interface responseType {
retcode: number; retcode: number;
data: any; data: any;
retmsg: string; retmsg: string;
status: number status: number;
} }
const errorHandler = (error: { response: Response, message: string }): Response => { const errorHandler = (error: {
response: Response;
message: string;
}): Response => {
const { response } = error; const { response } = error;
// 手动中断请求 abort // 手动中断请求 abort
if (error.message === ABORT_REQUEST_ERR_MESSAGE) { if (error.message === ABORT_REQUEST_ERR_MESSAGE) {
console.log('user abort request'); console.log('user abort request');
} else { } else {
if (response && response.status) { if (response && response.status) {
const errorText = retcodeMessage[response.status as retcode] || response.statusText; const errorText =
retcodeMessage[response.status as retcode] || response.statusText;
const { status, url } = response; const { status, url } = response;
notification.error({ notification.error({
message: `请求错误 ${status}: ${url}`, message: `请求错误 ${status}: ${url}`,
@ -80,21 +84,21 @@ const errorHandler = (error: { response: Response, message: string }): Response
const request = extend({ const request = extend({
errorHandler, // 默认错误处理 errorHandler, // 默认错误处理
timeout: 3000000, timeout: 3000000,
getResponse: true getResponse: true,
}); });
request.interceptors.request.use((url: string, options: any) => { request.interceptors.request.use((url: string, options: any) => {
const Authorization = localStorage.getItem('Authorization') const authorization = authorizationUtil.getAuthorization();
return { return {
url, url,
options: { options: {
...options, ...options,
headers: { headers: {
...(options.skipToken ? undefined : { Authorization }), ...(options.skipToken ? undefined : { [Authorization]: authorization }),
...options.headers ...options.headers,
}, },
interceptors: true interceptors: true,
} },
}; };
}); });
@ -103,7 +107,7 @@ request.interceptors.request.use((url: string, options: any) => {
* */ * */
request.interceptors.response.use(async (response: any, request) => { request.interceptors.response.use(async (response: any, request) => {
console.log(response, request) console.log(response, request);
const data: responseType = await response.clone().json(); const data: responseType = await response.clone().json();
// response 拦截 // response 拦截
@ -113,6 +117,8 @@ request.interceptors.response.use(async (response: any, request) => {
description: data.retmsg, description: data.retmsg,
duration: 3, duration: 3,
}); });
authorizationUtil.removeAll();
// history.push('/login'); // Will not jump to the login page
} else if (data.retcode !== 0) { } else if (data.retcode !== 0) {
if (data.retcode === 100) { if (data.retcode === 100) {
message.error(data.retmsg); message.error(data.retmsg);
@ -126,7 +132,6 @@ request.interceptors.response.use(async (response: any, request) => {
return response; return response;
} else { } else {
return response; return response;
} }
}); });

View File

@ -1,12 +1,11 @@
import { Navigate, Outlet } from 'umi' import { useAuth } from '@/hooks/authHook';
import { Navigate, Outlet } from 'umi';
export default (props) => { export default () => {
// const { isLogin } = useAuth(); const { isLogin } = useAuth();
console.log(props) if (isLogin) {
const isLogin = false return <Outlet />;
if (isLogin) { } else {
return <Outlet />; return <Navigate to="/login" />;
} else { }
return <Navigate to="/login" />; };
}
}