315 lines
8.8 KiB
Vue
315 lines
8.8 KiB
Vue
<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 === 1" type="success">管理员</el-tag>
|
||
<el-tag v-else-if="row.sourceType === 2">用户</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: 2 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 = 2;
|
||
};
|
||
|
||
// 分页
|
||
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>
|