From 877aab858be9fbd1b3871eea0aeb34a54ccf3b01 Mon Sep 17 00:00:00 2001
From: archer <545436317@qq.com>
Date: Fri, 14 Jul 2023 18:27:08 +0800
Subject: [PATCH] fix: phone ui
---
client/src/components/ChatBox/index.tsx | 20 +-
.../src/components/Icon/icons/file/html.svg | 1 +
.../components/Icon/icons/file/markdown.svg | 1 +
client/src/components/Icon/icons/file/pdf.svg | 1 +
client/src/components/Icon/index.tsx | 5 +-
client/src/components/Layout/index.tsx | 59 +++---
client/src/pages/_app.tsx | 3 +-
.../src/pages/chat/components/ChatHeader.tsx | 60 ++++++
.../chat/components/ChatHistorySlider.tsx | 30 ++-
.../src/pages/chat/components/SliderApps.tsx | 2 +-
client/src/pages/chat/components/ToolMenu.tsx | 33 +++-
client/src/pages/chat/index.tsx | 72 +++-----
client/src/pages/chat/share.tsx | 172 +++++++-----------
client/src/store/chat.ts | 10 +-
14 files changed, 259 insertions(+), 210 deletions(-)
create mode 100644 client/src/components/Icon/icons/file/html.svg
create mode 100644 client/src/components/Icon/icons/file/markdown.svg
create mode 100644 client/src/components/Icon/icons/file/pdf.svg
create mode 100644 client/src/pages/chat/components/ChatHeader.tsx
diff --git a/client/src/components/ChatBox/index.tsx b/client/src/components/ChatBox/index.tsx
index 5946ce462..353833a03 100644
--- a/client/src/components/ChatBox/index.tsx
+++ b/client/src/components/ChatBox/index.tsx
@@ -312,8 +312,8 @@ const ChatBox = (
};
const controlContainerStyle = {
className: 'control',
- display: isChatting ? 'none' : ['flex', 'none'],
color: 'myGray.400',
+ display: ['flex', 'none'],
pl: 1,
mt: 2,
position: 'absolute' as any,
@@ -321,12 +321,17 @@ const ChatBox = (
w: '100%'
};
+ const hasVariableInput = useMemo(
+ () => variableModules || welcomeText,
+ [variableModules, welcomeText]
+ );
+
return (
-
-
+
+
{/* variable input */}
- {(variableModules || welcomeText) && (
+ {hasVariableInput && (
{/* avatar */}
)}
+ {/* empty guide */}
+
{/* chat history */}
-
+
{chatHistory.map((item, index) => (
{item.value}
-
+
+ {/* input */}
{variableIsFinish ? (
\ No newline at end of file
diff --git a/client/src/components/Icon/icons/file/markdown.svg b/client/src/components/Icon/icons/file/markdown.svg
new file mode 100644
index 000000000..bc4b63601
--- /dev/null
+++ b/client/src/components/Icon/icons/file/markdown.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/components/Icon/icons/file/pdf.svg b/client/src/components/Icon/icons/file/pdf.svg
new file mode 100644
index 000000000..3767414c6
--- /dev/null
+++ b/client/src/components/Icon/icons/file/pdf.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/components/Icon/index.tsx b/client/src/components/Icon/index.tsx
index ce3273654..0b4f730ff 100644
--- a/client/src/components/Icon/index.tsx
+++ b/client/src/components/Icon/index.tsx
@@ -51,7 +51,10 @@ const map = {
variable: require('./icons/modules/variable.svg').default,
setTop: require('./icons/light/setTop.svg').default,
fullScreenLight: require('./icons/light/fullScreen.svg').default,
- voice: require('./icons/voice.svg').default
+ voice: require('./icons/voice.svg').default,
+ html: require('./icons/file/html.svg').default,
+ pdf: require('./icons/file/pdf.svg').default,
+ markdown: require('./icons/file/markdown.svg').default
};
export type IconName = keyof typeof map;
diff --git a/client/src/components/Layout/index.tsx b/client/src/components/Layout/index.tsx
index f81c690c7..8a64c8147 100644
--- a/client/src/components/Layout/index.tsx
+++ b/client/src/components/Layout/index.tsx
@@ -63,34 +63,39 @@ const Layout = ({ children }: { children: JSX.Element }) => {
return (
<>
-
- {pcUnShowLayoutRoute[router.pathname] ? (
- {children}
- ) : (
- <>
-
-
-
-
+ {isPc ? (
+ <>
+ {pcUnShowLayoutRoute[router.pathname] ? (
+ {children}
+ ) : (
+ <>
+
+
+
+
+ {children}
+
+ >
+ )}
+ >
+ ) : (
+ <>
+
+ {phoneUnShowLayoutRoute[router.pathname] || isChatPage ? (
{children}
-
- >
- )}
-
-
- {phoneUnShowLayoutRoute[router.pathname] || isChatPage ? (
- {children}
- ) : (
-
-
- {children}
-
-
-
-
-
- )}
-
+ ) : (
+
+
+ {children}
+
+
+
+
+
+ )}
+
+ >
+ )}
>
diff --git a/client/src/pages/_app.tsx b/client/src/pages/_app.tsx
index 4f6617cb6..993c6421d 100644
--- a/client/src/pages/_app.tsx
+++ b/client/src/pages/_app.tsx
@@ -44,7 +44,7 @@ function App({ Component, pageProps }: AppProps) {
<>
Fast GPT
-
+
- {/* @ts-ignore */}
diff --git a/client/src/pages/chat/components/ChatHeader.tsx b/client/src/pages/chat/components/ChatHeader.tsx
new file mode 100644
index 000000000..44bbc8f44
--- /dev/null
+++ b/client/src/pages/chat/components/ChatHeader.tsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import { Flex, useTheme, Box } from '@chakra-ui/react';
+import { useGlobalStore } from '@/store/global';
+import MyIcon from '@/components/Icon';
+import Tag from '@/components/Tag';
+import Avatar from '@/components/Avatar';
+import ToolMenu from './ToolMenu';
+import { ChatItemType } from '@/types/chat';
+
+const ChatHeader = ({
+ title,
+ history,
+ appAvatar,
+ onOpenSlider
+}: {
+ title: string;
+ history: ChatItemType[];
+ appAvatar: string;
+ onOpenSlider: () => void;
+}) => {
+ const theme = useTheme();
+ const { isPc } = useGlobalStore();
+ return (
+
+ {isPc ? (
+ <>
+
+ {title}
+
+
+
+ {history.length}条记录
+
+
+ >
+ ) : (
+ <>
+
+
+
+
+ {title}
+
+
+ >
+ )}
+ {/* control */}
+
+
+ );
+};
+
+export default ChatHeader;
diff --git a/client/src/pages/chat/components/ChatHistorySlider.tsx b/client/src/pages/chat/components/ChatHistorySlider.tsx
index c4223c465..f3c21c05e 100644
--- a/client/src/pages/chat/components/ChatHistorySlider.tsx
+++ b/client/src/pages/chat/components/ChatHistorySlider.tsx
@@ -7,7 +7,8 @@ import {
Menu,
MenuButton,
MenuList,
- MenuItem
+ MenuItem,
+ IconButton
} from '@chakra-ui/react';
import { useGlobalStore } from '@/store/global';
import { useRouter } from 'next/router';
@@ -29,8 +30,7 @@ const ChatHistorySlider = ({
activeHistoryId,
onChangeChat,
onDelHistory,
- onSetHistoryTop,
- onCloseSlider
+ onSetHistoryTop
}: {
appId?: string;
appName: string;
@@ -40,7 +40,6 @@ const ChatHistorySlider = ({
onChangeChat: (historyId?: string) => void;
onDelHistory: (historyId: string) => void;
onSetHistoryTop?: (e: { historyId: string; top: boolean }) => void;
- onCloseSlider: () => void;
}) => {
const theme = useTheme();
const router = useRouter();
@@ -180,6 +179,29 @@ const ChatHistorySlider = ({
))}
+
+ {!isPc && appId && (
+ router.push('/app/list')}
+ >
+ }
+ bg={'white'}
+ boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
+ h={'28px'}
+ size={'sm'}
+ borderRadius={'50%'}
+ aria-label={''}
+ />
+ 切换应用
+
+ )}
);
};
diff --git a/client/src/pages/chat/components/SliderApps.tsx b/client/src/pages/chat/components/SliderApps.tsx
index 091c9f8b1..24949645f 100644
--- a/client/src/pages/chat/components/SliderApps.tsx
+++ b/client/src/pages/chat/components/SliderApps.tsx
@@ -21,7 +21,7 @@ const SliderApps = ({ appId }: { appId: string }) => {
px={3}
borderRadius={'md'}
_hover={{ bg: 'myGray.200' }}
- onClick={() => router.back()}
+ onClick={() => router.push('/app/list')}
>
{
const { onExportChat } = useChatBox();
+ const menuList = useRef([
+ {
+ icon: 'shareLight',
+ label: '分享对话',
+ onClick: () => {}
+ },
+ {
+ icon: 'apiLight',
+ label: 'HTML导出',
+ onClick: () => onExportChat({ type: 'html', history })
+ },
+ {
+ icon: 'markdown',
+ label: 'Markdown导出',
+ onClick: () => onExportChat({ type: 'md', history })
+ },
+ { icon: 'pdf', label: 'PDF导出', onClick: () => onExportChat({ type: 'pdf', history }) }
+ ]);
return (
);
diff --git a/client/src/pages/chat/index.tsx b/client/src/pages/chat/index.tsx
index ce32f130f..dc6a9f1cb 100644
--- a/client/src/pages/chat/index.tsx
+++ b/client/src/pages/chat/index.tsx
@@ -1,11 +1,6 @@
import React, { useCallback, useState, useRef } from 'react';
import { useRouter } from 'next/router';
-import {
- getInitChatSiteInfo,
- delChatRecordByIndex,
- delChatHistoryById,
- putChatHistory
-} from '@/api/chat';
+import { getInitChatSiteInfo, delChatRecordByIndex, putChatHistory } from '@/api/chat';
import {
Box,
Flex,
@@ -39,6 +34,7 @@ import ChatHistorySlider from './components/ChatHistorySlider';
import SliderApps from './components/SliderApps';
import Tag from '@/components/Tag';
import ToolMenu from './components/ToolMenu';
+import ChatHeader from './components/ChatHeader';
const Chat = () => {
const router = useRouter();
@@ -59,6 +55,7 @@ const Chat = () => {
history,
loadHistory,
updateHistory,
+ delHistory,
chatData,
setChatData
} = useChatStore();
@@ -138,14 +135,6 @@ const Chat = () => {
},
[historyId, setChatData]
);
- // delete a history
- const delHistoryById = useCallback(
- async (historyId: string) => {
- await delChatHistoryById(historyId);
- loadHistory({ appId });
- },
- [appId, loadHistory]
- );
// get chat app info
const loadChatInfo = useCallback(
@@ -232,7 +221,7 @@ const Chat = () => {
useQuery(['loadHistory', appId], () => (appId ? loadHistory({ appId }) : null));
return (
-
+
{/* pc show myself apps */}
{isPc && (
@@ -270,15 +259,22 @@ const Chat = () => {
appId
}
});
+ if (!isPc) {
+ onCloseSlider();
+ }
}}
- onDelHistory={delHistoryById}
+ onDelHistory={delHistory}
onSetHistoryTop={async (e) => {
try {
await putChatHistory(e);
- loadHistory({ appId });
+ const historyItem = history.find((item) => item._id === e.historyId);
+ if (!historyItem) return;
+ updateHistory({
+ ...historyItem,
+ top: e.top
+ });
} catch (error) {}
}}
- onCloseSlider={onCloseSlider}
/>
)}
{/* chat container */}
@@ -289,38 +285,14 @@ const Chat = () => {
flex={'1 0 0'}
flexDirection={'column'}
>
-
- {isPc ? (
- <>
-
- {chatData.title}
-
-
-
- {chatData.history.length}条记录
-
- >
- ) : (
- <>
-
- >
- )}
-
-
-
+ {/* header */}
+
+
{/* chat box */}
{
- const theme = useTheme();
+const ShareChat = ({ shareId, historyId }: { shareId: string; historyId: string }) => {
const router = useRouter();
- const { shareId = '', historyId } = router.query as { shareId: string; historyId: string };
const { toast } = useToast();
const { isOpen: isOpenSlider, onClose: onCloseSlider, onOpen: onOpenSlider } = useDisclosure();
const { isPc } = useGlobalStore();
@@ -48,8 +36,6 @@ const ShareChat = () => {
const startChat = useCallback(
async ({ messages, controller, generatingMessage, variables }: StartChatFnProps) => {
- console.log(messages, variables);
-
const prompts = messages.slice(-shareChatData.maxContext - 2);
const { responseText } = await streamFetch({
data: {
@@ -103,8 +89,8 @@ const ShareChat = () => {
);
const loadAppInfo = useCallback(
- async (shareId?: string) => {
- if (!shareId) return null;
+ async (shareId: string, historyId: string) => {
+ if (!shareId || !historyId) return null;
const history = shareChatHistory.find((item) => item._id === historyId) || defaultHistory;
ChatBoxRef.current?.resetHistory(history.chats);
@@ -140,74 +126,52 @@ const ShareChat = () => {
return history;
},
- [
- delManyShareChatHistoryByShareId,
- historyId,
- setShareChatData,
- shareChatData,
- shareChatHistory,
- toast
- ]
+ [delManyShareChatHistoryByShareId, setShareChatData, shareChatData, shareChatHistory, toast]
);
- useQuery(['init', shareId, historyId], () => {
- return loadAppInfo(shareId);
- });
+ useEffect(() => {
+ loadAppInfo(shareId, historyId);
+ }, [shareId, historyId]);
return (
- {/* slider */}
- {isPc ? (
-
- item.shareId === shareId)
- .map((item) => ({
- id: item._id,
- title: item.title
- }))}
- onChangeChat={(historyId) => {
- router.push({
- query: {
- historyId: historyId || '',
- shareId
- }
- });
- }}
- onDelHistory={delOneShareHistoryByHistoryId}
- onCloseSlider={onCloseSlider}
- />
-
- ) : (
-
-
-
- ({
- id: item._id,
- title: item.title
- }))}
- onChangeChat={(historyId) => {
- router.push({
- query: {
- historyId: historyId || '',
- shareId
- }
- });
- }}
- onDelHistory={delOneShareHistoryByHistoryId}
- onCloseSlider={onCloseSlider}
- />
-
-
+ {((children: React.ReactNode) => {
+ return isPc ? (
+ {children}
+ ) : (
+
+
+
+ {children}
+
+
+ );
+ })(
+ ({
+ id: item._id,
+ title: item.title
+ }))}
+ onChangeChat={(historyId) => {
+ router.push({
+ query: {
+ historyId: historyId || '',
+ shareId
+ }
+ });
+ if (!isPc) {
+ onCloseSlider();
+ }
+ }}
+ onDelHistory={delOneShareHistoryByHistoryId}
+ onCloseSlider={onCloseSlider}
+ />
)}
+
{/* chat container */}
{
flex={'1 0 0'}
flexDirection={'column'}
>
-
- {isPc ? (
- <>
-
- {shareChatData.history.title}
-
-
-
- {shareChatData.history.chats.length}条记录
-
- >
- ) : (
- <>
-
- >
- )}
-
+ {/* header */}
+
{/* chat box */}
{
);
};
+export async function getServerSideProps(context: any) {
+ const shareId = context?.query?.shareId || '';
+ const historyId = context?.query?.historyId || '';
+
+ return {
+ props: { shareId, historyId }
+ };
+}
+
export default ShareChat;
diff --git a/client/src/store/chat.ts b/client/src/store/chat.ts
index e901b82de..8ebf16680 100644
--- a/client/src/store/chat.ts
+++ b/client/src/store/chat.ts
@@ -4,12 +4,12 @@ import { immer } from 'zustand/middleware/immer';
import { ChatHistoryItemType } from '@/types/chat';
import type { InitChatResponse } from '@/api/response/chat';
-import { getChatHistory } from '@/api/chat';
-import { HUMAN_ICON } from '@/constants/chat';
+import { delChatHistoryById, getChatHistory } from '@/api/chat';
type State = {
history: ChatHistoryItemType[];
loadHistory: (data: { appId?: string }) => Promise;
+ delHistory(history: string): Promise;
updateHistory: (history: ChatHistoryItemType) => void;
chatData: InitChatResponse;
setChatData: (e: InitChatResponse | ((e: InitChatResponse) => InitChatResponse)) => void;
@@ -63,6 +63,12 @@ export const useChatStore = create()(
});
return null;
},
+ async delHistory(historyId) {
+ set((state) => {
+ state.history = state.history.filter((item) => item._id !== historyId);
+ });
+ await delChatHistoryById(historyId);
+ },
updateHistory(history) {
const index = get().history.findIndex((item) => item._id === history._id);
set((state) => {