diff --git a/agent/application/pages/login.py b/agent/application/pages/login.py index c120339..6b918d7 100644 --- a/agent/application/pages/login.py +++ b/agent/application/pages/login.py @@ -6,6 +6,7 @@ import reflex as rx from application.states import AuthState + def login_page() -> rx.Component: """ 登录页面 @@ -32,12 +33,12 @@ def login_page() -> rx.Component: on_change=AuthState.set_email, # 获取焦点事件:重置错误信息 on_focus=AuthState.reset_error, + line_height="16px", width="100%", height="45px", padding="4px", margin_bottom="24px", border_radius="var(--prismui-border-radius-4)", - line_height="16px", ), # 验证码输入框 rx.hstack( @@ -58,30 +59,40 @@ def login_page() -> rx.Component: border="none !important", ), rx.button( - # 若再次发送验证码倒计时大于0则显示倒计时,否则显示获取验证码 - rx.cond( - AuthState.resend_captcha_code_countdown > 0, - f"{AuthState.resend_captcha_code_countdown} s", - "获取验证码", + rx.text( + rx.cond( + AuthState.resend_captcha_code_countdown > 0, + f"{AuthState.resend_captcha_code_countdown} s", + "获取验证码", + ), + line_height="16px", + white_space="nowrap", + # 若验证码发送禁用状态为是则颜色设置为 color-4,否则设置为 color-5(主题色) + color=rx.cond( + AuthState.is_captcha_code_sending_button_disabled, + "var(--prismui-color-4)", + "var(--prismui-color-5)", + ), + padding="0 12px", ), + # 若再次发送验证码倒计时大于0则显示倒计时,否则显示获取验证码 # 点击事件:发送验证码 on_click=AuthState.send_captcha_code, # 是否禁用绑定验证码发送禁用状态 disabled=AuthState.is_captcha_code_sending_button_disabled, margin="0 8px", background_color="var(--prismui-background-color-1)", - line_height="16px", - # 若验证码发送禁用状态为是则颜色设置为 color-4,否则设置为 color-5(主题色) - color=rx.cond( - AuthState.is_captcha_code_sending_button_disabled, - "var(--prismui-color-4)", - "var(--prismui-color-5)", - ), + border="none", cursor=rx.cond( AuthState.is_captcha_code_sending_button_disabled, "not-allowed", "pointer", ), + style={ + "_hover": { + "background-color": "var(--prismui-background-color-1)" + } + }, ), width="100%", height="45px", @@ -161,14 +172,19 @@ def login_page() -> rx.Component: ), rx.button( "登录", - width="100%", - height="38px", - border_radius="var(--prismui-border-radius-4)", - background_color="var(--prismui-color-5)", - color="var(--prismui-color-9)", - cursor="pointer", on_click=AuthState.login, loading=AuthState.is_logging_in, + color="var(--prismui-color-9)", + width="100%", + height="38px", + background_color="var(--prismui-background-color-4)", + border_radius="var(--prismui-border-radius-4)", + cursor="pointer", + style={ + "_hover": { + "background-color": "var(--prismui-background-color-5)" + } + }, ), rx.text( "登录遇到问题?加他微信去吐槽", @@ -218,4 +234,4 @@ def login_page() -> rx.Component: width="100vw", height="100vh", backdrop_filter="blur(4px)", - ) \ No newline at end of file + ) diff --git a/agent/application/pages/task.py b/agent/application/pages/task.py index 9a84d37..b87bc70 100644 --- a/agent/application/pages/task.py +++ b/agent/application/pages/task.py @@ -8,9 +8,9 @@ from application.states import AuthState, TaskState from application.states.models import MessageHistoryItem, MessageType, WorkflowType -def workflow_button(workflow_type: WorkflowType): +def shortcut(workflow_type: WorkflowType): """ - 工作流按钮 + 快捷方式 :param workflow_type: 工作类型 :return: rx.Component """ @@ -19,17 +19,16 @@ def workflow_button(workflow_type: WorkflowType): # 点击事件:设置工作流 on_click=lambda: TaskState.set_workflow(workflow_type), padding="10px 16px", - background_color="var(--prismui-background-color-6)", + background_color="var(--prismui-background-color-9)", border_radius="var(--prismui-border-radius-9)", - color="var(--prismui-color-10)", cursor="pointer", ) -def use_guidance() -> rx.Component: +def welcome() -> rx.Component: """ - 使用指引 - :return: Component + 欢迎 + :return: rx.Component """ return rx.vstack( # 品牌图标、名称和介绍 @@ -77,13 +76,13 @@ def use_guidance() -> rx.Component: ), rx.hstack( # 工作流按钮:预定航班 - workflow_button(WorkflowType.BOOK_FLIGHT), + shortcut(WorkflowType.BOOK_FLIGHT), # 工作流按钮:银行客户服务 - workflow_button(WorkflowType.BANK_CUSTOMER_SERVICE), + shortcut(WorkflowType.BANK_CUSTOMER_SERVICE), # 工作流按钮:联网检索 - workflow_button(WorkflowType.WEB_RETRIEVE), + shortcut(WorkflowType.WEB_RETRIEVE), # 工作流按钮:知识库检索 - workflow_button(WorkflowType.KNOWLEDGE_BASE_RETRIEVE), + shortcut(WorkflowType.KNOWLEDGE_BASE_RETRIEVE), flex_wrap="wrap", align_items="center", gap="12px", @@ -194,7 +193,7 @@ def thinking(item: MessageHistoryItem) -> rx.Component: width="100%", line_height="1.6", font_size="var(--prismui-font-size-1)", - color="var(--prismui-color-3)", + color="var(--prismui-color-2)", ), rx.fragment(), ), @@ -305,7 +304,7 @@ def tool_call(item: MessageHistoryItem) -> rx.Component: True, item.id ), padding="0 12px", - background_color="var(--prismui-background-color-7)", + background_color="var(--prismui-background-color-9)", border_radius="var(--prismui-border-radius-3)", line_height="18px", font_size="var(--prismui-font-size-1)", @@ -368,7 +367,7 @@ def text(item: MessageHistoryItem) -> rx.Component: "code": lambda text: rx.text( text, display="inline", - background_color="var(--prismui-background-color-6)", + background_color="var(--prismui-background-color-9)", border_radius="var(--prismui-border-radius-1)", color="var(--prismui-color-5)", ), @@ -415,7 +414,7 @@ def text(item: MessageHistoryItem) -> rx.Component: width="4.5px", height="4.5px", margin_right="8px", - background_color="var(--prismui-background-color-7)", + background_color="var(--prismui-background-color-4)", border_radius="100%", ), rx.text( @@ -445,7 +444,7 @@ def text(item: MessageHistoryItem) -> rx.Component: "th": lambda children: rx.el.th( children, padding="8px 12px", - background_color="var(--prismui-background-color-6)", + background_color="var(--prismui-background-color-9)", border="1px solid var(--prismui-background-color-2)", text_align="left", ), @@ -487,10 +486,10 @@ def message_history() -> rx.Component: :return: Component """ return rx.vstack( - # 若消息历史为空则显示使用指引,否则渲染消息历史项 + # 若消息历史为空则渲染欢迎,否则渲染消息历史项 rx.cond( TaskState.message_history.length() == 0, - use_guidance(), + welcome(), rx.vstack( rx.hstack( rx.hstack( @@ -518,8 +517,9 @@ def message_history() -> rx.Component: TaskState.task_last_run_at, line_height="20px", font_size="var(--prismui-font-size-1)", - color="var(--prismui-color-3)", + color="var(--prismui-color-2)", ), + # 渲染产品面板按钮 rx.tooltip( rx.box( rx.icon( @@ -544,91 +544,117 @@ def message_history() -> rx.Component: ), content="产物面板", ), - rx.hstack( - # 渲染更多下拉菜单 - rx.menu.root( - rx.menu.trigger( - rx.box( - rx.icon( - "ellipsis", - width="16px", - height="16px", - object_fit="contain", - color="var(--prismui-color-2)", - ), - display="flex", - align_items="center", - justify_content="center", - width="32px", - height="32px", - border_radius="var(--prismui-border-radius-3)", - cursor="pointer", - style={ - "_hover": { - "background_color": "var(--prismui-background-color-9)" - } - }, - ), - ), - rx.menu.content( - # 渲染删除项 - rx.menu.item( - rx.hstack( - rx.icon( - "trash", - width="12px", - height="12px", - object_fit="contain", - color="var(--prismui-color-1)", - ), - rx.text("删除", line_height="20px"), - align_items="center", - gap="8px", - ), - height="28px", - width="100%", - cursor="pointer", - on_click=TaskState.show_task_delete_confirm, - style={ - "_hover": { - "background_color": "var(--prismui-background-color-9)" - } - }, + # 渲染更多按钮 + rx.menu.root( + rx.menu.trigger( + rx.box( + rx.icon( + "ellipsis", + width="16px", + height="16px", + object_fit="contain", + color="var(--prismui-color-2)", ), + display="flex", + align_items="center", + justify_content="center", + width="32px", + height="32px", + border_radius="var(--prismui-border-radius-3)", + cursor="pointer", + style={ + "_hover": { + "background_color": "var(--prismui-background-color-9)" + } + }, ), ), - # 渲染删除确认弹窗 - rx.popover.root( - rx.popover.trigger(rx.box(width="0", height="32px")), - rx.popover.content( + rx.menu.content( + # 渲染删除项 + rx.menu.item( + rx.hstack( + rx.icon( + "trash", + width="12px", + height="12px", + object_fit="contain", + color="var(--prismui-color-1)", + ), + rx.text("删除", line_height="20px"), + align_items="center", + gap="8px", + ), + height="28px", + width="100%", + cursor="pointer", + # 点击事件:显示当前任务删除确认 + on_select=TaskState.toggle_task_delete_confirm( + True + ).stop_propagation, + style={ + "_hover": { + "background_color": "var(--prismui-background-color-9)" + } + }, + ), + ), + ), + # 渲染任务删除确认 + rx.popover.root( + rx.popover.trigger(rx.box(width="0", height="32px")), + rx.popover.content( + rx.vstack( rx.vstack( - rx.text("删除任务?", line_height="20px"), + rx.text( + "删除任务?", + line_height="20px", + font_weight="var(--prismui-font-weight-3)", + ), rx.text( "删除后,任务将不可恢复。", line_height="20px", - font_size="var(--prismui-font-size-1)", - ), - rx.hstack( - rx.spacer(), - rx.hstack( - rx.popover.close( - rx.button( - "取消", - # 点击事件:隐藏当前任务删除确认 - on_click=TaskState.hide_task_delete_confirm, - ) - ), - rx.popover.close(rx.button("确认")), - ), - align_items="space-between", - width="100%", + font_size="var(--prismui-font-size-1) !important", ), + gap="8px", width="100%", - ) + ), + rx.hstack( + rx.spacer(), + rx.hstack( + rx.popover.close( + rx.button( + "取消", + style={ + "_hover": { + "background_color": "var(--prismui-background-color-9)" + } + }, + ) + ), + rx.button( + "确认", + color="var(--prismui-color-9)", + background_color="var(--prismui-background-color-6)", + style={ + "_hover": { + "background_color": "var(--prismui-background-color-7)" + } + }, + on_click=TaskState.delete_task, + ), + ), + align_items="space-between", + width="100%", + ), + gap="24px", + width="100%", ), - # 显示绑定:显示当前任务删除确认 - open=TaskState.is_task_delete_confirm_shown, + width="240px", + padding="16px", ), + # 显示绑定:显示当前任务删除确认 + open=TaskState.is_task_delete_confirm_shown, + on_open_change=TaskState.toggle_task_delete_confirm, ), align_items="center", gap="4px", @@ -748,8 +774,8 @@ def user_prompt_sending_box() -> rx.Component: padding="0 12px", background_color=rx.cond( TaskState.is_user_prompt_sending_button_disabled, - "var(--prismui-color-11)", - "var(--prismui-color-5)", + "var(--prismui-background-color-8)", + "var(--prismui-background-color-4)", ), border="none", border_radius="var(--prismui-border-radius-5)", @@ -761,6 +787,14 @@ def user_prompt_sending_box() -> rx.Component: "not-allowed", "pointer", ), + style={ + "_hover": { + "background-color": "var(--prismui-background-color-5)", + }, + "&:disabled:hover": { + "background-color": "var(--prismui-background-color-8)", + }, + }, ), justify_content="flex-end", align_items="center", diff --git a/agent/application/pages/workbench.py b/agent/application/pages/workbench.py index 6f6493a..665f824 100644 --- a/agent/application/pages/workbench.py +++ b/agent/application/pages/workbench.py @@ -103,7 +103,7 @@ def task_history_item( item.last_run_at, line_height="20px", font_size="var(--prismui-font-size-1)", - color="var(--prismui-color-3)", + color="var(--prismui-color-2)", flex_shrink=0, # 禁止缩放 ), align_items="center", @@ -148,91 +148,6 @@ def task_history() -> rx.Component: ) -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", - ), - 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: """ 侧边栏 @@ -241,6 +156,17 @@ def sidebar() -> 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.alert_dialog.title("确认退出登录?"), + rx.alert_dialog.description( + "退出登录不会丢失任何数据,你仍可以登录此账号。" + ), + rx.alert_dialog.cancel("取消"), + rx.alert_dialog.action("退出登录"), + ), + ), # 渲染系统图标和名称 rx.hstack( # 系统图标 @@ -291,12 +217,128 @@ def sidebar() -> rx.Component: width="100%", ), rx.vstack( - rx.vstack( - # 设置按钮 - settings_button(), + rx.divider( + width="100%", background_color="var(--prismui-background-color-3)" ), - padding_bottom="16px", - gap="8px", + 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", + style={ + "_hover": { + "background": "var(--prismui-background-color-2)", + }, + }, + ), + ), + 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", diff --git a/agent/application/states/task.py b/agent/application/states/task.py index b891c19..f062645 100644 --- a/agent/application/states/task.py +++ b/agent/application/states/task.py @@ -4,7 +4,7 @@ """ from datetime import date as Date, datetime from typing import AsyncGenerator - +from reflex_base.event import EventSpec from pydantic_ai import DeferredToolRequests, DeferredToolResults, ToolApproved from pydantic_ai.messages import ( FunctionToolResultEvent, @@ -51,8 +51,10 @@ class TaskState(rx.State): # 临时用户提示词 temporary_user_prompt: str = "" - # 显示当前任务删除确认 + # 当前任务删除确认显示 is_task_delete_confirm_shown: bool = False + # 上一次任务删除确认显示日期时间 + last_task_delete_confirm_show_at: float = 0 # 当前数据库状态(私有变量) # 私有变量:reflex 约定以 _ 开头的变量为私有变量,后端不序列化,前端不可使用 @@ -155,26 +157,26 @@ class TaskState(rx.State): return f"更新于 {task.last_run_at.strftime("%Y-%m-%d %H:%M:%S")}" @rx.event - async def show_task_delete_confirm(self) -> None: + async def toggle_task_delete_confirm(self, is_shown: bool) -> None: """ - 显示当前任务删除确认 + 切换当前任务删除确认 + :param is_shown: 显示当前任务删除确认 :return: None """ - self.is_task_delete_confirm_shown = True + # 当前日期时间 + now = datetime.now().timestamp() + # 根据当前时间与上一次任务删除确认显示日期时间间隔防抖 + if now - self.last_task_delete_confirm_show_at < 0.2: + return + + self.is_task_delete_confirm_shown = is_shown + self.last_task_delete_confirm_show_at = now @rx.event - async def hide_task_delete_confirm(self) -> None: + async def delete_task(self) -> EventSpec | None: """ - 隐藏当前任务删除确认 - :return: None - """ - self.is_task_delete_confirm_shown = False - - @rx.event - async def confirm_task_delete(self) -> None: - """ - 确认当前任务删除 - :return: None + 删除当前任务 + :return: RX事件 """ from application.states import SidebarState @@ -195,6 +197,9 @@ class TaskState(rx.State): sidebar_state.nav_button = "" # 将空设置为当前任务唯一标识 self.task_id = "" + # 将任务删除确认显示设置为否 + self.is_task_delete_confirm_shown = False + return rx.toast.success("删除成功") @rx.event def set_task_id(self, task_id: str) -> None: diff --git a/agent/assets/styles.css b/agent/assets/styles.css index 872d8c7..603fc1b 100644 --- a/agent/assets/styles.css +++ b/agent/assets/styles.css @@ -2,10 +2,10 @@ --prismui-background-color-1: #ffffff; --prismui-background-color-2: #e6e6e6; --prismui-background-color-3: rgb(230, 230, 230); - --prismui-background-color-4: #babbc0; - --prismui-background-color-5: #ffffff33; - --prismui-background-color-6: #f2f2f3; - --prismui-background-color-7: #5e7ce0; + --prismui-background-color-4: #5e7ce0; + --prismui-background-color-5: #758ee0; + --prismui-background-color-6: rgb(232, 92, 92); + --prismui-background-color-7: rgb(236, 116, 116); --prismui-background-color-8: #beccfa; --prismui-background-color-9: rgb(242, 242, 242); /* @@ -26,7 +26,7 @@ --prismui-font-weight-4: 700; --prismui-color-1: #252b3a; --prismui-color-2: #575d6c; - --prismui-color-3: #babbc0; + --prismui-color-3: rgb(222, 222, 222); --prismui-color-4: rgba(37, 43, 58, 0.5); --prismui-color-5: #5e7ce0; --prismui-color-6: #f66f6a; @@ -147,7 +147,16 @@ pre, pre code { /* Button */ .rt-Button { - font-family: var(--prismui-font-family) !important; + font-family: var(--prismui-font-family); font-size: var(--prismui-font-size-2); color: var(--prismui-color-1); + height: 32px; + width: 68px; + background-color: var(--prismui-background-color-1); + border: 1px solid var(--prismui-color-3); + border-radius: var(--prismui-border-radius-3); + cursor: pointer; +} +.rt-Button:hover { + background-color: inherit; } \ No newline at end of file diff --git a/agent/database.db b/agent/database.db index 88a907c..5c99655 100644 Binary files a/agent/database.db and b/agent/database.db differ