实现创建节点功能并测试通过

This commit is contained in:
jingrow 2025-09-11 21:36:30 +08:00
parent cb89e9306c
commit 423dda59c3
5 changed files with 125 additions and 16 deletions

View File

@ -1,6 +1,7 @@
import axios from 'axios'
import type { AIAgent, AgentExecutionResult } from '../types'
import { get_session_api_headers } from './auth'
// 重新导出类型,供其他模块使用
export type { AIAgent, AgentExecutionResult }
@ -160,4 +161,24 @@ export const updateAgentApi = async (name: string, data: Partial<AIAgent>): Prom
console.error("Error in updateAgentApi:", error)
throw new Error(error.response?.data?.message || error.message || '更新AI Agent失败')
}
}
// 创建 AI Agent通用 PageType 接口,使用会话 + 认证头)
export const createAgent = async (data: Record<string, any>): Promise<{ success: boolean; data?: any; message?: string }> => {
try {
const response = await axios.post(
`${BACKEND_SERVER_URL}/api/data/AI Agent`,
data,
{
headers: get_session_api_headers(),
withCredentials: true
}
)
const message = response.data?.message
return { success: true, data: message || response.data }
} catch (error: any) {
console.error('Error in createAgent:', error)
return { success: false, message: error.response?.data?.message || error.message || '创建AI Agent失败' }
}
}

View File

@ -1,4 +1,18 @@
import { LoginRequest, LoginResponse, UserInfo } from './types'
// 本文件内自定义认证相关类型,避免外部依赖耦合
export interface LoginResponse {
message: string
user: UserInfo
}
export interface UserInfo {
id: string
username: string
email: string
avatar: string
first_name: string
last_name: string
user_type: string
}
// 获取Session用户信息从Cookie
export function getSessionUser(): string | null {
@ -77,3 +91,11 @@ export const logoutApi = async (): Promise<void> => {
credentials: 'include'
})
}
// 仅使用会话Cookie的最小鉴权头部不影响现有API Key逻辑
export function get_session_api_headers() {
return {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}

View File

@ -0,0 +1,26 @@
import axios from 'axios'
import { get_session_api_headers } from './auth'
const BACKEND_SERVER_URL = ''
// 创建节点(通用 PageType 接口,使用会话 + 认证头)
export const createNode = async (data: Record<string, any>): Promise<{ success: boolean; data?: any; message?: string }> => {
try {
const response = await axios.post(
`${BACKEND_SERVER_URL}/api/data/AI Node Schema`,
data,
{
headers: get_session_api_headers(),
withCredentials: true
}
)
const message = response.data?.message
return { success: true, data: message || response.data }
} catch (error: any) {
console.error('Error in createNode:', error)
return { success: false, message: error.response?.data?.message || error.message || '创建节点失败' }
}
}

View File

@ -26,11 +26,11 @@
<div class="property-group">
<div class="property-item">
<label>{{ t('Node Type') }}</label>
<input type="text" v-model="nodeRecord.node_type" readonly />
<input type="text" v-model="nodeRecord.node_type" />
</div>
<div class="property-item">
<label>{{ t('Node Label') }}</label>
<input type="text" v-model="nodeRecord.node_type" />
<input type="text" v-model="nodeRecord.node_label" />
</div>
<div class="property-item">
<label>{{ t('Node Icon') }}</label>
@ -95,6 +95,7 @@ const route = useRoute()
const message = useMessage()
const nodeName = computed(() => String(route.params.name || ''))
const isNew = computed(() => nodeName.value === 'new' || nodeName.value === '')
const loading = ref(true)
const saving = ref(false)
const nodeRecord = ref<any>({})
@ -110,7 +111,14 @@ const schemaText = ref('')
async function load() {
loading.value = true
try {
//
if (isNew.value) {
//
nodeRecord.value = { node_type: '', node_label: '', node_icon: '', node_color: '#6b7280', node_group: '', node_component: '', node_description: '', status: 'Draft' }
schema.value = {}
schemaText.value = JSON.stringify(schema.value, null, 2)
return
}
//
const recordRes = await fetch(`/api/action/jingrow.ai.utils.node_schema.get_node_record?name=${encodeURIComponent(nodeName.value)}`)
const recordData = await recordRes.json()
nodeRecord.value = recordData.message || recordData.data || {}
@ -136,22 +144,51 @@ async function save() {
}
saving.value = true
try {
//
const nodeData = {
...nodeRecord.value,
node_schema: schemaBody
if (isNew.value) {
//
const res = await fetch('/api/data/AI Node Schema', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
credentials: 'include',
body: JSON.stringify({
node_type: nodeRecord.value.node_type,
node_label: nodeRecord.value.node_label,
node_icon: nodeRecord.value.node_icon,
node_color: nodeRecord.value.node_color,
node_group: nodeRecord.value.node_group,
node_component: nodeRecord.value.node_component,
node_description: nodeRecord.value.node_description,
status: nodeRecord.value.status || 'Draft',
node_schema: schemaBody
})
})
const data = await res.json()
const created = data?.message ?? data
const newName = created?.name
?? created?.data?.name
?? created?.message?.name
?? created?.document?.name
if (newName) {
window.location.href = `/nodes/${encodeURIComponent(newName)}`
return
}
// name
if (res.ok) {
// 退
window.location.href = '/nodes'
return
}
throw new Error('create failed')
}
// API
//
const nodeData = { ...nodeRecord.value, node_schema: schemaBody }
const res = await fetch('/api/action/jingrow.ai.utils.node_schema.update_node', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: nodeName.value, node_data: nodeData })
})
const data = await res.json()
if (data.exc || data._server_messages) {
throw new Error('save failed')
}
if (data.exc || data._server_messages) throw new Error('save failed')
await load()
} catch (e) {
message.error(t('Save failed, please check permission and server logs'))

View File

@ -41,7 +41,7 @@
<button class="refresh-btn" @click="reload" :disabled="loading">
<i :class="loading ? 'fa fa-spinner fa-spin' : 'fa fa-refresh'"></i>
</button>
<button class="create-btn" @click="createNode">
<button class="create-btn" @click="handleCreateNode" :disabled="creating || loading">
<i class="fa fa-plus"></i>
{{ t('Create Node') }}
</button>
@ -125,9 +125,11 @@ import { ref, onMounted, computed, watch } from 'vue'
import { useRouter } from 'vue-router'
import { t } from '../../shared/i18n'
import { NInput, NSelect, NPagination } from 'naive-ui'
import { createNode } from '../../shared/api/nodes'
const router = useRouter()
const loading = ref(true)
const creating = ref(false)
const nodes = ref<any[]>([])
const allNodes = ref<any[]>([]) //
const total = ref(0)
@ -246,8 +248,9 @@ function openDetail(name: string) {
router.push({ name: 'NodeDetail', params: { name } })
}
function createNode() {
router.push({ name: 'NodeCreate' })
function handleCreateNode() {
//
router.push({ name: 'NodeDetail', params: { name: 'new' } })
}
onMounted(() => {