Explorar el Código

去除会话完成状态

moki hace 3 días
padre
commit
e20ff5cae5

+ 9 - 12
src/components/PortStatusCard.vue

@@ -1,21 +1,19 @@
 <script setup lang="ts">
-import { computed } from 'vue'
-import type { PortState, StatusCode } from '@/types'
-import { STATUS_CONFIG } from '@/types'
+import {computed} from 'vue'
+import type {PortState, StatusCode} from '@/types'
+import {STATUS_CONFIG} from '@/types'
 import {
+  BulbOutlined,
   CheckCircleOutlined,
-  LoadingOutlined,
-  SyncOutlined,
+  CloseCircleOutlined,
   EditOutlined,
-  BulbOutlined,
-  ToolOutlined,
-  ThunderboltOutlined,
-  SmileOutlined,
+  LoadingOutlined,
   LockOutlined,
-  CloseCircleOutlined,
   PauseCircleOutlined,
+  SyncOutlined,
+  ThunderboltOutlined,
+  ToolOutlined,
 } from '@ant-design/icons-vue'
-import StatusTag from './StatusTag.vue'
 
 const props = defineProps<{
   state: PortState
@@ -51,7 +49,6 @@ const iconMap: Record<StatusCode, typeof CheckCircleOutlined> = {
   using_tool: ToolOutlined,
   running: ThunderboltOutlined,
   completed: CheckCircleOutlined,
-  session_completed: SmileOutlined,
   permission: LockOutlined,
   error: CloseCircleOutlined,
 }

+ 0 - 99
src/components/SessionCompletedCard.vue

@@ -1,99 +0,0 @@
-<script lang="ts" setup>
-const ringCount = 4
-</script>
-
-<template>
-  <div class="session-card">
-    <div class="glow glow-1"/>
-    <div class="glow glow-2"/>
-    <div class="ring-group">
-      <div
-          v-for="i in ringCount"
-          :key="i"
-          :style="{ animationDelay: `${(i - 1) * 0.5}s` }"
-          class="ring"
-      />
-    </div>
-  </div>
-</template>
-
-<style scoped>
-.session-card {
-  position: relative;
-  aspect-ratio: 3 / 1;
-  background: #161616;
-  border-radius: 8px;
-  overflow: hidden;
-  border: 1px solid rgba(140, 140, 140, 0.2);
-  box-shadow: 0 0 12px rgba(140, 140, 140, 0.05),
-  inset 0 0 20px rgba(0, 0, 0, 0.3);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-.glow {
-  position: absolute;
-  inset: -50%;
-  filter: blur(40px);
-}
-
-.glow-1 {
-  background: radial-gradient(ellipse at 40% 50%, #8c8c8c 0%, transparent 55%);
-  opacity: 0.12;
-  animation: drift-1 8s ease-in-out infinite alternate;
-}
-
-.glow-2 {
-  background: radial-gradient(ellipse at 60% 50%, #595959 0%, transparent 50%);
-  opacity: 0.1;
-  animation: drift-2 10s ease-in-out infinite alternate;
-}
-
-.ring-group {
-  position: absolute;
-  inset: 0;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1;
-}
-
-.ring {
-  position: absolute;
-  border-radius: 50%;
-  border: 1.5px solid #8c8c8c;
-  animation: fade-expand 3s ease-out infinite;
-}
-
-@keyframes fade-expand {
-  0% {
-    width: 8px;
-    height: 8px;
-    opacity: 0.8;
-  }
-  100% {
-    width: 90px;
-    height: 90px;
-    opacity: 0;
-  }
-}
-
-@keyframes drift-1 {
-  0% {
-    transform: translate(-15%, -10%) scale(0.9);
-  }
-  100% {
-    transform: translate(15%, 10%) scale(1.1);
-  }
-}
-
-@keyframes drift-2 {
-  0% {
-    transform: translate(10%, 10%) scale(1.1);
-  }
-  100% {
-    transform: translate(-10%, -10%) scale(0.9);
-  }
-}
-</style>

+ 34 - 0
src/components/StatusCard.vue

@@ -0,0 +1,34 @@
+<script lang="ts" setup>
+import type {StatusCode} from '@/types'
+import ReasoningCard from './ReasoningCard.vue'
+import BusyCard from './BusyCard.vue'
+import IdleCard from './IdleCard.vue'
+import RetryCard from './RetryCard.vue'
+import PendingCard from './PendingCard.vue'
+import UsingToolCard from './UsingToolCard.vue'
+import RunningCard from './RunningCard.vue'
+import CompletedCard from './CompletedCard.vue'
+import PermissionCard from './PermissionCard.vue'
+import ErrorCard from './ErrorCard.vue'
+
+const props = defineProps<{
+  code: StatusCode
+}>()
+
+const cardMap: Record<StatusCode, typeof ReasoningCard | null> = {
+  reasoning: ReasoningCard,
+  busy: BusyCard,
+  idle: IdleCard,
+  retry: RetryCard,
+  pending: PendingCard,
+  using_tool: UsingToolCard,
+  running: RunningCard,
+  completed: CompletedCard,
+  permission: PermissionCard,
+  error: ErrorCard,
+}
+</script>
+
+<template>
+  <component :is="cardMap[code]" v-if="cardMap[code]"/>
+</template>

+ 0 - 2
src/types/index.ts

@@ -49,7 +49,6 @@ export type StatusCode =
   | 'using_tool'
   | 'running'
   | 'completed'
-  | 'session_completed'
   | 'permission'
   | 'error'
 
@@ -76,7 +75,6 @@ export const STATUS_CONFIG: Record<StatusCode, { color: string; label: string }>
   using_tool: { color: 'orange', label: '使用工具中' },
   running: { color: 'cyan', label: '运行中' },
   completed: { color: 'lime', label: '工具执行完成' },
-  session_completed: { color: 'default', label: '会话完成' },
   permission: { color: 'yellow', label: '等待权限' },
   error: { color: 'red', label: '错误' },
 }

+ 41 - 32
src/views/Dashboard.vue

@@ -4,17 +4,7 @@ import {useSSE} from '@/composables/useSSE'
 import {getClients} from '@/api/client'
 import type {PortState, StatusMessage} from '@/types'
 import PortStatusCard from '@/components/PortStatusCard.vue'
-import ReasoningCard from '@/components/ReasoningCard.vue'
-import BusyCard from '@/components/BusyCard.vue'
-import IdleCard from '@/components/IdleCard.vue'
-import RetryCard from '@/components/RetryCard.vue'
-import PendingCard from '@/components/PendingCard.vue'
-import UsingToolCard from '@/components/UsingToolCard.vue'
-import RunningCard from '@/components/RunningCard.vue'
-import CompletedCard from '@/components/CompletedCard.vue'
-import SessionCompletedCard from '@/components/SessionCompletedCard.vue'
-import PermissionCard from '@/components/PermissionCard.vue'
-import ErrorCard from '@/components/ErrorCard.vue'
+import StatusCard from '@/components/StatusCard.vue'
 
 const { connected, onMessage, onDisconnect } = useSSE('/api/events')
 
@@ -34,11 +24,6 @@ function sendNotification(port: number, status: string) {
 }
 
 const removeListener = onMessage((msg: StatusMessage) => {
-  const prev = ports.get(msg.port)
-  if (prev && msg.code === 'session_completed' && prev.code !== 'session_completed' && !notified.has(msg.port)) {
-    notified.add(msg.port)
-    sendNotification(msg.port, msg.status)
-  }
   if (msg.code === 'idle') {
     notified.delete(msg.port)
   }
@@ -119,23 +104,20 @@ onUnmounted(removeDisconnectListener)
     <a-empty v-if="portList.length === 0" description="等待端口状态推送..." />
 
     <div class="port-grid">
-      <PortStatusCard v-for="port in portList" :key="port.port" :state="port" />
+      <div v-for="port in portList" :key="port.port" class="port-item">
+        <StatusCard :code="port.code" class="port-anim"/>
+        <PortStatusCard :state="port" class="port-info"/>
+      </div>
     </div>
 
     <div style="margin-top: 24px;">
-      <h3 style="margin-bottom: 12px; color: var(--text-secondary);">调试:动画卡片预览</h3>
-      <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px;">
-        <ReasoningCard style="grid-column: span 2;"/>
-        <BusyCard style="grid-column: span 2;"/>
-        <IdleCard style="grid-column: span 2;"/>
-        <RetryCard style="grid-column: span 2;"/>
-        <PendingCard style="grid-column: span 2;"/>
-        <UsingToolCard style="grid-column: span 2;"/>
-        <RunningCard style="grid-column: span 2;"/>
-        <CompletedCard style="grid-column: span 2;"/>
-        <SessionCompletedCard style="grid-column: span 2;"/>
-        <PermissionCard style="grid-column: span 2;"/>
-        <ErrorCard style="grid-column: span 2;"/>
+      <h3 style="margin-bottom: 12px; color: var(--text-secondary);">动画卡片预览</h3>
+      <div class="preview-grid">
+        <div
+            v-for="code in (['reasoning','busy','idle','retry','pending','using_tool','running','completed','permission','error'] as const)"
+            :key="code" class="preview-item">
+          <StatusCard :code="code"/>
+        </div>
       </div>
     </div>
   </div>
@@ -192,10 +174,37 @@ onUnmounted(removeDisconnectListener)
 
 .port-grid {
   display: grid;
-  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
+  grid-template-columns: 1fr;
   gap: 16px;
 }
 
+.port-item {
+  display: flex;
+  gap: 12px;
+  align-items: stretch;
+}
+
+.port-anim {
+  aspect-ratio: 3 / 1;
+  flex-shrink: 0;
+}
+
+.port-info {
+  flex: 1;
+  min-width: 0;
+  overflow: hidden;
+}
+
+.preview-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+  gap: 16px;
+}
+
+.preview-item {
+  aspect-ratio: 3 / 1;
+}
+
 @media (max-width: 767px) {
   .stats-bar {
     flex-wrap: wrap;
@@ -221,7 +230,7 @@ onUnmounted(removeDisconnectListener)
   }
 
   .port-grid {
-    grid-template-columns: repeat(2, 1fr);
+    grid-template-columns: 1fr;
     gap: 12px;
   }
 }