2026-06-16 14:30:09 +08:00
|
|
|
|
// =============================================================================
|
|
|
|
|
|
// 排查模板 API 客户端
|
|
|
|
|
|
// =============================================================================
|
|
|
|
|
|
// 对接后端 /api/troubleshooting-templates 5 个 REST 端点
|
|
|
|
|
|
// 5 个端点:GET 列表 / GET 详情 / POST 新建 / PUT 更新 / DELETE 删除
|
|
|
|
|
|
// =============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
import axios from 'axios'
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
// 类型定义
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
/** 步骤节点(顺序执行) */
|
|
|
|
|
|
export interface PathStepNode {
|
|
|
|
|
|
id: string
|
|
|
|
|
|
type: 'step'
|
|
|
|
|
|
label: string
|
|
|
|
|
|
status?: 'done' | 'current' | 'pending'
|
|
|
|
|
|
children?: FlowchartNode[]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 决策节点(yes/no 分支) */
|
|
|
|
|
|
export interface DecisionNode {
|
|
|
|
|
|
id: string
|
|
|
|
|
|
type: 'decision'
|
|
|
|
|
|
label: string
|
|
|
|
|
|
status?: 'done' | 'current' | 'pending'
|
|
|
|
|
|
yes_branch?: FlowchartNode
|
|
|
|
|
|
no_branch?: FlowchartNode
|
|
|
|
|
|
children?: FlowchartNode[]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 流程图节点(递归) */
|
|
|
|
|
|
export type FlowchartNode = PathStepNode | DecisionNode
|
|
|
|
|
|
|
|
|
|
|
|
/** 排查模板 */
|
|
|
|
|
|
export interface TroubleshootingTemplate {
|
|
|
|
|
|
id?: string
|
|
|
|
|
|
name: string
|
|
|
|
|
|
category: string
|
|
|
|
|
|
description?: string
|
|
|
|
|
|
estimated_time?: number
|
|
|
|
|
|
difficulty?: number
|
|
|
|
|
|
tags?: string[]
|
2026-07-04 21:01:39 +08:00
|
|
|
|
flowchart: FlowchartNode
|
2026-06-16 14:30:09 +08:00
|
|
|
|
version?: string
|
|
|
|
|
|
status?: 'draft' | 'published'
|
|
|
|
|
|
created_at?: string
|
|
|
|
|
|
updated_at?: string
|
|
|
|
|
|
// 后端可能附加的统计字段
|
|
|
|
|
|
nodeCount?: number
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** API 响应通用结构 */
|
|
|
|
|
|
interface ApiResponse<T> {
|
|
|
|
|
|
code: number
|
|
|
|
|
|
message: string
|
|
|
|
|
|
data: T
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2026-07-07 22:56:49 +08:00
|
|
|
|
// 复用全局 apiClient(CTRT-01 统一契约)
|
2026-06-16 14:30:09 +08:00
|
|
|
|
// -----------------------------------------------------------------------------
|
2026-07-07 22:56:49 +08:00
|
|
|
|
import apiClient from './index'
|
2026-06-16 14:30:09 +08:00
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
// 5 个端点
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
/** GET /api/troubleshooting-templates — 获取模板列表 */
|
|
|
|
|
|
export async function listTemplates(): Promise<TroubleshootingTemplate[]> {
|
2026-07-07 22:56:49 +08:00
|
|
|
|
const res = await apiClient.get<TroubleshootingTemplate[]>('/troubleshooting-templates')
|
|
|
|
|
|
return res || []
|
2026-06-16 14:30:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** GET /api/troubleshooting-templates/{id} — 获取模板详情 */
|
|
|
|
|
|
export async function getTemplate(id: string): Promise<TroubleshootingTemplate> {
|
2026-07-07 22:56:49 +08:00
|
|
|
|
return await apiClient.get<TroubleshootingTemplate>(`/troubleshooting-templates/${id}`)
|
2026-06-16 14:30:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** POST /api/troubleshooting-templates — 新建模板 */
|
|
|
|
|
|
export async function createTemplate(
|
|
|
|
|
|
data: TroubleshootingTemplate
|
|
|
|
|
|
): Promise<TroubleshootingTemplate> {
|
2026-07-07 22:56:49 +08:00
|
|
|
|
return await apiClient.post<TroubleshootingTemplate>('/troubleshooting-templates', data)
|
2026-06-16 14:30:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** PUT /api/troubleshooting-templates/{id} — 更新模板 */
|
|
|
|
|
|
export async function updateTemplate(
|
|
|
|
|
|
id: string,
|
|
|
|
|
|
data: TroubleshootingTemplate
|
|
|
|
|
|
): Promise<TroubleshootingTemplate> {
|
2026-07-09 11:50:08 +08:00
|
|
|
|
return await apiClient.put(`/troubleshooting-templates/${id}`, data) as any
|
2026-06-16 14:30:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** DELETE /api/troubleshooting-templates/{id} — 删除模板 */
|
|
|
|
|
|
export async function deleteTemplate(id: string): Promise<void> {
|
2026-07-07 22:56:49 +08:00
|
|
|
|
await apiClient.delete(`/troubleshooting-templates/${id}`)
|
2026-06-16 14:30:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 工具:把对象格式化成 JSON 字符串(带缩进) */
|
|
|
|
|
|
export function formatJson(obj: unknown): string {
|
|
|
|
|
|
return JSON.stringify(obj, null, 2)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 工具:校验 JSON 字符串是否合法,返回 {ok, data, error} */
|
|
|
|
|
|
export function validateJson(
|
|
|
|
|
|
text: string
|
|
|
|
|
|
): { ok: true; data: TroubleshootingTemplate } | { ok: false; error: string } {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const data = JSON.parse(text) as TroubleshootingTemplate
|
|
|
|
|
|
return { ok: true, data }
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
const err = e as Error
|
|
|
|
|
|
return { ok: false, error: err.message }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 工具:统计节点数(递归) */
|
|
|
|
|
|
export function countNodes(node: FlowchartNode | undefined): number {
|
|
|
|
|
|
if (!node) return 0
|
|
|
|
|
|
let count = 1
|
|
|
|
|
|
if (node.children) {
|
|
|
|
|
|
for (const child of node.children) {
|
|
|
|
|
|
count += countNodes(child)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 决策节点的 yes/no 分支
|
|
|
|
|
|
if ('yes_branch' in node && node.yes_branch) {
|
|
|
|
|
|
count += countNodes(node.yes_branch)
|
|
|
|
|
|
}
|
|
|
|
|
|
if ('no_branch' in node && node.no_branch) {
|
|
|
|
|
|
count += countNodes(node.no_branch)
|
|
|
|
|
|
}
|
|
|
|
|
|
return count
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 工具:统计决策节点数 */
|
|
|
|
|
|
export function countDecisions(node: FlowchartNode | undefined): number {
|
|
|
|
|
|
if (!node) return 0
|
|
|
|
|
|
let count = node.type === 'decision' ? 1 : 0
|
|
|
|
|
|
if (node.children) {
|
|
|
|
|
|
for (const child of node.children) {
|
|
|
|
|
|
count += countDecisions(child)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ('yes_branch' in node && node.yes_branch) {
|
|
|
|
|
|
count += countDecisions(node.yes_branch)
|
|
|
|
|
|
}
|
|
|
|
|
|
if ('no_branch' in node && node.no_branch) {
|
|
|
|
|
|
count += countDecisions(node.no_branch)
|
|
|
|
|
|
}
|
|
|
|
|
|
return count
|
|
|
|
|
|
}
|