Files
boss_font/src/composables/useAiAction.ts
ddrwode 68882f94cf ha'ha
2026-03-06 16:35:38 +08:00

245 lines
6.7 KiB
TypeScript
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 { useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { onMounted, onBeforeUnmount, nextTick } from 'vue'
/**
* AI 操作处理器(简化版)
*
* 可以是简单函数,也可以是配置对象
*/
export type AiActionHandler<T = any> =
| ((args: T) => Promise<void> | void)
| {
/** 执行函数 */
execute: (args: T) => Promise<void> | void
/** 是否需要确认(默认 true */
needConfirm?: boolean
/** 确认消息(支持函数或字符串) */
confirmMessage?: string | ((args: T) => string)
/** 成功消息(支持函数或字符串) */
successMessage?: string | ((args: T) => string)
/** 是否调用后端 API默认 false如果为 true 则自动调用 executeCommand */
callBackendApi?: boolean
}
/**
* AI 操作配置
*/
export interface UseAiActionOptions {
/** 操作映射表:函数名 -> 处理器 */
actionHandlers?: Record<string, AiActionHandler>
/** 数据刷新函数(操作完成后调用) */
onRefresh?: () => Promise<void> | void
/** 自动搜索处理函数 */
onAutoSearch?: (keywords: string) => void
/** 当前路由路径(用于执行命令时传递) */
currentRoute?: string
}
/**
* AI 操作 Composable
*
* 统一处理 AI 助手传递的操作,支持:
* - 自动搜索(通过 keywords + autoSearch 参数)
* - 执行 AI 操作(通过 aiAction 参数)
* - 配置化的操作处理器
*/
export function useAiAction(options: UseAiActionOptions = {}) {
const route = useRoute()
const { actionHandlers = {}, onRefresh, onAutoSearch, currentRoute = route.path } = options
// 用于跟踪是否已卸载,防止在卸载后执行回调
let isUnmounted = false
/**
* 执行 AI 操作(统一处理确认、执行、反馈流程)
*/
async function executeAiAction(action: any) {
if (isUnmounted) return
// 兼容两种入参:{ functionName, arguments } 或 { functionCall: { name, arguments } }
const fnCall = action.functionCall ?? {
name: action.functionName,
arguments: action.arguments
}
if (!fnCall?.name) {
ElMessage.warning('未识别的 AI 操作')
return
}
// 查找对应的处理器
const handler = actionHandlers[fnCall.name]
if (!handler) {
ElMessage.warning(`暂不支持操作: ${fnCall.name}`)
return
}
try {
// 判断处理器类型(函数 or 配置对象)
const isSimpleFunction = typeof handler === 'function'
if (isSimpleFunction) {
// 简单函数形式:直接执行
await handler(fnCall.arguments)
} else {
// 配置对象形式:统一处理确认、执行、反馈
const config = handler
// 1. 确认阶段(默认需要确认)
if (config.needConfirm !== false) {
const confirmMsg =
typeof config.confirmMessage === 'function'
? config.confirmMessage(fnCall.arguments)
: config.confirmMessage || '确认执行此操作吗?'
await ElMessageBox.confirm(confirmMsg, 'AI 助手操作确认', {
confirmButtonText: '确认执行',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true
})
}
// 2. 执行阶段
if (config.callBackendApi) {
// AI 后端 API 暂未实现
ElMessage.warning('AI 后端接口暂未实现')
} else {
// 执行自定义函数
await config.execute(fnCall.arguments)
}
// 3. 成功反馈
const successMsg =
typeof config.successMessage === 'function'
? config.successMessage(fnCall.arguments)
: config.successMessage || '操作执行成功'
ElMessage.success(successMsg)
}
// 4. 刷新数据
if (onRefresh) {
await onRefresh()
}
} catch (error: any) {
// 处理取消操作
if (error === 'cancel') {
ElMessage.info('已取消操作')
return
}
console.error('AI 操作执行失败:', error)
ElMessage.error(error.message || '操作执行失败')
}
}
/**
* 执行后端命令(通用方法)
*/
async function executeCommand(
functionName: string,
args: any,
options: {
originalCommand?: string
confirmMode?: 'auto' | 'manual'
needConfirm?: boolean
confirmMessage?: string
} = {}
) {
const {
originalCommand = '',
confirmMode = 'manual',
needConfirm = false,
confirmMessage
} = options
// 如果需要确认,先显示确认对话框
if (needConfirm && confirmMessage) {
try {
await ElMessageBox.confirm(confirmMessage, 'AI 助手操作确认', {
confirmButtonText: '确认执行',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true
})
} catch {
ElMessage.info('已取消操作')
return
}
}
// AI 后端 API 暂未实现
ElMessage.warning('AI 后端接口暂未实现')
}
/**
* 处理自动搜索
*/
function handleAutoSearch(keywords: string) {
if (onAutoSearch) {
onAutoSearch(keywords)
} else {
ElMessage.info(`AI 助手已为您自动搜索:${keywords}`)
}
}
/**
* 初始化:处理 URL 参数中的 AI 操作
*
* 注意:此方法只处理 AI 相关参数,不负责页面数据的初始加载
* 页面数据加载应由组件的 onMounted 钩子自行处理
*/
async function init() {
if (isUnmounted) return
// 检查是否有 AI 助手传递的参数
const keywords = route.query.keywords as string
const autoSearch = route.query.autoSearch as string
const aiActionParam = route.query.aiAction as string
// 如果没有任何 AI 参数,直接返回
if (!keywords && !autoSearch && !aiActionParam) {
return
}
// 在 nextTick 中执行,确保页面数据已加载
nextTick(async () => {
if (isUnmounted) return
// 1. 处理自动搜索
if (autoSearch === 'true' && keywords) {
handleAutoSearch(keywords)
}
// 2. 处理 AI 操作
if (aiActionParam) {
try {
const aiAction = JSON.parse(decodeURIComponent(aiActionParam))
await executeAiAction(aiAction)
} catch (error) {
console.error('解析 AI 操作失败:', error)
ElMessage.error('AI 操作参数解析失败')
}
}
})
}
// 组件挂载时自动初始化
onMounted(() => {
init()
})
// 组件卸载时清理
onBeforeUnmount(() => {
isUnmounted = true
})
return {
executeAiAction,
executeCommand,
handleAutoSearch,
init
}
}