feat: layout the knowledge list page and modify the page switching button in the header (#48)

* feat: remove unnecessary 'loading' fields from other files

* feat: layout the knowledge list page

* feat: modify the page switching button in the header
This commit is contained in:
balibabu 2024-01-31 19:29:57 +08:00 committed by GitHub
parent 362ec6c364
commit af3ef26977
29 changed files with 940 additions and 786 deletions

View File

@ -16,6 +16,11 @@ export default defineConfig({
},
plugins: ['@react-dev-inspector/umi4-plugin', '@umijs/plugins/dist/dva'],
dva: {},
lessLoader: {
modifyVars: {
hack: `true; @import "~@/less/variable.less";`,
},
},
// proxy: {
// '/v1': {
// 'target': 'http://54.80.112.79:9380/',

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 10H15M2.5 5H17.5M7.5 15H12.5" stroke="#344054" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 234 B

View File

@ -0,0 +1,12 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1164_5493)">
<path
d="M3.08282 12.894V10.0795M3.08282 4.45031V1.63574M1.67554 3.04303H4.49011M1.67554 11.4867H4.49011M7.86759 2.19866L6.8914 4.73676C6.73265 5.1495 6.65328 5.35588 6.52984 5.52947C6.42045 5.68332 6.28603 5.81774 6.13218 5.92713C5.95858 6.05057 5.75221 6.12994 5.33947 6.28869L2.80137 7.26488L5.33947 8.24107C5.75221 8.39982 5.95859 8.4792 6.13218 8.60263C6.28603 8.71203 6.42045 8.84645 6.52984 9.0003C6.65328 9.17389 6.73265 9.38026 6.8914 9.79301L7.86759 12.3311L8.84378 9.79301C9.00253 9.38026 9.08191 9.17389 9.20534 9.0003C9.31474 8.84645 9.44916 8.71203 9.60301 8.60263C9.7766 8.4792 9.98297 8.39982 10.3957 8.24107L12.9338 7.26488L10.3957 6.28869C9.98297 6.12994 9.7766 6.05057 9.60301 5.92713C9.44916 5.81774 9.31474 5.68332 9.20534 5.52947C9.08191 5.35588 9.00253 5.1495 8.84378 4.73676L7.86759 2.19866Z"
stroke="black" stroke-width="1.68874" stroke-linecap="round" stroke-linejoin="round" />
</g>
<defs>
<clipPath id="clip0_1164_5493">
<rect width="13.5099" height="13.5099" fill="white" transform="translate(0.549805 0.509888)" />
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M18.1777 8C23.2737 8 23.2737 16 18.1777 16C13.0827 16 11.0447 8 5.43875 8C0.85375 8 0.85375 16 5.43875 16C11.0447 16 13.0828 8 18.1788 8H18.1777Z"
stroke="#7F56D9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</svg>

After

Width:  |  Height:  |  Size: 362 B

View File

@ -0,0 +1,11 @@
<svg width="24" height="6" viewBox="0 0 24 6" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M12 4.25C12.6904 4.25 13.25 3.69036 13.25 3C13.25 2.30964 12.6904 1.75 12 1.75C11.3096 1.75 10.75 2.30964 10.75 3C10.75 3.69036 11.3096 4.25 12 4.25Z"
stroke="#98A2B3" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" />
<path
d="M20.75 4.25C21.4404 4.25 22 3.69036 22 3C22 2.30964 21.4404 1.75 20.75 1.75C20.0596 1.75 19.5 2.30964 19.5 3C19.5 3.69036 20.0596 4.25 20.75 4.25Z"
stroke="#98A2B3" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" />
<path
d="M3.25 4.25C3.94036 4.25 4.5 3.69036 4.5 3C4.5 2.30964 3.94036 1.75 3.25 1.75C2.55964 1.75 2 2.30964 2 3C2 3.69036 2.55964 4.25 3.25 4.25Z"
stroke="#98A2B3" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" />
</svg>

After

Width:  |  Height:  |  Size: 883 B

View File

@ -0,0 +1,46 @@
.tag {
height: 40px;
padding: 0 30px;
margin: 0 5px;
border: 1px solid #000;
border-radius: 10px;
cursor: pointer;
}
.checked {
color: #1677ff;
border-color: #1677ff;
}
.appIcon {
vertical-align: middle;
}
.appName {
vertical-align: middle;
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px;
}
.radioGroup {
background: rgba(249, 249, 249, 1) !important;
& > label {
border: 0 !important;
&::before {
display: none !important;
}
}
:global(.ant-radio-button-wrapper-checked) {
border-radius: 6px !important;
}
}
.ant-radio-button-wrapper-checked {
border-radius: 6px !important;
}
.radioButtonIcon {
vertical-align: middle;
}

View File

@ -0,0 +1,74 @@
import { ReactComponent as StarIon } from '@/assets/svg/chat-star.svg';
import { ReactComponent as Logo } from '@/assets/svg/logo.svg';
import { Layout, Radio, Space, theme } from 'antd';
import styles from './index.less';
import { useMemo } from 'react';
import { useLocation, useNavigate } from 'umi';
import User from '../user';
const { Header } = Layout;
const RagHeader = () => {
const {
token: { colorBgContainer },
} = theme.useToken();
const navigate = useNavigate();
const { pathname } = useLocation();
const tagsData = [
{ path: '/knowledge', name: 'knowledge' },
{ path: '/chat', name: 'chat' },
{ path: '/file', name: 'file' },
];
const currentPath = useMemo(() => {
return tagsData.find((x) => x.path === pathname)?.name || 'knowledge';
}, [pathname]);
const handleChange = (path: string) => {
navigate(path);
};
return (
<Header
style={{
padding: '0 16px',
background: colorBgContainer,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
height: '72px',
}}
>
<Space size={12}>
<Logo className={styles.appIcon}></Logo>
<label className={styles.appName}>Infinity flow</label>
</Space>
<Space size={[0, 8]} wrap>
<Radio.Group
defaultValue="a"
buttonStyle="solid"
className={styles.radioGroup}
value={currentPath}
>
{tagsData.map((item) => (
<Radio.Button
value={item.name}
onClick={() => handleChange(item.path)}
>
<Space>
<StarIon className={styles.radioButtonIcon}></StarIon>
{item.name}
</Space>
</Radio.Button>
))}
</Radio.Group>
</Space>
<User></User>
</Header>
);
};
export default RagHeader;

View File

@ -18,16 +18,6 @@ body {
margin: 0;
}
.tag {
height: 40px;
padding: 0 30px;
margin: 0 5px;
border: 1px solid #000;
border-radius: 10px;
cursor: pointer;
.divider {
margin: 0;
}
.checked {
color: #1677ff;
border-color: #1677ff;
}

View File

@ -1,74 +1,26 @@
import logo from '@/assets/logo.png';
import { Layout, Space, theme } from 'antd';
import classnames from 'classnames';
import React, { useEffect, useState } from 'react';
import { Divider, Layout, theme } from 'antd';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Outlet, useLocation, useNavigate } from 'umi';
import { Outlet } from 'umi';
import '../locales/config';
import User from './components/user';
import Header from './components/header';
import styles from './index.less';
const { Header, Content } = Layout;
const { Content } = Layout;
const App: React.FC = (props) => {
const App: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
const {
token: { colorBgContainer, borderRadiusLG },
} = theme.useToken();
const [current, setCurrent] = useState('knowledge');
const location = useLocation();
useEffect(() => {
if (location.pathname !== '/') {
const path = location.pathname.split('/');
// setCurrent(path[1]);
}
console.log(location.pathname.split('/'));
}, [location.pathname]);
const handleChange = (path: string) => {
// setCurrent(path)
navigate(path);
};
const tagsData = [
{ path: '/knowledge', name: 'knowledge' },
{ path: '/chat', name: 'chat' },
{ path: '/file', name: 'file' },
];
return (
<Layout className={styles.layout}>
<Layout>
<Header
style={{
padding: '0 8px',
background: colorBgContainer,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<img src={logo} alt="" style={{ height: 30, width: 30 }} />
<Space size={[0, 8]} wrap>
{tagsData.map((item) => (
<span
key={item.name}
className={classnames(styles['tag'], {
[styles['checked']]: current === item.name,
})}
onClick={() => handleChange(item.path)}
>
{item.name}
</span>
))}
</Space>
<User></User>
</Header>
<Header></Header>
<Divider orientationMargin={0} className={styles.divider} />
<Content
style={{
margin: '24px 16px',
minHeight: 280,
background: colorBgContainer,
borderRadius: borderRadiusLG,

View File

@ -0,0 +1 @@
@fontWeight600: 600;

View File

@ -1,5 +1,4 @@
import { Button, Result } from 'antd';
import React from 'react';
import { history } from 'umi';
const NoFoundPage = () => {

View File

@ -2,7 +2,6 @@ import { DvaModel } from 'umi';
export interface kAModelState {
isShowPSwModal: boolean;
isShowTntModal: boolean;
loading: boolean;
tenantIfo: any;
activeKey: string;
id: string;
@ -14,7 +13,6 @@ const model: DvaModel<kAModelState> = {
state: {
isShowPSwModal: false,
isShowTntModal: false,
loading: false,
tenantIfo: {},
activeKey: 'setting',
id: '',

View File

@ -1,40 +1,43 @@
// @import '~@/less/variable.less';
.knowledge {
padding: 24px;
padding: 48px 60px;
}
.container {
height: 100px;
.topWrapper {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
padding-bottom: 72px;
.content {
.title {
font-family: Inter;
font-size: 30px;
font-style: normal;
font-weight: @fontWeight600;
line-height: 38px;
color: rgba(16, 24, 40, 1);
}
.description {
font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 24px;
color: rgba(71, 84, 103, 1);
}
.topButton {
font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: @fontWeight600;
line-height: 20px;
}
.filterButton {
display: flex;
justify-content: space-between;
.context {
flex: 1;
}
}
.footer {
height: 20px;
.text {
margin-left: 10px;
}
align-items: center;
.topButton();
}
}
.card {
:global {
.ant-card-body {
padding: 10px;
margin: 0;
}
margin-bottom: 10px;
}
cursor: pointer;
}

View File

@ -1,13 +1,10 @@
import { formatDate } from '@/utils/date';
import {
DeleteOutlined,
MinusSquareOutlined,
PlusOutlined,
} from '@ant-design/icons';
import { Card, Col, FloatButton, Popconfirm, Row } from 'antd';
import { ReactComponent as FilterIcon } from '@/assets/filter.svg';
import { PlusOutlined } from '@ant-design/icons';
import { Button, Col, Row, Space } from 'antd';
import { useCallback, useEffect } from 'react';
import { useDispatch, useNavigate, useSelector } from 'umi';
import styles from './index.less';
import KnowledgeCard from './knowledge-card';
const Knowledge = () => {
const dispatch = useDispatch();
@ -22,98 +19,54 @@ const Knowledge = () => {
});
}, []);
const confirm = (id: string) => {
dispatch({
type: 'knowledgeModel/rmKb',
payload: {
kb_id: id,
},
});
};
const handleAddKnowledge = () => {
navigate(`add/setting?activeKey=setting`);
};
const handleEditKnowledge = (id: string) => {
navigate(`add/setting?activeKey=file&id=${id}`);
};
useEffect(() => {
fetchList();
}, [fetchList]);
return (
<>
<div className={styles.knowledge}>
<FloatButton
onClick={handleAddKnowledge}
icon={<PlusOutlined />}
type="primary"
style={{ right: 24, top: 100 }}
/>
<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}
>
<Card
className={styles.card}
onClick={() => {
handleEditKnowledge(item.id);
}}
>
<div className={styles.container}>
<div className={styles.content}>
<span className={styles.context}>{item.name}</span>
<span className={styles.delete}>
<Popconfirm
title="Delete the task"
description="Are you sure to delete this task?"
onConfirm={(e: any) => {
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
confirm(item.id);
}}
okText="Yes"
cancelText="No"
>
<DeleteOutlined
onClick={(e) => {
e.stopPropagation();
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>
</Card>
</Col>
);
})}
</Row>
<div className={styles.knowledge}>
<div className={styles.topWrapper}>
<div>
<span className={styles.title}>Welcome back, Zing</span>
<p className={styles.description}>
Which database are we going to use today?
</p>
</div>
<Space size={'large'}>
<Button icon={<FilterIcon />} className={styles.filterButton}>
Filters
</Button>
<Button
type="primary"
icon={<PlusOutlined />}
onClick={handleAddKnowledge}
className={styles.topButton}
>
Create knowledge base
</Button>
</Space>
</div>
</>
<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}
>
<KnowledgeCard item={item}></KnowledgeCard>
</Col>
);
})}
</Row>
</div>
);
};

View File

@ -0,0 +1,73 @@
.container {
height: 251px;
display: flex;
flex-direction: column;
justify-content: space-between;
.content {
display: flex;
justify-content: space-between;
.context {
flex: 1;
}
}
.footer {
// text-align: left;
}
.footerTop {
padding-bottom: 2px;
}
}
.card {
border-radius: 12px;
border: 1px solid rgba(234, 236, 240, 1);
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
padding: 24px;
min-width: 300px;
cursor: pointer;
.titleWrapper {
// flex: 1;
.title {
font-size: 24px;
line-height: 32px;
font-weight: 600;
color: rgba(0, 0, 0, 0.88);
}
.description {
font-size: 12px;
font-weight: 600;
line-height: 20px;
color: rgba(0, 0, 0, 0.45);
}
}
:global {
.ant-card-body {
padding: 0;
margin: 0;
}
}
.bottom {
display: flex;
align-items: center;
justify-content: space-between;
}
.bottomLeft {
vertical-align: middle;
}
.leftIcon {
margin-right: 10px;
font-size: 18px;
vertical-align: middle;
}
.rightText {
font-size: 12px;
font-weight: 600;
color: rgba(0, 0, 0, 0.65);
vertical-align: middle;
}
}

View File

@ -0,0 +1,123 @@
import { ReactComponent as MoreIcon } from '@/assets/svg/more.svg';
import { formatDate } from '@/utils/date';
import {
AntDesignOutlined,
CalendarOutlined,
DeleteOutlined,
FileTextOutlined,
UserOutlined,
} from '@ant-design/icons';
import { Avatar, Card, Dropdown, MenuProps, Space, Tooltip } from 'antd';
import { MouseEvent } from 'react';
import { useDispatch, useNavigate } from 'umi';
import styles from './index.less';
interface IProps {
item: any;
}
const KnowledgeCard = ({ item }: IProps) => {
const navigate = useNavigate();
const dispatch = useDispatch();
const handleDelete = (e: MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
};
const items: MenuProps['items'] = [
{
key: '1',
label: (
<Space>
<DeleteOutlined onClick={handleDelete} />
</Space>
),
},
];
const confirm = (id: string) => {
dispatch({
type: 'knowledgeModel/rmKb',
payload: {
kb_id: id,
},
});
};
const handleCardClick = () => {
navigate(`add/setting?activeKey=file&id=${item.id}`);
};
const onConfirmDelete = (e?: MouseEvent<HTMLElement>) => {
e?.stopPropagation();
e?.nativeEvent.stopImmediatePropagation();
confirm(item.id);
};
return (
<Card className={styles.card} onClick={handleCardClick}>
<div className={styles.container}>
<div className={styles.content}>
<Avatar size={34} icon={<UserOutlined />} />
<span className={styles.delete}>
{/* <Popconfirm
title="Delete the task"
description="Are you sure to delete this task?"
onConfirm={onConfirmDelete}
okText="Yes"
cancelText="No"
>
<DeleteOutlined onClick={handleDelete} />
</Popconfirm> */}
<Dropdown menu={{ items }}>
<MoreIcon />
</Dropdown>
</span>
</div>
<div className={styles.titleWrapper}>
<span className={styles.title}>{item.name}</span>
<p>A comprehensive knowledge base for crafting effective resumes.</p>
</div>
<div className={styles.footer}>
<div className={styles.footerTop}>
<div className={styles.bottomLeft}>
<FileTextOutlined className={styles.leftIcon} />
<span className={styles.rightText}>
<Space>{item.doc_num}</Space>
</span>
</div>
</div>
<div className={styles.bottom}>
<div className={styles.bottomLeft}>
<CalendarOutlined className={styles.leftIcon} />
<span className={styles.rightText}>
{formatDate(item.update_date)}
</span>
</div>
<Avatar.Group size={25}>
<Avatar src="https://api.dicebear.com/7.x/miniavs/svg?seed=1" />
<a href="https://ant.design">
<Avatar style={{ backgroundColor: '#f56a00' }}>K</Avatar>
</a>
<Tooltip title="Ant User" placement="top">
<Avatar
style={{ backgroundColor: '#87d068' }}
icon={<UserOutlined />}
/>
</Tooltip>
<Avatar
style={{ backgroundColor: '#1677ff' }}
icon={<AntDesignOutlined />}
/>
</Avatar.Group>
</div>
</div>
</div>
</Card>
);
};
export default KnowledgeCard;

View File

@ -19,7 +19,7 @@ const model: DvaModel<KnowledgeModelState> = {
},
},
effects: {
*rmKb({ payload = {}, callback }, { call, put }) {
*rmKb({ payload = {} }, { call, put }) {
const { data } = yield call(kbService.rmKb, payload);
const { retcode } = data;
if (retcode === 0) {

View File

@ -12,6 +12,8 @@ const Login = () => {
(state) => state.loading.effects,
);
// TODO: When the server address request is not accessible, the value of dva-loading always remains true.
const signLoading =
effectsLoading['loginModel/login'] || effectsLoading['loginModel/register'];

View File

@ -32,10 +32,8 @@ const model: DvaModel<LoginModelState> = {
},
effects: {
*login({ payload = {} }, { call, put }) {
console.log(111, payload);
const { data, response } = yield call(userService.login, payload);
const { retcode, data: res, retmsg } = data;
console.log();
const { retcode, data: res } = data;
const authorization = response.headers.get(Authorization);
if (retcode === 0) {
message.success('登录成功!');

View File

@ -1,92 +1,78 @@
import { connect, Dispatch } from 'umi';
import i18n from 'i18next';
import { useTranslation, Trans } from 'react-i18next'
import { Input, Modal, Form } from 'antd'
import { rsaPsw } from '@/utils'
import styles from './index.less';
import { FC } from 'react';
import { rsaPsw } from '@/utils';
import { Form, Input, Modal } from 'antd';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'umi';
type FieldType = {
newPassword?: string;
password?: string;
newPassword?: string;
password?: string;
};
interface CPwModalProps {
dispatch: Dispatch;
settingModel: any
}
const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => {
const { isShowPSwModal } = settingModel
const { t } = useTranslation()
const handleCancel = () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowPSwModal: false
}
});
};
const [form] = Form.useForm()
const handleOk = async () => {
try {
const values = await form.validateFields();
var password = rsaPsw(values.password)
var new_password = rsaPsw(values.newPassword)
dispatch({
type: 'settingModel/setting',
payload: {
password,
new_password
},
callback: () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowPSwModal: false
}
});
dispatch({
type: 'settingModel/getUserInfo',
payload: {
const CpwModal = () => {
const dispatch = useDispatch();
const settingModel = useSelector((state: any) => state.settingModel);
const { isShowPSwModal } = settingModel;
const { t } = useTranslation();
const [form] = Form.useForm();
}
});
}
});
const handleCancel = () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowPSwModal: false,
},
});
};
const handleOk = async () => {
try {
const values = await form.validateFields();
var password = rsaPsw(values.password);
var new_password = rsaPsw(values.newPassword);
} catch (errorInfo) {
console.log('Failed:', errorInfo);
}
};
dispatch({
type: 'settingModel/setting',
payload: {
password,
new_password,
},
});
} catch (errorInfo) {
console.log('Failed:', errorInfo);
}
};
return (
<Modal title="Basic Modal" open={isShowPSwModal} onOk={handleOk} onCancel={handleCancel}>
<Form
form={form}
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
style={{ maxWidth: 600 }}
autoComplete="off"
>
<Form.Item<FieldType>
label="旧密码"
name="password"
rules={[{ required: true, message: 'Please input value' }]}
>
<Input.Password />
</Form.Item>
<Form.Item<FieldType>
label="新密码"
name="newPassword"
rules={[{ required: true, message: 'Please input your newPassword!' }]}
>
<Input.Password />
</Form.Item>
</Form>
</Modal >
);
}
export default connect(({ settingModel, loading }) => ({ settingModel, loading }))(Index);
return (
<Modal
title="Basic Modal"
open={isShowPSwModal}
onOk={handleOk}
onCancel={handleCancel}
>
<Form
form={form}
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
style={{ maxWidth: 600 }}
autoComplete="off"
>
<Form.Item<FieldType>
label="旧密码"
name="password"
rules={[{ required: true, message: 'Please input value' }]}
>
<Input.Password />
</Form.Item>
<Form.Item<FieldType>
label="新密码"
name="newPassword"
rules={[
{ required: true, message: 'Please input your newPassword!' },
]}
>
<Input.Password />
</Form.Item>
</Form>
</Modal>
);
};
export default CpwModal;

