From 1835e405268f02b8ecb7c8a5ce3a7eefe038bae1 Mon Sep 17 00:00:00 2001 From: yorn <1057707203@qq.com> Date: Thu, 5 Jun 2025 14:23:16 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=A6=96=E9=A1=B5=E7=9A=84ui?= =?UTF-8?q?=E4=BA=A4=E4=BA=92=EF=BC=8C=E8=A7=A3=E5=86=B3=E6=89=93=E5=8C=85?= =?UTF-8?q?=E7=94=9F=E4=BA=A7=E7=8E=AF=E5=A2=83=E4=B8=8B=E5=86=99=E5=85=A5?= =?UTF-8?q?sessionStorage=E9=94=99=E8=AF=AF=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=9D=83=E9=99=90=E8=B7=AF=E7=94=B1=E7=9A=84=E8=B7=B3=E8=BD=AC?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../contract-template/ContractSearchHero.tsx | 4 +- app/components/layout/Sidebar.tsx | 8 +-- app/root.tsx | 41 +++++++++++---- app/routes/_index.tsx | 6 +-- app/routes/login.tsx | 48 +++++++++--------- app/styles/pages/contract-template.css | 7 +-- app/styles/pages/home.css | 18 ++++--- public/images/icon_anjuan.png | Bin 0 -> 5811 bytes public/images/icon_assistant.png | Bin 0 -> 6230 bytes public/images/icon_hetong.png | Bin 0 -> 5717 bytes 10 files changed, 77 insertions(+), 55 deletions(-) create mode 100644 public/images/icon_anjuan.png create mode 100644 public/images/icon_assistant.png create mode 100644 public/images/icon_hetong.png diff --git a/app/components/contract-template/ContractSearchHero.tsx b/app/components/contract-template/ContractSearchHero.tsx index bde2cda..3265850 100644 --- a/app/components/contract-template/ContractSearchHero.tsx +++ b/app/components/contract-template/ContractSearchHero.tsx @@ -49,8 +49,8 @@ export function ContractSearchHero({ textAlign: 'center', padding: '60px 0', background: 'linear-gradient(135deg, rgba(0, 104, 74, 0.05) 0%, rgba(0, 104, 74, 0.02) 100%)', - borderRadius: '16px', - marginBottom: '32px' + borderRadius: '5px', + // marginBottom: '32px' }}>

= { // 应用模块图标映射 const APP_ICON_MAP: Record = { - 'contract': 'ri-file-list-2-fill', - 'record': 'ri-folder-shared-fill', - 'model': 'ri-robot-2-fill' + 'contract': '/images/icon_hetong.png', + 'record': '/images/icon_anjuan.png', + 'model': '/images/icon_assistant.png' }; export function Sidebar({ onToggle, collapsed, userRole, selectedApp = '' }: SidebarProps) { @@ -367,7 +367,7 @@ export function Sidebar({ onToggle, collapsed, userRole, selectedApp = '' }: Sid ) : ( <> - + {APP_NAME_MAP[currentApp] {APP_NAME_MAP[currentApp] || ''} )} diff --git a/app/root.tsx b/app/root.tsx index a73da21..49ee049 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -38,19 +38,21 @@ export const developerOnlyPaths = [ '/settings', '/config-lists', '/document-types', - '/prompts' + '/prompts', ]; // 创建基于Cookie的会话存储 // 在实际应用中,应该使用环境变量来设置密钥 -const sessionStorage = createCookieSessionStorage({ +export const sessionStorage = createCookieSessionStorage({ cookie: { - name: "__session", + name: "__lgsession", httpOnly: true, path: "/", sameSite: "lax", secrets: ["s3cr3t"], // 应该从环境变量读取 - secure: process.env.NODE_ENV === "production", + // secure: process.env.NODE_ENV === "production", + maxAge: 60 * 60 * 24 * 1, // 1天 + secure: false, // 开发环境中禁用secure }, }); @@ -63,9 +65,18 @@ export async function getSession(request: Request) { // 获取用户登录状态 export async function getUserSession(request: Request) { const session = await getSession(request); + const isAuthenticated = session.get("isAuthenticated") === true; + const userRole = session.get("userRole") || 'common' as UserRole; + + console.log("获取会话状态:", + // "Cookie:", request.headers.get("Cookie"), + "是否认证:", isAuthenticated, + "用户角色:", userRole + ); + return { - isAuthenticated: session.get("isAuthenticated") === true, - userRole: session.get("userRole") || 'common' as UserRole + isAuthenticated, + userRole }; } @@ -74,10 +85,15 @@ export async function createUserSession(isAuthenticated: boolean, userRole: User const session = await sessionStorage.getSession(); session.set("isAuthenticated", isAuthenticated); session.set("userRole", userRole); - console.log("session-----", session.get("userRole")); + + const cookie = await sessionStorage.commitSession(session); + console.log("创建会话 - 设置Cookie:", !!cookie); + console.log("创建会话 - 用户角色:", userRole); + console.log("创建会话 - 重定向到:", redirectTo); + return redirect(redirectTo, { headers: { - "Set-Cookie": await sessionStorage.commitSession(session), + "Set-Cookie": cookie, }, }); } @@ -117,15 +133,17 @@ export async function loader({ request }: LoaderFunctionArgs) { // 获取用户会话 const { isAuthenticated, userRole } = await getUserSession(request); - // console.log("Auth status:", { isAuthenticated, userRole, pathname }); + console.log("是否公开路径:", isPublicPath, "是否已认证:", isAuthenticated); // 如果访问需要认证的路径但未登录,重定向到登录页 if (!isPublicPath && !isAuthenticated) { + console.log("未认证,需要重定向到登录页"); // 保存请求的URL,以便登录后重定向回来 const session = await getSession(request); // 如果路径是/home,则将重定向目标设置为/ - const redirectTarget = pathname === "/home" ? "/" : pathname; + const redirectTarget = pathname !== "/" ? "/" : pathname; + // const redirectTarget = pathname === "home" ? "/" : pathname; // 保存重定向目标 session.set("redirectTo", redirectTarget); @@ -138,12 +156,13 @@ export async function loader({ request }: LoaderFunctionArgs) { // 如果已登录且访问登录页,重定向到首页 if (pathname === "/login" && isAuthenticated) { - // console.log("Already authenticated, redirecting from login to /"); + console.log("已认证,重定向到首页"); return redirect("/"); } // 检查访问权限 - 如果是common用户访问了开发者专属页面,重定向到首页 if (userRole === 'common' && developerOnlyPaths.some(path => pathname.startsWith(path))) { + console.log("用户没有访问权限,重定向到首页"); return redirect("/"); } diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index ffb9f72..8cee19b 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -151,7 +151,7 @@ export default function Index() { tabIndex={0} aria-label="合同管理" > - + 合同管理 合同管理 @@ -164,7 +164,7 @@ export default function Index() { tabIndex={0} aria-label="案卷智能评查" > - + 案卷智能评查 案卷智能评查 @@ -177,7 +177,7 @@ export default function Index() { tabIndex={0} aria-label="智慧法务大模型" > - + 智慧法务大模型 智慧法务大模型 diff --git a/app/routes/login.tsx b/app/routes/login.tsx index 79da34e..55c1780 100644 --- a/app/routes/login.tsx +++ b/app/routes/login.tsx @@ -1,8 +1,8 @@ import { useState } from "react"; -import { Form, useActionData, useNavigation } from "@remix-run/react"; +import { useActionData } from "@remix-run/react"; import { type MetaFunction, type ActionFunctionArgs, redirect, type LoaderFunctionArgs } from "@remix-run/node"; import styles from "~/styles/pages/login.css?url"; -import { createUserSession, getUserSession, getSession, type UserRole } from "~/root"; +import { getUserSession, getSession, type UserRole, sessionStorage } from "~/root"; export const links = () => [ { rel: "stylesheet", href: styles } @@ -31,22 +31,30 @@ export async function action({ request }: ActionFunctionArgs) { if (userRole === 'developer') { if (username !== 'admin' || password !== 'admin') { - // toastService.error("管理员用户名或密码错误"); return Response.json({ error: "管理员用户名或密码错误" }); } } - // 在实际应用中,这里应该是对用户名和密码的验证逻辑 - // 简化起见,我们直接视为登录成功 - // 获取session中存储的重定向URL,如果没有则默认到/ const session = await getSession(request); // 查看session中存储的redirectTo值 const redirectTo = session.get("redirectTo") || "/"; - // console.log("登录后重定向到:", redirectTo); + console.log("登录后重定向到:", redirectTo); - // 创建登录会话并重定向 - return createUserSession(true, userRole, redirectTo); + // 创建会话cookie + const newSession = await sessionStorage.getSession(); + newSession.set("isAuthenticated", true); + newSession.set("userRole", userRole); + const cookie = await sessionStorage.commitSession(newSession); + + console.log("设置cookie:", !!cookie); + + // 使用新方法进行重定向 + return redirect(redirectTo, { + headers: { + "Set-Cookie": cookie + } + }); } // 加载器,获取当前会话状态 @@ -66,18 +74,7 @@ export default function Login() { const [password, setPassword] = useState(""); const [userRole, setUserRole] = useState("common"); const actionData = useActionData(); - const navigation = useNavigation(); - // 使用 useEffect 确保错误提示只显示一次 - // useEffect(() => { - // if(actionData?.error) { - // toastService.error(actionData.error); - // } - // }, [actionData?.error]); - - // 判断是否正在提交表单 - const isSubmitting = navigation.state === "submitting"; - return (
@@ -88,7 +85,11 @@ export default function Login() {

用户登录

-
+ {actionData?.error && (
@@ -140,11 +141,10 @@ export default function Login() { - +
diff --git a/app/styles/pages/contract-template.css b/app/styles/pages/contract-template.css index fbf76bf..967b189 100644 --- a/app/styles/pages/contract-template.css +++ b/app/styles/pages/contract-template.css @@ -14,15 +14,15 @@ } .contract-template-search { - padding: 24px; + /* padding: 24px; */ background: var(--gradient-bg); - min-height: 100vh; + min-height: calc(100vh - 90px); } .contract-search-results { padding: 24px; background: var(--gradient-bg); - min-height: 100vh; + min-height: calc(100vh - 90px); } /* 搜索英雄区域 */ @@ -158,6 +158,7 @@ display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; + padding:8px; margin-top: 40px; } diff --git a/app/styles/pages/home.css b/app/styles/pages/home.css index bce1242..e028381 100644 --- a/app/styles/pages/home.css +++ b/app/styles/pages/home.css @@ -14,7 +14,8 @@ align-items: center; padding: 0.75rem 1rem; background-color: white; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); + box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.15); + z-index: 1; } .logo-container { @@ -74,7 +75,6 @@ /* 主要内容区域 */ .index-main-content { - border-radius: 0.5rem 0.5rem 0 0; height: 100%; flex: 1; display: flex; @@ -98,7 +98,7 @@ transform: translateY(-7rem); } .welcome-text { - font-size: 1.75rem; + font-size: 1.95rem; font-weight: 500; color: #333; margin-bottom: 5rem; @@ -115,9 +115,12 @@ .module-card { display: flex; align-items: center; - width: 250px; - padding: 2rem 1.5rem; - background: linear-gradient(to bottom, #ebebeb, #ffffff); + justify-content: flex-start; + gap: 1.5rem; + padding: 0 2rem; + height: 136px; + width: 290px; + background: linear-gradient(180deg, #ebf1f7 0%, #ffffff 100%); border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s; @@ -144,8 +147,7 @@ } */ .module-name { - margin-left: 1rem; - font-size: 1.125rem; + font-size: 1.25rem; font-weight: 500; color: #333; } diff --git a/public/images/icon_anjuan.png b/public/images/icon_anjuan.png new file mode 100644 index 0000000000000000000000000000000000000000..8d50695e39d8bfb91e2e15619a97950261573d79 GIT binary patch literal 5811 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 literal 0 HcmV?d00001 diff --git a/public/images/icon_assistant.png b/public/images/icon_assistant.png new file mode 100644 index 0000000000000000000000000000000000000000..c7baeecb83d7e4b615ed934545ebdeb7dcc3387f GIT binary patch literal 6230 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 Hu0mjfmv7a7 literal 0 HcmV?d00001