ForcePilot/web/src/composables/external-systems/useExternalTool.js
Kris f2b21c27b6 feat(external-systems): 新增外部系统集成模块完整功能
新增23个API模块、路由、状态管理与通用组件,重构重复代码,完成外部系统集成全功能搭建
2026-06-20 22:21:34 +08:00

590 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { ref, reactive, computed } from 'vue'
import {
getToolListApi,
getToolDetailApi,
createToolApi,
updateToolApi,
deleteToolApi,
getEnabledToolsApi,
getToolOptionsApi,
exportToolsApi,
exportToolWsdlApi,
importToolsApi,
importToolsFromWsdlApi,
executeToolApi,
batchExecuteToolsApi,
batchCloneToolsApi,
cloneToolApi,
getToolVersionsApi,
compareToolVersionsApi,
rollbackToolVersionApi,
getToolParameterTemplateApi,
getToolExecutionTrendApi,
getToolAssetsApi
} from '@/apis/external-systems/tool_api'
import { getEnvironmentListApi } from '@/apis/external-systems/environment_api'
import { getAccessRuleListApi } from '@/apis/external-systems/access_rule_api'
import { unwrap } from './utils'
/**
* 工具管理 composable
* 封装工具列表/详情/CRUD/执行/批量/克隆/版本/参数模板/执行趋势/依赖资产/访问规则的 API 调用与状态管理
*
* 字段契约对齐 backend/server/routers/external_systems/tool_router.py
* - list_tools: query 用 offset/limit非 skiplimit 默认 100 最大 500
* - execute: body 用 tool_slug/env_key/arguments非 tool_id/environment_id/parameters
* - batch_execute: body 用 executions: [{tool_slug, system_id, env_key, arguments}]
* - clone: body 用 system_id非 target_system_id
* - batch_clone: body 用 source_tool_ids非 tool_ids
* - execution_trend: query 用 interval/env_key非 granularity/environment_id
*/
export function useExternalTool() {
// ===== 列表 =====
const list = ref([])
const listLoading = ref(false)
const listError = ref(null)
const total = ref(0)
const pagination = reactive({
current: 1,
pageSize: 100
})
const filters = reactive({
system_id: undefined,
category: undefined,
adapter_type: undefined,
enabled: undefined,
keyword: ''
})
// ===== 详情 =====
const detail = ref(null)
const detailLoading = ref(false)
const detailError = ref(null)
// ===== 版本 =====
const versions = ref([])
const versionsLoading = ref(false)
const versionsError = ref(null)
const compareResult = ref(null)
const compareLoading = ref(false)
const compareError = ref(null)
// ===== 参数模板 =====
const parameterTemplate = ref(null)
const parameterTemplateLoading = ref(false)
const parameterTemplateError = ref(null)
// ===== 执行趋势 =====
const executionTrend = ref(null)
const executionTrendLoading = ref(false)
const executionTrendError = ref(null)
// ===== 依赖资产 =====
const assets = ref(null)
const assetsLoading = ref(false)
const assetsError = ref(null)
// ===== 访问规则(详情页访问规则 Tab=====
const accessRules = ref([])
const accessRulesLoading = ref(false)
const accessRulesError = ref(null)
// ===== 选项与启用列表 =====
const options = ref(null)
const optionsLoading = ref(false)
const enabledTools = ref([])
const enabledToolsLoading = ref(false)
// ===== 环境列表(用于执行趋势/执行弹窗的环境筛选)=====
const environments = ref([])
const environmentsLoading = ref(false)
// ===== 操作状态 =====
const submitting = ref(false)
const submitError = ref(null)
const executing = ref(false)
const executeResult = ref(null)
const executeError = ref(null)
const cloning = ref(false)
const batchCloning = ref(false)
const batchExecuting = ref(false)
const importing = ref(false)
const importResult = ref(null)
const rollingBack = ref(false)
const isEmpty = computed(() => !list.value?.length)
// ===== 列表 =====
async function fetchList() {
listLoading.value = true
listError.value = null
try {
const params = {
offset: (pagination.current - 1) * pagination.pageSize,
limit: pagination.pageSize,
...filters
}
// 清理 undefined 字段
Object.keys(params).forEach((k) => {
if (params[k] === undefined || params[k] === '' || params[k] === null) {
delete params[k]
}
})
const res = unwrap(await getToolListApi(params))
list.value = res?.items || []
total.value = res?.total ?? list.value.length
} catch (err) {
listError.value = err
list.value = []
total.value = 0
} finally {
listLoading.value = false
}
}
function setFilter(newFilters) {
Object.assign(filters, newFilters)
pagination.current = 1
}
function resetFilters() {
filters.system_id = undefined
filters.category = undefined
filters.adapter_type = undefined
filters.enabled = undefined
filters.keyword = ''
pagination.current = 1
}
function setPagination({ page, pageSize }) {
if (pageSize) pagination.pageSize = pageSize
if (page) pagination.current = page
}
// ===== 详情 =====
async function fetchDetail(id) {
detailLoading.value = true
detailError.value = null
detail.value = null
try {
detail.value = unwrap(await getToolDetailApi(id)) || null
} catch (err) {
detailError.value = err
} finally {
detailLoading.value = false
}
}
// ===== CRUD =====
async function create(data) {
submitting.value = true
submitError.value = null
try {
return unwrap(await createToolApi(data))
} catch (err) {
submitError.value = err
throw err
} finally {
submitting.value = false
}
}
async function update(id, data) {
submitting.value = true
submitError.value = null
try {
return unwrap(await updateToolApi(id, data))
} catch (err) {
submitError.value = err
throw err
} finally {
submitting.value = false
}
}
async function remove(id) {
submitError.value = null
try {
await deleteToolApi(id)
return true
} catch (err) {
submitError.value = err
throw err
}
}
// ===== 克隆 =====
async function clone(id, data) {
cloning.value = true
submitError.value = null
try {
return unwrap(await cloneToolApi(id, data))
} catch (err) {
submitError.value = err
throw err
} finally {
cloning.value = false
}
}
async function batchClone(data) {
batchCloning.value = true
submitError.value = null
try {
return unwrap(await batchCloneToolsApi(data))
} catch (err) {
submitError.value = err
throw err
} finally {
batchCloning.value = false
}
}
// ===== 执行 =====
async function execute(data) {
executing.value = true
executeError.value = null
executeResult.value = null
try {
executeResult.value = unwrap(await executeToolApi(data)) || null
return executeResult.value
} catch (err) {
executeError.value = err
throw err
} finally {
executing.value = false
}
}
async function batchExecute(data) {
batchExecuting.value = true
submitError.value = null
try {
return unwrap(await batchExecuteToolsApi(data))
} catch (err) {
submitError.value = err
throw err
} finally {
batchExecuting.value = false
}
}
// ===== 版本 =====
async function fetchVersions(id, params) {
versionsLoading.value = true
versionsError.value = null
try {
const res = unwrap(await getToolVersionsApi(id, params))
versions.value = res?.items || res || []
} catch (err) {
versionsError.value = err
versions.value = []
} finally {
versionsLoading.value = false
}
}
async function compareVersions(id, v1, v2) {
compareLoading.value = true
compareError.value = null
compareResult.value = null
try {
compareResult.value = unwrap(await compareToolVersionsApi(id, v1, v2)) || null
return compareResult.value
} catch (err) {
compareError.value = err
throw err
} finally {
compareLoading.value = false
}
}
async function rollbackVersion(id, v) {
rollingBack.value = true
submitError.value = null
try {
return unwrap(await rollbackToolVersionApi(id, v))
} catch (err) {
submitError.value = err
throw err
} finally {
rollingBack.value = false
}
}
// ===== 参数模板 =====
async function fetchParameterTemplate(id) {
parameterTemplateLoading.value = true
parameterTemplateError.value = null
parameterTemplate.value = null
try {
parameterTemplate.value = unwrap(await getToolParameterTemplateApi(id)) || null
return parameterTemplate.value
} catch (err) {
parameterTemplateError.value = err
throw err
} finally {
parameterTemplateLoading.value = false
}
}
// ===== 执行趋势 =====
async function fetchExecutionTrend(id, params) {
executionTrendLoading.value = true
executionTrendError.value = null
try {
executionTrend.value = unwrap(await getToolExecutionTrendApi(id, params)) || null
return executionTrend.value
} catch (err) {
executionTrendError.value = err
} finally {
executionTrendLoading.value = false
}
}
// ===== 依赖资产 =====
async function fetchAssets(id) {
assetsLoading.value = true
assetsError.value = null
try {
assets.value = unwrap(await getToolAssetsApi(id)) || null
return assets.value
} catch (err) {
assetsError.value = err
} finally {
assetsLoading.value = false
}
}
// ===== 访问规则(按 tool_slug 查询,供详情页访问规则 Tab 使用)=====
async function fetchAccessRules(toolSlug, params = {}) {
accessRulesLoading.value = true
accessRulesError.value = null
try {
const res = unwrap(await getAccessRuleListApi({ tool_slug: toolSlug, ...params }))
accessRules.value = res?.items || []
return accessRules.value
} catch (err) {
accessRulesError.value = err
accessRules.value = []
} finally {
accessRulesLoading.value = false
}
}
// ===== 选项与启用列表 =====
async function fetchOptions(params) {
optionsLoading.value = true
try {
options.value = unwrap(await getToolOptionsApi(params)) || null
return options.value
} catch {
options.value = null
} finally {
optionsLoading.value = false
}
}
async function fetchEnabledTools(params) {
enabledToolsLoading.value = true
try {
const res = unwrap(await getEnabledToolsApi(params))
enabledTools.value = res?.items || res || []
return enabledTools.value
} catch {
enabledTools.value = []
} finally {
enabledToolsLoading.value = false
}
}
// ===== 环境列表(用于执行趋势/执行弹窗的环境筛选)=====
async function fetchEnvironments(params) {
environmentsLoading.value = true
try {
const res = unwrap(await getEnvironmentListApi(params))
environments.value = res?.items || []
return environments.value
} catch {
environments.value = []
} finally {
environmentsLoading.value = false
}
}
// ===== 导入 =====
async function importTools(data) {
importing.value = true
importResult.value = null
try {
importResult.value = unwrap(await importToolsApi(data)) || null
return importResult.value
} catch (err) {
submitError.value = err
throw err
} finally {
importing.value = false
}
}
async function importFromWsdl(data) {
importing.value = true
importResult.value = null
try {
importResult.value = unwrap(await importToolsFromWsdlApi(data)) || null
return importResult.value
} catch (err) {
submitError.value = err
throw err
} finally {
importing.value = false
}
}
// ===== 导出blob=====
async function exportTools(params) {
try {
const response = await exportToolsApi(params)
return response
} catch (err) {
submitError.value = err
throw err
}
}
async function exportWsdl(params) {
try {
const response = await exportToolWsdlApi(params)
return response
} catch (err) {
submitError.value = err
throw err
}
}
// ===== 重置 =====
function resetDetail() {
detail.value = null
detailError.value = null
detailLoading.value = false
}
function resetVersions() {
versions.value = []
versionsError.value = null
compareResult.value = null
compareError.value = null
}
function resetExecute() {
executeResult.value = null
executeError.value = null
}
function resetErrors() {
listError.value = null
detailError.value = null
versionsError.value = null
compareError.value = null
parameterTemplateError.value = null
executionTrendError.value = null
assetsError.value = null
accessRulesError.value = null
submitError.value = null
executeError.value = null
}
return {
// 列表
list,
listLoading,
listError,
total,
pagination,
filters,
isEmpty,
fetchList,
setFilter,
resetFilters,
setPagination,
// 详情
detail,
detailLoading,
detailError,
fetchDetail,
resetDetail,
// CRUD
create,
update,
remove,
submitting,
submitError,
// 克隆
clone,
batchClone,
cloning,
batchCloning,
// 执行
execute,
batchExecute,
executing,
batchExecuting,
executeResult,
executeError,
resetExecute,
// 版本
versions,
versionsLoading,
versionsError,
fetchVersions,
compareResult,
compareLoading,
compareError,
compareVersions,
rollbackVersion,
rollingBack,
resetVersions,
// 参数模板
parameterTemplate,
parameterTemplateLoading,
parameterTemplateError,
fetchParameterTemplate,
// 执行趋势
executionTrend,
executionTrendLoading,
executionTrendError,
fetchExecutionTrend,
// 依赖资产
assets,
assetsLoading,
assetsError,
fetchAssets,
// 访问规则
accessRules,
accessRulesLoading,
accessRulesError,
fetchAccessRules,
// 选项与启用
options,
optionsLoading,
fetchOptions,
enabledTools,
enabledToolsLoading,
fetchEnabledTools,
// 环境(用于执行趋势/执行弹窗筛选)
environments,
environmentsLoading,
fetchEnvironments,
// 导入
importTools,
importFromWsdl,
importing,
importResult,
// 导出
exportTools,
exportWsdl,
// 重置
resetErrors
}
}