View File

@ -1,196 +1,146 @@
import { connect, Dispatch } from 'umi';
import i18n from 'i18next';
import { useTranslation, Trans } from 'react-i18next'
import { useTranslation } from 'react-i18next';
import { useEffect, useState } from 'react';
import styles from './index.less';
import type { ColumnsType } from 'antd/es/table';
import { useEffect, useState, FC } from 'react';
import { RadarChartOutlined } from '@ant-design/icons';
import { ProCard } from '@ant-design/pro-components';
import { Button, Tag, Row, Col, Card } from 'antd';
import { Button, Card, Col, Row, Tag } from 'antd';
import { useDispatch, useSelector } from 'umi';
interface DataType {
key: React.Key;
name: string;
age: number;
address: string;
description: string;
key: React.Key;
name: string;
age: number;
address: string;
description: string;
}
interface ListProps {
dispatch: Dispatch;
settingModel: any
}
const Index: FC<ListProps> = ({ settingModel, dispatch }) => {
const { llmInfo = {}, factoriesList, myLlm = [] } = settingModel
const { OpenAI = [], tongyi = [] } = llmInfo
console.log(OpenAI)
const [collapsed, setCollapsed] = useState(true);
const { t } = useTranslation()
const columns: ColumnsType<DataType> = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Age', dataIndex: 'age', key: 'age' },
{
title: 'Action',
dataIndex: '',
key: 'x',
render: () => <a>Delete</a>,
},
];
useEffect(() => {
dispatch({
type: 'settingModel/factories_list',
payload: {
},
});
dispatch({
type: 'settingModel/llm_list',
payload: {
},
});
dispatch({
type: 'settingModel/my_llm',
payload: {
},
});
}, [])
const data: DataType[] = [
{
key: 1,
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.',
},
{
key: 2,
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.',
},
{
key: 3,
name: 'Not Expandable',
age: 29,
address: 'Jiangsu No. 1 Lake Park',
description: 'This not expandable',
},
{
key: 4,
name: 'Joe Black',
age: 32,
address: 'Sydney No. 1 Lake Park',
description: 'My name is Joe Black, I am 32 years old, living in Sydney No. 1 Lake Park.',
},
];
const SettingList = () => {
const dispatch = useDispatch();
const settingModel = useSelector((state: any) => state.settingModel);
const { llmInfo = {}, factoriesList, myLlm = [] } = settingModel;
const { OpenAI = [], tongyi = [] } = llmInfo;
const [collapsed, setCollapsed] = useState(true);
const { t } = useTranslation();
return (
<div
className={styles.list}
style={{
display: 'flex',
flexDirection: 'column',
padding: 24,
gap: 12,
useEffect(() => {
dispatch({
type: 'settingModel/factories_list',
payload: {},
});
dispatch({
type: 'settingModel/llm_list',
payload: {},
});
dispatch({
type: 'settingModel/my_llm',
payload: {},
});
}, []);
return (
<div
className={styles.list}
style={{
display: 'flex',
flexDirection: 'column',
padding: 24,
gap: 12,
}}
>
{myLlm.map((item: any) => {
return (
<ProCard
key={item.llm_factory}
// title={<div>可折叠-图标自定义</div>}
collapsibleIconRender={({
collapsed: buildInCollapsed,
}: {
collapsed: boolean;
}) => {
return (
<div>
<h3>
<RadarChartOutlined />
{item.llm_factory}
</h3>
<div>
{item.tags.split(',').map((d: string) => {
return <Tag key={d}>{d}</Tag>;
})}
</div>
{buildInCollapsed ? (
<span>{OpenAI.length}</span>
) : (
<span>{OpenAI.length} </span>
)}
</div>
);
}}
>
{
myLlm.map((item: any) => {
return (<ProCard
key={item.llm_factory}
// title={<div>可折叠-图标自定义</div>}
collapsibleIconRender={({
collapsed: buildInCollapsed,
}: {
collapsed: boolean;
}) => {
return (<div>
<h3><RadarChartOutlined />{item.llm_factory}</h3>
<div>{item.tags.split(',').map((d: string) => {
return <Tag key={d}>{d}</Tag>
})}</div>
{
buildInCollapsed ? <span>{OpenAI.length}</span> : <span>{OpenAI.length} </span>
}
</div>)
}}
extra={
<Button
size="small"
type='link'
onClick={(e) => {
e.stopPropagation();
dispatch({
type: 'settingModel/updateState',
payload: {
llm_factory: item.llm_factory,
isShowSAKModal: true
}
});
}}
>
</Button>
}
style={{ marginBlockStart: 16 }}
headerBordered
collapsible
defaultCollapsed
>
{/* <ul>
{OpenAI.map(item => {
return <li key={item.llm_name}>
<span>{item.llm_name}</span>
<span className={styles[item.available ? 'statusAvailable' : 'statusDisaabled']}>
</span>
</li>
})}
</ul> */}
</ProCard>)
})
extra={
<Button
size="small"
type="link"
onClick={(e) => {
e.stopPropagation();
dispatch({
type: 'settingModel/updateState',
payload: {
llm_factory: item.llm_factory,
isShowSAKModal: true,
},
});
}}
>
</Button>
}
style={{ marginBlockStart: 16 }}
headerBordered
collapsible
defaultCollapsed
></ProCard>
);
})}
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}>
{
factoriesList.map((item: any) => {
return (<Col key={item.name} xs={24} sm={12} md={8} lg={6}>
<Card title={item.name} bordered={false} extra={
<Button
size="small"
type='link'
onClick={(e) => {
e.stopPropagation();
dispatch({
type: 'settingModel/updateState',
payload: {
llm_factory: item.name,
isShowSAKModal: true
}
});
}}
>
</Button>
}>
<div>
{
item.tags.split(',').map((d: string) => {
return <Tag key={d}>{d}</Tag>
})
}
</div>
</Card>
</Col>)
})
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}>
{factoriesList.map((item: any) => {
return (
<Col key={item.name} xs={24} sm={12} md={8} lg={6}>
<Card
title={item.name}
bordered={false}
extra={
<Button
size="small"
type="link"
onClick={(e) => {
e.stopPropagation();
dispatch({
type: 'settingModel/updateState',
payload: {
llm_factory: item.name,
isShowSAKModal: true,
},
});
}}
>
</Button>
}
</Row>
</div>
);
}
export default connect(({ settingModel, loading }) => ({ settingModel, loading }))(Index);
>
<div>
{item.tags.split(',').map((d: string) => {
return <Tag key={d}>{d}</Tag>;
})}
</div>
</Card>
</Col>
);
})}
</Row>
</div>
);
};
export default SettingList;

View File

@ -1,83 +1,66 @@
import { connect, Dispatch } from 'umi';
import i18n from 'i18next';
import { FC } from 'react'
import { useTranslation, Trans } from 'react-i18next'
import { Input, Modal, Form } from 'antd'
import styles from './index.less';
import { Form, Input, Modal } from 'antd';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'umi';
type FieldType = {
api_key?: string;
api_key?: string;
};
interface SAKModalProps {
dispatch: Dispatch;
settingModel: any
}
const Index: FC<SAKModalProps> = ({ settingModel, dispatch }) => {
const { isShowSAKModal, llm_factory } = settingModel
console.log(llm_factory)
const { t } = useTranslation()
const handleCancel = () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowSAKModal: false
}
});
};
const [form] = Form.useForm()
const handleOk = async () => {
try {
const values = await form.validateFields();
dispatch({
type: 'settingModel/set_api_key',
payload: {
api_key: values.api_key,
llm_factory: llm_factory
},
callback: () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowSAKModal: false
}
});
// dispatch({
// type: 'settingModel/getUserInfo',
// payload: {
const SakModal = () => {
const dispatch = useDispatch();
const settingModel = useSelector((state: any) => state.settingModel);
const { isShowSAKModal, llm_factory } = settingModel;
const { t } = useTranslation();
const [form] = Form.useForm();
// }
// });
}
});
const handleCancel = () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowSAKModal: false,
},
});
};
const handleOk = async () => {
try {
const values = await form.validateFields();
} catch (errorInfo) {
console.log('Failed:', errorInfo);
}
};
dispatch({
type: 'settingModel/set_api_key',
payload: {
api_key: values.api_key,
llm_factory: llm_factory,
},
});
} catch (errorInfo) {
console.log('Failed:', errorInfo);
}
};
return (
<Modal title="Basic Modal" open={isShowSAKModal} onOk={handleOk} onCancel={handleCancel}>
<Form
form={form}
name="validateOnly"
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
style={{ maxWidth: 600 }}
autoComplete="off"
>
<Form.Item<FieldType>
label="API Key"
name="api_key"
rules={[{ required: true, message: 'Please input ' }]}
>
<Input />
</Form.Item>
</Form>
</Modal >
);
}
export default connect(({ settingModel, loading }) => ({ settingModel, loading }))(Index);
return (
<Modal
title="Basic Modal"
open={isShowSAKModal}
onOk={handleOk}
onCancel={handleCancel}
>
<Form
form={form}
name="validateOnly"
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
style={{ maxWidth: 600 }}
autoComplete="off"
>
<Form.Item<FieldType>
label="API Key"
name="api_key"
rules={[{ required: true, message: 'Please input ' }]}
>
<Input />
</Form.Item>
</Form>
</Modal>
);
};
export default SakModal;

