App.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. <template>
  2. <div class="app-shell">
  3. <aside class="sidebar">
  4. <div class="brand">Windows 监控</div>
  5. <el-menu :default-active="activeView" background-color="#1f2937" text-color="#d1d5db" active-text-color="#fff" @select="activeView = $event">
  6. <el-menu-item index="dashboard">仪表盘</el-menu-item>
  7. <el-menu-item index="pending">待确认中心</el-menu-item>
  8. <el-menu-item index="services">Windows 服务</el-menu-item>
  9. <el-menu-item index="processes">Windows 进程</el-menu-item>
  10. <el-menu-item index="tags">标签管理</el-menu-item>
  11. <el-menu-item index="settings">系统设置</el-menu-item>
  12. <el-sub-menu index="ai">
  13. <template #title>AI 配置</template>
  14. <el-menu-item index="ai-providers">AI 服务商管理</el-menu-item>
  15. <el-menu-item index="ai-models">AI 模型管理</el-menu-item>
  16. <el-menu-item index="ai-test">AI 服务测试</el-menu-item>
  17. </el-sub-menu>
  18. <el-sub-menu index="automation">
  19. <template #title>自动化</template>
  20. <el-menu-item index="automation-actions">自动化操作</el-menu-item>
  21. <el-menu-item index="automation-workflows">自动化工作流</el-menu-item>
  22. <el-menu-item index="automation-screens">已识别界面</el-menu-item>
  23. <el-menu-item index="automation-errors">自动化错误记录</el-menu-item>
  24. </el-sub-menu>
  25. <el-menu-item index="sensors">传感器信息</el-menu-item>
  26. <el-menu-item index="smart">硬盘 SMART</el-menu-item>
  27. <el-menu-item index="scans">扫描历史</el-menu-item>
  28. </el-menu>
  29. </aside>
  30. <main class="main">
  31. <div class="topbar">
  32. <div>
  33. <div class="page-title">{{ title }}</div>
  34. <div class="muted">{{ subtitle }}</div>
  35. </div>
  36. <el-button type="primary" :loading="scanning" @click="runScan">执行扫描</el-button>
  37. </div>
  38. <section v-if="activeView === 'dashboard'">
  39. <div class="metrics">
  40. <div class="metric"><div class="metric-label">服务总数</div><div class="metric-value">{{ dashboard.service_total || 0 }}</div></div>
  41. <div class="metric"><div class="metric-label">进程总数</div><div class="metric-value">{{ dashboard.process_total || 0 }}</div></div>
  42. <div class="metric"><div class="metric-label">待确认服务</div><div class="metric-value">{{ dashboard.pending_services || 0 }}</div></div>
  43. <div class="metric"><div class="metric-label">待确认进程</div><div class="metric-value">{{ dashboard.pending_processes || 0 }}</div></div>
  44. <div class="metric"><div class="metric-label">本次未出现</div><div class="metric-value">{{ (dashboard.missing_services || 0) + (dashboard.missing_processes || 0) }}</div></div>
  45. </div>
  46. <div class="panel">
  47. <el-descriptions title="最近扫描" :column="2" border>
  48. <el-descriptions-item label="状态">{{ dashboard.latest_scan?.status || '-' }}</el-descriptions-item>
  49. <el-descriptions-item label="开始时间">{{ dashboard.latest_scan?.started_at || '-' }}</el-descriptions-item>
  50. <el-descriptions-item label="服务数量">{{ dashboard.latest_scan?.services_found ?? '-' }}</el-descriptions-item>
  51. <el-descriptions-item label="进程数量">{{ dashboard.latest_scan?.processes_found ?? '-' }}</el-descriptions-item>
  52. </el-descriptions>
  53. </div>
  54. </section>
  55. <section v-if="activeView === 'services'">
  56. <ItemTable type="service" ref="serviceTable" />
  57. </section>
  58. <section v-if="activeView === 'processes'">
  59. <ItemTable type="process" ref="processTable" />
  60. </section>
  61. <section v-if="activeView === 'pending'">
  62. <el-tabs v-model="pendingTab">
  63. <el-tab-pane label="待确认服务" name="services">
  64. <ItemTable type="service" confirm-status="PENDING" ref="pendingServiceTable" />
  65. </el-tab-pane>
  66. <el-tab-pane label="待确认进程" name="processes">
  67. <ItemTable type="process" confirm-status="PENDING" ref="pendingProcessTable" />
  68. </el-tab-pane>
  69. </el-tabs>
  70. </section>
  71. <section v-if="activeView === 'tags'">
  72. <TagManager />
  73. </section>
  74. <section v-if="activeView === 'settings'">
  75. <SystemSettingsView ref="systemSettingsView" />
  76. </section>
  77. <section v-if="activeView === 'ai-providers'">
  78. <AiProviderManager ref="aiProviderManager" />
  79. </section>
  80. <section v-if="activeView === 'ai-models'">
  81. <AiModelManager ref="aiModelManager" />
  82. </section>
  83. <section v-if="activeView === 'ai-test'">
  84. <AiTestView ref="aiTestView" />
  85. </section>
  86. <section v-if="activeView === 'automation-actions'">
  87. <AutomationActionView ref="automationActionView" />
  88. </section>
  89. <section v-if="activeView === 'automation-workflows'">
  90. <AutomationWorkflowView ref="automationWorkflowView" />
  91. </section>
  92. <section v-if="activeView === 'automation-screens'">
  93. <AutomationScreensView ref="automationScreensView" />
  94. </section>
  95. <section v-if="activeView === 'automation-errors'">
  96. <AutomationErrorsView ref="automationErrorsView" />
  97. </section>
  98. <section v-if="activeView === 'sensors'">
  99. <SensorView />
  100. </section>
  101. <section v-if="activeView === 'smart'">
  102. <SmartView />
  103. </section>
  104. <section v-if="activeView === 'scans'" class="panel">
  105. <el-table :data="scans.items" border stripe>
  106. <el-table-column prop="id" label="ID" width="80" />
  107. <el-table-column prop="status" label="状态" width="110" />
  108. <el-table-column prop="started_at" label="开始时间" min-width="180" />
  109. <el-table-column prop="finished_at" label="完成时间" min-width="180" />
  110. <el-table-column prop="services_found" label="服务" width="90" />
  111. <el-table-column prop="processes_found" label="进程" width="90" />
  112. <el-table-column prop="new_services" label="新增服务" width="100" />
  113. <el-table-column prop="new_processes" label="新增进程" width="100" />
  114. <el-table-column prop="error_message" label="错误" min-width="180" />
  115. </el-table>
  116. </section>
  117. </main>
  118. </div>
  119. </template>
  120. <script setup>
  121. import { computed, nextTick, onMounted, ref, watch } from 'vue'
  122. import { ElMessage } from 'element-plus'
  123. import { api } from './api'
  124. import AiModelManager from './components/AiModelManager.vue'
  125. import AiProviderManager from './components/AiProviderManager.vue'
  126. import AiTestView from './components/AiTestView.vue'
  127. import AutomationActionView from './components/AutomationActionView.vue'
  128. import AutomationErrorsView from './components/AutomationErrorsView.vue'
  129. import AutomationScreensView from './components/AutomationScreensView.vue'
  130. import AutomationWorkflowView from './components/AutomationWorkflowView.vue'
  131. import ItemTable from './components/ItemTable.vue'
  132. import SensorView from './components/SensorView.vue'
  133. import SmartView from './components/SmartView.vue'
  134. import SystemSettingsView from './components/SystemSettingsView.vue'
  135. import TagManager from './components/TagManager.vue'
  136. const activeView = ref('dashboard')
  137. const pendingTab = ref('services')
  138. const dashboard = ref({})
  139. const scans = ref({ items: [] })
  140. const scanning = ref(false)
  141. const serviceTable = ref(null)
  142. const processTable = ref(null)
  143. const pendingServiceTable = ref(null)
  144. const pendingProcessTable = ref(null)
  145. const aiProviderManager = ref(null)
  146. const aiModelManager = ref(null)
  147. const aiTestView = ref(null)
  148. const systemSettingsView = ref(null)
  149. const automationActionView = ref(null)
  150. const automationWorkflowView = ref(null)
  151. const automationScreensView = ref(null)
  152. const automationErrorsView = ref(null)
  153. const title = computed(() => ({
  154. dashboard: '仪表盘',
  155. pending: '待确认中心',
  156. services: 'Windows 服务',
  157. processes: 'Windows 进程',
  158. tags: '标签管理',
  159. settings: '系统设置',
  160. 'ai-providers': 'AI 服务商管理',
  161. 'ai-models': 'AI 模型管理',
  162. 'ai-test': 'AI 服务测试',
  163. 'automation-actions': '自动化操作',
  164. 'automation-workflows': '自动化工作流',
  165. 'automation-screens': '已识别界面',
  166. 'automation-errors': '自动化错误记录',
  167. sensors: '传感器信息',
  168. smart: '硬盘 SMART',
  169. scans: '扫描历史',
  170. })[activeView.value])
  171. const subtitle = computed(() => {
  172. if (String(activeView.value).startsWith('automation')) {
  173. return '通过 AI 视觉识别 Windows 界面,执行自动化动作,并沉淀可复用工作流。'
  174. }
  175. return '采集 Windows 服务和进程,确认可信状态,并整理给 AI 分析的数据。'
  176. })
  177. async function loadDashboard() {
  178. const { data } = await api.get('/api/dashboard')
  179. dashboard.value = data
  180. }
  181. async function loadScans() {
  182. const { data } = await api.get('/api/scans')
  183. scans.value = data
  184. }
  185. async function refreshCurrent() {
  186. await loadDashboard()
  187. if (activeView.value === 'scans') await loadScans()
  188. await nextTick()
  189. serviceTable.value?.load()
  190. processTable.value?.load()
  191. pendingServiceTable.value?.load()
  192. pendingProcessTable.value?.load()
  193. aiProviderManager.value?.load()
  194. aiModelManager.value?.refreshAll()
  195. aiTestView.value?.loadOptions()
  196. systemSettingsView.value?.load()
  197. automationActionView.value?.loadOptions()
  198. automationWorkflowView.value?.load()
  199. automationScreensView.value?.load()
  200. automationErrorsView.value?.load()
  201. }
  202. async function runScan() {
  203. scanning.value = true
  204. try {
  205. const { data } = await api.post('/api/scans/run')
  206. ElMessage.success(`扫描完成:服务 ${data.services_found},进程 ${data.processes_found}`)
  207. await refreshCurrent()
  208. } catch (error) {
  209. ElMessage.error(error.response?.data?.detail || '扫描失败')
  210. } finally {
  211. scanning.value = false
  212. }
  213. }
  214. watch(activeView, async (view) => {
  215. if (view === 'dashboard') await loadDashboard()
  216. if (view === 'scans') await loadScans()
  217. if (view === 'settings') await systemSettingsView.value?.load()
  218. if (view === 'automation-workflows') await automationWorkflowView.value?.load()
  219. if (view === 'automation-screens') await automationScreensView.value?.load()
  220. if (view === 'automation-errors') await automationErrorsView.value?.load()
  221. })
  222. onMounted(refreshCurrent)
  223. </script>