新增提示词管理
This commit is contained in:
@@ -20,6 +20,41 @@ export interface ModelFormEntry {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 提示词管理接口类型
|
||||||
|
export interface PromptItem {
|
||||||
|
id: number | string;
|
||||||
|
tenantId?: number;
|
||||||
|
creator?: string;
|
||||||
|
createdAt?: string;
|
||||||
|
updater?: string;
|
||||||
|
updatedAt?: string;
|
||||||
|
deletedAt?: string | null;
|
||||||
|
nodeType: string;
|
||||||
|
prompt: string;
|
||||||
|
sourceType: number; // 0-自定义 1-公共
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PromptListResponse {
|
||||||
|
list: PromptItem[];
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PromptListParams {
|
||||||
|
pageNum?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
keyword?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreatePromptParams {
|
||||||
|
nodeType: string;
|
||||||
|
prompt: string;
|
||||||
|
sourceType: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdatePromptParams extends CreatePromptParams {
|
||||||
|
id: number | string;
|
||||||
|
}
|
||||||
|
|
||||||
/** 模型类型(listType 接口项,字段名以后端为准,前端做兼容解析) */
|
/** 模型类型(listType 接口项,字段名以后端为准,前端做兼容解析) */
|
||||||
export interface ModelTypeListItem {
|
export interface ModelTypeListItem {
|
||||||
id?: number | string;
|
id?: number | string;
|
||||||
@@ -251,3 +286,46 @@ export function getOperatorList() {
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户提示词列表
|
||||||
|
*/
|
||||||
|
export function getMyPromptList(params: PromptListParams) {
|
||||||
|
return request<PromptListResponse>({
|
||||||
|
url: '/node/prompt/listMy',
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建提示词
|
||||||
|
*/
|
||||||
|
export function createPrompt(data: CreatePromptParams) {
|
||||||
|
return request({
|
||||||
|
url: '/node/prompt/create',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改提示词
|
||||||
|
*/
|
||||||
|
export function updatePrompt(data: UpdatePromptParams) {
|
||||||
|
return request({
|
||||||
|
url: '/node/prompt/update',
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除提示词
|
||||||
|
*/
|
||||||
|
export function deletePrompt(id: number | string) {
|
||||||
|
return request({
|
||||||
|
url: `/node/prompt/delete/${id}`,
|
||||||
|
method: 'delete',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
110
src/api/settings/promptManager/index.ts
Normal file
110
src/api/settings/promptManager/index.ts
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import request from '/@/utils/request';
|
||||||
|
|
||||||
|
// 提示词管理接口类型
|
||||||
|
export interface PromptItem {
|
||||||
|
id: number | string;
|
||||||
|
tenantId?: number;
|
||||||
|
creator?: string;
|
||||||
|
createdAt?: string;
|
||||||
|
updater?: string;
|
||||||
|
updatedAt?: string;
|
||||||
|
deletedAt?: string | null;
|
||||||
|
nodeType: string;
|
||||||
|
prompt: string;
|
||||||
|
sourceType: number; // 0-自定义 1-公共
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PromptListResponse {
|
||||||
|
list: PromptItem[];
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PromptListParams {
|
||||||
|
pageNum?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
keyword?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreatePromptParams {
|
||||||
|
nodeType: string;
|
||||||
|
prompt: string;
|
||||||
|
sourceType: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdatePromptParams extends CreatePromptParams {
|
||||||
|
id: number | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 节点库项接口类型
|
||||||
|
export interface NodeLibraryNode {
|
||||||
|
nodeId: string;
|
||||||
|
nodeCode: string;
|
||||||
|
modelType: number;
|
||||||
|
nodeName: string;
|
||||||
|
skillOption: boolean;
|
||||||
|
promptOption: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeLibraryGroup {
|
||||||
|
group: string;
|
||||||
|
label: string;
|
||||||
|
items: NodeLibraryNode[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeLibraryResponse {
|
||||||
|
groups: NodeLibraryGroup[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取节点类型列表(节点库)
|
||||||
|
*/
|
||||||
|
export function getNodeLibraryList() {
|
||||||
|
return request<NodeLibraryResponse>({
|
||||||
|
url: '/ai-agent/node/library/list',
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户提示词列表
|
||||||
|
*/
|
||||||
|
export function getMyPromptList(params: PromptListParams) {
|
||||||
|
return request<PromptListResponse>({
|
||||||
|
url: '/ai-agent/node/prompt/listMy',
|
||||||
|
method: 'get',
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建提示词
|
||||||
|
*/
|
||||||
|
export function createPrompt(data: CreatePromptParams) {
|
||||||
|
return request({
|
||||||
|
url: '/ai-agent/node/prompt/create',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改提示词
|
||||||
|
*/
|
||||||
|
export function updatePrompt(data: UpdatePromptParams) {
|
||||||
|
return request({
|
||||||
|
url: '/ai-agent/node/prompt/update',
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除提示词
|
||||||
|
*/
|
||||||
|
export function deletePrompt(id: number | string) {
|
||||||
|
return request({
|
||||||
|
url: '/ai-agent/node/prompt/delete',
|
||||||
|
method: 'delete',
|
||||||
|
data: { id },
|
||||||
|
});
|
||||||
|
}
|
||||||
314
src/views/settings/promptManager/index.vue
Normal file
314
src/views/settings/promptManager/index.vue
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
<template>
|
||||||
|
<div class="prompt-manager-container">
|
||||||
|
<!-- 搜索栏 -->
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-input v-model="searchQuery" placeholder="搜索提示词内容..." prefix-icon="Search" style="width: 300px" clearable @input="handleSearch" />
|
||||||
|
<el-button type="primary" @click="showCreateDialog = true">
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
新增提示词
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<div class="table-container">
|
||||||
|
<el-table :data="filteredList" v-loading="loading" border style="width: 100%">
|
||||||
|
<el-table-column prop="nodeType" label="节点类型" width="150" />
|
||||||
|
<el-table-column prop="prompt" label="提示词内容" min-width="350">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tooltip v-if="row.prompt.length > 80" content="hover" :enterable="false">
|
||||||
|
<template #content>
|
||||||
|
<div style="max-width: 400px; white-space: pre-wrap">{{ row.prompt }}</div>
|
||||||
|
</template>
|
||||||
|
<span>{{ row.prompt.slice(0, 80) }}...</span>
|
||||||
|
</el-tooltip>
|
||||||
|
<span v-else>{{ row.prompt }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="sourceType" label="来源" width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag v-if="row.sourceType === 0">自定义</el-tag>
|
||||||
|
<el-tag v-else-if="row.sourceType === 1" type="success">公共</el-tag>
|
||||||
|
<el-tag v-else type="info">{{ row.sourceType }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="creator" label="创建者" width="120" />
|
||||||
|
<el-table-column prop="createdAt" label="创建时间" width="170" />
|
||||||
|
<el-table-column label="操作" width="120" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button type="primary" link size="small" @click="handleEdit(row)">编辑</el-button>
|
||||||
|
<el-button type="danger" link size="small" @click="handleDeleteConfirm(row.id)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
|
<div class="pagination-container">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="pagination.current"
|
||||||
|
v-model:page-size="pagination.size"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
layout="total, sizes, ->, prev, pager, next, jumper"
|
||||||
|
:total="pagination.total"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 新增/编辑弹窗 -->
|
||||||
|
<el-dialog v-model="showCreateDialog" :title="isEdit ? '编辑提示词' : '新增提示词'" width="600px" :close-on-click-modal="false">
|
||||||
|
<el-form ref="createFormRef" :model="createForm" label-width="100px">
|
||||||
|
<el-form-item label="节点类型" required>
|
||||||
|
<el-select v-model="createForm.nodeType" placeholder="请选择节点类型" style="width: 100%" clearable v-loading="nodeLibraryLoading">
|
||||||
|
<el-option v-for="option in nodeOptions" :key="option.value" :label="option.label" :value="option.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="提示词内容" required>
|
||||||
|
<el-input v-model="createForm.prompt" type="textarea" :rows="8" placeholder="请输入提示词内容..." clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="cancelCreate">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmitCreate" :loading="submitLoading">
|
||||||
|
{{ isEdit ? '保存修改' : '确 定' }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 删除确认弹窗 -->
|
||||||
|
<el-dialog v-model="showDeleteDialog" title="确认删除" width="400px" :close-on-click-modal="false">
|
||||||
|
<div>确定要删除这个提示词吗?</div>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="showDeleteDialog = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="handleDelete" :loading="deleteLoading">确 定</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="promptManager">
|
||||||
|
import { ref, reactive, computed, onMounted } from 'vue';
|
||||||
|
import { Plus } from '@element-plus/icons-vue';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { getNodeLibraryList, getMyPromptList, createPrompt, updatePrompt, deletePrompt, type NodeLibraryGroup, type NodeLibraryNode, type PromptItem } from '/@/api/settings/promptManager/index';
|
||||||
|
|
||||||
|
const searchQuery = ref('');
|
||||||
|
const loading = ref(false);
|
||||||
|
const list = ref<PromptItem[]>([]);
|
||||||
|
const showCreateDialog = ref(false);
|
||||||
|
const isEdit = ref(false);
|
||||||
|
const submitLoading = ref(false);
|
||||||
|
const createFormRef = ref();
|
||||||
|
const editId = ref<number | string | null>(null);
|
||||||
|
const nodeLibraryLoading = ref(false);
|
||||||
|
const nodeLibraryGroups = ref<NodeLibraryGroup[]>([]);
|
||||||
|
const showDeleteDialog = ref(false);
|
||||||
|
const deleteLoading = ref(false);
|
||||||
|
const deleteId = ref<number | string | null>(null);
|
||||||
|
const nodeOptions = computed(() => {
|
||||||
|
const options: Array<{ label: string; value: string }> = [];
|
||||||
|
nodeLibraryGroups.value.forEach((group: NodeLibraryGroup) => {
|
||||||
|
group.items.forEach((item: NodeLibraryNode) => {
|
||||||
|
// 只显示支持提示词配置的节点
|
||||||
|
if (item.promptOption) {
|
||||||
|
options.push({
|
||||||
|
label: item.nodeName,
|
||||||
|
value: item.nodeCode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return options;
|
||||||
|
});
|
||||||
|
|
||||||
|
const createForm = reactive({
|
||||||
|
nodeType: '',
|
||||||
|
prompt: '',
|
||||||
|
sourceType: 0 as number,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载节点库
|
||||||
|
const loadNodeLibrary = async () => {
|
||||||
|
nodeLibraryLoading.value = true;
|
||||||
|
try {
|
||||||
|
const res = await getNodeLibraryList();
|
||||||
|
if (res && res.data && res.data.groups) {
|
||||||
|
nodeLibraryGroups.value = res.data.groups;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载节点库失败:', e);
|
||||||
|
ElMessage.error('加载节点类型失败');
|
||||||
|
} finally {
|
||||||
|
nodeLibraryLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const pagination = reactive({
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 过滤后的列表
|
||||||
|
const filteredList = computed(() => {
|
||||||
|
if (!searchQuery.value) {
|
||||||
|
return list.value;
|
||||||
|
}
|
||||||
|
const query = searchQuery.value.toLowerCase();
|
||||||
|
return list.value.filter(
|
||||||
|
(item) => item.nodeType.toLowerCase().includes(query) || item.prompt.toLowerCase().includes(query) || item.creator?.toLowerCase().includes(query)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载列表
|
||||||
|
const loadList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const res = await getMyPromptList({
|
||||||
|
pageNum: pagination.current,
|
||||||
|
pageSize: pagination.size,
|
||||||
|
});
|
||||||
|
if (res && res.data && res.data.list) {
|
||||||
|
list.value = res.data.list;
|
||||||
|
pagination.total = res.data.total || 0;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
ElMessage.error('加载失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 搜索
|
||||||
|
const handleSearch = () => {
|
||||||
|
pagination.current = 1;
|
||||||
|
loadList();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
const handleSubmitCreate = async () => {
|
||||||
|
// 验证
|
||||||
|
if (!createForm.nodeType?.trim()) {
|
||||||
|
ElMessage.warning('请选择节点类型');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!createForm.prompt?.trim()) {
|
||||||
|
ElMessage.warning('请输入提示词内容');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
submitLoading.value = true;
|
||||||
|
try {
|
||||||
|
if (isEdit.value && editId.value) {
|
||||||
|
await updatePrompt({
|
||||||
|
id: editId.value,
|
||||||
|
...createForm,
|
||||||
|
});
|
||||||
|
ElMessage.success('修改成功');
|
||||||
|
} else {
|
||||||
|
await createPrompt({
|
||||||
|
nodeType: createForm.nodeType.trim(),
|
||||||
|
prompt: createForm.prompt.trim(),
|
||||||
|
sourceType: createForm.sourceType,
|
||||||
|
});
|
||||||
|
ElMessage.success('创建成功');
|
||||||
|
}
|
||||||
|
showCreateDialog.value = false;
|
||||||
|
cancelCreate();
|
||||||
|
loadList();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
ElMessage.error('操作失败');
|
||||||
|
} finally {
|
||||||
|
submitLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 编辑
|
||||||
|
const handleEdit = (row: PromptItem) => {
|
||||||
|
isEdit.value = true;
|
||||||
|
editId.value = row.id;
|
||||||
|
createForm.nodeType = row.nodeType || '';
|
||||||
|
createForm.prompt = row.prompt || '';
|
||||||
|
createForm.sourceType = row.sourceType || 0;
|
||||||
|
showCreateDialog.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开删除确认弹窗
|
||||||
|
const handleDeleteConfirm = (id: number | string) => {
|
||||||
|
deleteId.value = id;
|
||||||
|
showDeleteDialog.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
const handleDelete = async () => {
|
||||||
|
if (!deleteId.value) return;
|
||||||
|
deleteLoading.value = true;
|
||||||
|
try {
|
||||||
|
await deletePrompt(deleteId.value);
|
||||||
|
ElMessage.success('删除成功');
|
||||||
|
showDeleteDialog.value = false;
|
||||||
|
loadList();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
ElMessage.error('删除失败');
|
||||||
|
} finally {
|
||||||
|
deleteLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消
|
||||||
|
const cancelCreate = () => {
|
||||||
|
createFormRef.value?.resetFields();
|
||||||
|
isEdit.value = false;
|
||||||
|
editId.value = null;
|
||||||
|
createForm.nodeType = '';
|
||||||
|
createForm.prompt = '';
|
||||||
|
createForm.sourceType = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
const handleSizeChange = (size: number) => {
|
||||||
|
pagination.size = size;
|
||||||
|
pagination.current = 1;
|
||||||
|
loadList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCurrentChange = (current: number) => {
|
||||||
|
pagination.current = current;
|
||||||
|
loadList();
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadNodeLibrary();
|
||||||
|
loadList();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.prompt-manager-container {
|
||||||
|
padding: 16px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
.pagination-container {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user