View File

@ -1,152 +1,144 @@
import { connect, Dispatch } from 'umi';
import { FC } from 'react'
import i18n from 'i18next';
import { useTranslation, Trans } from 'react-i18next'
import { Input, Modal, Form, Select } from 'antd'
import styles from './index.less';
import { Form, Modal, Select } from 'antd';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'umi';
type FieldType = {
embd_id?: string;
img2txt_id?: string;
llm_id?: string;
asr_id?: string
embd_id?: string;
img2txt_id?: string;
llm_id?: string;
asr_id?: string;
};
interface SSModalProps {
dispatch: Dispatch;
settingModel: any
}
const Index: FC<SSModalProps> = ({ settingModel, dispatch }) => {
const { isShowSSModal, llmInfo = {}, tenantIfo } = settingModel
const { t } = useTranslation()
const handleCancel = () => {
const SsModal = () => {
const dispatch = useDispatch();
const settingModel = useSelector((state: any) => state.settingModel);
const { isShowSSModal, llmInfo = {}, tenantIfo } = settingModel;
const [form] = Form.useForm();
const { t } = useTranslation();
const handleCancel = () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowSSModal: false,
},
});
};
const handleOk = async () => {
try {
const values = await form.validateFields();
const retcode = await dispatch<any>({
type: 'settingModel/set_tenant_info',
payload: {
...values,
tenant_id: tenantIfo.tenant_id,
},
});
retcode === 0 &&
dispatch({
type: 'settingModel/updateState',
payload: {
isShowSSModal: false
}
type: 'settingModel/updateState',
payload: {
isShowSSModal: false,
},
});
};
const [form] = Form.useForm()
const handleOk = async () => {
try {
const values = await form.validateFields();
console.log(values)
dispatch({
type: 'settingModel/set_tenant_info',
payload: {
...values,
tenant_id: tenantIfo.tenant_id,
},
callback: () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowSSModal: false
}
});
// dispatch({
// type: 'settingModel/getUserInfo',
// payload: {
// }
// });
}
});
} catch (errorInfo) {
console.log('Failed:', errorInfo);
}
};
const handleChange = () => {
} catch (errorInfo) {
console.log('Failed:', errorInfo);
}
};
return (
<Modal title="Basic Modal" open={isShowSSModal} onOk={handleOk} onCancel={handleCancel}>
<Form
form={form}
name="validateOnly"
// labelCol={{ span: 8 }}
// wrapperCol={{ span: 16 }}
style={{ maxWidth: 600 }}
autoComplete="off"
layout="vertical"
>
<Form.Item<FieldType>
label="embedding 模型"
name="embd_id"
rules={[{ required: true, message: 'Please input value' }]}
initialValue={tenantIfo.embd_id}
const handleChange = () => {};
>
<Select
// style={{ width: 200 }}
onChange={handleChange}
// fieldNames={label:}
options={Object.keys(llmInfo).map(t => {
const options = llmInfo[t].filter((d: any) => d.model_type === 'embedding').map((d: any) => ({ label: d.llm_name, value: d.llm_name, }))
return { label: t, options }
})}
/>
</Form.Item>
<Form.Item<FieldType>
label="chat 模型"
name="llm_id"
rules={[{ required: true, message: 'Please input value' }]}
initialValue={tenantIfo.llm_id}
>
<Select
// style={{ width: 200 }}
onChange={handleChange}
// fieldNames={label:}
options={Object.keys(llmInfo).map(t => {
const options = llmInfo[t].filter((d: any) => d.model_type === 'chat').map((d: any) => ({ label: d.llm_name, value: d.llm_name, }))
return { label: t, options }
})}
/>
</Form.Item>
<Form.Item<FieldType>
label="image2text 模型"
name="img2txt_id"
rules={[{ required: true, message: 'Please input value' }]}
initialValue={tenantIfo.img2txt_id}
>
<Select
// style={{ width: 200 }}
onChange={handleChange}
// fieldNames={label:}
options={Object.keys(llmInfo).map(t => {
const options = llmInfo[t].filter((d: any) => d.model_type === 'image2text').map((d: any) => ({ label: d.llm_name, value: d.llm_name, }))
return { label: t, options }
})}
/>
</Form.Item>
<Form.Item<FieldType>
label="speech2text 模型"
name="asr_id"
rules={[{ required: true, message: 'Please input value' }]}
initialValue={tenantIfo.asr_id}
>
<Select
// style={{ width: 200 }}
onChange={handleChange}
// fieldNames={label:}
options={Object.keys(llmInfo).map(t => {
const options = llmInfo[t].filter((d: any) => d.model_type === 'speech2text').map((d: any) => ({ label: d.llm_name, value: d.llm_name, }))
return { label: t, options }
})}
/>
</Form.Item>
</Form>
</Modal >
);
}
export default connect(({ settingModel, loading }) => ({ settingModel, loading }))(Index);
return (
<Modal
title="Basic Modal"
open={isShowSSModal}
onOk={handleOk}
onCancel={handleCancel}
>
<Form
form={form}
name="validateOnly"
// labelCol={{ span: 8 }}
// wrapperCol={{ span: 16 }}
style={{ maxWidth: 600 }}
autoComplete="off"
layout="vertical"
>
<Form.Item<FieldType>
label="embedding 模型"
name="embd_id"
rules={[{ required: true, message: 'Please input value' }]}
initialValue={tenantIfo.embd_id}
>
<Select
// style={{ width: 200 }}
onChange={handleChange}
// fieldNames={label:}
options={Object.keys(llmInfo).map((t) => {
const options = llmInfo[t]
.filter((d: any) => d.model_type === 'embedding')
.map((d: any) => ({ label: d.llm_name, value: d.llm_name }));
return { label: t, options };
})}
/>
</Form.Item>
<Form.Item<FieldType>
label="chat 模型"
name="llm_id"
rules={[{ required: true, message: 'Please input value' }]}
initialValue={tenantIfo.llm_id}
>
<Select
// style={{ width: 200 }}
onChange={handleChange}
// fieldNames={label:}
options={Object.keys(llmInfo).map((t) => {
const options = llmInfo[t]
.filter((d: any) => d.model_type === 'chat')
.map((d: any) => ({ label: d.llm_name, value: d.llm_name }));
return { label: t, options };
})}
/>
</Form.Item>
<Form.Item<FieldType>
label="image2text 模型"
name="img2txt_id"
rules={[{ required: true, message: 'Please input value' }]}
initialValue={tenantIfo.img2txt_id}
>
<Select
// style={{ width: 200 }}
onChange={handleChange}
// fieldNames={label:}
options={Object.keys(llmInfo).map((t) => {
const options = llmInfo[t]
.filter((d: any) => d.model_type === 'image2text')
.map((d: any) => ({ label: d.llm_name, value: d.llm_name }));
return { label: t, options };
})}
/>
</Form.Item>
<Form.Item<FieldType>
label="speech2text 模型"
name="asr_id"
rules={[{ required: true, message: 'Please input value' }]}
initialValue={tenantIfo.asr_id}
>
<Select
// style={{ width: 200 }}
onChange={handleChange}
// fieldNames={label:}
options={Object.keys(llmInfo).map((t) => {
const options = llmInfo[t]
.filter((d: any) => d.model_type === 'speech2text')
.map((d: any) => ({ label: d.llm_name, value: d.llm_name }));
return { label: t, options };
})}
/>
</Form.Item>
</Form>
</Modal>
);
};
export default SsModal;

