新增提示词管理

This commit is contained in:
2026-06-02 14:52:01 +08:00
parent d3a315525e
commit ccbf6de863
3 changed files with 502 additions and 0 deletions

View File

@@ -20,6 +20,41 @@ export interface ModelFormEntry {
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 接口项,字段名以后端为准,前端做兼容解析) */
export interface ModelTypeListItem {
id?: number | string;
@@ -251,3 +286,46 @@ export function getOperatorList() {
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',
});
}

View 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 },
});
}

View 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>