增加用户反馈功能

This commit is contained in:
张元坤 2025-07-10 09:36:28 +08:00
parent f6258c970b
commit 8094d5e128

View File

@ -1,33 +1,26 @@
import type { FC } from 'react'
import {
useEffect,
useState,
} from 'react'
import { useAsyncEffect } from 'ahooks'
import { useThemeContext } from '@/app/components/chat/embedded-chatbot/theme/theme-context'
import {
ChatWithHistoryContext,
useChatWithHistoryContext,
} from './context'
import { useChatWithHistory } from './hooks'
import Sidebar from './sidebar'
import HeaderInMobile from './header-in-mobile'
import ConfigPanel from './config-panel'
import ChatWrapper from './chat-wrapper'
import type { InstalledApp } from '@/models/explore'
import Loading from '@/app/components/base/loading'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { useRouter } from 'next/navigation'
import AppUnavailable from '@/app/components/base/app-unavailable'
import type { FC } from "react";
import "antd/dist/reset.css"; // 引入 antd 的样式
import { useEffect, useState } from "react";
import { useAsyncEffect } from "ahooks";
import { useThemeContext } from "@/app/components/chat/embedded-chatbot/theme/theme-context";
import { ChatWithHistoryContext, useChatWithHistoryContext } from "./context";
import { useChatWithHistory } from "./hooks";
import Sidebar from "./sidebar";
import HeaderInMobile from "./header-in-mobile";
import ConfigPanel from "./config-panel";
import ChatWrapper from "./chat-wrapper";
import type { InstalledApp } from "@/models/explore";
import Loading from "@/app/components/base/loading";
import useBreakpoints, { MediaType } from "@/hooks/use-breakpoints";
import { useRouter } from "next/navigation";
import AppUnavailable from "@/app/components/base/app-unavailable";
type ChatWithHistoryProps = {
className?: string
userStr?: string
}
const ChatWithHistory: FC<ChatWithHistoryProps> = ({
className,
userStr,
}) => {
className?: string;
userStr?: string;
};
const ChatWithHistory: FC<ChatWithHistoryProps> = ({ className, userStr }) => {
const {
appInfoError,
appData,
@ -38,82 +31,78 @@ const ChatWithHistory: FC<ChatWithHistoryProps> = ({
chatShouldReloadKey,
isMobile,
themeBuilder,
} = useChatWithHistoryContext()
} = useChatWithHistoryContext();
const chatReady = (!showConfigPanelBeforeChat || !!appPrevChatTree.length)
const customConfig = appData?.custom_config
const site = appData?.site
const chatReady = !showConfigPanelBeforeChat || !!appPrevChatTree.length;
const customConfig = appData?.custom_config;
const site = appData?.site;
useEffect(() => {
themeBuilder?.buildTheme(site?.chat_color_theme, site?.chat_color_theme_inverted)
themeBuilder?.buildTheme(
site?.chat_color_theme,
site?.chat_color_theme_inverted
);
if (site) {
if (customConfig)
document.title = `${site.title}`
else
document.title = `${site.title} - Powered by Dify`
if (customConfig) document.title = `${site.title}`;
else document.title = `${site.title} - Powered by Dify`;
}
}, [site, customConfig, themeBuilder])
}, [site, customConfig, themeBuilder]);
if (appInfoLoading) {
return (
<Loading type='app' />
)
return <Loading type="app" />;
}
if (appInfoError) {
return (
<AppUnavailable />
)
return <AppUnavailable />;
}
return (
<div className={`h-full flex bg-white ${className} ${isMobile && 'flex-col'}`}>
{
!isMobile && (
<Sidebar userStr={userStr} />
)
}
{
isMobile && (
<HeaderInMobile />
)
}
<div className={`grow overflow-hidden ${showConfigPanelBeforeChat && !appPrevChatTree.length && 'flex items-center justify-center'}`}>
{
showConfigPanelBeforeChat && !appChatListDataLoading && !appPrevChatTree.length && (
<div className={`flex w-full items-center justify-center h-full ${isMobile && 'px-4'}`}>
<div
className={`h-full flex bg-white ${className} ${isMobile && "flex-col"}`}
>
{!isMobile && <Sidebar userStr={userStr} />}
{isMobile && <HeaderInMobile />}
<div
className={`grow overflow-hidden ${
showConfigPanelBeforeChat &&
!appPrevChatTree.length &&
"flex items-center justify-center"
}`}
>
{showConfigPanelBeforeChat &&
!appChatListDataLoading &&
!appPrevChatTree.length && (
<div
className={`flex w-full items-center justify-center h-full ${
isMobile && "px-4"
}`}
>
<ConfigPanel />
</div>
)
}
{
appChatListDataLoading && chatReady && (
<Loading type='app' />
)
}
{
chatReady && !appChatListDataLoading && (
<ChatWrapper key={chatShouldReloadKey} />
)
}
)}
{appChatListDataLoading && chatReady && <Loading type="app" />}
{chatReady && !appChatListDataLoading && (
<ChatWrapper key={chatShouldReloadKey} />
)}
</div>
</div>
)
}
);
};
export type ChatWithHistoryWrapProps = {
installedAppInfo?: InstalledApp
className?: string
userStr?: string
}
installedAppInfo?: InstalledApp;
className?: string;
userStr?: string;
};
const ChatWithHistoryWrap: FC<ChatWithHistoryWrapProps> = ({
installedAppInfo,
className,
userStr,
}) => {
const media = useBreakpoints()
const isMobile = media === MediaType.mobile
const themeBuilder = useThemeContext()
const media = useBreakpoints();
const isMobile = media === MediaType.mobile;
const themeBuilder = useThemeContext();
const {
appInfoError,
@ -146,93 +135,99 @@ const ChatWithHistoryWrap: FC<ChatWithHistoryWrapProps> = ({
appId,
handleFeedback,
currentChatInstanceRef,
} = useChatWithHistory(installedAppInfo)
feedbackModal,
} = useChatWithHistory(installedAppInfo);
return (
<ChatWithHistoryContext.Provider value={{
appInfoError,
appInfoLoading,
appData,
appParams,
appMeta,
appChatListDataLoading,
currentConversationId,
currentConversationItem,
appPrevChatTree,
pinnedConversationList,
conversationList,
showConfigPanelBeforeChat,
newConversationInputs,
newConversationInputsRef,
handleNewConversationInputsChange,
inputsForms,
handleNewConversation,
handleStartChat,
handleChangeConversation,
handlePinConversation,
handleUnpinConversation,
handleDeleteConversation,
conversationRenaming,
handleRenameConversation,
handleNewConversationCompleted,
chatShouldReloadKey,
isMobile,
isInstalledApp,
appId,
handleFeedback,
currentChatInstanceRef,
themeBuilder,
}}>
<ChatWithHistoryContext.Provider
value={{
appInfoError,
appInfoLoading,
appData,
appParams,
appMeta,
appChatListDataLoading,
currentConversationId,
currentConversationItem,
appPrevChatTree,
pinnedConversationList,
conversationList,
showConfigPanelBeforeChat,
newConversationInputs,
newConversationInputsRef,
handleNewConversationInputsChange,
inputsForms,
handleNewConversation,
handleStartChat,
handleChangeConversation,
handlePinConversation,
handleUnpinConversation,
handleDeleteConversation,
conversationRenaming,
handleRenameConversation,
handleNewConversationCompleted,
chatShouldReloadKey,
isMobile,
isInstalledApp,
appId,
handleFeedback,
currentChatInstanceRef,
themeBuilder,
}}
>
<ChatWithHistory className={className} userStr={userStr} />
{feedbackModal} {/* 确保 feedbackModal 正确渲染 */}
</ChatWithHistoryContext.Provider>
)
}
);
};
const ChatWithHistoryWrapWithCheckToken: FC<ChatWithHistoryWrapProps> = ({
installedAppInfo,
className,
}) => {
const [initialized, setInitialized] = useState(false)
const [appUnavailable, setAppUnavailable] = useState<boolean>(false)
const [resCode, setResCode] = useState<number>(200)
const router = useRouter()
const [userName, setUserName] = useState('')
const [nickName, setNickName] = useState('')
const [initialized, setInitialized] = useState(false);
const [appUnavailable, setAppUnavailable] = useState<boolean>(false);
const [resCode, setResCode] = useState<number>(200);
const router = useRouter();
const [userName, setUserName] = useState("");
const [nickName, setNickName] = useState("");
useAsyncEffect(async () => {
if (!initialized) {
if (!installedAppInfo) {
const accessToken = localStorage.getItem('token')
const accessToken = localStorage.getItem("token");
if (!accessToken) {
router.replace('/login')
router.replace("/login");
} else {
fetch(`${process.env.NEXT_PUBLIC_BASE_API_URL}/getInfo`, {
method: 'GET',
method: "GET",
headers: {
Authorization: `Bearer ${accessToken}`,
},
}).then(res => res.json()).then(data => {
if (data.code !== 200) {
localStorage.removeItem('token')
router.replace('/login')
} else {
setUserName(data.user.userName)
setNickName(data.user.nickName)
}
}).catch(() => {
setResCode(500)
setAppUnavailable(true)
})
.then((res) => res.json())
.then((data) => {
if (data.code !== 200) {
localStorage.removeItem("token");
router.replace("/login");
} else {
setUserName(data.user.userName);
setNickName(data.user.nickName);
}
})
.catch(() => {
setResCode(500);
setAppUnavailable(true);
});
}
}
setInitialized(true)
setInitialized(true);
}
}, [])
}, []);
if (!initialized)
return null
if (!initialized) return null;
if (appUnavailable)
return <AppUnavailable code={resCode} />
if (appUnavailable) return <AppUnavailable code={resCode} />;
return (
<ChatWithHistoryWrap
@ -240,7 +235,7 @@ const ChatWithHistoryWrapWithCheckToken: FC<ChatWithHistoryWrapProps> = ({
className={className}
userStr={`${nickName}[${userName}]`}
/>
)
}
);
};
export default ChatWithHistoryWrapWithCheckToken
export default ChatWithHistoryWrapWithCheckToken;