fix
This commit is contained in:
@@ -2,13 +2,10 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/minilogo.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Uppeta</title>
|
<title>Limq</title>
|
||||||
<!-- Material Icons -->
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" rel="stylesheet">
|
|
||||||
<!-- Poppins Font -->
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
BIN
src/assets/minilogo.png
Normal file
BIN
src/assets/minilogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
@@ -8,11 +8,11 @@ import Editor from "@monaco-editor/react";
|
|||||||
|
|
||||||
export default function ChatAIDrawer({ open, onClose, onExport }) {
|
export default function ChatAIDrawer({ open, onClose, onExport }) {
|
||||||
const STORAGE_KEY = 'chat_history';
|
const STORAGE_KEY = 'chat_history';
|
||||||
const [storedMessages, setStoredMessages] = useSessionStorage(STORAGE_KEY, '[]');
|
const [storedMessages, setStoredMessages] = useSessionStorage(STORAGE_KEY, []);
|
||||||
|
|
||||||
const { messages, input, handleSubmit, handleInputChange, isLoading, setMessages } = useChat({
|
const { messages, input, handleSubmit, handleInputChange, isLoading, setMessages } = useChat({
|
||||||
api: "https://test-ai-quirkyai.vercel.app/api/chat",
|
api: "https://test-ai-quirkyai.vercel.app/api/chat",
|
||||||
initialMessages: JSON.parse(storedMessages),
|
initialMessages: storedMessages.length>0? JSON.parse(storedMessages):[],
|
||||||
});
|
});
|
||||||
|
|
||||||
const messagesEndRef = useRef(null);
|
const messagesEndRef = useRef(null);
|
||||||
@@ -88,7 +88,6 @@ export default function ChatAIDrawer({ open, onClose, onExport }) {
|
|||||||
width={800}
|
width={800}
|
||||||
open={open}
|
open={open}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
className="rounded-l-xl"
|
|
||||||
>
|
>
|
||||||
<div className="flex flex-col h-[calc(100vh-108px)]">
|
<div className="flex flex-col h-[calc(100vh-108px)]">
|
||||||
<div className="flex-1 overflow-y-auto px-4 space-y-6">
|
<div className="flex-1 overflow-y-auto px-4 space-y-6">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import logo from "@/assets/logo.png";
|
import logo from "@/assets/logo.png";
|
||||||
import logoCollapsed from "@/assets/logo-collapsed.png";
|
import logoCollapsed from "@/assets/minilogo.png";
|
||||||
|
|
||||||
export const Logo = ({ collapsed, isDarkMode }) => (
|
export const Logo = ({ collapsed, isDarkMode }) => (
|
||||||
<div className="logo">
|
<div className="logo">
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { CodeHighlight } from "@mantine/code-highlight";
|
|||||||
import { DownloadOutlined, EditOutlined, CheckOutlined, CloseOutlined } from '@ant-design/icons';
|
import { DownloadOutlined, EditOutlined, CheckOutlined, CloseOutlined } from '@ant-design/icons';
|
||||||
import { useRef, useEffect, useState } from 'react';
|
import { useRef, useEffect, useState } from 'react';
|
||||||
import { useDifyChat } from '@/hooks/aichat';
|
import { useDifyChat } from '@/hooks/aichat';
|
||||||
|
import Editor from "@monaco-editor/react";
|
||||||
|
import {useTheme}from '@/contexts/ThemeContext'
|
||||||
|
|
||||||
export default function DifyChatDrawer({ open, onClose, onExport }) {
|
export default function DifyChatDrawer({ open, onClose, onExport }) {
|
||||||
const {
|
const {
|
||||||
@@ -14,7 +16,7 @@ export default function DifyChatDrawer({ open, onClose, onExport }) {
|
|||||||
storedMessages,
|
storedMessages,
|
||||||
setStoredMessages
|
setStoredMessages
|
||||||
} = useDifyChat();
|
} = useDifyChat();
|
||||||
|
const {isDarkMode}=useTheme()
|
||||||
const [input, setInput] = useState('');
|
const [input, setInput] = useState('');
|
||||||
const messagesEndRef = useRef(null);
|
const messagesEndRef = useRef(null);
|
||||||
|
|
||||||
@@ -25,6 +27,20 @@ export default function DifyChatDrawer({ open, onClose, onExport }) {
|
|||||||
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (storedMessages && storedMessages.length > 0) {
|
||||||
|
console.log(storedMessages,'storedMessages');
|
||||||
|
|
||||||
|
setMessages(storedMessages);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (messages.length > 0) {
|
||||||
|
setStoredMessages(messages);
|
||||||
|
}
|
||||||
|
}, [messages]);
|
||||||
|
|
||||||
const handleSendMessage = async (e) => {
|
const handleSendMessage = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await sendMessage(input);
|
await sendMessage(input);
|
||||||
@@ -67,15 +83,20 @@ export default function DifyChatDrawer({ open, onClose, onExport }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClearHistory = () => {
|
||||||
|
clearHistory();
|
||||||
|
setStoredMessages([]);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
title={
|
title={
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span className="text-lg font-medium text-gray-800">AI 助手</span>
|
<span className="text-lg font-medium dark:text-gray-200">AI 助手</span>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
className="hover:bg-gray-100"
|
className="hover:bg-gray-100 dark:hover:bg-gray-700"
|
||||||
onClick={clearHistory}
|
onClick={handleClearHistory}
|
||||||
>
|
>
|
||||||
清空历史
|
清空历史
|
||||||
</Button>
|
</Button>
|
||||||
@@ -85,7 +106,6 @@ export default function DifyChatDrawer({ open, onClose, onExport }) {
|
|||||||
width={800}
|
width={800}
|
||||||
open={open}
|
open={open}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
className="rounded-l-xl"
|
|
||||||
>
|
>
|
||||||
<div className="flex flex-col h-[calc(100vh-108px)]">
|
<div className="flex flex-col h-[calc(100vh-108px)]">
|
||||||
<div className="flex-1 overflow-y-auto px-4 space-y-6">
|
<div className="flex-1 overflow-y-auto px-4 space-y-6">
|
||||||
@@ -94,13 +114,15 @@ export default function DifyChatDrawer({ open, onClose, onExport }) {
|
|||||||
key={message.id}
|
key={message.id}
|
||||||
className={`rounded-lg p-4 transition-all ${
|
className={`rounded-lg p-4 transition-all ${
|
||||||
message.role === 'assistant'
|
message.role === 'assistant'
|
||||||
? 'bg-blue-50 hover:bg-blue-100'
|
? 'bg-blue-50 hover:bg-blue-100 dark:bg-blue-900/30 dark:hover:bg-blue-900/50'
|
||||||
: 'bg-gray-50 hover:bg-gray-100'
|
: 'bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex justify-between items-center mb-3">
|
<div className="flex justify-between items-center mb-3">
|
||||||
<span className={`font-medium ${
|
<span className={`font-medium ${
|
||||||
message.role === 'assistant' ? 'text-blue-600' : 'text-gray-600'
|
message.role === 'assistant'
|
||||||
|
? 'text-blue-600 dark:text-blue-400'
|
||||||
|
: 'text-gray-600 dark:text-gray-300'
|
||||||
}`}>
|
}`}>
|
||||||
{message.role === 'assistant' ? 'AI 助手' : '用户'}
|
{message.role === 'assistant' ? 'AI 助手' : '用户'}
|
||||||
</span>
|
</span>
|
||||||
@@ -112,7 +134,7 @@ export default function DifyChatDrawer({ open, onClose, onExport }) {
|
|||||||
icon={<EditOutlined />}
|
icon={<EditOutlined />}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
onClick={() => handleEdit(message)}
|
onClick={() => handleEdit(message)}
|
||||||
className="text-gray-500 hover:text-blue-600"
|
className="text-gray-500 hover:text-blue-600 dark:text-gray-400 dark:hover:text-blue-400"
|
||||||
>
|
>
|
||||||
编辑
|
编辑
|
||||||
</Button>
|
</Button>
|
||||||
@@ -121,7 +143,7 @@ export default function DifyChatDrawer({ open, onClose, onExport }) {
|
|||||||
size="small"
|
size="small"
|
||||||
icon={<DownloadOutlined />}
|
icon={<DownloadOutlined />}
|
||||||
onClick={() => handleExport(message.content)}
|
onClick={() => handleExport(message.content)}
|
||||||
className="text-gray-500 hover:text-blue-600"
|
className="text-gray-500 hover:text-blue-600 dark:text-gray-400 dark:hover:text-blue-400"
|
||||||
>
|
>
|
||||||
导出
|
导出
|
||||||
</Button>
|
</Button>
|
||||||
@@ -132,12 +154,12 @@ export default function DifyChatDrawer({ open, onClose, onExport }) {
|
|||||||
{message.role === "assistant" ? (
|
{message.role === "assistant" ? (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
{editingMessageId === message.id ? (
|
{editingMessageId === message.id ? (
|
||||||
<div className="rounded-lg border border-blue-200">
|
<div className="rounded-lg border border-blue-200 dark:border-blue-700">
|
||||||
<Editor
|
<Editor
|
||||||
height="300px"
|
height="300px"
|
||||||
defaultLanguage="json"
|
defaultLanguage="json"
|
||||||
value={editingContent}
|
value={editingContent}
|
||||||
theme="vs-light"
|
theme={isDarkMode ? "vs-dark" : "vs-light"}
|
||||||
options={{
|
options={{
|
||||||
minimap: { enabled: false },
|
minimap: { enabled: false },
|
||||||
scrollBeyondLastLine: false,
|
scrollBeyondLastLine: false,
|
||||||
@@ -152,12 +174,12 @@ export default function DifyChatDrawer({ open, onClose, onExport }) {
|
|||||||
editor.focus();
|
editor.focus();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="flex justify-end gap-2 p-2 bg-gray-50 border-t">
|
<div className="flex justify-end gap-2 p-2 bg-gray-50 dark:bg-gray-800 border-t dark:border-gray-700">
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
icon={<CloseOutlined />}
|
icon={<CloseOutlined />}
|
||||||
onClick={handleCancelEdit}
|
onClick={handleCancelEdit}
|
||||||
className="hover:bg-gray-200"
|
className="hover:bg-gray-200 dark:hover:bg-gray-700"
|
||||||
>
|
>
|
||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
@@ -166,7 +188,7 @@ export default function DifyChatDrawer({ open, onClose, onExport }) {
|
|||||||
size="small"
|
size="small"
|
||||||
icon={<CheckOutlined />}
|
icon={<CheckOutlined />}
|
||||||
onClick={handleSaveEdit}
|
onClick={handleSaveEdit}
|
||||||
className="bg-blue-600 hover:bg-blue-700"
|
className="bg-blue-600 hover:bg-blue-700 dark:bg-blue-700 dark:hover:bg-blue-800"
|
||||||
>
|
>
|
||||||
保存
|
保存
|
||||||
</Button>
|
</Button>
|
||||||
@@ -179,12 +201,12 @@ export default function DifyChatDrawer({ open, onClose, onExport }) {
|
|||||||
copyLabel="复制代码"
|
copyLabel="复制代码"
|
||||||
copiedLabel="已复制!"
|
copiedLabel="已复制!"
|
||||||
withLineNumbers
|
withLineNumbers
|
||||||
className="rounded-lg"
|
className="rounded-lg dark:border-gray-700"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="text-gray-700 whitespace-pre-wrap break-words">
|
<div className="text-gray-700 dark:text-gray-300 whitespace-pre-wrap break-words">
|
||||||
{message.content}
|
{message.content}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -193,20 +215,20 @@ export default function DifyChatDrawer({ open, onClose, onExport }) {
|
|||||||
<div ref={messagesEndRef} />
|
<div ref={messagesEndRef} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border-t bg-white p-4">
|
<div className="border-t dark:border-gray-700 bg-white dark:bg-gray-800 p-4">
|
||||||
<form onSubmit={handleSendMessage} className="flex gap-2">
|
<form onSubmit={handleSendMessage} className="flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
value={input}
|
value={input}
|
||||||
placeholder="请输入您的问题..."
|
placeholder="请输入您的问题..."
|
||||||
onChange={(e) => setInput(e.target.value)}
|
onChange={(e) => setInput(e.target.value)}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
className="flex-1 rounded-lg border-gray-300 hover:border-blue-400 focus:border-blue-600 focus:shadow-blue-100"
|
className="flex-1 rounded-lg border-gray-300 dark:border-gray-600 hover:border-blue-400 dark:hover:border-blue-500 focus:border-blue-600 dark:focus:border-blue-500 focus:shadow-blue-100 dark:focus:shadow-blue-900 dark:bg-gray-700 dark:text-gray-200"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
htmlType="submit"
|
htmlType="submit"
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
className="rounded-lg bg-blue-600 hover:bg-blue-700"
|
className="rounded-lg bg-blue-600 hover:bg-blue-700 dark:bg-blue-700 dark:hover:bg-blue-800"
|
||||||
>
|
>
|
||||||
发送
|
发送
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const STORAGE_KEY = 'dify_chat_history';
|
|||||||
const CONVERSATION_ID_KEY = 'dify_conversation_id';
|
const CONVERSATION_ID_KEY = 'dify_conversation_id';
|
||||||
|
|
||||||
export function useDifyChat() {
|
export function useDifyChat() {
|
||||||
const [storedMessages, setStoredMessages] = useSessionStorage(STORAGE_KEY, '[]');
|
const [storedMessages, setStoredMessages] = useSessionStorage(STORAGE_KEY, []);
|
||||||
const [conversationId, setConversationId] = useSessionStorage(CONVERSATION_ID_KEY, '');
|
const [conversationId, setConversationId] = useSessionStorage(CONVERSATION_ID_KEY, '');
|
||||||
const [messages, setMessages] = useState([]);
|
const [messages, setMessages] = useState([]);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
@@ -18,7 +18,7 @@ export function useDifyChat() {
|
|||||||
|
|
||||||
const clearHistory = () => {
|
const clearHistory = () => {
|
||||||
setMessages([]);
|
setMessages([]);
|
||||||
setStoredMessages('[]');
|
setStoredMessages([]);
|
||||||
setConversationId('');
|
setConversationId('');
|
||||||
message.success('历史记录已清空');
|
message.success('历史记录已清空');
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ export default function MenuManagement() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gradient-to-b from-gray-50 to-white min-h-screen p-2">
|
<div className="bg-gradient-to-b min-h-screen p-2">
|
||||||
<Card className="shadow-lg rounded-lg">
|
<Card className="shadow-lg rounded-lg">
|
||||||
<div className="flex justify-between items-center mb-4">
|
<div className="flex justify-between items-center mb-4">
|
||||||
<Title level={4} className="mb-0">菜单权限管理</Title>
|
<Title level={4} className="mb-0">菜单权限管理</Title>
|
||||||
|
|||||||
@@ -89,10 +89,7 @@ const AppRoutes = () => {
|
|||||||
index
|
index
|
||||||
element={<Navigate to="/company/serviceTemplate" replace />}
|
element={<Navigate to="/company/serviceTemplate" replace />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 渲染所有路由 */}
|
|
||||||
{renderRoutes(allRoutes)}
|
{renderRoutes(allRoutes)}
|
||||||
|
|
||||||
<Route path="*" element={<NotFound />} />
|
<Route path="*" element={<NotFound />} />
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|||||||
@@ -112,27 +112,27 @@ body {
|
|||||||
.dark {
|
.dark {
|
||||||
@apply bg-gray-900;
|
@apply bg-gray-900;
|
||||||
|
|
||||||
.ant-card {
|
// .ant-card {
|
||||||
background: #1f1f1f;
|
// background: #1f1f1f;
|
||||||
|
|
||||||
.ant-card-head {
|
// .ant-card-head {
|
||||||
color: rgba(255, 255, 255, 0.85);
|
// color: rgba(255, 255, 255, 0.85);
|
||||||
border-bottom-color: #303030;
|
// border-bottom-color: #303030;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
.ant-table {
|
// .ant-table {
|
||||||
background: #1f1f1f;
|
// background: #1f1f1f;
|
||||||
|
|
||||||
.ant-table-thead>tr>th {
|
// .ant-table-thead>tr>th {
|
||||||
background: #141414;
|
// background: #141414;
|
||||||
color: rgba(255, 255, 255, 0.85);
|
// color: rgba(255, 255, 255, 0.85);
|
||||||
}
|
// }
|
||||||
|
|
||||||
.ant-table-tbody>tr>td {
|
// .ant-table-tbody>tr>td {
|
||||||
border-bottom: 1px solid #303030;
|
// border-bottom: 1px solid #303030;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statistics card styles
|
// Statistics card styles
|
||||||
|
|||||||
@@ -13,15 +13,21 @@ const getAntIcon = (iconName) => {
|
|||||||
const generateMenuItems = (routes, menuKeys = [], parentPath = "") => {
|
const generateMenuItems = (routes, menuKeys = [], parentPath = "") => {
|
||||||
return routes
|
return routes
|
||||||
.filter((route) => {
|
.filter((route) => {
|
||||||
if (!menuKeys.length) return !route.hidden;
|
if (route.hidden) return false;
|
||||||
|
|
||||||
|
if (!menuKeys.length) return true;
|
||||||
|
|
||||||
const isRouteAllowed = menuKeys.includes(route.key);
|
const isRouteAllowed = menuKeys.includes(route.key);
|
||||||
|
|
||||||
// 如果有子路由,只要子路由中有被授权的,父路由就应该显示
|
// 如果有子路由,只要子路由中有被授权的,父路由就应该显示
|
||||||
if (route.children) {
|
if (route.children) {
|
||||||
const hasAllowedChildren = route.children.some(child =>
|
const hasAllowedChildren = route.children.some(child =>
|
||||||
menuKeys.includes(child.key) ||
|
!child.hidden && (
|
||||||
(child.children && child.children.some(grandChild => menuKeys.includes(grandChild.key)))
|
menuKeys.includes(child.key) ||
|
||||||
|
(child.children && child.children.some(grandChild =>
|
||||||
|
!grandChild.hidden && menuKeys.includes(grandChild.key)
|
||||||
|
))
|
||||||
|
)
|
||||||
);
|
);
|
||||||
return hasAllowedChildren || isRouteAllowed;
|
return hasAllowedChildren || isRouteAllowed;
|
||||||
}
|
}
|
||||||
@@ -56,16 +62,12 @@ export const filterRoutesByMenuKeys = (routes, menuKeys) => {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return routes.reduce((acc, route) => {
|
return routes.reduce((acc, route) => {
|
||||||
// 检查当前路由的 key 是否在 menuKeys 中
|
|
||||||
const isRouteAllowed = menuKeys.includes(route.key);
|
const isRouteAllowed = menuKeys.includes(route.key);
|
||||||
|
|
||||||
// 递归处理子路由
|
|
||||||
let filteredChildren = [];
|
let filteredChildren = [];
|
||||||
if (route.children) {
|
if (route.children) {
|
||||||
filteredChildren = filterRoutesByMenuKeys(route.children, menuKeys);
|
filteredChildren = filterRoutesByMenuKeys(route.children, menuKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果当前路由被允许或者有被允许的子路由,则保留该路由
|
|
||||||
if (isRouteAllowed || filteredChildren.length > 0) {
|
if (isRouteAllowed || filteredChildren.length > 0) {
|
||||||
acc.push({
|
acc.push({
|
||||||
...route,
|
...route,
|
||||||
|
|||||||
Reference in New Issue
Block a user