View File

@ -1,58 +1,65 @@
import { connect, Dispatch } from 'umi';
import { FC } from 'react'
import i18n from 'i18next';
import { useTranslation, Trans } from 'react-i18next'
import { Modal, Table } from 'antd'
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
import { Modal, Table } from 'antd';
import { ColumnsType } from 'antd/es/table';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'umi';
import styles from './index.less';
import type { ColumnsType } from 'antd/es/table';
interface DataType {
key: React.Key;
name: string;
role: string;
time: string;
key: React.Key;
name: string;
role: string;
time: string;
}
interface TntodalProps {
dispatch: Dispatch;
settingModel: any
}
const TntModal = () => {
const dispatch = useDispatch();
const settingModel = useSelector((state: any) => state.settingModel);
const { isShowTntModal, tenantIfo, factoriesList } = settingModel;
const { t } = useTranslation();
const loading = useOneNamespaceEffectsLoading('settingModel', [
'getTenantInfo',
]);
const Index: FC<TntodalProps> = ({ settingModel, dispatch }) => {
const { isShowTntModal, tenantIfo, loading, factoriesList } = settingModel
const { t } = useTranslation()
const handleCancel = () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowTntModal: false
}
});
};
console.log(tenantIfo)
const handleOk = async () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowTntModal: false
}
});
};
const columns: ColumnsType<DataType> = [
{ title: '姓名', dataIndex: 'name', key: 'name' },
{ title: '活动时间', dataIndex: 'update_date', key: 'update_date' },
{ title: '角色', dataIndex: 'role', key: 'age' },
const columns: ColumnsType<DataType> = [
{ title: '姓名', dataIndex: 'name', key: 'name' },
{ title: '活动时间', dataIndex: 'update_date', key: 'update_date' },
{ title: '角色', dataIndex: 'role', key: 'age' },
];
];
const handleCancel = () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowTntModal: false,
},
});
};
return (
<Modal title="用户" open={isShowTntModal} onOk={handleOk} onCancel={handleCancel}>
<div className={styles.tenantIfo}>
{tenantIfo.name}
</div>
<Table rowKey='name' loading={loading} columns={columns} dataSource={factoriesList} />
</Modal >
);
}
export default connect(({ settingModel, loading }) => ({ settingModel, loading }))(Index);
const handleOk = async () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowTntModal: false,
},
});
};
return (
<Modal
title="用户"
open={isShowTntModal}
onOk={handleOk}
onCancel={handleCancel}
>
<div className={styles.tenantIfo}>{tenantIfo.name}</div>
<Table
rowKey="name"
loading={loading}
columns={columns}
dataSource={factoriesList}
/>
</Modal>
);
};
export default TntModal;

