245 lines
6.7 KiB
TypeScript
245 lines
6.7 KiB
TypeScript
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
|
||
}
|
||
}
|