# -*- coding: utf-8 -*- """ 工作台 """ import reflex as rx from application.pages import task_page, knowledge_base_page, login_page from application.states import AuthState, TaskState from application.states.models import TaskHistoryItem # 导航按钮字典 NAV_BUTTONS: dict = { "create_task": {"src": "/create_task.svg", "text": "创建任务"}, } """ 约定: 1 若组件仅用于当前页面则无需抽象为通用组件(application.components.*) """ def nav_button( nav_button: str, ) -> rx.Component: """ 导航按钮 :param nav_button: 导航按钮 :return : Component """ # 导航按钮选中状态 is_selected = nav_button == AuthState.selected_nav_button return rx.hstack( # 导航按钮的图标 rx.image( NAV_BUTTONS[nav_button]["src"], width="16px", height="16px", object_fit="contain", # 保持图标宽高比 ), # 导航按钮的文本 rx.text( NAV_BUTTONS[nav_button]["text"], line_height="20px", font_size="var(--prismui-font-size-2)", font_weight=rx.cond( is_selected, "var(--prismui-font-weight-3)", None ), # 通过加粗字体区分是否选中 color="var(--prismui-color-1)", ), align_items="center", gap="8px", width="100%", padding="5px 12px", background_color=rx.cond( is_selected, "var(--prismui-background-color-2)", "transparent" ), # 通过背景颜色区分是否选中 border_radius="var(--prismui-border-radius-3)", cursor="pointer", # 点击事件:设置选中导航按钮 on_click=AuthState.set_selected_nav_button(nav_button), ) def task_history_item( item: TaskHistoryItem, ) -> rx.Component: """ 任务历史项 :param item: 任务历史项 :return: Component """ # 高亮 is_highlight = (item.id == TaskState.popover_shown_task_history_item_id) | ( item.id == TaskState.task_id ) return rx.list.item( rx.hstack( # 渲染任务正在运行图标 rx.cond( item.is_running, rx.icon( "play", width="14px", height="14px", color="var(--prismui-color-2)" ), rx.fragment(), ), # 渲染任务描述 rx.text( item.description, flex=1, line_height="20px", color="var(--prismui-color-2)", text_overflow="ellipsis", white_space="nowrap", overflow="hidden", ), display="flex", align_items="center", width="100%", padding="5px 0", # 点击事件:将指定任务唯一标识设置为当前任务唯一标识 on_click=lambda: TaskState.set_task_id(item.id), ), width="100%", ) def task_history() -> rx.Component: """ 任务历史 :return: rx.Component """ return rx.auto_scroll( rx.list( rx.foreach( TaskState.task_history, task_history_item, ), display="flex", flex_direction="column", gap="2px", width="100%", style={ "&::-webkit-scrollbar": { "display": "none", }, }, overflow="auto", ), width="100%", ) def settings_button(): """ 设置按钮 :return: Component """ return rx.box( rx.hover_card.root( # 触发事件:点击自定义按钮 rx.hover_card.trigger( rx.box( rx.icon( "settings", stroke_width=1.5, width="20px", height="20px", color="var(--prismui-color-1)", ), display="flex", flex_flow="column", justify_content="center", align_items="center", width="36px", height="36px", border_radius="var(--prismui-border-radius-3)", style={ "&:hover": { "background": "var(--prismui-background-color-5)", }, # 鼠标悬停背景颜色 }, cursor="pointer", ) ), # 悬停卡片 rx.hover_card.content( rx.box( rx.box( transform="translateX(-50%) rotate(45deg)", position="absolute", top="calc(50% - 4px)", left="0", width="8px", height="8px", background_color="var(--prismui-background-color-1)", ), rx.box( "退出登录", display="flex", justify_content="center", align_items="center", width="100%", height="24px", line_height="16px", border_radius="var(--prismui-border-radius-1)", style={ "_hover": { "background_color": "var(--prismui-background-color-6)", }, }, # 点击事件:退出登录 on_click=lambda: AuthState.logout(), ), cursor="pointer", ), side="left", side_offset=8, position="relative", align="center", padding="4px 12px", border_radius="var(--prismui-border-radius-1)", box_shadow="var(--prismui-box-shadow-3)", font_family="var(--prismui-font-family)", overflow="visible", style={ "font-size": "var(--prismui-font-size-1) !important", "color": "var(--prismui-color-1) !important", }, ), open=AuthState.is_settings_hover_card_open, # 悬停卡片打开状态变化事件:设置设置悬停卡片打开状态 on_open_change=AuthState.set_settings_hover_card_open, ), min_width="14px", cursor="pointer", ) def sidebar() -> rx.Component: """ 侧边栏 :return: rx.Component """ return rx.vstack( rx.vstack( # 渲染系统图标和名称 rx.hstack( # 系统图标 rx.image( src="/logo.png", width="20px", height="20px", object_fit="contain", ), # 系统名称 rx.text( "棱镜球", line_height="20px", font_size="var(--prismui-font-size-2)", font_weight="var(--prismui-font-weight-4)", ), align_items="center", gap="4px", width="100%", height="56px", padding="0 12px 12px", ), # 渲染导航按钮 rx.vstack( # 渲染导航按钮:创建任务 nav_button("create_task"), gap="2px", width="100%", padding_bottom="16px", ), # 渲染最近任务 rx.vstack( # 标题 rx.text( "最近", line_height="20px", font_size="var(--prismui-font-size-2)", padding="5px 10px 5px 22px", ), # 历史任务 task_history(), gap="2px", width="100%", padding="0 12px", ), align_items="flex-start", gap="2px", width="100%", ), rx.vstack( rx.vstack( # 设置按钮 settings_button(), ), padding_bottom="16px", gap="8px", ), flex_shrink="0", justify_content="space-between", align_items="flex-start", width="264px", height="100%", padding="0 12px", background="var(--prismui-background-1)", ) def workbench() -> rx.Component: """ 工作台 """ return rx.fragment( # 若用户未登录则渲染登录页面 rx.cond( AuthState.user_id, rx.fragment(), login_page(), ), rx.hstack( # 侧边栏 sidebar(), # 根据选中的导航按钮渲染对应的页面 rx.match( AuthState.selected_nav_button, # 知识库页面 ("knowledge_base", knowledge_base_page()), # 任务页面 task_page(), ), width="100%", height="100vh", ), )