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'], plugins: ['@react-dev-inspector/umi4-plugin', '@umijs/plugins/dist/dva'],
dva: {}, dva: {},
lessLoader: {
modifyVars: {
hack: `true; @import "~@/less/variable.less";`,
},
},
// proxy: { // proxy: {
// '/v1': { // '/v1': {
// 'target': 'http://54.80.112.79:9380/', // '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; margin: 0;
} }
.tag { .divider {
height: 40px; margin: 0;
padding: 0 30px;
margin: 0 5px;
border: 1px solid #000;
border-radius: 10px;
cursor: pointer;
} }
.checked {
color: #1677ff;
border-color: #1677ff;
}

View File

@ -1,74 +1,26 @@
import logo from '@/assets/logo.png'; import { Divider, Layout, theme } from 'antd';
import { Layout, Space, theme } from 'antd'; import React from 'react';
import classnames from 'classnames';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Outlet, useLocation, useNavigate } from 'umi'; import { Outlet } from 'umi';
import '../locales/config'; import '../locales/config';
import User from './components/user'; import Header from './components/header';
import styles from './index.less'; 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 { t } = useTranslation();
const navigate = useNavigate();
const { const {
token: { colorBgContainer, borderRadiusLG }, token: { colorBgContainer, borderRadiusLG },
} = theme.useToken(); } = 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 ( return (
<Layout className={styles.layout}> <Layout className={styles.layout}>
<Layout> <Layout>
<Header <Header></Header>
style={{ <Divider orientationMargin={0} className={styles.divider} />
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>
<Content <Content
style={{ style={{
margin: '24px 16px',
minHeight: 280, minHeight: 280,
background: colorBgContainer, background: colorBgContainer,
borderRadius: borderRadiusLG, borderRadius: borderRadiusLG,

View File

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

View File

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

View File

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

View File

@ -1,40 +1,43 @@
// @import '~@/less/variable.less';
.knowledge { .knowledge {
padding: 24px; padding: 48px 60px;
} }
.container { .topWrapper {
height: 100px;
display: flex; display: flex;
flex-direction: column;
justify-content: space-between; 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; display: flex;
justify-content: space-between; align-items: center;
.topButton();
.context {
flex: 1;
}
}
.footer {
height: 20px;
.text {
margin-left: 10px;
}
} }
} }
.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 { ReactComponent as FilterIcon } from '@/assets/filter.svg';
import { import { PlusOutlined } from '@ant-design/icons';
DeleteOutlined, import { Button, Col, Row, Space } from 'antd';
MinusSquareOutlined,
PlusOutlined,
} from '@ant-design/icons';
import { Card, Col, FloatButton, Popconfirm, Row } from 'antd';
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect } from 'react';
import { useDispatch, useNavigate, useSelector } from 'umi'; import { useDispatch, useNavigate, useSelector } from 'umi';
import styles from './index.less'; import styles from './index.less';
import KnowledgeCard from './knowledge-card';
const Knowledge = () => { const Knowledge = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -22,98 +19,54 @@ const Knowledge = () => {
}); });
}, []); }, []);
const confirm = (id: string) => {
dispatch({
type: 'knowledgeModel/rmKb',
payload: {
kb_id: id,
},
});
};
const handleAddKnowledge = () => { const handleAddKnowledge = () => {
navigate(`add/setting?activeKey=setting`); navigate(`add/setting?activeKey=setting`);
}; };
const handleEditKnowledge = (id: string) => {
navigate(`add/setting?activeKey=file&id=${id}`);
};
useEffect(() => { useEffect(() => {
fetchList(); fetchList();
}, [fetchList]); }, [fetchList]);
return ( return (
<> <div className={styles.knowledge}>
<div className={styles.knowledge}> <div className={styles.topWrapper}>
<FloatButton <div>
onClick={handleAddKnowledge} <span className={styles.title}>Welcome back, Zing</span>
icon={<PlusOutlined />} <p className={styles.description}>
type="primary" Which database are we going to use today?
style={{ right: 24, top: 100 }} </p>
/> </div>
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}> <Space size={'large'}>
{data.map((item: any) => { <Button icon={<FilterIcon />} className={styles.filterButton}>
return ( Filters
<Col </Button>
className="gutter-row" <Button
key={item.name} type="primary"
xs={24} icon={<PlusOutlined />}
sm={12} onClick={handleAddKnowledge}
md={8} className={styles.topButton}
lg={6} >
> Create knowledge base
<Card </Button>
className={styles.card} </Space>
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> </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: { effects: {
*rmKb({ payload = {}, callback }, { call, put }) { *rmKb({ payload = {} }, { call, put }) {
const { data } = yield call(kbService.rmKb, payload); const { data } = yield call(kbService.rmKb, payload);
const { retcode } = data; const { retcode } = data;
if (retcode === 0) { if (retcode === 0) {

View File

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

View File

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

View File

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

View File

@ -1,196 +1,146 @@
import { connect, Dispatch } from 'umi'; import { useTranslation } from 'react-i18next';
import i18n from 'i18next';
import { useTranslation, Trans } from 'react-i18next'
import { useEffect, useState } from 'react';
import styles from './index.less'; 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 { RadarChartOutlined } from '@ant-design/icons';
import { ProCard } from '@ant-design/pro-components'; 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 { interface DataType {
key: React.Key; key: React.Key;
name: string; name: string;
age: number; age: number;
address: string; address: string;
description: 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 SettingList = () => {
const data: DataType[] = [ const dispatch = useDispatch();
{ const settingModel = useSelector((state: any) => state.settingModel);
key: 1, const { llmInfo = {}, factoriesList, myLlm = [] } = settingModel;
name: 'John Brown', const { OpenAI = [], tongyi = [] } = llmInfo;
age: 32, const [collapsed, setCollapsed] = useState(true);
address: 'New York No. 1 Lake Park', const { t } = useTranslation();
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.',
},
];
return ( useEffect(() => {
<div dispatch({
className={styles.list} type: 'settingModel/factories_list',
style={{ payload: {},
display: 'flex', });
flexDirection: 'column', dispatch({
padding: 24, type: 'settingModel/llm_list',
gap: 12, 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>
);
}} }}
> extra={
{ <Button
myLlm.map((item: any) => { size="small"
return (<ProCard type="link"
key={item.llm_factory} onClick={(e) => {
// title={<div>可折叠-图标自定义</div>} e.stopPropagation();
collapsibleIconRender={({ dispatch({
collapsed: buildInCollapsed, type: 'settingModel/updateState',
}: { payload: {
collapsed: boolean; llm_factory: item.llm_factory,
}) => { isShowSAKModal: true,
return (<div> },
<h3><RadarChartOutlined />{item.llm_factory}</h3> });
<div>{item.tags.split(',').map((d: string) => { }}
return <Tag key={d}>{d}</Tag> >
})}</div>
{ </Button>
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>)
})
} }
style={{ marginBlockStart: 16 }}
headerBordered
collapsible
defaultCollapsed
></ProCard>
);
})}
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}>
{factoriesList.map((item: any) => {
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}> return (
{ <Col key={item.name} xs={24} sm={12} md={8} lg={6}>
factoriesList.map((item: any) => { <Card
return (<Col key={item.name} xs={24} sm={12} md={8} lg={6}> title={item.name}
<Card title={item.name} bordered={false} extra={ bordered={false}
<Button extra={
size="small" <Button
type='link' size="small"
onClick={(e) => { type="link"
e.stopPropagation(); onClick={(e) => {
dispatch({ e.stopPropagation();
type: 'settingModel/updateState', dispatch({
payload: { type: 'settingModel/updateState',
llm_factory: item.name, payload: {
isShowSAKModal: true llm_factory: item.name,
} isShowSAKModal: true,
}); },
}} });
> }}
>
</Button>
}> </Button>
<div>
{
item.tags.split(',').map((d: string) => {
return <Tag key={d}>{d}</Tag>
})
}
</div>
</Card>
</Col>)
})
} }
</Row> >
</div> <div>
); {item.tags.split(',').map((d: string) => {
} return <Tag key={d}>{d}</Tag>;
export default connect(({ settingModel, loading }) => ({ settingModel, loading }))(Index); })}
</div>
</Card>
</Col>
);
})}
</Row>
</div>
);
};
export default SettingList;

View File

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

View File

@ -1,152 +1,144 @@
import { connect, Dispatch } from 'umi'; import { Form, Modal, Select } from 'antd';
import { FC } from 'react' import { useTranslation } from 'react-i18next';
import i18n from 'i18next'; import { useDispatch, useSelector } from 'umi';
import { useTranslation, Trans } from 'react-i18next'
import { Input, Modal, Form, Select } from 'antd'
import styles from './index.less';
type FieldType = { type FieldType = {
embd_id?: string; embd_id?: string;
img2txt_id?: string; img2txt_id?: string;
llm_id?: string; llm_id?: string;
asr_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 SsModal = () => {
const handleCancel = () => { 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({ dispatch({
type: 'settingModel/updateState', type: 'settingModel/updateState',
payload: { payload: {
isShowSSModal: false isShowSSModal: false,
} },
}); });
}; } catch (errorInfo) {
const [form] = Form.useForm() console.log('Failed:', errorInfo);
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 = () => {
} }
};
return ( const handleChange = () => {};
<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}
> return (
<Select <Modal
// style={{ width: 200 }} title="Basic Modal"
onChange={handleChange} open={isShowSSModal}
// fieldNames={label:} onOk={handleOk}
options={Object.keys(llmInfo).map(t => { onCancel={handleCancel}
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
})} form={form}
/> name="validateOnly"
</Form.Item> // labelCol={{ span: 8 }}
<Form.Item<FieldType> // wrapperCol={{ span: 16 }}
label="chat 模型" style={{ maxWidth: 600 }}
name="llm_id" autoComplete="off"
rules={[{ required: true, message: 'Please input value' }]} layout="vertical"
initialValue={tenantIfo.llm_id} >
<Form.Item<FieldType>
> label="embedding 模型"
<Select name="embd_id"
// style={{ width: 200 }} rules={[{ required: true, message: 'Please input value' }]}
onChange={handleChange} initialValue={tenantIfo.embd_id}
// fieldNames={label:} >
options={Object.keys(llmInfo).map(t => { <Select
const options = llmInfo[t].filter((d: any) => d.model_type === 'chat').map((d: any) => ({ label: d.llm_name, value: d.llm_name, })) // style={{ width: 200 }}
return { label: t, options } onChange={handleChange}
})} // fieldNames={label:}
/> options={Object.keys(llmInfo).map((t) => {
</Form.Item> const options = llmInfo[t]
<Form.Item<FieldType> .filter((d: any) => d.model_type === 'embedding')
label="image2text 模型" .map((d: any) => ({ label: d.llm_name, value: d.llm_name }));
name="img2txt_id" return { label: t, options };
rules={[{ required: true, message: 'Please input value' }]} })}
initialValue={tenantIfo.img2txt_id} />
</Form.Item>
> <Form.Item<FieldType>
<Select label="chat 模型"
// style={{ width: 200 }} name="llm_id"
onChange={handleChange} rules={[{ required: true, message: 'Please input value' }]}
// fieldNames={label:} initialValue={tenantIfo.llm_id}
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, })) <Select
return { label: t, options } // style={{ width: 200 }}
})} onChange={handleChange}
/> // fieldNames={label:}
</Form.Item> options={Object.keys(llmInfo).map((t) => {
<Form.Item<FieldType> const options = llmInfo[t]
label="speech2text 模型" .filter((d: any) => d.model_type === 'chat')
name="asr_id" .map((d: any) => ({ label: d.llm_name, value: d.llm_name }));
rules={[{ required: true, message: 'Please input value' }]} return { label: t, options };
initialValue={tenantIfo.asr_id} })}
/>
> </Form.Item>
<Select <Form.Item<FieldType>
// style={{ width: 200 }} label="image2text 模型"
onChange={handleChange} name="img2txt_id"
// fieldNames={label:} rules={[{ required: true, message: 'Please input value' }]}
options={Object.keys(llmInfo).map(t => { initialValue={tenantIfo.img2txt_id}
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 } <Select
})} // style={{ width: 200 }}
/> onChange={handleChange}
</Form.Item> // fieldNames={label:}
options={Object.keys(llmInfo).map((t) => {
const options = llmInfo[t]
</Form> .filter((d: any) => d.model_type === 'image2text')
</Modal > .map((d: any) => ({ label: d.llm_name, value: d.llm_name }));
return { label: t, options };
})}
); />
} </Form.Item>
export default connect(({ settingModel, loading }) => ({ settingModel, loading }))(Index); <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 { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
import { FC } from 'react' import { Modal, Table } from 'antd';
import i18n from 'i18next'; import { ColumnsType } from 'antd/es/table';
import { useTranslation, Trans } from 'react-i18next' import { useTranslation } from 'react-i18next';
import { Modal, Table } from 'antd' import { useDispatch, useSelector } from 'umi';
import styles from './index.less'; import styles from './index.less';
import type { ColumnsType } from 'antd/es/table';
interface DataType { interface DataType {
key: React.Key; key: React.Key;
name: string; name: string;
role: string; role: string;
time: string; time: string;
} }
interface TntodalProps { const TntModal = () => {
dispatch: Dispatch; const dispatch = useDispatch();
settingModel: any 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 columns: ColumnsType<DataType> = [
const { isShowTntModal, tenantIfo, loading, factoriesList } = settingModel { title: '姓名', dataIndex: 'name', key: 'name' },
const { t } = useTranslation() { title: '活动时间', dataIndex: 'update_date', key: 'update_date' },
const handleCancel = () => { { title: '角色', dataIndex: 'role', key: 'age' },
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 handleCancel = () => {
dispatch({
type: 'settingModel/updateState',
payload: {
isShowTntModal: false,
},
});
};
return ( const handleOk = async () => {
<Modal title="用户" open={isShowTntModal} onOk={handleOk} onCancel={handleCancel}> dispatch({
<div className={styles.tenantIfo}> type: 'settingModel/updateState',
{tenantIfo.name} payload: {
</div> isShowTntModal: false,
<Table rowKey='name' loading={loading} columns={columns} dataSource={factoriesList} /> },
</Modal > });
); };
}
export default connect(({ settingModel, loading }) => ({ settingModel, loading }))(Index); 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 { Button, FloatButton } from 'antd';
import i18n from 'i18next'; import i18n from 'i18next';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Dispatch, connect } from 'umi';
import authorizationUtil from '@/utils/authorizationUtil'; import authorizationUtil from '@/utils/authorizationUtil';
import { FC, useEffect } from 'react'; import { useEffect } from 'react';
import { useDispatch, useSelector } from 'umi';
import CPwModal from './CPwModal'; import CPwModal from './CPwModal';
import List from './List'; import List from './List';
import SAKModal from './SAKModal'; import SAKModal from './SAKModal';
import SSModal from './SSModal'; import SSModal from './SSModal';
import TntModal from './TntModal'; import TntModal from './TntModal';
import styles from './index.less'; import styles from './index.less';
interface CPwModalProps {
dispatch: Dispatch; const Setting = () => {
settingModel: any; const dispatch = useDispatch();
} const settingModel = useSelector((state: any) => state.settingModel);
const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => {
// const [llm_factory, set_llm_factory] = useState('')
const { t } = useTranslation(); const { t } = useTranslation();
const userInfo = authorizationUtil.getUserInfoObject(); const userInfo = authorizationUtil.getUserInfoObject();
const changeLang = (val: string) => { const changeLang = (val: string) => {
// 改变状态里的 语言 进行切换 // 改变状态里的 语言 进行切换
i18n.changeLanguage(val); i18n.changeLanguage(val);
}; };
useEffect(() => { useEffect(() => {
dispatch({ dispatch({
type: 'settingModel/getTenantInfo', type: 'settingModel/getTenantInfo',
payload: {}, payload: {},
}); });
}, []); }, []);
const showCPwModal = () => { const showCPwModal = () => {
dispatch({ dispatch({
type: 'settingModel/updateState', type: 'settingModel/updateState',
@ -52,11 +53,6 @@ const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => {
isShowSSModal: true, isShowSSModal: true,
}, },
}); });
// dispatch({
// type: 'settingModel/getTenantInfo',
// payload: {
// }
// });
}; };
return ( return (
<div className={styles.settingPage}> <div className={styles.settingPage}>
@ -99,7 +95,4 @@ const Index: FC<CPwModalProps> = ({ settingModel, dispatch }) => {
</div> </div>
); );
}; };
export default connect(({ settingModel, loading }) => ({ export default Setting;
settingModel,
loading,
}))(Index);

View File

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

View File

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

View File

@ -12,9 +12,9 @@ export function lastWeek() {
return formatDate(moment().subtract(1, 'weeks')); return formatDate(moment().subtract(1, 'weeks'));
} }
export function formatDate(date) { export function formatDate(date: any) {
if (!date) { if (!date) {
return ''; 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({ const request: RequestMethod = extend({
errorHandler, // 默认错误处理 errorHandler, // 默认错误处理
timeout: 3000000, timeout: 300000,
getResponse: true, getResponse: true,
}); });