Эх сурвалжийг харах

[Mod 0000]AI助手增加全局统一的空提示组件

wangkeyi 4 өдөр өмнө
parent
commit
75f8c31508

+ 2 - 8
src/views/ventAI/manageAssistent/components/chat/Input/SessionPopup.vue

@@ -23,7 +23,7 @@
         <div class="session-item-icon"></div>
         <span class="session-item-name">{{ task.name }}</span>
       </div>
-      <div v-if="list.length === 0" class="session-empty">暂无匹配会话</div>
+      <EmptyState v-if="list.length === 0" description="暂无匹配会话" />
     </div>
     <div class="session-popup-footer">
       <span v-if="selectedCount >= 5" class="max-hint">最多选择5个会话</span>
@@ -35,6 +35,7 @@
 <script setup lang="ts">
   import { computed, ref } from 'vue';
   import { onClickOutside } from '@vueuse/core';
+  import EmptyState from '/@/views/ventAI/manageAssistent/components/common/EmptyState.vue';
 
   interface SessionOption {
     id: string;
@@ -168,14 +169,7 @@
         }
       }
 
-      .session-empty {
-        text-align: center;
-        color: #8b949e;
-        font-size: 13px;
-        padding: 20px 0;
-      }
     }
-
     .session-popup-footer {
       padding: 8px 14px;
       font-size: 12px;

+ 2 - 7
src/views/ventAI/manageAssistent/components/chat/Input/SkillPopup.vue

@@ -22,7 +22,7 @@
         <div class="skill-item-icon"></div>
         <span class="skill-item-name">{{ skill.display_name }}</span>
       </div>
-      <div v-if="list.length === 0" class="skill-empty">{{ loadFailed ? '技能列表加载失败,请稍后重试' : '暂无匹配技能' }}</div>
+      <EmptyState v-if="list.length === 0" :description="loadFailed ? '技能列表加载失败,请稍后重试' : '暂无匹配技能'" />
     </div>
     <div class="skill-popup-footer">
       <span>点击选择技能(仅可选1个)</span>
@@ -31,6 +31,7 @@
 </template>
 
 <script setup lang="ts">
+  import EmptyState from '/@/views/ventAI/manageAssistent/components/common/EmptyState.vue';
   import { ref } from 'vue';
   import { onClickOutside } from '@vueuse/core';
 
@@ -156,12 +157,6 @@
         }
       }
 
