* 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
| return parserList; | return parserList; | ||||
| }; | }; | ||||
| export const useLogout = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const logout = useCallback((): number => { | |||||
| return dispatch<any>({ type: 'loginModel/logout' }); | |||||
| }, [dispatch]); | |||||
| return logout; | |||||
| }; |
| import { useFetchUserInfo, useSelectUserInfo } from '@/hooks/userSettingHook'; | |||||
| import { | |||||
| useFetchUserInfo, | |||||
| useLogout, | |||||
| useSelectUserInfo, | |||||
| } from '@/hooks/userSettingHook'; | |||||
| import authorizationUtil from '@/utils/authorizationUtil'; | import authorizationUtil from '@/utils/authorizationUtil'; | ||||
| import type { MenuProps } from 'antd'; | import type { MenuProps } from 'antd'; | ||||
| import { Avatar, Button, Dropdown } 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 { useTranslation } from 'react-i18next'; | ||||
| import { history } from 'umi'; | import { history } from 'umi'; | ||||
| const App: React.FC = () => { | const App: React.FC = () => { | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const userInfo = useSelectUserInfo(); | 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 = () => { | const toSetting = () => { | ||||
| history.push('/setting'); | history.push('/setting'); | ||||
| return [ | return [ | ||||
| { | { | ||||
| key: '1', | key: '1', | ||||
| onClick: logout, | |||||
| onClick: handleLogout, | |||||
| label: <Button type="text">{t('header.logout')}</Button>, | label: <Button type="text">{t('header.logout')}</Button>, | ||||
| }, | }, | ||||
| { | { | ||||
| label: <Button type="text">{t('header.setting')}</Button>, | label: <Button type="text">{t('header.setting')}</Button>, | ||||
| }, | }, | ||||
| ]; | ]; | ||||
| }, [t]); | |||||
| }, [t, handleLogout]); | |||||
| useFetchUserInfo(); | useFetchUserInfo(); | ||||
| .chunkText; | .chunkText; | ||||
| } | } | ||||
| .chunkCard { | |||||
| width: 100%; | |||||
| } | |||||
| .cardSelected { | .cardSelected { | ||||
| background-color: @selectedBackgroundColor; | background-color: @selectedBackgroundColor; | ||||
| } | } |
| import Image from '@/components/image'; | import Image from '@/components/image'; | ||||
| import { IChunk } from '@/interfaces/database/knowledge'; | import { IChunk } from '@/interfaces/database/knowledge'; | ||||
| import { Card, Checkbox, CheckboxProps, Flex, Popover, Switch } from 'antd'; | import { Card, Checkbox, CheckboxProps, Flex, Popover, Switch } from 'antd'; | ||||
| import classNames from 'classnames'; | |||||
| import { useState } from 'react'; | import { useState } from 'react'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| interface IProps { | interface IProps { | ||||
| }; | }; | ||||
| return ( | 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> | |||||
| ); | ); | ||||
| }; | }; | ||||
| justify-content: space-between; | justify-content: space-between; | ||||
| } | } | ||||
| .pagePdfWrapper { | |||||
| width: 60%; | |||||
| } | |||||
| .pageContent { | .pageContent { | ||||
| flex: 1; | flex: 1; | ||||
| width: 100%; | width: 100%; | ||||
| } | } | ||||
| .chunkContainer { | .chunkContainer { | ||||
| height: calc(100vh - 320px); | |||||
| overflow: auto; | |||||
| width: 100%; | |||||
| height: calc(100vh - 332px); | |||||
| } | } | ||||
| .pageFooter { | .pageFooter { | ||||
| padding-top: 10px; | |||||
| height: 32px; | height: 32px; | ||||
| } | } | ||||
| } | } |
| const { removeChunk } = useDeleteChunkByIds(); | const { removeChunk } = useDeleteChunkByIds(); | ||||
| const documentInfo = useSelectDocumentInfo(); | const documentInfo = useSelectDocumentInfo(); | ||||
| const { handleChunkCardClick, selectedChunkId } = useHandleChunkCardClick(); | const { handleChunkCardClick, selectedChunkId } = useHandleChunkCardClick(); | ||||
| const isPdf = documentInfo.type === 'pdf'; | |||||
| const getChunkList = useCallback(() => { | const getChunkList = useCallback(() => { | ||||
| const payload: PayloadType = { | const payload: PayloadType = { | ||||
| ></ChunkToolBar> | ></ChunkToolBar> | ||||
| <Divider></Divider> | <Divider></Divider> | ||||
| <Flex flex={1} gap={'middle'}> | <Flex flex={1} gap={'middle'}> | ||||
| <Flex flex={1} vertical> | |||||
| <Flex vertical className={isPdf ? styles.pagePdfWrapper : ''}> | |||||
| <div className={styles.pageContent}> | <div className={styles.pageContent}> | ||||
| <Spin spinning={loading} className={styles.spin} size="large"> | <Spin spinning={loading} className={styles.spin} size="large"> | ||||
| <Space | <Space | ||||
| </div> | </div> | ||||
| </Flex> | </Flex> | ||||
| {documentInfo.type === 'pdf' && ( | |||||
| {isPdf && ( | |||||
| <section className={styles.documentPreview}> | <section className={styles.documentPreview}> | ||||
| <DocumentPreview | <DocumentPreview | ||||
| selectedChunkId={selectedChunkId} | selectedChunkId={selectedChunkId} |
| <Flex vertical gap={8} flex={1}> | <Flex vertical gap={8} flex={1}> | ||||
| <b>{isAssistant ? '' : userInfo.nickname}</b> | <b>{isAssistant ? '' : userInfo.nickname}</b> | ||||
| <div className={styles.messageText}> | <div className={styles.messageText}> | ||||
| {item.content ? ( | |||||
| {item.content !== '' ? ( | |||||
| <Markdown | <Markdown | ||||
| rehypePlugins={[rehypeWrapReference]} | rehypePlugins={[rehypeWrapReference]} | ||||
| components={ | components={ |
| }; | }; | ||||
| }, | }, | ||||
| }, | }, | ||||
| subscriptions: { | |||||
| setup({ dispatch, history }) { | |||||
| history.listen((location) => {}); | |||||
| }, | |||||
| }, | |||||
| effects: { | effects: { | ||||
| *login({ payload = {} }, { call, put }) { | |||||
| *login({ payload = {} }, { call }) { | |||||
| const { data, response } = yield call(userService.login, payload); | const { data, response } = yield call(userService.login, payload); | ||||
| const { retcode, data: res } = data; | const { retcode, data: res } = data; | ||||
| const authorization = response.headers.get(Authorization); | const authorization = response.headers.get(Authorization); | ||||
| if (retcode === 0) { | if (retcode === 0) { | ||||
| message.success('登录成功!'); | |||||
| message.success('logged!'); | |||||
| const token = res.access_token; | const token = res.access_token; | ||||
| const userInfo = { | const userInfo = { | ||||
| avatar: res.avatar, | avatar: res.avatar, | ||||
| } | } | ||||
| return retcode; | 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(); | console.log(); | ||||
| const { retcode, data: res, retmsg } = data; | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | if (retcode === 0) { | ||||
| message.success('注册成功!'); | message.success('注册成功!'); | ||||
| } | } | ||||
| return retcode; | 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; | export default model; |
| const { | const { | ||||
| login, | login, | ||||
| logout, | |||||
| register, | register, | ||||
| setting, | setting, | ||||
| user_info, | user_info, | ||||
| url: login, | url: login, | ||||
| method: 'post', | method: 'post', | ||||
| }, | }, | ||||
| logout: { | |||||
| url: logout, | |||||
| method: 'get', | |||||
| }, | |||||
| register: { | register: { | ||||
| url: register, | url: register, | ||||
| method: 'post', | method: 'post', |
| export default { | export default { | ||||
| // 用户 | // 用户 | ||||
| login: `${api_host}/user/login`, | login: `${api_host}/user/login`, | ||||
| logout: `${api_host}/user/logout`, | |||||
| register: `${api_host}/user/register`, | register: `${api_host}/user/register`, | ||||
| setting: `${api_host}/user/setting`, | setting: `${api_host}/user/setting`, | ||||
| user_info: `${api_host}/user/info`, | user_info: `${api_host}/user/info`, |