ForcePilot/web/src/composables/external-systems/useExternalTool.js

590 lines
14 KiB
JavaScript
Raw Normal View History

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
}
}