add file
This commit is contained in:
parent
6f1c5d6ef5
commit
e0b6261596
15 changed files with 289 additions and 180 deletions
7
client/package-lock.json
generated
7
client/package-lock.json
generated
|
|
@ -19,6 +19,7 @@
|
||||||
"umi-request": "^1.4.0"
|
"umi-request": "^1.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/lodash": "^4.14.202",
|
||||||
"@types/react": "^18.0.33",
|
"@types/react": "^18.0.33",
|
||||||
"@types/react-dom": "^18.0.11",
|
"@types/react-dom": "^18.0.11",
|
||||||
"@umijs/plugins": "^4.1.0",
|
"@umijs/plugins": "^4.1.0",
|
||||||
|
|
@ -2557,6 +2558,12 @@
|
||||||
"resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="
|
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/lodash": {
|
||||||
|
"version": "4.14.202",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.202.tgz",
|
||||||
|
"integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/minimist": {
|
"node_modules/@types/minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/minimist/-/minimist-1.2.5.tgz",
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
"umi-request": "^1.4.0"
|
"umi-request": "^1.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/lodash": "^4.14.202",
|
||||||
"@types/react": "^18.0.33",
|
"@types/react": "^18.0.33",
|
||||||
"@types/react-dom": "^18.0.11",
|
"@types/react-dom": "^18.0.11",
|
||||||
"@umijs/plugins": "^4.1.0",
|
"@umijs/plugins": "^4.1.0",
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ const routes = [
|
||||||
name: '知识库',
|
name: '知识库',
|
||||||
icon: 'home',
|
icon: 'home',
|
||||||
auth: [3, 4, 100],
|
auth: [3, 4, 100],
|
||||||
path: '/knowledge/add',
|
path: '/knowledge/add/*',
|
||||||
component: '@/pages/add-knowledge',
|
component: '@/pages/add-knowledge',
|
||||||
pathname: 'knowledge',
|
pathname: 'knowledge',
|
||||||
// routes: [{
|
// routes: [{
|
||||||
|
|
|
||||||
BIN
client/src/assets/logo.png
Normal file
BIN
client/src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -3,19 +3,19 @@ import { history, Outlet, useLocation, useNavigate } from 'umi';
|
||||||
import { useTranslation, Trans } from 'react-i18next'
|
import { useTranslation, Trans } from 'react-i18next'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import '../locales/config';
|
import '../locales/config';
|
||||||
|
import logo from '@/assets/logo.png'
|
||||||
import {
|
import {
|
||||||
MenuFoldOutlined,
|
RedditOutlined
|
||||||
MenuUnfoldOutlined,
|
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { Layout, Button, theme, Space, } from 'antd';
|
import { Layout, Button, theme, Space, } from 'antd';
|
||||||
import styles from './index.less'
|
import styles from './index.less'
|
||||||
import User from './components/user'
|
import User from './components/user'
|
||||||
|
import { head } from 'lodash';
|
||||||
|
|
||||||
const { Header, Content } = Layout;
|
const { Header, Content } = Layout;
|
||||||
|
|
||||||
const App: React.FC = (props) => {
|
const App: React.FC = (props) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const {
|
const {
|
||||||
token: { colorBgContainer, borderRadiusLG },
|
token: { colorBgContainer, borderRadiusLG },
|
||||||
|
|
@ -40,17 +40,9 @@ const App: React.FC = (props) => {
|
||||||
return (
|
return (
|
||||||
<Layout className={styles.layout} >
|
<Layout className={styles.layout} >
|
||||||
<Layout>
|
<Layout>
|
||||||
<Header style={{ padding: 0, background: colorBgContainer, display: 'flex', justifyContent: 'space-between' }}>
|
<Header style={{ padding: '0 8px', background: colorBgContainer, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
<Button
|
|
||||||
type="text"
|
<img src={logo} alt="" style={{ height: 30, width: 30 }} />
|
||||||
icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
|
|
||||||
onClick={() => setCollapsed(!collapsed)}
|
|
||||||
style={{
|
|
||||||
fontSize: '16px',
|
|
||||||
width: 64,
|
|
||||||
height: 64,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Space size={[0, 8]} wrap>
|
<Space size={[0, 8]} wrap>
|
||||||
{tagsData.map((item) =>
|
{tagsData.map((item) =>
|
||||||
(<span key={item.name} className={classnames(styles['tag'], {
|
(<span key={item.name} className={classnames(styles['tag'], {
|
||||||
|
|
@ -65,7 +57,7 @@ const App: React.FC = (props) => {
|
||||||
<Content
|
<Content
|
||||||
style={{
|
style={{
|
||||||
margin: '24px 16px',
|
margin: '24px 16px',
|
||||||
padding: 24,
|
|
||||||
minHeight: 280,
|
minHeight: 280,
|
||||||
background: colorBgContainer,
|
background: colorBgContainer,
|
||||||
borderRadius: borderRadiusLG,
|
borderRadius: borderRadiusLG,
|
||||||
|
|
|
||||||
|
|
@ -11,4 +11,14 @@
|
||||||
.operate {
|
.operate {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.img {
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column {
|
||||||
|
min-width: 200px
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
import { Space, Table, Tag, Input, Button } from 'antd';
|
import { Space, Table, Tag, Input, Button, Switch, Popover, Dropdown, } from 'antd';
|
||||||
import { PlusOutlined } from '@ant-design/icons'
|
import type { MenuProps } from 'antd';
|
||||||
|
import { PlusOutlined, DownOutlined } from '@ant-design/icons'
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import type { ColumnsType } from 'antd/es/table';
|
import type { ColumnsType } from 'antd/es/table';
|
||||||
import styles from './idnex.less'
|
import styles from './idnex.less'
|
||||||
|
|
@ -10,57 +11,10 @@ interface DataType {
|
||||||
name: string;
|
name: string;
|
||||||
age: number;
|
age: number;
|
||||||
address: string;
|
address: string;
|
||||||
tags: string[];
|
status: boolean;
|
||||||
}
|
}
|
||||||
|
const onChangeStatus = () => { }
|
||||||
|
|
||||||
const columns: ColumnsType<DataType> = [
|
|
||||||
{
|
|
||||||
title: 'Name',
|
|
||||||
dataIndex: 'name',
|
|
||||||
key: 'name',
|
|
||||||
render: (text) => <a>{text}</a>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Age',
|
|
||||||
dataIndex: 'age',
|
|
||||||
key: 'age',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Address',
|
|
||||||
dataIndex: 'address',
|
|
||||||
key: 'address',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Tags',
|
|
||||||
key: 'tags',
|
|
||||||
dataIndex: 'tags',
|
|
||||||
render: (_, { tags }) => (
|
|
||||||
<>
|
|
||||||
{tags.map((tag) => {
|
|
||||||
let color = tag.length > 5 ? 'geekblue' : 'green';
|
|
||||||
if (tag === 'loser') {
|
|
||||||
color = 'volcano';
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Tag color={color} key={tag}>
|
|
||||||
{tag.toUpperCase()}
|
|
||||||
</Tag>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Action',
|
|
||||||
key: 'action',
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space size="middle">
|
|
||||||
<a>Invite {record.name}</a>
|
|
||||||
<a>Delete</a>
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const data: DataType[] = [
|
const data: DataType[] = [
|
||||||
{
|
{
|
||||||
|
|
@ -68,21 +22,62 @@ const data: DataType[] = [
|
||||||
name: 'John Brown',
|
name: 'John Brown',
|
||||||
age: 32,
|
age: 32,
|
||||||
address: 'New York No. 1 Lake Park',
|
address: 'New York No. 1 Lake Park',
|
||||||
tags: ['nice', 'developer'],
|
status: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: '2',
|
key: '2',
|
||||||
name: 'Jim Green',
|
name: 'Jim Green',
|
||||||
age: 42,
|
age: 42,
|
||||||
address: 'London No. 1 Lake Park',
|
address: 'London No. 1 Lake Park',
|
||||||
tags: ['loser'],
|
status: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: '3',
|
key: '3',
|
||||||
name: 'Joe Black',
|
name: 'Joe Black',
|
||||||
age: 32,
|
age: 32,
|
||||||
address: 'Sydney No. 1 Lake Park',
|
address: 'Sydney No. 1 Lake Park',
|
||||||
tags: ['cool', 'teacher'],
|
status: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '4',
|
||||||
|
name: 'John Brown',
|
||||||
|
age: 32,
|
||||||
|
address: 'New York No. 1 Lake Park',
|
||||||
|
status: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '5',
|
||||||
|
name: 'Jim Green',
|
||||||
|
age: 42,
|
||||||
|
address: 'London No. 1 Lake Park',
|
||||||
|
status: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '6',
|
||||||
|
name: 'Joe Black',
|
||||||
|
age: 32,
|
||||||
|
address: 'Sydney No. 1 Lake Park',
|
||||||
|
status: true,
|
||||||
|
}, {
|
||||||
|
key: '7',
|
||||||
|
name: 'John Brown',
|
||||||
|
age: 32,
|
||||||
|
address: 'New York No. 1 Lake Park',
|
||||||
|
status: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '8',
|
||||||
|
name: 'Jim Green',
|
||||||
|
age: 42,
|
||||||
|
address: 'London No. 1 Lake Park',
|
||||||
|
status: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '9',
|
||||||
|
name: 'Joe Black',
|
||||||
|
age: 32,
|
||||||
|
address: 'Sydney No. 1 Lake Park',
|
||||||
|
status: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -92,7 +87,6 @@ const App: React.FC = () => {
|
||||||
const changeValue = (value: string) => {
|
const changeValue = (value: string) => {
|
||||||
{
|
{
|
||||||
console.log(value)
|
console.log(value)
|
||||||
|
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -105,22 +99,88 @@ const App: React.FC = () => {
|
||||||
debounceCallback(e.target.value)
|
debounceCallback(e.target.value)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
const actionItems: MenuProps['items'] = [
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
label: (
|
||||||
|
<div>
|
||||||
|
<Button type="link">导入文件</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2',
|
||||||
|
label: (
|
||||||
|
<div>
|
||||||
|
<Button type="link"> 导入虚拟文件</Button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
// disabled: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const columns: ColumnsType<DataType> = [
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
render: (text) => <a><img className={styles.img} src='https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg' alt="" />{text}</a>,
|
||||||
|
className: `${styles.column}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '数据总量',
|
||||||
|
dataIndex: 'total',
|
||||||
|
key: 'total',
|
||||||
|
className: `${styles.column}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Tokens',
|
||||||
|
dataIndex: 'tokens',
|
||||||
|
key: 'tokens',
|
||||||
|
className: `${styles.column}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
key: 'status',
|
||||||
|
dataIndex: 'status',
|
||||||
|
className: `${styles.column}`,
|
||||||
|
render: (_, { status }) => (
|
||||||
|
<>
|
||||||
|
<Switch defaultChecked onChange={onChangeStatus} />
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Action',
|
||||||
|
key: 'action',
|
||||||
|
className: `${styles.column}`,
|
||||||
|
render: (_, record) => (
|
||||||
|
<Space size="middle">
|
||||||
|
<Dropdown menu={{ items: actionItems }}>
|
||||||
|
<a>
|
||||||
|
分段设置 <DownOutlined />
|
||||||
|
</a>
|
||||||
|
</Dropdown>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
return <>
|
return <>
|
||||||
<div className={styles.filter}>
|
<div className={styles.filter}>
|
||||||
<div className="search">
|
<div className="search">
|
||||||
<Input placeholder="搜索" value={inputValue} allowClear onChange={handleInputChange} />
|
<Input placeholder="搜索" value={inputValue} allowClear onChange={handleInputChange} />
|
||||||
</div>
|
</div>
|
||||||
<div className="operate">
|
<div className="operate">
|
||||||
<Button
|
<Dropdown menu={{ items: actionItems }}>
|
||||||
type="primary"
|
<a>
|
||||||
icon={<PlusOutlined />}
|
导入文件 <DownOutlined />
|
||||||
onClick={() => { }}
|
</a>
|
||||||
>
|
</Dropdown>
|
||||||
添加
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Table columns={columns} dataSource={data} loading={loading} />
|
<Table columns={columns} dataSource={data} loading={loading} pagination={false} scroll={{ scrollToFirstRowOnChange: true, x: true }} />
|
||||||
</>
|
</>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ const App: React.FC = () => {
|
||||||
{...layout}
|
{...layout}
|
||||||
name="nest-messages"
|
name="nest-messages"
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
style={{ maxWidth: 600 }}
|
style={{ maxWidth: 1000, padding: 14 }}
|
||||||
validateMessages={validateMessages}
|
validateMessages={validateMessages}
|
||||||
>
|
>
|
||||||
<Form.Item name={['user', 'name']} label="知识库名称" rules={[{ required: true }]}>
|
<Form.Item name={['user', 'name']} label="知识库名称" rules={[{ required: true }]}>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,19 @@
|
||||||
.tab {
|
.container {
|
||||||
:global {
|
display: flex;
|
||||||
.ant-tabs-tabpane {
|
|
||||||
margin: 20px;
|
.menu {
|
||||||
|
.defaultWidth {
|
||||||
|
width: 256px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.minWidth {
|
||||||
|
width: 50px
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-x: auto;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useMemo, useState, useEffect } from 'react';
|
||||||
import type { RadioChangeEvent } from 'antd';
|
import type { MenuProps } from 'antd';
|
||||||
import { Radio, Space, Tabs } from 'antd';
|
import { Radio, Space, Tabs, Menu } from 'antd';
|
||||||
import {
|
import {
|
||||||
ToolOutlined,
|
ToolOutlined,
|
||||||
BarsOutlined,
|
BarsOutlined,
|
||||||
|
|
@ -10,40 +10,78 @@ import File from './components/knowledge-file'
|
||||||
import Setting from './components/knowledge-setting'
|
import Setting from './components/knowledge-setting'
|
||||||
import Search from './components/knowledge-search'
|
import Search from './components/knowledge-search'
|
||||||
import styles from './index.less'
|
import styles from './index.less'
|
||||||
|
import { getWidth } from '@/utils'
|
||||||
|
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
type keyType = 'setting' | 'file' | 'search'
|
const [activeKey, setActiveKey] = useState<string>('file')
|
||||||
const [activeKey, setActiveKey] = useState<keyType>('file')
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
// type tab = { label: string, icon: Element, tag: string }
|
const [windowWidth, setWindowWidth] = useState(getWidth());
|
||||||
const tabs = [{ label: '配置', icon: <ToolOutlined />, tag: 'setting' }, { label: '知识库', icon: <BarsOutlined />, tag: 'file' }, { label: '搜索测试', icon: <SearchOutlined />, tag: 'search' }]
|
|
||||||
|
|
||||||
const onTabClick = (activeKey: keyType) => {
|
// 标记一下
|
||||||
setActiveKey(activeKey)
|
useEffect(() => {
|
||||||
|
const widthSize = () => {
|
||||||
|
const width = getWidth()
|
||||||
|
console.log(width)
|
||||||
|
|
||||||
|
setWindowWidth(width);
|
||||||
|
};
|
||||||
|
window.addEventListener("resize", widthSize);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("resize", widthSize);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
if (windowWidth.width > 957) {
|
||||||
|
setCollapsed(false)
|
||||||
|
} else {
|
||||||
|
setCollapsed(true)
|
||||||
|
}
|
||||||
|
}, [windowWidth.width])
|
||||||
|
type MenuItem = Required<MenuProps>['items'][number];
|
||||||
|
|
||||||
|
function getItem(
|
||||||
|
label: React.ReactNode,
|
||||||
|
key: React.Key,
|
||||||
|
icon?: React.ReactNode,
|
||||||
|
children?: MenuItem[],
|
||||||
|
type?: 'group',
|
||||||
|
): MenuItem {
|
||||||
|
return {
|
||||||
|
key,
|
||||||
|
icon,
|
||||||
|
children,
|
||||||
|
label,
|
||||||
|
type,
|
||||||
|
} as MenuItem;
|
||||||
}
|
}
|
||||||
// type stringKey = Record<string, Element>
|
const items: MenuItem[] = [
|
||||||
|
getItem('配置', 'setting', <ToolOutlined />),
|
||||||
const mapComponent = {
|
getItem('知识库', 'file', <BarsOutlined />),
|
||||||
file: <File />,
|
getItem('搜索测试', 'search', <SearchOutlined />),
|
||||||
setting: <Setting />,
|
];
|
||||||
search: <Search />
|
const handleSelect: MenuProps['onSelect'] = (e) => {
|
||||||
|
setActiveKey(e.key)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tabs
|
<div className={styles.container}>
|
||||||
tabPosition='left'
|
<div className={styles.menu}>
|
||||||
activeKey={activeKey}
|
<Menu
|
||||||
onTabClick={(activeKey: keyType, e: KeyboardEvent<Element> | MouseEvent<Element, MouseEvent>) => { onTabClick(activeKey) }}
|
selectedKeys={[activeKey]}
|
||||||
className={styles.tab}
|
mode="inline"
|
||||||
items={tabs.map((item) => {
|
className={windowWidth.width > 957 ? styles.defaultWidth : styles.minWidth}
|
||||||
return {
|
inlineCollapsed={collapsed}
|
||||||
label: item.label,
|
items={items}
|
||||||
icon: item.icon,
|
onSelect={handleSelect}
|
||||||
key: item.tag,
|
/>
|
||||||
children: mapComponent[activeKey] as Element,
|
</div>
|
||||||
};
|
<div className={styles.content}>
|
||||||
})}
|
{activeKey === 'file' && <File />}
|
||||||
/>
|
{activeKey === 'setting' && <Setting />}
|
||||||
|
{activeKey === 'search' && <Search />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
.knowledge {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
height: 100px;
|
height: 100px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -28,6 +32,8 @@
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState, } from 'react';
|
import React, { useState, } from 'react';
|
||||||
import { useNavigate } from 'umi'
|
import { useNavigate } from 'umi'
|
||||||
import { Card, List, Popconfirm, message, FloatButton } from 'antd';
|
import { Card, List, Popconfirm, message, FloatButton, Row, Col } from 'antd';
|
||||||
import { MinusSquareOutlined, DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
import { MinusSquareOutlined, DeleteOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
import styles from './index.less'
|
import styles from './index.less'
|
||||||
|
|
||||||
|
|
@ -41,47 +41,52 @@ const App: React.FC = () => {
|
||||||
};
|
};
|
||||||
const handleAddKnowledge = () => {
|
const handleAddKnowledge = () => {
|
||||||
// setDatas((datas) => [...datas, ...dd])
|
// setDatas((datas) => [...datas, ...dd])
|
||||||
navigate('add');
|
navigate('add/file');
|
||||||
}
|
}
|
||||||
return (<><FloatButton onClick={handleAddKnowledge} icon={<PlusOutlined />} type="primary" style={{ right: 24, top: 100 }} />
|
|
||||||
<List
|
|
||||||
grid={{ gutter: 16, column: 4 }}
|
|
||||||
dataSource={datas}
|
|
||||||
renderItem={(item, index) => (
|
|
||||||
<List.Item>
|
|
||||||
<Card className={styles.card}>
|
|
||||||
<div className={styles.container}>
|
|
||||||
<div className={styles.content}>
|
|
||||||
<span className={styles.context}>
|
|
||||||
content
|
|
||||||
</span>
|
|
||||||
<span className={styles.delete}>
|
|
||||||
<Popconfirm
|
|
||||||
title="Delete the task"
|
|
||||||
description="Are you sure to delete this task?"
|
|
||||||
onConfirm={() => { confirm(index) }}
|
|
||||||
okText="Yes"
|
|
||||||
cancelText="No"
|
|
||||||
>
|
|
||||||
<DeleteOutlined />
|
|
||||||
</Popconfirm>
|
|
||||||
|
|
||||||
</span>
|
return (<>
|
||||||
</div>
|
<div className={styles.knowledge}>
|
||||||
<div className={styles.footer}>
|
<FloatButton onClick={handleAddKnowledge} icon={<PlusOutlined />} type="primary" style={{ right: 24, top: 100 }} />
|
||||||
<span className={styles.text}>
|
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}>
|
||||||
<MinusSquareOutlined />{item.text}
|
{
|
||||||
</span>
|
data.map((item, index) => {
|
||||||
<span className={styles.text}>
|
return (<Col className="gutter-row" key={item.title} xs={24} sm={12} md={8} lg={6}>
|
||||||
<MinusSquareOutlined />{item.des}
|
<Card className={styles.card}>
|
||||||
</span>
|
<div className={styles.container}>
|
||||||
</div>
|
<div className={styles.content}>
|
||||||
|
<span className={styles.context}>
|
||||||
|
content
|
||||||
|
</span>
|
||||||
|
<span className={styles.delete}>
|
||||||
|
<Popconfirm
|
||||||
|
title="Delete the task"
|
||||||
|
description="Are you sure to delete this task?"
|
||||||
|
onConfirm={() => { confirm(index) }}
|
||||||
|
okText="Yes"
|
||||||
|
cancelText="No"
|
||||||
|
>
|
||||||
|
<DeleteOutlined />
|
||||||
|
</Popconfirm>
|
||||||
|
|
||||||
</div>
|
</span>
|
||||||
</Card>
|
</div>
|
||||||
</List.Item>
|
<div className={styles.footer}>
|
||||||
)}
|
<span className={styles.text}>
|
||||||
/></>
|
<MinusSquareOutlined />{item.text}
|
||||||
|
</span>
|
||||||
|
<span className={styles.text}>
|
||||||
|
<MinusSquareOutlined />{item.des}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Col>)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import store from '@/utils/persistStore';
|
|
||||||
import { addParam } from '@/utils';
|
import { addParam } from '@/utils';
|
||||||
import loginService from '@/services/loginService';
|
import loginService from '@/services/loginService';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,32 +2,7 @@ import { debounce } from 'lodash';
|
||||||
import semver from 'semver';
|
import semver from 'semver';
|
||||||
import merge from 'lodash/merge';
|
import merge from 'lodash/merge';
|
||||||
import isPlainObject from 'lodash/isPlainObject';
|
import isPlainObject from 'lodash/isPlainObject';
|
||||||
/**
|
|
||||||
* 统一localStorage存储管理器
|
|
||||||
*
|
|
||||||
* 参数说明:
|
|
||||||
* lazy: boolean 是否懒加载,未开启懒加载在初始化时就读取localstorage,开启懒加载将在第一次获取或设置值时读取localstorage
|
|
||||||
* namespace: string localstorage的key,定义多个manager时区分
|
|
||||||
* version: string 'x.x.x'格式,采用语义化版本控制,用于重置用户设备中的localstorage
|
|
||||||
*
|
|
||||||
* 使用说明:
|
|
||||||
* 创建一个初始结构,可用来初始化用户存储,或者重置用户存储, 格式类似于redux里的state
|
|
||||||
* const store = {
|
|
||||||
* token: '',
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* 创建manager对象, 此处传入version便于标明版本号,方便后续升级重置用户数据
|
|
||||||
* const manager = new StorageManager(store, { version: '0.0.0' });
|
|
||||||
*
|
|
||||||
* 直接设置属性,将存入localstorage, 多次设置只会存入最后的值,此处使用debounce减少io操作
|
|
||||||
* manager.token = '123456'
|
|
||||||
* manager.token = '123'
|
|
||||||
* manager.token = '456'
|
|
||||||
*
|
|
||||||
* 直接读取值,获取到的的localstorage中的值
|
|
||||||
* console.log(manager.token)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class StorageManager {
|
class StorageManager {
|
||||||
constructor(store, options) {
|
constructor(store, options) {
|
||||||
options = Object.assign(
|
options = Object.assign(
|
||||||
|
|
|
||||||
|
|
@ -147,9 +147,13 @@ export const formatRequestUrlByDomainPrefix = url => {
|
||||||
}
|
}
|
||||||
return `${prefix}${url}`;
|
return `${prefix}${url}`;
|
||||||
};
|
};
|
||||||
|
export const getWidth = () => {
|
||||||
|
return { width: window.innerWidth };
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
parseQuery,
|
parseQuery,
|
||||||
downloadWithIframe,
|
downloadWithIframe,
|
||||||
formatRequestUrlByDomainPrefix
|
formatRequestUrlByDomainPrefix,
|
||||||
|
getWidth
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue