@@ -16,6 +16,10 @@
< / template >
< / el-input >
< el-button type = "primary" @click ="handleSearch" > 搜索 < / el -button >
< el-button type = "primary" plain @click ="handleCreate" >
< el -icon > < Plus / > < / el-icon >
新增提示词
< / el-button >
< / div >
< / div >
@@ -27,11 +31,20 @@
< el-table-column label = "来源" width = "80" >
< template # default = "{ row }" >
< el-tag : type = "row.sourceType === 1 ? 'success' : 'info'" size = "small" >
{ { row . sourceType === 1 ? '公共 ' : '自定义' } }
{ { row . sourceType === 1 ? '管理员 ' : row . sourceType === 2 ? '用户' : row . sourceType } }
< / el-tag >
< / template >
< / el-table-column >
< el-table-column label = "选择 " width = "6 0" align = "center" >
< el-table-column label = "操作 " width = "12 0" align = "center" fixed = "right" >
< template # default = "{ row }" >
< template v-if = "canManagePrompt(row)" >
< el -button type = "primary" link size = "small" @click.stop ="handleEdit(row)" > 编辑 < / el -button >
< el-button type = "danger" link size = "small" @click.stop ="handleDeleteConfirm(row)" > 删除 < / el -button >
< / template >
< span v-else class = "operation-placeholder" > - < / span >
< / template >
< / el-table-column >
< el-table-column label = "选择" width = "60" align = "center" fixed = "right" >
< template # default = "{ row }" >
< el-icon v-if = "selectedPrompt?.id === row.id" class="check-icon" color="#67c23a" >
< CircleCheck / >
@@ -59,15 +72,61 @@
< template # footer >
< el-button @click ="handleClose" > 取消 < / el -button >
< el-button type = "primary" :disabled = "!selectedPrompt" @click ="handleConfirm" > 确定 < / el -button >
< el-button type = "primary" :disabled = "!selectedPrompt" :loading = "confirmLoading" @click ="handleConfirm" > 确定 < / el -button >
< / template >
< / el-dialog >
< el-dialog
v-model = "showFormDialog"
: title = "isEdit ? '编辑提示词' : '新增提示词'"
width = "600px"
:close-on-click-modal = "false"
destroy -on -close
@close ="resetFormState"
>
< el-form :model = "formState" label -width = " 100px " >
< el-form-item label = "节点类型" required >
< el-select v-model = "formState.nodeType" placeholder="请选择节点类型" class="w100" clearable :disabled="Boolean(props.nodeType)" v-loading="nodeLibraryLoading" >
< el -option v-for = "option in nodeOptions" :key="option.value" :label="option.label" :value="option.value" / >
< / el-select >
< / el-form-item >
< el-form-item label = "提示词内容" required >
< el-input v-model = "formState.prompt" type="textarea" :rows="8" placeholder="请输入提示词内容" clearable / >
< / el-form-item >
< / el-form >
< template # footer >
< el-button @click ="showFormDialog = false" > 取消 < / el -button >
< el-button type = "primary" :loading = "submitLoading" @click ="handleSubmit" >
{{ isEdit ? ' 保存修改 ' : ' 确定 ' }}
< / el -button >
< / template >
< / el-dialog >
< el-dialog v-model = "showDeleteDialog" title="确认删除" width="400px" :close-on-click-modal="false" destroy -on -close >
< div > 确定要删除这个提示词吗 ? < / div >
< template # footer >
< el-button @click ="showDeleteDialog = false" > 取消 < / el -button >
< el-button type = "primary" :loading = "deleteLoading" @click ="handleDelete" > 确定 < / 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 ';
import { computed , onMounted , reactive , ref , watch } from 'vue' ;
import { Search , CircleCheck , Plus } from '@element-plus/icons-vue' ;
import { ElMessage } from 'element-plus ';
import {
checkIsSuperAdmin ,
createPrompt ,
deletePrompt ,
getNodeLibraryList ,
getPromptList ,
updatePrompt ,
type CreatePromptResponse ,
type NodeLibraryGroup ,
type NodeLibraryNode ,
type PromptItem ,
} from '/@/api/settings/promptManager' ;
interface Props {
modelValue : boolean ;
@@ -90,10 +149,39 @@ const emit = defineEmits<Emits>();
const visible = ref ( false ) ;
const loading = ref ( false ) ;
const nodeLibraryLoading = ref ( false ) ;
const submitLoading = ref ( false ) ;
const deleteLoading = ref ( false ) ;
const confirmLoading = ref ( false ) ;
const showFormDialog = ref ( false ) ;
const showDeleteDialog = ref ( false ) ;
const isEdit = ref ( false ) ;
const editId = ref < number | string | null > ( null ) ;
const deleteId = ref < number | string | null > ( null ) ;
const promptList = ref < PromptItem [ ] > ( [ ] ) ;
const selectedPrompt = ref < PromptItem | null > ( null ) ;
const nodeLibraryGroups = ref < NodeLibraryGroup [ ] > ( [ ] ) ;
const searchParams = reactive ( { keyword : '' } ) ;
const pagination = reactive ( { pageNum : 1 , pageSize : 10 , total : 0 } ) ;
const formState = reactive ( {
nodeType : '' ,
prompt : '' ,
sourceType : 2 ,
} ) ;
const nodeOptions = computed ( ( ) => {
const options : Array < { label : string ; value : string } > = [ ] ;
nodeLibraryGroups . value . forEach ( ( group : NodeLibraryGroup ) => {
group . items . forEach ( ( item : NodeLibraryNode ) => {
if ( ! item . promptOption ) return ;
options . push ( {
label : item . nodeName ,
value : item . nodeCode ,
} ) ;
} ) ;
} ) ;
return options ;
} ) ;
const displayTotal = computed ( ( ) => {
if ( pagination . total > 0 ) return pagination . total ;
@@ -111,6 +199,7 @@ watch(
selectedPrompt . value = props . defaultPrompt || null ;
pagination . pageNum = 1 ;
fetchPromptList ( ) ;
loadNodeLibrary ( ) ;
}
}
) ;
@@ -122,6 +211,9 @@ watch(
pagination . pageNum = 1 ;
fetchPromptList ( ) ;
}
if ( ! showFormDialog . value ) {
formState . nodeType = props . nodeType || '' ;
}
}
) ;
@@ -131,6 +223,8 @@ watch(visible, (val) => {
}
} ) ;
const canManagePrompt = ( prompt : PromptItem ) => Number ( prompt ? . sourceType ) === 2 ;
const resolvePromptList = ( payload : any ) : PromptItem [ ] => {
if ( Array . isArray ( payload ? . data ? . list ) ) return payload . data . list ;
if ( Array . isArray ( payload ? . list ) ) return payload . list ;
@@ -145,6 +239,47 @@ const resolvePromptTotal = (payload: any, list: PromptItem[]) => {
return list . length ;
} ;
const resolveNodeLibraryGroups = ( payload : any ) : NodeLibraryGroup [ ] => {
if ( Array . isArray ( payload ? . data ? . groups ) ) return payload . data . groups ;
if ( Array . isArray ( payload ? . groups ) ) return payload . groups ;
return [ ] ;
} ;
const resolveIsSuperAdmin = ( payload : any ) => {
if ( typeof payload ? . data ? . isSuperAdmin === 'boolean' ) return payload . data . isSuperAdmin ;
if ( typeof payload ? . isSuperAdmin === 'boolean' ) return payload . isSuperAdmin ;
return false ;
} ;
const resolveCreatedPrompt = ( payload : any , fallback : PromptItem ) : PromptItem => {
const created = ( payload ? . data || payload ) as CreatePromptResponse | undefined ;
return {
id : created ? . id ? ? fallback . id ,
tenantId : created ? . tenantId ,
creator : created ? . creator ,
createdAt : created ? . createdAt ,
updater : created ? . updater ,
updatedAt : created ? . updatedAt ,
deletedAt : created ? . deletedAt ? ? null ,
nodeType : created ? . nodeType || fallback . nodeType ,
prompt : created ? . prompt || fallback . prompt ,
sourceType : Number ( created ? . sourceType ? ? 2 ) ,
} ;
} ;
const loadNodeLibrary = async ( ) => {
if ( nodeLibraryGroups . value . length > 0 ) return ;
nodeLibraryLoading . value = true ;
try {
const res = await getNodeLibraryList ( ) ;
nodeLibraryGroups . value = resolveNodeLibraryGroups ( res ) ;
} catch ( error ) {
ElMessage . error ( '加载节点类型失败' ) ;
} finally {
nodeLibraryLoading . value = false ;
}
} ;
const fetchPromptList = async ( ) => {
loading . value = true ;
try {
@@ -158,6 +293,9 @@ const fetchPromptList = async () => {
const list = resolvePromptList ( res ) ;
promptList . value = list ;
pagination . total = resolvePromptTotal ( res , list ) ;
if ( selectedPrompt . value ? . id ) {
selectedPrompt . value = list . find ( ( item ) => item . id === selectedPrompt . value ? . id ) || selectedPrompt . value ;
}
} catch ( error ) {
promptList . value = [ ] ;
pagination . total = 0 ;
@@ -166,6 +304,14 @@ const fetchPromptList = async () => {
}
} ;
const resetFormState = ( ) => {
isEdit . value = false ;
editId . value = null ;
formState . nodeType = props . nodeType || '' ;
formState . prompt = '' ;
formState . sourceType = 2 ;
} ;
const handleSearch = ( ) => {
pagination . pageNum = 1 ;
fetchPromptList ( ) ;
@@ -185,16 +331,140 @@ const handleSelectPrompt = (prompt: PromptItem) => {
selectedPrompt . value = prompt ;
} ;
const handleConfirm = ( ) => {
const handleCreate = async ( ) => {
await loadNodeLibrary ( ) ;
resetFormState ( ) ;
showFormDialog . value = true ;
} ;
const handleEdit = async ( prompt : PromptItem ) => {
if ( ! canManagePrompt ( prompt ) ) return ;
await loadNodeLibrary ( ) ;
isEdit . value = true ;
editId . value = prompt . id ;
formState . nodeType = prompt . nodeType || props . nodeType || '' ;
formState . prompt = prompt . prompt || '' ;
formState . sourceType = Number ( prompt . sourceType ? ? 0 ) ;
showFormDialog . value = true ;
} ;
const handleSubmit = async ( ) => {
if ( ! formState . nodeType ? . trim ( ) ) {
ElMessage . warning ( '请选择节点类型' ) ;
return ;
}
if ( ! formState . prompt ? . trim ( ) ) {
ElMessage . warning ( '请输入提示词内容' ) ;
return ;
}
submitLoading . value = true ;
try {
const payload = {
nodeType : formState . nodeType . trim ( ) ,
prompt : formState . prompt . trim ( ) ,
sourceType : formState . sourceType ,
} ;
if ( isEdit . value && editId . value !== null ) {
await updatePrompt ( {
id : editId . value ,
... payload ,
} ) ;
ElMessage . success ( '修改成功' ) ;
} else {
await createPrompt ( payload ) ;
ElMessage . success ( '创建成功' ) ;
}
showFormDialog . value = false ;
resetFormState ( ) ;
pagination . pageNum = 1 ;
await fetchPromptList ( ) ;
} catch ( error ) {
ElMessage . error ( isEdit . value ? '修改失败' : '创建失败' ) ;
} finally {
submitLoading . value = false ;
}
} ;
const handleDeleteConfirm = ( prompt : PromptItem ) => {
if ( ! canManagePrompt ( prompt ) ) return ;
deleteId . value = prompt . id ;
showDeleteDialog . value = true ;
} ;
const handleDelete = async ( ) => {
if ( deleteId . value === null ) return ;
deleteLoading . value = true ;
try {
await deletePrompt ( deleteId . value ) ;
ElMessage . success ( '删除成功' ) ;
showDeleteDialog . value = false ;
if ( selectedPrompt . value ? . id === deleteId . value ) {
selectedPrompt . value = null ;
}
if ( promptList . value . length === 1 && pagination . pageNum > 1 ) {
pagination . pageNum -= 1 ;
}
await fetchPromptList ( ) ;
} catch ( error ) {
ElMessage . error ( '删除失败' ) ;
} finally {
deleteLoading . value = false ;
deleteId . value = null ;
}
} ;
const handleConfirm = async ( ) => {
if ( ! selectedPrompt . value ) return ;
emit ( 'confirm' , selectedPrompt . value ) ;
confirmLoading . value = true ;
try {
let finalPrompt = selectedPrompt . value ;
const isAdminPrompt = Number ( finalPrompt . sourceType ) === 1 ;
if ( isAdminPrompt ) {
const roleRes = await checkIsSuperAdmin ( ) ;
const isSuperAdmin = resolveIsSuperAdmin ( roleRes ) ;
if ( ! isSuperAdmin ) {
const createRes = await createPrompt ( {
nodeType : finalPrompt . nodeType ,
prompt : finalPrompt . prompt ,
sourceType : 2 ,
} ) ;
finalPrompt = resolveCreatedPrompt ( createRes , {
... finalPrompt ,
id : ` copied- ${ finalPrompt . id } ` ,
sourceType : 2 ,
} ) ;
selectedPrompt . value = finalPrompt ;
ElMessage . success ( '已复制为你的用户提示词' ) ;
await fetchPromptList ( ) ;
}
}
emit ( 'confirm' , finalPrompt ) ;
handleClose ( ) ;
} catch ( error ) {
ElMessage . error ( '选择提示词失败' ) ;
} finally {
confirmLoading . value = false ;
}
} ;
const handleClose = ( ) => {
visible . value = false ;
selectedPrompt . value = null ;
showFormDialog . value = false ;
showDeleteDialog . value = false ;
resetFormState ( ) ;
deleteId . value = null ;
} ;
onMounted ( ( ) => {
resetFormState ( ) ;
} ) ;
< / script >
< style scoped lang = "scss" >
@@ -221,6 +491,10 @@ const handleClose = () => {
min - height : 360 px ;
}
. operation - placeholder {
color : var ( -- el - text - color - placeholder ) ;
}
. pagination - panel {
display : flex ;
align - items : center ;
@@ -239,4 +513,8 @@ const handleClose = () => {
. pagination - panel : deep ( . el - pagination ) {
margin - left : auto ;
}
. w100 {
width : 100 % ;
}
< / style >