更新local_ai_agent_toolbar.vue

This commit is contained in:
jingrow 2025-11-02 20:05:33 +08:00
parent 67119d3265
commit deccb557c0

View File

@ -1,9 +1,57 @@
<template>
<n-space :size="8">
<n-space align="center">
<!-- 侧边栏位置切换按钮 -->
<n-button
type="default"
size="medium"
:disabled="executing"
@click="$emit('toggle-sidebar-position')"
:title="sidebarPosition === 'left' ? '切换到右侧' : '切换到左侧'"
class="header-action-btn"
>
<template #icon>
<n-icon>
<Icon :icon="sidebarPosition === 'left' ? 'fluent:panel-right-16-regular' : 'fluent:panel-left-16-regular'" />
</n-icon>
</template>
</n-button>
<!-- 刷新按钮 -->
<n-button
type="default"
size="medium"
@click="$emit('refresh')"
:disabled="loading || isNew"
:title="t('Refresh')"
class="header-action-btn"
>
<template #icon>
<n-icon>
<Icon icon="tabler:refresh" />
</n-icon>
</template>
</n-button>
<!-- 删除按钮 -->
<n-button
type="default"
size="medium"
@click="$emit('delete')"
:disabled="loading || isNew"
:title="t('Delete')"
class="header-action-btn delete-btn"
>
<template #icon>
<n-icon>
<Icon icon="tabler:trash" />
</n-icon>
</template>
</n-button>
<!-- 执行按钮 -->
<n-button
type="default"
size="medium"
:disabled="executing || loading"
@click="handleExecute"
v-if="!isNew"
class="toolbar-btn execute-btn"
@ -13,10 +61,13 @@
</template>
{{ executing ? t('Executing...') : t('Execute') }}
</n-button>
<!-- 流程编排按钮 -->
<n-button
type="default"
size="medium"
@click="handleFlowBuilder"
:disabled="loading"
class="toolbar-btn flow-builder-btn"
>
<template #icon>
@ -24,38 +75,102 @@
</template>
{{ t('Flow Builder') }}
</n-button>
<!-- 返回按钮 -->
<n-button type="default" size="medium" @click="$emit('go-back')" :disabled="loading">
<template #icon>
<n-icon><Icon icon="tabler:arrow-left" /></n-icon>
</template>
{{ t('Back') }}
</n-button>
<!-- 保存按钮 -->
<n-button
type="primary"
size="medium"
:disabled="loading"
@click="$emit('save')"
v-if="canEdit"
class="save-btn-brand"
>
<template #icon>
<n-icon>
<Icon icon="tabler:check" />
</n-icon>
</template>
{{ t('Save') }}
</n-button>
</n-space>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { NSpace, NButton, NIcon, useMessage } from 'naive-ui'
import { ref, computed, watch, onMounted } from 'vue'
import { NButton, NSpace, NIcon, useMessage } from 'naive-ui'
import { Icon } from '@iconify/vue'
import { useRouter } from 'vue-router'
import { t } from '@/shared/i18n'
const props = defineProps<{ context: {
entity: any
id: any
record: any
canEdit: any
loading: any
save: () => Promise<void> | void
router: any
t: (k: string) => string
} }>()
interface Props {
entity: string
id: string
record?: any
canEdit: boolean
loading: boolean
sidebarPosition?: 'left' | 'right'
}
interface Emits {
(e: 'toggle-sidebar-position'): void
(e: 'refresh'): void
(e: 'delete'): void
(e: 'go-back'): void
(e: 'save'): void
}
const props = withDefaults(defineProps<Props>(), {
sidebarPosition: 'left',
record: () => ({})
})
defineEmits<Emits>()
const message = useMessage()
const router = useRouter()
const executing = ref(false)
const t = props.context.t
const isNew = computed(() => String(props.context.id?.value || props.context.id) === 'new')
//
const isNew = computed(() => {
const idValue = props.id
return idValue === 'new' || idValue.startsWith('new-')
})
// localStorage
const sidebarPosition = ref<'left' | 'right'>(props.sidebarPosition || 'left')
// props
watch(() => props.sidebarPosition, (newPos) => {
if (newPos) {
sidebarPosition.value = newPos
}
}, { immediate: true })
onMounted(() => {
// sidebarPosition localStorage
if (!props.sidebarPosition) {
const savedPosition = localStorage.getItem('jingrow-sidebar-position')
if (savedPosition === 'left' || savedPosition === 'right') {
sidebarPosition.value = savedPosition
}
}
})
//
async function handleExecute() {
if (isNew.value) return
try {
executing.value = true
const id = String(props.context.id?.value || props.context.id)
const name = props.context.record?.value?.agent_name || props.context.record?.agent_name || ''
const id = String(props.id)
const name = props.record?.agent_name || ''
const response = await fetch('/jingrow/agents/execute', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@ -78,27 +193,120 @@ async function handleExecute() {
}
}
//
async function handleFlowBuilder() {
try {
const raw = props.context.record?.value?.agent_flow ?? props.context.record?.agent_flow ?? {}
const raw = props.record?.agent_flow ?? {}
let flowData: any = raw
if (typeof raw === 'string') {
try { flowData = JSON.parse(raw) } catch { flowData = {} }
}
const agentId = props.context.record?.value?.name || props.context.record?.name || ''
const agentId = props.record?.name || ''
const { useFlowBuilderStore } = await import('@/shared/stores/flowBuilder')
const flowBuilderStore = useFlowBuilderStore()
flowBuilderStore.activateFlowBuilder(flowData, agentId)
props.context.router.push({ name: 'FlowBuilder', query: { agentId } })
router.push({ name: 'FlowBuilder', query: { agentId } })
} catch (_) {}
}
</script>
<style scoped>
/* 头部操作按钮统一样式 */
.header-action-btn {
display: inline-flex;
align-items: center;
justify-content: center;
}
/* 删除按钮悬浮时使用红色 */
.header-action-btn.delete-btn:hover:not(:disabled) {
background: #ef4444 !important;
border-color: #ef4444 !important;
color: white !important;
}
.header-action-btn.delete-btn:hover:not(:disabled) :deep(.n-button__border),
.header-action-btn.delete-btn:hover:not(:disabled) :deep(.n-button__state-border) {
border-color: #ef4444 !important;
}
/* 保存按钮 - 使用柔和的品牌色系,与列表页创建按钮一致 */
.save-btn-brand {
background: #e6f8f0 !important;
border: 1px solid #1fc76f !important;
color: #0d684b !important;
}
.save-btn-brand :deep(.n-button__border) {
border: none !important;
border-color: transparent !important;
}
.save-btn-brand :deep(.n-button__state-border) {
border: none !important;
border-color: transparent !important;
}
.save-btn-brand:hover {
background: #dcfce7 !important;
border-color: #1fc76f !important;
border: 1px solid #1fc76f !important;
color: #166534 !important;
box-shadow: 0 2px 8px rgba(31, 199, 111, 0.15) !important;
}
.save-btn-brand:hover :deep(.n-button__border),
.save-btn-brand:hover :deep(.n-button__state-border) {
border: none !important;
border-color: transparent !important;
}
.save-btn-brand:focus {
background: #dcfce7 !important;
border-color: #1fc76f !important;
border: 1px solid #1fc76f !important;
color: #166534 !important;
box-shadow: 0 0 0 2px rgba(31, 199, 111, 0.2) !important;
}
.save-btn-brand:focus :deep(.n-button__border),
.save-btn-brand:focus :deep(.n-button__state-border) {
border: none !important;
border-color: transparent !important;
}
.save-btn-brand:active {
background: #1fc76f !important;
border-color: #1fc76f !important;
border: 1px solid #1fc76f !important;
color: white !important;
box-shadow: 0 1px 4px rgba(31, 199, 111, 0.2) !important;
}
.save-btn-brand:active :deep(.n-button__border),
.save-btn-brand:active :deep(.n-button__state-border) {
border: none !important;
border-color: transparent !important;
}
.save-btn-brand:disabled {
background: #f1f5f9 !important;
border: 1px solid #e2e8f0 !important;
border-color: #e2e8f0 !important;
color: #94a3b8 !important;
opacity: 0.6 !important;
cursor: not-allowed !important;
}
.save-btn-brand:disabled :deep(.n-button__border),
.save-btn-brand:disabled :deep(.n-button__state-border) {
border: none !important;
border-color: transparent !important;
}
/* 工具栏按钮基础样式 - 与返回按钮一致使用badge配色方案 */
.toolbar-btn {
background: #f3f4f6 !important;
@ -165,4 +373,3 @@ async function handleFlowBuilder() {
}
</style>