# -*- coding: utf-8 -*- """ 首页 """ import reflex as rx from application.pages import render_conversation, render_library from application.pages.conversation import render_conversation from application.states import AuthState # 导航按钮字典 nav_buttons: dict = { "conversation": {"src": "/conversation.svg", "text": "会话"}, "library": {"src": "/library.svg", "text": "知识库"}, } """ 约定: 1 若组件仅用于当前页面则无需抽象为通用组件(application.components.*) """ def render_nav_button( nav_button: str, ) -> rx.Component: """ 渲染导航按钮 :param nav_button: 指定的导航按钮 :return : Component """ # 导航按钮激活状态 is_actived = nav_button == AuthState.activated_nav_button return rx.vstack( # 渲染图标 rx.image( nav_buttons[nav_button]["src"], width="36px", height="36px", object_fit="contain", padding="6px", background_color=rx.cond( is_actived, "var(--prismui-background-color-1)", "transparent" ), border_radius="var(--prismui-border-radius-1)", box_shadow=rx.cond(is_actived, "var(--prismui-box-shadow-1)", "none"), ), # 渲染标签 rx.text( nav_buttons[nav_button]["text"], line_height="20px", color="var(--prismui-color-1)", font_size="var(--prismui-font-size-2)", ), align_items="center", gap="4px", cursor="pointer", # 点击事件:将指定导航按钮设置为激活的导航按钮 on_click=AuthState.switch_activated_nav_button(nav_button), ) def render_sidebar() -> rx.Component: """ 渲染侧边栏 :return: Component """ return rx.vstack( rx.vstack( rx.vstack( # 品牌图标 rx.image( src="/logo.png", width="34px", height="34px", object_fit="contain", ), # 品牌名称 rx.text( "棱镜球", line_height="20px", font_size="11px", font_weight="var(--prismui-font-weight-1)", color="var(--prismui-color-1)", ), align_items="center", gap="4px", ), # 渲染分隔线 rx.divider( width="32px", height="1px", margin="16px 0", background_color="var(--prismui-background-color-4)", ), rx.vstack( # 渲染会话导航按钮 render_nav_button("conversation"), # 渲染知识库导航按钮 render_nav_button("library"), gap="8px", ), align_items="center", width="100%", margin_top="12px", ), flex_shrink="0", justify_content="space-between", align_items="center", width="60px", min_width="60px", max_width="60px", height="100%", ) def render_login_window() -> rx.Component: """ 渲染登录窗 :return: Component """ return rx.center( rx.hstack( rx.vstack( rx.text( "登录", font_size="20px", font_weight="600", margin_bottom="24px", ), rx.input( placeholder="请输入邮箱地址", value=AuthState.email, on_change=AuthState.set_email, width="100%", ), rx.hstack( rx.input( placeholder="请输入验证码", value=AuthState.captcha, on_change=AuthState.set_captcha, flex=1, ), rx.button( rx.cond( AuthState.captcha_sending_countdown > 0, f"{AuthState.captcha_sending_countdown} s111111", "获取验证码", ), variant="outline", width="120px", on_click=AuthState.send_captcha, disabled=AuthState.captcha_sending_countdown > 0, ), gap="8px", width="100%", ), rx.text(AuthState.notification, color="red", font_size="12px"), rx.hstack( rx.checkbox( checked=AuthState.is_policies_agreed, on_change=AuthState.toggle_policies_agreed, ), rx.text("我已阅读并同意 ", font_size="13px"), rx.link("用户协议、隐私政策", font_size="13px", href="#"), align_items="center", ), rx.button( "登录", width="100%", bg="#0a0e29", color="white", margin_top="12px", on_click=AuthState.login, loading=AuthState.is_logging_in, disabled=AuthState.is_logging_in, ), rx.text( "登录有问题?去反馈", font_size="12px", color="#666", margin_top="8px", ), width="360px", gap="16px", padding="40px 32px", align_items="start", ), rx.divider(orientation="vertical"), rx.vstack( rx.image( src="/qrcode.png", width="160px", height="160px", padding="8px", border="1px solid #eee", border_radius="8px", bg="white", ), rx.text( "添加微信申请使用", font_size="18px", font_weight="600", margin_top="16px", ), align_items="center", width="320px", padding="40px 32px", style={"background": "#f8f9fc"}, ), ), position="fixed", top="0", left="0", width="100vw", height="100vh", bg="rgba(255, 255, 255, 0.85)", z_index="9999", overflow="hidden", ) def render_index() -> rx.Component: """ 渲染首页 """ return rx.fragment( rx.hstack( # 渲染侧边栏 render_sidebar(), # 根据侧边栏状态中激活的导航按钮渲染相应页面(本项目采用卡片布局) rx.match( AuthState.activated_nav_button, # 渲染知识库页面 ("library", render_library()), # 渲染会话页面 render_conversation(), ), width="100%", height="100vh", overflow="auto", padding="8px 8px 8px 0", background="var(--prismui-background-1)", # 挂载事件: on_mount=AuthState.check, ), # 若用户唯一标识为空则渲染登录窗 rx.cond( AuthState.user_id == "", render_login_window(), rx.fragment(), ), )