View File

@ -1,34 +1,35 @@
import { Button, FloatButton } from 'antd';
import i18n from 'i18next';
import { useTranslation } from 'react-i18next';
import { Dispatch, connect } from 'umi';
import authorizationUtil from '@/utils/authorizationUtil';
import { FC, useEffect } from 'react';
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'umi';
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';
interface CPwModalProps {
dispatch: Dispatch;
settingModel: any;
}
const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => {
// const [llm_factory, set_llm_factory] = useState('')
const Setting = () => {
const dispatch = useDispatch();
const settingModel = useSelector((state: any) => state.settingModel);
const { t } = useTranslation();
const userInfo = authorizationUtil.getUserInfoObject();
const changeLang = (val: string) => {
// 改变状态里的 语言 进行切换
i18n.changeLanguage(val);
};
useEffect(() => {
dispatch({
type: 'settingModel/getTenantInfo',
payload: {},
});
}, []);
const showCPwModal = () => {
dispatch({
type: 'settingModel/updateState',
@ -52,11 +53,6 @@ const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => {
isShowSSModal: true,
},
});
// dispatch({
// type: 'settingModel/getTenantInfo',
// payload: {
// }
// });
};
return (
<div className={styles.settingPage}>
@ -99,7 +95,4 @@ const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => {
</div>
);
};
export default connect(({ settingModel, loading }) => ({
settingModel,
loading,
}))(Index);
export default Setting;

View File

@ -9,7 +9,6 @@ export interface SettingModelState {
isShowSAKModal: boolean;
isShowSSModal: boolean;
llm_factory: string;
loading: boolean;
tenantIfo: any;
llmInfo: any;
myLlm: any[];
@ -24,7 +23,6 @@ const model: DvaModel<SettingModelState> = {
isShowSAKModal: false,
isShowSSModal: false,
llm_factory: '',
loading: false,
tenantIfo: {},
llmInfo: {},
myLlm: [],
@ -44,12 +42,21 @@ const model: DvaModel<SettingModelState> = {
},
},
effects: {
*setting({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(userService.setting, payload);
const { retcode, data: res, retmsg } = data;
*setting({ payload = {} }, { call, put }) {
const { data } = yield call(userService.setting, payload);
const { retcode } = data;
if (retcode === 0) {
message.success('密码修改成功!');
callback && callback();
yield put({
type: 'updateState',
payload: {
isShowPSwModal: false,
},
});
yield put({
type: 'getUserInfo',
payload: {},
});
}
},
*getUserInfo({ payload = {} }, { call, put }) {
@ -72,11 +79,8 @@ const model: DvaModel<SettingModelState> = {
loading: true,
},
});
const { data, response } = yield call(
userService.get_tenant_info,
payload,
);
const { retcode, data: res, retmsg } = data;
const { data } = yield call(userService.get_tenant_info, payload);
const { retcode, data: res } = data;
// llm_id 对应chat_id
// asr_id 对应speech2txt
@ -98,11 +102,8 @@ const model: DvaModel<SettingModelState> = {
}
},
*set_tenant_info({ payload = {} }, { call, put }) {
const { data, response } = yield call(
userService.set_tenant_info,
payload,
);
const { retcode, data: res, retmsg } = data;
const { data } = yield call(userService.set_tenant_info, payload);
const { retcode } = data;
// llm_id 对应chat_id
// asr_id 对应speech2txt
if (retcode === 0) {
@ -116,6 +117,7 @@ const model: DvaModel<SettingModelState> = {
type: 'getTenantInfo',
});
}
return retcode;
},
*factories_list({ payload = {} }, { call, put }) {
@ -157,12 +159,17 @@ const model: DvaModel<SettingModelState> = {
});
}
},
*set_api_key({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(userService.set_api_key, payload);
const { retcode, data: res, retmsg } = data;
*set_api_key({ payload = {} }, { call, put }) {
const { data } = yield call(userService.set_api_key, payload);
const { retcode } = data;
if (retcode === 0) {
message.success('设置API KEY成功');
callback && callback();
yield put({
type: 'updateState',
payload: {
isShowSAKModal: false,
},
});
}
},
},

View File

@ -1,14 +1,8 @@
let api_host = `http://54.80.112.79:9380/v1`;
let api_host = `http://223.111.148.200:9380/v1`;
export { api_host };
export default {
// 用户
login: `${api_host}/user/login`,
register: `${api_host}/user/register`,
@ -23,8 +17,6 @@ export default {
my_llm: `${api_host}/llm/my_llms`,
set_api_key: `${api_host}/llm/set_api_key`,
//知识库管理
kb_list: `${api_host}/kb/list`,
create_kb: `${api_host}/kb/create`,
@ -41,9 +33,6 @@ export default {
rm_chunk: `${api_host}/chunk/rm`,
retrieval_test: `${api_host}/chunk/retrieval_test`,
// 上传
upload: `${api_host}/document/upload`,
get_document_list: `${api_host}/document/list`,
@ -51,5 +40,4 @@ export default {
document_rm: `${api_host}/document/rm`,
document_create: `${api_host}/document/create`,
document_change_parser: `${api_host}/document/change_parser`,
};

View File

@ -12,9 +12,9 @@ export function lastWeek() {
return formatDate(moment().subtract(1, 'weeks'));
}
export function formatDate(date) {
export function formatDate(date: any) {
if (!date) {
return '';
}
return moment(date).format('YYYY-MM-DD');
return moment(date).format('DD/MM/YYYY');
}

View File

@ -83,7 +83,7 @@ const errorHandler = (error: {
*/
const request: RequestMethod = extend({
errorHandler, // 默认错误处理
timeout: 3000000,
timeout: 300000,
getResponse: true,
});