-      .skill-empty {
-        text-align: center;
-        color: #8b949e;
-        font-size: 13px;
-        padding: 20px 0;
-      }
     }
 
     .skill-popup-footer {

+ 47 - 0
src/views/ventAI/manageAssistent/components/common/EmptyState.vue

@@ -0,0 +1,47 @@
+<template>
+  <div :class="['empty-state', `empty-state-${size}`]">{{ description }}</div>
+</template>
+
+<script setup lang="ts">
+  /**
+   * 空态占位:数据为空时的一行居中提示。
+   *
+   * 统一前模块内有 7 处各写一份的同类样式(字号 12/13px、颜色三种灰、内边距 8/16/20px 各不相同),
+   * 这里收敛为两档尺寸:
+   * - md(默认):面板级空态,13px / 次级文字色 / 上下 20px
+   * - sm:列表与弹层内的紧凑空态,12px / 更弱的文字色 / 上下 12px
+   *
+   * 颜色取自 styles/tokens.less 的既有基线值(@color-text-muted=#8b949e、@color-text-dim=#6a7a8a),
+   * 对原来用这两个色的位置是等值替换。
+   *
+   * 不覆盖的几种情况(语义不同,刻意保留各自实现):
+   * - 新对话缺省图(是图片,不是文字空态);
+   * - 预览面板的"不支持此格式"(图标 + 主文案 + 副文案三级结构);
+   * - 子智能体详情里的"继承主 Agent 全部工具"(行内斜体说明,非居中占位);
+   * - 各处已有的 a-empty(用的是组件库现成件,本就统一)。
+   */
+  withDefaults(defineProps<{ description: string; size?: 'md' | 'sm' }>(), { size: 'md' });
+</script>
+
+<style scoped lang="less">
+  @import '../../styles/tokens.less';
+
+  .empty-state {
+    /* width:100% 是必需的:本组件会被放进 flex 容器(如工具标签区),
+       不写宽度时块级元素会退化成文字宽度,既不再撑满一行、也失去居中的视觉位置 */
+    width: 100%;
+    text-align: center;
+  }
+
+  .empty-state-md {
+    padding: 20px 0;
+    font-size: 13px;
+    color: @color-text-muted;
+  }
+
+  .empty-state-sm {
+    padding: 12px 0;
+    font-size: 12px;
+    color: @color-text-dim;
+  }
+</style>

+ 2 - 8
src/views/ventAI/manageAssistent/components/modals/CreateSubAgentModal.vue

@@ -65,7 +65,7 @@
                   <span class="tool-tag-name">{{ tool.display_name }}</span>
                   <div v-if="form.tools.includes(tool.name)" class="tool-tag-check"></div>
                 </div>
-                <div v-if="filteredActiveTools.length === 0" class="tools-empty-hint">无匹配工具</div>
+                <EmptyState v-if="filteredActiveTools.length === 0" size="sm" description="无匹配工具" />
               </div>
             </div>
           </div>
@@ -103,6 +103,7 @@
 </template>
 
 <script setup lang="ts">
+  import EmptyState from '/@/views/ventAI/manageAssistent/components/common/EmptyState.vue';
   import { ref, reactive, computed, watch } from 'vue';
   import { createSubAgent, updateSubAgent, getSubAgentTools, extractApiErrorMessage } from '/@/views/ventAI/manageAssistent/api';
   import { message } from 'ant-design-vue';
@@ -536,13 +537,6 @@
     }
   }
 
-  .tools-empty-hint {
-    font-size: 12px;
-    color: #6a7a8a;
-    padding: 20px 0;
-    text-align: center;
-    width: 100%;
-  }
 
   .tools-selected-summary {
     display: flex;

+ 2 - 7
src/views/ventAI/manageAssistent/components/panels/FileListPanel.vue

@@ -12,12 +12,13 @@
           <div class="file-size-small">{{ formatFileSize(file.size) }}</div>
         </div>
       </div>
-      <div v-if="files.length === 0" class="empty-file-list">暂无附件</div>
+      <EmptyState v-if="files.length === 0" description="暂无附件" />
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
+  import EmptyState from '/@/views/ventAI/manageAssistent/components/common/EmptyState.vue';
   import { CloseOutlined } from '@ant-design/icons-vue';
   import { formatFileSize, getFileIconVar } from '/@/views/ventAI/manageAssistent/lib/index';
   import type { AttachedFile } from '/@/views/ventAI/manageAssistent/types/index';
@@ -122,12 +123,6 @@
         }
       }
 
-      .empty-file-list {
-        padding: 20px;
-        text-align: center;
-        color: #8b949e;
-        font-size: 12px;
-      }
     }
   }
 </style>

+ 2 - 7
src/views/ventAI/manageAssistent/components/panels/RightPanelTabs.vue

@@ -25,7 +25,7 @@
               ></div>
               <span class="tab-list-item-title">{{ tab.title }}</span>
             </div>
-            <div v-if="filteredTabs.length === 0" class="tab-list-empty">暂无匹配标签页</div>
+            <EmptyState v-if="filteredTabs.length === 0" size="sm" description="暂无匹配标签页" />
           </div>
         </div>
       </div>
@@ -78,6 +78,7 @@
 </template>
 
 <script setup lang="ts">
+  import EmptyState from '/@/views/ventAI/manageAssistent/components/common/EmptyState.vue';
   import { computed, nextTick, ref } from 'vue';
   import { onClickOutside, useResizeObserver } from '@vueuse/core';
   import FilePreviewPanel from '/@/views/ventAI/manageAssistent/components/resource/FilePreviewPanel.vue';
@@ -337,12 +338,6 @@
               }
             }
 
