Merge branch 'PingChuan' into shiy-temp
This commit is contained in:
+190
-190
@@ -1,191 +1,191 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useNavigate, Form, useLoaderData } from '@remix-run/react';
|
||||
import { type MetaFunction, type ActionFunctionArgs, LoaderFunctionArgs, redirect } from "@remix-run/node";
|
||||
import styles from "~/styles/pages/home.css?url";
|
||||
import dayjs from 'dayjs';
|
||||
import { getUserSession, logout } from "~/root";
|
||||
|
||||
export const links = () => [
|
||||
{ rel: "stylesheet", href: styles }
|
||||
];
|
||||
|
||||
export const meta: MetaFunction = () => {
|
||||
return [
|
||||
{ title: "中国烟草AI合同及卷宗审核系统 - 首页" },
|
||||
{ name: "description", content: "中国烟草AI合同及卷宗审核系统首页" },
|
||||
];
|
||||
};
|
||||
|
||||
// 处理登出请求
|
||||
export async function action({ request }: ActionFunctionArgs) {
|
||||
const formData = await request.formData();
|
||||
const intent = formData.get("intent");
|
||||
|
||||
if (intent === "logout") {
|
||||
return logout(request);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 验证用户登录状态
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const { isAuthenticated, userRole } = await getUserSession(request);
|
||||
|
||||
if (!isAuthenticated) {
|
||||
return redirect("/login");
|
||||
}
|
||||
return Response.json({ userRole });
|
||||
}
|
||||
|
||||
export default function Index() {
|
||||
const navigate = useNavigate();
|
||||
const { userRole } = useLoaderData<typeof loader>();
|
||||
const [currentDateTime, setCurrentDateTime] = useState({
|
||||
date: '',
|
||||
time: ''
|
||||
});
|
||||
|
||||
// 打印服务器端传递的用户角色
|
||||
useEffect(() => {
|
||||
console.log('_index 服务器返回的用户角色:', userRole);
|
||||
}, [userRole]);
|
||||
|
||||
// 更新日期时间
|
||||
useEffect(() => {
|
||||
const updateDateTime = () => {
|
||||
const now = dayjs();
|
||||
// 格式化日期: YYYY/MM/DD
|
||||
setCurrentDateTime({
|
||||
date: now.format('YYYY/MM/DD'),
|
||||
time: now.format('HH:mm:ss')
|
||||
});
|
||||
};
|
||||
|
||||
// 初始化时间
|
||||
updateDateTime();
|
||||
|
||||
// 每秒更新一次
|
||||
const timerID = setInterval(updateDateTime, 1000);
|
||||
|
||||
return () => clearInterval(timerID);
|
||||
}, []);
|
||||
|
||||
// 处理模块点击
|
||||
const handleModuleClick = (path: string, reviewType: string) => {
|
||||
// 将reviewType存入sessionStorage
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.setItem('reviewType', reviewType);
|
||||
}
|
||||
navigate(path);
|
||||
};
|
||||
|
||||
// 处理键盘事件
|
||||
const handleKeyDown = (path: string, reviewType: string, e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
handleModuleClick(path, reviewType);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理登出
|
||||
const handleLogout = () => {
|
||||
// 清除sessionStorage中的所有数据
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.clear();
|
||||
}
|
||||
|
||||
// 使用Form组件提交登出请求
|
||||
const form = document.getElementById('logout-form') as HTMLFormElement;
|
||||
if (form) {
|
||||
form.submit();
|
||||
} else {
|
||||
// 如果找不到表单,直接导航到登录页
|
||||
navigate('/login');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="home-page">
|
||||
{/* 登出表单 - 隐藏 */}
|
||||
<Form method="post" id="logout-form" className="hidden">
|
||||
<input type="hidden" name="intent" value="logout" />
|
||||
</Form>
|
||||
|
||||
{/* 头部 */}
|
||||
<header className="header">
|
||||
<div className="logo-container">
|
||||
<img src="/logo.svg" alt="中国烟草" className="logo" />
|
||||
<div className="flex flex-col">
|
||||
<span className="logo-text ">中国烟草</span>
|
||||
<span className="logo-text-en">CHINA TOBACCO</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="user-info">
|
||||
<span className="datetime">{currentDateTime.date} {currentDateTime.time}</span>
|
||||
<div className="user">
|
||||
<img src="/avatar.png" alt="用户头像" className="avatar" />
|
||||
<span className="username">{userRole === 'developer' ? '系统管理员' : '普通用户'}</span>
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="logout-button"
|
||||
aria-label="登出"
|
||||
>
|
||||
<i className="ri-logout-box-line"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* 主要内容 */}
|
||||
<main className="index-main-content">
|
||||
<h1 className="welcome-text">- 欢迎来到智慧法务平台 -</h1>
|
||||
|
||||
<div className="modules-container">
|
||||
{/* 合同管理模块 */}
|
||||
<div
|
||||
className="module-card"
|
||||
onClick={() => handleModuleClick('/contract-template/search', 'contract')}
|
||||
onKeyDown={(e) => handleKeyDown('/contract-template/search', 'contract', e)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="合同管理"
|
||||
>
|
||||
<i className="ri-file-list-2-fill text-[3rem] text-[#269b6c]"></i>
|
||||
<span className="module-name">合同管理</span>
|
||||
</div>
|
||||
|
||||
{/* 案卷智能评查模块 */}
|
||||
<div
|
||||
className="module-card"
|
||||
onClick={() => handleModuleClick('/home', 'record')}
|
||||
onKeyDown={(e) => handleKeyDown('/home', 'record', e)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="案卷智能评查"
|
||||
>
|
||||
<i className="ri-folder-shared-fill text-[3rem] text-[#269b6c]"></i>
|
||||
<span className="module-name">案卷智能评查</span>
|
||||
</div>
|
||||
|
||||
{/* 智慧法务大模型模块 */}
|
||||
<div
|
||||
className="module-card"
|
||||
onClick={() => handleModuleClick('/', 'model')}
|
||||
onKeyDown={(e) => handleKeyDown('/', 'model', e)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="智慧法务大模型"
|
||||
>
|
||||
<i className="ri-robot-2-fill text-[3rem] text-[#269b6c]"></i>
|
||||
<span className="module-name">智慧法务大模型</span>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
{/* 底部山水背景 */}
|
||||
<footer className="footer">
|
||||
<div className="mountains-bg"></div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
);
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useNavigate, Form, useLoaderData } from '@remix-run/react';
|
||||
import { type MetaFunction, type ActionFunctionArgs, LoaderFunctionArgs, redirect } from "@remix-run/node";
|
||||
import styles from "~/styles/pages/home.css?url";
|
||||
import dayjs from 'dayjs';
|
||||
import { getUserSession, logout } from "~/root";
|
||||
|
||||
export const links = () => [
|
||||
{ rel: "stylesheet", href: styles }
|
||||
];
|
||||
|
||||
export const meta: MetaFunction = () => {
|
||||
return [
|
||||
{ title: "中国烟草AI合同及卷宗审核系统 - 首页" },
|
||||
{ name: "description", content: "中国烟草AI合同及卷宗审核系统首页" },
|
||||
];
|
||||
};
|
||||
|
||||
// 处理登出请求
|
||||
export async function action({ request }: ActionFunctionArgs) {
|
||||
const formData = await request.formData();
|
||||
const intent = formData.get("intent");
|
||||
|
||||
if (intent === "logout") {
|
||||
return logout(request);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 验证用户登录状态
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const { isAuthenticated, userRole } = await getUserSession(request);
|
||||
|
||||
if (!isAuthenticated) {
|
||||
return redirect("/login");
|
||||
}
|
||||
return Response.json({ userRole });
|
||||
}
|
||||
|
||||
export default function Index() {
|
||||
const navigate = useNavigate();
|
||||
const { userRole } = useLoaderData<typeof loader>();
|
||||
const [currentDateTime, setCurrentDateTime] = useState({
|
||||
date: '',
|
||||
time: ''
|
||||
});
|
||||
|
||||
// 打印服务器端传递的用户角色
|
||||
useEffect(() => {
|
||||
console.log('_index 服务器返回的用户角色:', userRole);
|
||||
}, [userRole]);
|
||||
|
||||
// 更新日期时间
|
||||
useEffect(() => {
|
||||
const updateDateTime = () => {
|
||||
const now = dayjs();
|
||||
// 格式化日期: YYYY/MM/DD
|
||||
setCurrentDateTime({
|
||||
date: now.format('YYYY/MM/DD'),
|
||||
time: now.format('HH:mm:ss')
|
||||
});
|
||||
};
|
||||
|
||||
// 初始化时间
|
||||
updateDateTime();
|
||||
|
||||
// 每秒更新一次
|
||||
const timerID = setInterval(updateDateTime, 1000);
|
||||
|
||||
return () => clearInterval(timerID);
|
||||
}, []);
|
||||
|
||||
// 处理模块点击
|
||||
const handleModuleClick = (path: string, reviewType: string) => {
|
||||
// 将reviewType存入sessionStorage
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.setItem('reviewType', reviewType);
|
||||
}
|
||||
navigate(path);
|
||||
};
|
||||
|
||||
// 处理键盘事件
|
||||
const handleKeyDown = (path: string, reviewType: string, e: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
handleModuleClick(path, reviewType);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理登出
|
||||
const handleLogout = () => {
|
||||
// 清除sessionStorage中的所有数据
|
||||
if (typeof window !== 'undefined') {
|
||||
sessionStorage.clear();
|
||||
}
|
||||
|
||||
// 使用Form组件提交登出请求
|
||||
const form = document.getElementById('logout-form') as HTMLFormElement;
|
||||
if (form) {
|
||||
form.submit();
|
||||
} else {
|
||||
// 如果找不到表单,直接导航到登录页
|
||||
navigate('/login');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="home-page">
|
||||
{/* 登出表单 - 隐藏 */}
|
||||
<Form method="post" id="logout-form" className="hidden">
|
||||
<input type="hidden" name="intent" value="logout" />
|
||||
</Form>
|
||||
|
||||
{/* 头部 */}
|
||||
<header className="header">
|
||||
<div className="logo-container">
|
||||
<img src="/logo.svg" alt="中国烟草" className="logo" />
|
||||
<div className="flex flex-col">
|
||||
<span className="logo-text ">中国烟草</span>
|
||||
<span className="logo-text-en">CHINA TOBACCO</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="user-info">
|
||||
<span className="datetime">{currentDateTime.date} {currentDateTime.time}</span>
|
||||
<div className="user">
|
||||
<img src="/avatar.png" alt="用户头像" className="avatar" />
|
||||
<span className="username">{userRole === 'developer' ? '系统管理员' : '普通用户'}</span>
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="logout-button"
|
||||
aria-label="登出"
|
||||
>
|
||||
<i className="ri-logout-box-line"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* 主要内容 */}
|
||||
<main className="index-main-content">
|
||||
<h1 className="welcome-text">- 欢迎来到智慧法务平台 -</h1>
|
||||
|
||||
<div className="modules-container">
|
||||
{/* 合同管理模块 */}
|
||||
<div
|
||||
className="module-card"
|
||||
onClick={() => handleModuleClick('/contract-template/search', 'contract')}
|
||||
onKeyDown={(e) => handleKeyDown('/contract-template/search', 'contract', e)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="合同管理"
|
||||
>
|
||||
<i className="ri-file-list-2-fill text-[3rem] text-[#269b6c]"></i>
|
||||
<span className="module-name">合同管理</span>
|
||||
</div>
|
||||
|
||||
{/* 案卷智能评查模块 */}
|
||||
<div
|
||||
className="module-card"
|
||||
onClick={() => handleModuleClick('/home', 'record')}
|
||||
onKeyDown={(e) => handleKeyDown('/home', 'record', e)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="案卷智能评查"
|
||||
>
|
||||
<i className="ri-folder-shared-fill text-[3rem] text-[#269b6c]"></i>
|
||||
<span className="module-name">案卷智能评查</span>
|
||||
</div>
|
||||
|
||||
{/* 智慧法务大模型模块 */}
|
||||
<div
|
||||
className="module-card"
|
||||
onClick={() => handleModuleClick('/chat-with-llm', 'model')}
|
||||
onKeyDown={(e) => handleKeyDown('/chat-with-llm', 'model', e)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="智慧法务大模型"
|
||||
>
|
||||
<i className="ri-robot-2-fill text-[3rem] text-[#269b6c]"></i>
|
||||
<span className="module-name">智慧法务大模型</span>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
{/* 底部山水背景 */}
|
||||
<footer className="footer">
|
||||
<div className="mountains-bg"></div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import { type ActionFunctionArgs } from '@remix-run/node';
|
||||
import { difyClient } from '../services/dify-client.server';
|
||||
import { getSessionInfo } from '../utils/session.server';
|
||||
|
||||
export async function action({ request }: ActionFunctionArgs) {
|
||||
if (request.method !== 'POST') {
|
||||
return new Response('Method not allowed', { status: 405 });
|
||||
}
|
||||
|
||||
try {
|
||||
const { user } = await getSessionInfo(request);
|
||||
const body = await request.json();
|
||||
|
||||
const {
|
||||
inputs,
|
||||
query,
|
||||
files,
|
||||
conversation_id: conversationId,
|
||||
response_mode: responseMode,
|
||||
} = body;
|
||||
|
||||
// ('🚀 Chat Messages API - User:', user, 'Query:', query?.substring(0, 100));
|
||||
|
||||
const response = await difyClient.createChatMessage(
|
||||
inputs,
|
||||
query,
|
||||
user,
|
||||
responseMode,
|
||||
conversationId,
|
||||
files
|
||||
);
|
||||
|
||||
// 对于流式响应,直接返回流
|
||||
if (responseMode === 'streaming') {
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
headers: {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Connection': 'keep-alive',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'POST',
|
||||
'Access-Control-Allow-Headers': 'Content-Type',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 对于非流式响应,返回JSON
|
||||
return new Response(JSON.stringify(response), {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
// console.error('❌ Chat Messages API - Error:', error);
|
||||
return new Response(
|
||||
JSON.stringify({ error: error.message || 'Failed to send message' }),
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { json, type ActionFunctionArgs } from '@remix-run/node';
|
||||
import { difyClient } from '../services/dify-client.server';
|
||||
import { getSessionInfo, commitSession } from '../utils/session.server';
|
||||
|
||||
export async function action({ request, params }: ActionFunctionArgs) {
|
||||
try {
|
||||
const { user, session } = await getSessionInfo(request);
|
||||
const { id } = params;
|
||||
|
||||
if (!id) {
|
||||
return json({ error: '会话ID不能为空' }, { status: 400 });
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { auto_generate, name } = body;
|
||||
|
||||
// console.log('💬 Rename Conversation API - User:', user, 'ID:', id, 'Auto Generate:', auto_generate, 'Name:', name);
|
||||
|
||||
// 调用服务端API重命名会话
|
||||
const data = await difyClient.renameConversation(id, name, user, auto_generate);
|
||||
|
||||
// console.log('✅ Rename Conversation API - Success:', data);
|
||||
|
||||
return json(data, {
|
||||
headers: {
|
||||
'Set-Cookie': await commitSession(session),
|
||||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error('❌ Rename Conversation API - Error:', error);
|
||||
return json(
|
||||
{
|
||||
error: error.message || '重命名会话失败'
|
||||
},
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Set-Cookie': await commitSession((await getSessionInfo(request)).session),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { json, type ActionFunctionArgs } from '@remix-run/node';
|
||||
import { difyClient } from '../services/dify-client.server';
|
||||
import { getSessionInfo, commitSession } from '../utils/session.server';
|
||||
|
||||
export async function action({ request, params }: ActionFunctionArgs) {
|
||||
try {
|
||||
const { user, session } = await getSessionInfo(request);
|
||||
const { id } = params;
|
||||
|
||||
if (!id) {
|
||||
return json({ error: '会话ID不能为空' }, { status: 400 });
|
||||
}
|
||||
|
||||
const method = request.method;
|
||||
|
||||
if (method === 'DELETE') {
|
||||
// console.log('🗑️ Delete Conversation API - User:', user, 'ID:', id);
|
||||
|
||||
// 调用服务端API删除会话
|
||||
const data = await difyClient.deleteConversation(id, user);
|
||||
|
||||
// console.log('✅ Delete Conversation API - Success:', data);
|
||||
|
||||
return json(data, {
|
||||
headers: {
|
||||
'Set-Cookie': await commitSession(session),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return json({ error: '不支持的请求方法' }, { status: 405 });
|
||||
} catch (error: any) {
|
||||
console.error('❌ Delete Conversation API - Error:', error);
|
||||
return json(
|
||||
{
|
||||
error: error.message || '删除会话失败'
|
||||
},
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Set-Cookie': await commitSession((await getSessionInfo(request)).session),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { json, type LoaderFunctionArgs } from '@remix-run/node';
|
||||
import { difyClient } from '../services/dify-client.server';
|
||||
import { getSessionInfo, commitSession } from '../utils/session.server';
|
||||
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
try {
|
||||
const { user, session } = await getSessionInfo(request);
|
||||
|
||||
// ('💬 Conversations API - User:', user);
|
||||
|
||||
const data = await difyClient.getConversations(user);
|
||||
|
||||
// ('✅ Conversations API - Success:', data);
|
||||
|
||||
return json(data, {
|
||||
headers: {
|
||||
'Set-Cookie': await commitSession(session),
|
||||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error('❌ Conversations API - Error:', error);
|
||||
return json(
|
||||
{
|
||||
data: [],
|
||||
error: error.message || 'Failed to fetch conversations'
|
||||
},
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Set-Cookie': await commitSession((await getSessionInfo(request)).session),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { json, type ActionFunctionArgs } from '@remix-run/node';
|
||||
import { difyClient } from '../services/dify-client.server';
|
||||
import { getSessionInfo, commitSession } from '../utils/session.server';
|
||||
|
||||
export async function action({ request }: ActionFunctionArgs) {
|
||||
try {
|
||||
const { user, session } = await getSessionInfo(request);
|
||||
|
||||
// console.log('💬 File Upload API - User:', user);
|
||||
|
||||
// 从请求中获取文件
|
||||
const formData = await request.formData();
|
||||
const file = formData.get('file') as File;
|
||||
|
||||
if (!file) {
|
||||
return json({ error: '没有找到文件' }, { status: 400 });
|
||||
}
|
||||
|
||||
// 获取文件内容
|
||||
const fileBuffer = await file.arrayBuffer();
|
||||
|
||||
// 这里需要在dify-client.server.ts中添加上传文件的方法
|
||||
// 目前我们返回一个临时响应
|
||||
// TODO: 实现文件上传功能
|
||||
|
||||
// 构造模拟响应
|
||||
const uploadId = `upload_${Date.now()}`;
|
||||
|
||||
// console.log('✅ File Upload API - Success:', { id: uploadId, fileName: file.name, size: file.size });
|
||||
|
||||
return json({ id: uploadId }, {
|
||||
headers: {
|
||||
'Set-Cookie': await commitSession(session),
|
||||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error('❌ File Upload API - Error:', error);
|
||||
return json(
|
||||
{
|
||||
error: error.message || '文件上传失败'
|
||||
},
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Set-Cookie': await commitSession((await getSessionInfo(request)).session),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { json, type LoaderFunctionArgs } from '@remix-run/node';
|
||||
import { difyClient } from '../services/dify-client.server';
|
||||
import { getSessionInfo, commitSession } from '../utils/session.server';
|
||||
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
try {
|
||||
const { user, session } = await getSessionInfo(request);
|
||||
const url = new URL(request.url);
|
||||
const conversationId = url.searchParams.get('conversation_id');
|
||||
|
||||
if (!conversationId) {
|
||||
return json(
|
||||
{ error: 'conversation_id is required' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// ('📨 Messages API - User:', user, 'ConversationId:', conversationId);
|
||||
|
||||
const data = await difyClient.getConversationMessages(user, conversationId);
|
||||
|
||||
// ('✅ Messages API - Success:', data);
|
||||
|
||||
return json(data, {
|
||||
headers: {
|
||||
'Set-Cookie': await commitSession(session),
|
||||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error('❌ Messages API - Error:', error);
|
||||
return json(
|
||||
{ error: error.message || 'Failed to fetch messages' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Set-Cookie': await commitSession((await getSessionInfo(request)).session),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { json, type LoaderFunctionArgs } from '@remix-run/node';
|
||||
import { difyClient } from '../services/dify-client.server';
|
||||
import { getSessionInfo, commitSession } from '../utils/session.server';
|
||||
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
try {
|
||||
const { user, session } = await getSessionInfo(request);
|
||||
|
||||
// ('📋 Parameters API - User:', user);
|
||||
|
||||
const data = await difyClient.getApplicationParameters(user);
|
||||
|
||||
// ('✅ Parameters API - Success:', data);
|
||||
|
||||
return json(data, {
|
||||
headers: {
|
||||
'Set-Cookie': await commitSession(session),
|
||||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error('❌ Parameters API - Error:', error);
|
||||
return json(
|
||||
{ error: error.message || 'Failed to fetch parameters' },
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Set-Cookie': await commitSession((await getSessionInfo(request)).session),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { json } from "@remix-run/node";
|
||||
import { type MetaFunction } from "@remix-run/node";
|
||||
import Chat from "~/components/chat";
|
||||
import chatIndexStyles from "~/styles/components/chat-with-llm/index.css?url";
|
||||
import chatMessageStyles from "~/styles/components/chat-with-llm/chat-message.css?url";
|
||||
import chatInputStyles from "~/styles/components/chat-with-llm/chat-input.css?url";
|
||||
import chatSidebarStyles from "~/styles/components/chat-with-llm/sidebar.css?url";
|
||||
import chatThoughtProcessStyles from "~/styles/components/chat-with-llm/thought-process.css?url";
|
||||
import chatMarkdownStyles from "~/styles/components/chat-with-llm/markdown.css?url";
|
||||
|
||||
export function links() {
|
||||
return [
|
||||
{ rel: "stylesheet", href: chatIndexStyles },
|
||||
{ rel: "stylesheet", href: chatMessageStyles },
|
||||
{ rel: "stylesheet", href: chatInputStyles },
|
||||
{ rel: "stylesheet", href: chatSidebarStyles },
|
||||
{ rel: "stylesheet", href: chatThoughtProcessStyles },
|
||||
{ rel: "stylesheet", href: chatMarkdownStyles }
|
||||
];
|
||||
}
|
||||
|
||||
export const meta: MetaFunction = () => {
|
||||
return [
|
||||
{ title: "AI对话 - 中国烟草AI合同及卷宗审核系统" },
|
||||
{
|
||||
name: "description",
|
||||
content: "与AI助手进行智能对话,获取专业的法务建议和文档分析"
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* 聊天主页面
|
||||
* 实现单页面应用模式,所有会话切换都在同一页面内完成
|
||||
*/
|
||||
export default function ChatWithLLMIndex() {
|
||||
return (
|
||||
<div className="h-full chat-container">
|
||||
<Chat />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Outlet } from "@remix-run/react";
|
||||
import { type MetaFunction } from "@remix-run/node";
|
||||
|
||||
export const meta: MetaFunction = () => {
|
||||
return [
|
||||
{ title: "AI对话 - 中国烟草AI合同及卷宗审核系统" },
|
||||
{
|
||||
name: "chat-with-llm",
|
||||
content: "AI对话模块,包括AI对话功能"
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
export const handle = {
|
||||
breadcrumb: "AI对话"
|
||||
};
|
||||
|
||||
/**
|
||||
* 配置列表路由布局
|
||||
*/
|
||||
export default function ContractSearchLayout() {
|
||||
return <Outlet />;
|
||||
}
|
||||
Reference in New Issue
Block a user