* feat: logout * feat: fixed the issue that some PDF documents could not be displayed on the chunk list page in small screenstags/v0.1.0
| @@ -64,3 +64,13 @@ export const useSelectParserList = (): Array<{ | |||
| return parserList; | |||
| }; | |||
| export const useLogout = () => { | |||
| const dispatch = useDispatch(); | |||
| const logout = useCallback((): number => { | |||
| return dispatch<any>({ type: 'loginModel/logout' }); | |||
| }, [dispatch]); | |||
| return logout; | |||
| }; | |||
| @@ -1,19 +1,27 @@ | |||
| import { useFetchUserInfo, useSelectUserInfo } from '@/hooks/userSettingHook'; | |||
| import { | |||
| useFetchUserInfo, | |||
| useLogout, | |||
| useSelectUserInfo, | |||
| } from '@/hooks/userSettingHook'; | |||
| import authorizationUtil from '@/utils/authorizationUtil'; | |||
| import type { MenuProps } from 'antd'; | |||
| import { Avatar, Button, Dropdown } from 'antd'; | |||
| import React, { useMemo } from 'react'; | |||
| import React, { useCallback, useMemo } from 'react'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { history } from 'umi'; | |||
| const App: React.FC = () => { | |||
| const { t } = useTranslation(); | |||
| const userInfo = useSelectUserInfo(); | |||
| const logout = useLogout(); | |||
| const logout = () => { | |||
| authorizationUtil.removeAll(); | |||
| history.push('/login'); | |||
| }; | |||
| const handleLogout = useCallback(async () => { | |||
| const retcode = await logout(); | |||
| if (retcode === 0) { | |||
| authorizationUtil.removeAll(); | |||
| history.push('/login'); | |||
| } | |||
| }, [logout]); | |||
| const toSetting = () => { | |||
| history.push('/setting'); | |||
| @@ -23,7 +31,7 @@ const App: React.FC = () => { | |||
| return [ | |||
| { | |||
| key: '1', | |||
| onClick: logout, | |||
| onClick: handleLogout, | |||
| label: <Button type="text">{t('header.logout')}</Button>, | |||
| }, | |||
| { | |||
| @@ -32,7 +40,7 @@ const App: React.FC = () => { | |||
| label: <Button type="text">{t('header.setting')}</Button>, | |||
| }, | |||
| ]; | |||
| }, [t]); | |||
| }, [t, handleLogout]); | |||
| useFetchUserInfo(); | |||
| @@ -12,6 +12,10 @@ | |||
| .chunkText; | |||
| } | |||
| .chunkCard { | |||
| width: 100%; | |||
| } | |||
| .cardSelected { | |||
| background-color: @selectedBackgroundColor; | |||
| } | |||
| @@ -1,7 +1,9 @@ | |||
| import Image from '@/components/image'; | |||
| import { IChunk } from '@/interfaces/database/knowledge'; | |||
| import { Card, Checkbox, CheckboxProps, Flex, Popover, Switch } from 'antd'; | |||
| import classNames from 'classnames'; | |||
| import { useState } from 'react'; | |||
| import styles from './index.less'; | |||
| interface IProps { | |||
| @@ -44,33 +46,35 @@ const ChunkCard = ({ | |||
| }; | |||
| return ( | |||
| <div> | |||
| <Card className={selected ? styles.cardSelected : ''}> | |||
| <Flex gap={'middle'} justify={'space-between'}> | |||
| <Checkbox onChange={handleCheck} checked={checked}></Checkbox> | |||
| {item.img_id && ( | |||
| <Popover | |||
| placement="topRight" | |||
| content={ | |||
| <Image id={item.img_id} className={styles.imagePreview}></Image> | |||
| } | |||
| > | |||
| <Image id={item.img_id} className={styles.image}></Image> | |||
| </Popover> | |||
| )} | |||
| <Card | |||
| className={classNames(styles.chunkCard, { | |||
| [styles.cardSelected]: selected, | |||
| })} | |||
| > | |||
| <Flex gap={'middle'} justify={'space-between'}> | |||
| <Checkbox onChange={handleCheck} checked={checked}></Checkbox> | |||
| {item.img_id && ( | |||
| <Popover | |||
| placement="topRight" | |||
| content={ | |||
| <Image id={item.img_id} className={styles.imagePreview}></Image> | |||
| } | |||
| > | |||
| <Image id={item.img_id} className={styles.image}></Image> | |||
| </Popover> | |||
| )} | |||
| <section | |||
| onDoubleClick={handleContentDoubleClick} | |||
| onClick={handleContentClick} | |||
| className={styles.content} | |||
| dangerouslySetInnerHTML={{ __html: item.content_with_weight }} | |||
| ></section> | |||
| <div> | |||
| <Switch checked={enabled} onChange={onChange} /> | |||
| </div> | |||
| </Flex> | |||
| </Card> | |||
| </div> | |||
| <section | |||
| onDoubleClick={handleContentDoubleClick} | |||
| onClick={handleContentClick} | |||
| className={styles.content} | |||
| dangerouslySetInnerHTML={{ __html: item.content_with_weight }} | |||
| ></section> | |||
| <div> | |||
| <Switch checked={enabled} onChange={onChange} /> | |||
| </div> | |||
| </Flex> | |||
| </Card> | |||
| ); | |||
| }; | |||
| @@ -12,6 +12,10 @@ | |||
| justify-content: space-between; | |||
| } | |||
| .pagePdfWrapper { | |||
| width: 60%; | |||
| } | |||
| .pageContent { | |||
| flex: 1; | |||
| width: 100%; | |||
| @@ -29,12 +33,11 @@ | |||
| } | |||
| .chunkContainer { | |||
| height: calc(100vh - 320px); | |||
| overflow: auto; | |||
| width: 100%; | |||
| height: calc(100vh - 332px); | |||
| } | |||
| .pageFooter { | |||
| padding-top: 10px; | |||
| height: 32px; | |||
| } | |||
| } | |||
| @@ -38,6 +38,7 @@ const Chunk = () => { | |||
| const { removeChunk } = useDeleteChunkByIds(); | |||
| const documentInfo = useSelectDocumentInfo(); | |||
| const { handleChunkCardClick, selectedChunkId } = useHandleChunkCardClick(); | |||
| const isPdf = documentInfo.type === 'pdf'; | |||
| const getChunkList = useCallback(() => { | |||
| const payload: PayloadType = { | |||
| @@ -164,7 +165,7 @@ const Chunk = () => { | |||
| ></ChunkToolBar> | |||
| <Divider></Divider> | |||
| <Flex flex={1} gap={'middle'}> | |||
| <Flex flex={1} vertical> | |||
| <Flex vertical className={isPdf ? styles.pagePdfWrapper : ''}> | |||
| <div className={styles.pageContent}> | |||
| <Spin spinning={loading} className={styles.spin} size="large"> | |||
| <Space | |||
| @@ -204,7 +205,7 @@ const Chunk = () => { | |||
| </div> | |||
| </Flex> | |||
| {documentInfo.type === 'pdf' && ( | |||
| {isPdf && ( | |||
| <section className={styles.documentPreview}> | |||
| <DocumentPreview | |||
| selectedChunkId={selectedChunkId} | |||
| @@ -177,7 +177,7 @@ const MessageItem = ({ | |||
| <Flex vertical gap={8} flex={1}> | |||
| <b>{isAssistant ? '' : userInfo.nickname}</b> | |||
| <div className={styles.messageText}> | |||
| {item.content ? ( | |||
| {item.content !== '' ? ( | |||
| <Markdown | |||
| rehypePlugins={[rehypeWrapReference]} | |||
| components={ | |||
| @@ -25,18 +25,13 @@ const model: DvaModel<LoginModelState> = { | |||
| }; | |||
| }, | |||
| }, | |||
| subscriptions: { | |||
| setup({ dispatch, history }) { | |||
| history.listen((location) => {}); | |||
| }, | |||
| }, | |||
| effects: { | |||
| *login({ payload = {} }, { call, put }) { | |||
| *login({ payload = {} }, { call }) { | |||
| const { data, response } = yield call(userService.login, payload); | |||
| const { retcode, data: res } = data; | |||
| const authorization = response.headers.get(Authorization); | |||
| if (retcode === 0) { | |||
| message.success('登录成功!'); | |||
| message.success('logged!'); | |||
| const token = res.access_token; | |||
| const userInfo = { | |||
| avatar: res.avatar, | |||
| @@ -51,15 +46,23 @@ const model: DvaModel<LoginModelState> = { | |||
| } | |||
| return retcode; | |||
| }, | |||
| *register({ payload = {} }, { call, put }) { | |||
| const { data, response } = yield call(userService.register, payload); | |||
| *register({ payload = {} }, { call }) { | |||
| const { data } = yield call(userService.register, payload); | |||
| console.log(); | |||
| const { retcode, data: res, retmsg } = data; | |||
| const { retcode } = data; | |||
| if (retcode === 0) { | |||
| message.success('注册成功!'); | |||
| } | |||
| return retcode; | |||
| }, | |||
| *logout({ payload = {} }, { call }) { | |||
| const { data } = yield call(userService.logout, payload); | |||
| const { retcode } = data; | |||
| if (retcode === 0) { | |||
| message.success('logout'); | |||
| } | |||
| return retcode; | |||
| }, | |||
| }, | |||
| }; | |||
| export default model; | |||
| @@ -4,6 +4,7 @@ import request from '@/utils/request'; | |||
| const { | |||
| login, | |||
| logout, | |||
| register, | |||
| setting, | |||
| user_info, | |||
| @@ -20,6 +21,10 @@ const methods = { | |||
| url: login, | |||
| method: 'post', | |||
| }, | |||
| logout: { | |||
| url: logout, | |||
| method: 'get', | |||
| }, | |||
| register: { | |||
| url: register, | |||
| method: 'post', | |||
| @@ -5,6 +5,7 @@ export { api_host }; | |||
| export default { | |||
| // 用户 | |||
| login: `${api_host}/user/login`, | |||
| logout: `${api_host}/user/logout`, | |||
| register: `${api_host}/user/register`, | |||
| setting: `${api_host}/user/setting`, | |||
| user_info: `${api_host}/user/info`, | |||