-            .tab-list-empty {
-              padding: 16px 0;
-              color: #6b7684;
-              text-align: center;
-              font-size: 12px;
-            }
           }
         }
       }

+ 2 - 7
src/views/ventAI/manageAssistent/components/panels/ScheduleDetailPanel.vue

@@ -73,7 +73,7 @@
               <div v-if="run.error" class="history-error">{{ run.error }}</div>
             </div>
           </template>
-          <div v-else class="history-empty">暂无执行记录</div>
+          <EmptyState v-else size="sm" description="暂无执行记录" />
         </div>
         <div v-else class="detail-history-loading">
           <a-spin size="small" />
@@ -86,6 +86,7 @@
 </template>
 
 <script setup lang="ts">
+  import EmptyState from '/@/views/ventAI/manageAssistent/components/common/EmptyState.vue';
   import { ref, watch } from 'vue';
   import { onClickOutside } from '@vueuse/core';
   import { message, Modal } from 'ant-design-vue';
@@ -545,12 +546,6 @@
     line-height: 1.6;
   }
 
-  .history-empty {
-    padding: 8px 0;
-    color: #6a7a8a;
-    text-align: center;
-    font-size: 12px;
-  }
 </style>
 
 <style scoped lang="less">

+ 3 - 14
src/views/ventAI/manageAssistent/components/panels/SchedulePanel.vue

@@ -84,12 +84,12 @@
                 <div v-if="run.error" class="history-error">{{ run.error }}</div>
               </div>
             </template>
-            <div v-else class="history-empty">暂无执行记录</div>
+            <EmptyState v-else size="sm" description="暂无执行记录" />
           </div>
         </div>
       </div>
       <template v-if="filteredScheduleList.length === 0">
-        <div v-if="searchKeyword" class="schedule-empty-hint">未找到匹配的任务</div>
+        <EmptyState v-if="searchKeyword" description="未找到匹配的任务" />
         <a-empty v-else description="暂无定时任务" />
       </template>
     </div>
@@ -109,6 +109,7 @@
 </template>
 
 <script setup lang="ts">
+  import EmptyState from '/@/views/ventAI/manageAssistent/components/common/EmptyState.vue';
   import { ref, reactive, computed, onMounted } from 'vue';
   import { PlusOutlined } from '@ant-design/icons-vue';
   import { getScheduleList, deleteSchedule, pauseSchedule, resumeSchedule, getScheduleRuns } from '/@/views/ventAI/manageAssistent/api';
@@ -729,17 +730,5 @@
     line-height: 1.6;
   }
 
-  .history-empty {
-    font-size: 12px;
-    color: #6a7a8a;
-    text-align: center;
-    padding: 8px 0;
-  }
 
-  .schedule-empty-hint {
-    text-align: center;
-    color: #8b949e;
-    font-size: 13px;
-    padding: 20px 0;
-  }
 </style>

+ 3 - 8
src/views/ventAI/manageAssistent/components/panels/TaskListPanel.vue

@@ -47,14 +47,15 @@
           <div class="task-delete" @click.stop="emit('delete-task', task, index)" title="删除"></div>
         </div>
       </div>
-      <div v-if="searchKeyword && filteredTaskList.length === 0" class="empty-hint"> 未找到匹配的任务 </div>
-      <div v-else-if="filteredTaskList.length === 0" class="empty-hint"> 还没有任务 </div>
+      <EmptyState v-if="searchKeyword && filteredTaskList.length === 0" description="未找到匹配的任务" />
+      <EmptyState v-else-if="filteredTaskList.length === 0" description="还没有任务" />
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
   import { ref, computed } from 'vue';
+  import EmptyState from '/@/views/ventAI/manageAssistent/components/common/EmptyState.vue';
   import type { Task } from '/@/views/ventAI/manageAssistent/types/index';
 
   const props = defineProps<{
@@ -297,12 +298,6 @@
         }
       }
 
-      .empty-hint {
-        text-align: center;
-        color: #8b949e;
-        font-size: 13px;
-        padding: 20px 0;
-      }
     }
 
     @keyframes task-spin {