节点新增字段和提示词弹窗
This commit is contained in:
@@ -37,6 +37,8 @@ export interface NodeLibraryItem {
|
|||||||
nodeName: string;
|
nodeName: string;
|
||||||
modelType: number;
|
modelType: number;
|
||||||
skillOption: boolean;
|
skillOption: boolean;
|
||||||
|
promptOption: boolean;
|
||||||
|
isSaveFile: boolean;
|
||||||
formConfig: NodeLibraryFormItem[];
|
formConfig: NodeLibraryFormItem[];
|
||||||
modelConfig: NodeLibraryModelConfig[];
|
modelConfig: NodeLibraryModelConfig[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export interface PromptListParams {
|
|||||||
pageNum?: number;
|
pageNum?: number;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
keyword?: string;
|
keyword?: string;
|
||||||
|
nodeType?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreatePromptParams {
|
export interface CreatePromptParams {
|
||||||
@@ -65,6 +66,17 @@ export function getNodeLibraryList() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取提示词列表(根据节点类型)
|
||||||
|
*/
|
||||||
|
export function getPromptList(params: PromptListParams) {
|
||||||
|
return request<PromptListResponse>({
|
||||||
|
url: '/ai-agent/node/prompt/list',
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前用户提示词列表
|
* 获取当前用户提示词列表
|
||||||
*/
|
*/
|
||||||
|
|||||||
242
src/views/settings/creation/component/PromptSelector.vue
Normal file
242
src/views/settings/creation/component/PromptSelector.vue
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="visible"
|
||||||
|
title="选择提示词"
|
||||||
|
width="900px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
destroy-on-close
|
||||||
|
@close="handleClose"
|
||||||
|
>
|
||||||
|
<div class="prompt-selector-dialog">
|
||||||
|
<div class="prompt-header">
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-input v-model="searchParams.keyword" placeholder="搜索提示词内容" clearable @clear="handleSearch" @keyup.enter="handleSearch">
|
||||||
|
<template #prefix>
|
||||||
|
<el-icon><Search /></el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="prompt-content" v-loading="loading">
|
||||||
|
<el-empty v-if="!loading && promptList.length === 0" description="暂无提示词数据" :image-size="100" />
|
||||||
|
<el-table v-else :data="promptList" height="360" border stripe style="width: 100%" @row-click="handleSelectPrompt">
|
||||||
|
<el-table-column label="节点类型" width="120" prop="nodeType" />
|
||||||
|
<el-table-column label="提示词内容" prop="prompt" show-overflow-tooltip />
|
||||||
|
<el-table-column label="来源" width="80">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="row.sourceType === 1 ? 'success' : 'info'" size="small">
|
||||||
|
{{ row.sourceType === 1 ? '公共' : '自定义' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="选择" width="60" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-icon v-if="selectedPrompt?.id === row.id" class="check-icon" color="#67c23a">
|
||||||
|
<CircleCheck />
|
||||||
|
</el-icon>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="shouldRenderPagination" class="pagination-panel">
|
||||||
|
<div class="pagination-summary">共 {{ displayTotal }} 条</div>
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="pagination.pageNum"
|
||||||
|
v-model:page-size="pagination.pageSize"
|
||||||
|
:total="displayTotal"
|
||||||
|
:page-sizes="[10, 20, 50]"
|
||||||
|
layout="sizes, prev, pager, next, jumper"
|
||||||
|
background
|
||||||
|
:hide-on-single-page="false"
|
||||||
|
@current-change="handlePageChange"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="handleClose">取消</el-button>
|
||||||
|
<el-button type="primary" :disabled="!selectedPrompt" @click="handleConfirm">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, reactive, ref, watch } from 'vue';
|
||||||
|
import { Search, CircleCheck } from '@element-plus/icons-vue';
|
||||||
|
import { getPromptList, type PromptItem } from '/@/api/settings/promptManager';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
modelValue: boolean;
|
||||||
|
defaultPrompt?: PromptItem | null;
|
||||||
|
nodeType?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'update:modelValue', value: boolean): void;
|
||||||
|
(e: 'confirm', prompt: PromptItem): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
modelValue: false,
|
||||||
|
defaultPrompt: null,
|
||||||
|
nodeType: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
|
const visible = ref(false);
|
||||||
|
const loading = ref(false);
|
||||||
|
const promptList = ref<PromptItem[]>([]);
|
||||||
|
const selectedPrompt = ref<PromptItem | null>(null);
|
||||||
|
const searchParams = reactive({ keyword: '' });
|
||||||
|
const pagination = reactive({ pageNum: 1, pageSize: 10, total: 0 });
|
||||||
|
|
||||||
|
const displayTotal = computed(() => {
|
||||||
|
if (pagination.total > 0) return pagination.total;
|
||||||
|
if (promptList.value.length > 0) return promptList.value.length;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const shouldRenderPagination = computed(() => displayTotal.value > 0);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(val) => {
|
||||||
|
visible.value = val;
|
||||||
|
if (val) {
|
||||||
|
selectedPrompt.value = props.defaultPrompt || null;
|
||||||
|
pagination.pageNum = 1;
|
||||||
|
fetchPromptList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.nodeType,
|
||||||
|
() => {
|
||||||
|
if (visible.value) {
|
||||||
|
pagination.pageNum = 1;
|
||||||
|
fetchPromptList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(visible, (val) => {
|
||||||
|
if (!val) {
|
||||||
|
emit('update:modelValue', false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const resolvePromptList = (payload: any): PromptItem[] => {
|
||||||
|
if (Array.isArray(payload?.data?.list)) return payload.data.list;
|
||||||
|
if (Array.isArray(payload?.list)) return payload.list;
|
||||||
|
if (Array.isArray(payload?.rows)) return payload.rows;
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolvePromptTotal = (payload: any, list: PromptItem[]) => {
|
||||||
|
const totalCandidates = [payload?.data?.total, payload?.total, payload?.data?.count, payload?.count];
|
||||||
|
const validTotal = totalCandidates.find((item) => typeof item === 'number' && !Number.isNaN(item));
|
||||||
|
if (typeof validTotal === 'number') return validTotal;
|
||||||
|
return list.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchPromptList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
pageNum: pagination.pageNum,
|
||||||
|
pageSize: pagination.pageSize,
|
||||||
|
keyword: searchParams.keyword || undefined,
|
||||||
|
nodeType: props.nodeType || undefined,
|
||||||
|
};
|
||||||
|
const res = await getPromptList(params);
|
||||||
|
const list = resolvePromptList(res);
|
||||||
|
promptList.value = list;
|
||||||
|
pagination.total = resolvePromptTotal(res, list);
|
||||||
|
} catch (error) {
|
||||||
|
promptList.value = [];
|
||||||
|
pagination.total = 0;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = () => {
|
||||||
|
pagination.pageNum = 1;
|
||||||
|
fetchPromptList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePageChange = () => {
|
||||||
|
fetchPromptList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSizeChange = (size: number) => {
|
||||||
|
pagination.pageSize = size;
|
||||||
|
pagination.pageNum = 1;
|
||||||
|
fetchPromptList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectPrompt = (prompt: PromptItem) => {
|
||||||
|
selectedPrompt.value = prompt;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleConfirm = () => {
|
||||||
|
if (!selectedPrompt.value) return;
|
||||||
|
emit('confirm', selectedPrompt.value);
|
||||||
|
handleClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
visible.value = false;
|
||||||
|
selectedPrompt.value = null;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.prompt-selector-dialog {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-header {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar :deep(.el-input) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-content {
|
||||||
|
min-height: 360px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-panel {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
padding-top: 8px;
|
||||||
|
border-top: 1px solid var(--el-border-color-lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-summary {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-panel :deep(.el-pagination) {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user