Python/agent/application/pages/workbench.py

441 lines
16 KiB
Python

# -*- coding: utf-8 -*-
"""
工作台
"""
import reflex as rx
from application.pages import task_page, knowledge_base_page, login_page
from application.states import AuthState, TaskState, SidebarState
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 == SidebarState.nav_button
return rx.hstack(
# 导航按钮的图标
rx.image(
NAV_BUTTONS[nav_button]["src"],
width="16px",
height="16px",
object_fit="contain", # 保持图标宽高比
color="var(--prismui-color-1)",
),
# 导航按钮的文本
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
), # 通过加粗字体区分是否选中
),
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=SidebarState.set_nav_button(nav_button),
)
def task_history_item(
item: TaskHistoryItem,
) -> rx.Component:
"""
任务历史项
:param item: 任务历史项
:return: Component
"""
# 选中状态
is_selected = item.id == TaskState.task_id
return rx.hstack(
rx.cond(
item.is_running,
rx.image(
"/spinner.svg",
width="16px",
height="16px",
object_fit="contain",
animation="spin 1.6s linear infinite",
),
),
# 渲染任务描述
rx.text(
item.description,
font_weight=rx.cond(is_selected, "var(--prismui-font-weight-3)", None),
flex=1,
min_width="0", # 自适应宽度
line_height="20px",
white_space="nowrap", # 禁止换行
overflow="hidden",
mask_image="linear-gradient(to right, white calc(100% - 24px), transparent 100%)", # 添加蒙版
),
# 渲染上一次运行日期时间
rx.text(
item.last_run_at,
line_height="20px",
font_size="var(--prismui-font-size-1)",
color="var(--prismui-color-2)",
flex_shrink=0, # 禁止缩放
),
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=SidebarState.set_task_id(item.id),
style={
"_hover": {
"background": "var(--prismui-background-color-2)",
}, # 鼠标悬停背景颜色
},
)
def task_history() -> rx.Component:
"""
任务历史
:return: rx.Component
"""
return rx.auto_scroll(
rx.foreach(
TaskState.task_history,
task_history_item,
),
display="flex",
flex_direction="column",
gap="2px",
width="100%",
overflow="auto",
style={
"&::-webkit-scrollbar": {
"display": "none",
},
},
)
def sidebar() -> rx.Component:
"""
侧边栏
:return: rx.Component
"""
return rx.vstack(
rx.vstack(
rx.alert_dialog.root(
rx.alert_dialog.trigger(rx.box(height="0", width="100%")),
rx.alert_dialog.content(
rx.vstack(
rx.text(
"确认退出登录?",
line_height="24px",
font_size="var(--prismui-font-size-3)",
font_weight="var(--prismui-font-weight-3)",
color="var(--prismui-color-1)",
margin_bottom="16px",
),
rx.text(
"退出登录不会丢失任何数据,你仍可以登录此账号。",
line_height="20px",
color="var(--prismui-color-2)",
margin_bottom="24px",
),
rx.hstack(
rx.spacer(),
rx.hstack(
rx.alert_dialog.cancel(
rx.button(
"取消",
style={
"_hover": {
"background": "var(--prismui-background-color-9)"
}
},
)
),
rx.alert_dialog.action(
rx.button(
"退出登录",
color="var(--prismui-color-9)",
width="80px",
background_color="var(--prismui-background-color-6)",
style={
"_hover": {
"background": "var(--prismui-background-color-7)"
}
},
),
# 点击事件:退出登录
on_click=AuthState.logout,
),
),
justify_content="space-between",
width="100%",
),
gap="0",
width="100%",
),
width="480px",
padding="24px",
border_radius="var(--prismui-border-radius-7)",
),
# 打开绑定退出登录确认打开状态
open=SidebarState.is_logout_confirm_open,
# 当打开状态变动时绑定切换退出登录确认打开状态
on_open_change=SidebarState.toggle_logout_confirm_open,
),
# 渲染系统图标和名称
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.divider(
width="100%", background_color="var(--prismui-background-color-3)"
),
rx.hstack(
# 渲染用户中心
rx.popover.root(
rx.popover.trigger(
rx.hstack(
rx.avatar(
fallback="M",
height="28px",
width="28px",
color="var(--prismui-color-5)",
border_radius="100%",
),
rx.text(
"刘弼仁",
line_height="20px",
font_size="var(--prismui-font-size-1)",
font_weight="var(--prismui-font-weight-3)",
),
flex="1",
align_items="center",
gap="10px",
padding="6px 8px",
margin="8px 8px 8px 0",
border_radius="var(--prismui-border-radius-3)",
cursor="pointer",
style={
"_hover": {
"background": "var(--prismui-background-color-2)",
},
},
),
),
rx.popover.content(
rx.vstack(
rx.hstack(
rx.avatar(
fallback="M",
height="40px",
width="40px",
color="var(--prismui-color-5)",
border_radius="100%",
),
rx.text(
"刘弼仁",
line_height="24px",
font_size="var(--prismui-font-size-3) !important",
font_weight="var(--prismui-font-weight-3)",
),
align_items="center",
width="100%",
padding="16px",
background_color="var(--prismui-background-color-1)",
border_radius="var(--prismui-border-radius-3)",
),
rx.vstack(
# 渲染退出登录
rx.popover.close(
rx.hstack(
rx.icon(
"log-out",
height="16px",
width="16px",
object_fit="contain",
color="var(--prismui-color-1)",
),
rx.text("退出登录", line_height="20px"),
align_items="center",
gap="8px",
width="100%",
padding="5px 8px",
border_radius="var(--prismui-border-radius-3)",
cursor="pointer",
# 点击事件:切换退出登录确认显示
on_click=SidebarState.toggle_logout_confirm_open(
True
).stop_propagation,
style={
"_hover": {
"background": "var(--prismui-background-color-9)",
},
},
),
width="100%",
),
width="100%",
padding="8px",
background_color="var(--prismui-background-color-1)",
border_radius="var(--prismui-border-radius-3)",
),
),
width="320px",
padding="8px",
background_color="var(--prismui-background-color-9)",
),
),
# 渲染消息中心
rx.tooltip(
rx.box(
rx.icon(
"bell",
height="16px",
width="16px",
object_fit="contain",
color="var(--prismui-color-1)",
),
display="flex",
align_items="center",
justify_content="center",
height="32px",
flex_shrink="0",
width="32px",
border_radius="var(--prismui-border-radius-3)",
cursor="pointer",
style={
"_hover": {
"background": "var(--prismui-background-color-2)",
},
},
),
content="消息中心",
),
align_items="center",
justify_content="space-between",
gap="4px",
width="100%",
),
width="100%",
),
flex_shrink="0",
justify_content="space-between",
align_items="flex-start",
width="264px",
height="100%",
padding="0 12px",
background_color="var(--prismui-background-color-9)",
)
def workbench() -> rx.Component:
"""
工作台
"""
return rx.fragment(
# 若用户未登录则渲染登录页面
rx.cond(
AuthState.user_id,
rx.fragment(),
login_page(),
),
rx.hstack(
# 侧边栏
sidebar(),
# 根据选中的导航按钮渲染对应的页面
rx.match(
SidebarState.nav_button,
# 知识库页面
("knowledge_base", knowledge_base_page()),
# 任务页面
task_page(),
),
width="100%",
height="100vh",
),
# 挂载事件:恢复认证状态
on_mount=AuthState.resume,
)