【增加】AI 角色定制
This commit is contained in:
parent
c06bc71020
commit
b2c15ab2cb
@ -10,6 +10,7 @@ export interface ChatRoleVO {
|
||||
sort: number // 角色排序
|
||||
description: string // 角色描述
|
||||
systemMessage: string // 角色设定
|
||||
welcomeMessage: string // 角色设定
|
||||
publicStatus: boolean // 是否公开
|
||||
status: number // 状态
|
||||
}
|
||||
@ -50,6 +51,8 @@ export const ChatRoleApi = {
|
||||
return await request.delete({ url: `/ai/chat-role/delete?id=` + id })
|
||||
},
|
||||
|
||||
// ======= chat 聊天
|
||||
|
||||
// 获取 my role
|
||||
getMyPage: async (params: ChatRolePageReqVO) => {
|
||||
return await request.get({ url: `/ai/chat-role/my-page`, params})
|
||||
@ -58,5 +61,20 @@ export const ChatRoleApi = {
|
||||
// 获取角色分类
|
||||
getCategoryList: async () => {
|
||||
return await request.get({ url: `/ai/chat-role/category-list`})
|
||||
}
|
||||
},
|
||||
|
||||
// 创建角色
|
||||
createMy: async (data: ChatRoleVO) => {
|
||||
return await request.post({ url: `/ai/chat-role/create-my`, data})
|
||||
},
|
||||
|
||||
// 更新角色
|
||||
updateMy: async (data: ChatRoleVO) => {
|
||||
return await request.put({ url: `/ai/chat-role/update-my`, data})
|
||||
},
|
||||
|
||||
// 删除角色 my
|
||||
deleteMy: async (id: number) => {
|
||||
return await request.delete({ url: `/ai/chat-role/delete-my?id=` + id })
|
||||
},
|
||||
}
|
||||
|
@ -1,6 +1,28 @@
|
||||
<template>
|
||||
<div class="card-list">
|
||||
<el-card class="card" body-class="card-body" v-for="role in roleList" :key="role.id">
|
||||
<!-- 更多 -->
|
||||
<div class="more-container">
|
||||
<el-dropdown @command="handleMoreClick">
|
||||
<span class="el-dropdown-link">
|
||||
<el-button type="text" >
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item :command="['edit', role]" >
|
||||
<el-icon><EditPen /></el-icon>编辑
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item :command="['delete', role]" style="color: red;" >
|
||||
<el-icon><Delete /></el-icon>
|
||||
<span>删除</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<!-- 头像 -->
|
||||
<div>
|
||||
<img class="avatar" :src="role.avatar"/>
|
||||
</div>
|
||||
@ -8,6 +30,7 @@
|
||||
<div class="content-container">
|
||||
<div class="title">{{ role.name }}</div>
|
||||
<div class="description">{{ role.description }}</div>
|
||||
|
||||
</div>
|
||||
<div class="btn-container">
|
||||
<el-button type="primary" size="small">使用</el-button>
|
||||
@ -20,6 +43,7 @@
|
||||
<script setup lang="ts">
|
||||
import {ChatRoleVO} from '@/api/ai/model/chatRole'
|
||||
import {PropType} from "vue";
|
||||
import {Delete, EditPen, More} from "@element-plus/icons-vue";
|
||||
|
||||
// 定义属性
|
||||
const props = defineProps({
|
||||
@ -28,6 +52,18 @@ const props = defineProps({
|
||||
required: true
|
||||
}
|
||||
})
|
||||
// 定义钩子
|
||||
const emits = defineEmits(['onDelete', 'onEdit'])
|
||||
// more 点击
|
||||
const handleMoreClick = async (data) => {
|
||||
const type = data[0]
|
||||
const role = data[1]
|
||||
if (type === 'delete') {
|
||||
emits('onDelete', role)
|
||||
} else {
|
||||
emits('onEdit', role)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
console.log('props', props.roleList)
|
||||
@ -38,13 +74,14 @@ onMounted(() => {
|
||||
<style lang="scss">
|
||||
// 重写 card 组件 body 样式
|
||||
.card-body {
|
||||
width: auto;
|
||||
max-width: 300px;
|
||||
width: 300px;
|
||||
padding: 15px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
position: relative;
|
||||
|
||||
}
|
||||
</style>
|
||||
@ -55,21 +92,36 @@ onMounted(() => {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
position: relative;
|
||||
|
||||
.card {
|
||||
margin-right: 20px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 30px;
|
||||
position: relative;
|
||||
|
||||
.more-container {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.right-container {
|
||||
margin-left: 10px;
|
||||
width: 100%;
|
||||
//height: 100px;
|
||||
|
||||
.content-container {
|
||||
height: 85px;
|
||||
overflow: hidden;
|
||||
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
|
@ -1,30 +1,38 @@
|
||||
<!-- chat 角色仓库 -->
|
||||
<template>
|
||||
<el-container class="role-container">
|
||||
<ChatRoleForm ref="formRef" @success="handlerAddRoleSuccess" />
|
||||
|
||||
<Header title="角色仓库"/>
|
||||
<el-main class="role-main">
|
||||
<div class="search-container" @click="handlerAddRole">
|
||||
<!-- 搜索按钮 -->
|
||||
<el-input
|
||||
v-model="search"
|
||||
class="search-input"
|
||||
size="large"
|
||||
size="default"
|
||||
placeholder="请输入搜索的内容"
|
||||
:suffix-icon="Search"
|
||||
@change="getActiveTabsRole"
|
||||
/>
|
||||
<el-button type="primary" style="margin-left: 20px;">
|
||||
<el-icon><User /></el-icon>
|
||||
添加角色
|
||||
</el-button>
|
||||
</div>
|
||||
<!-- tabs -->
|
||||
<el-tabs v-model="activeRole" class="tabs" @tab-click="handleTabsClick">
|
||||
<el-tab-pane class="role-pane" label="我的角色" name="my-role">
|
||||
<RoleCategoryList :category-list="categoryList" :active="activeCategory" @onCategoryClick="handlerCategoryClick" />
|
||||
<RoleList :role-list="myRoleList" style="margin-top: 20px;" />
|
||||
<RoleList :role-list="myRoleList" @onDelete="handlerCardDelete" @onEdit="handlerCardEdit" style="margin-top: 20px;" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="公共角色" name="public-role">
|
||||
<RoleCategoryList :category-list="categoryList" :active="activeCategory" @onCategoryClick="handlerCategoryClick" />
|
||||
<RoleList :role-list="publicRoleList" style="margin-top: 20px;" />
|
||||
<RoleList :role-list="publicRoleList" @onDelete="handlerCardDelete" @onEdit="handlerCardEdit" style="margin-top: 20px;" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
</template>
|
||||
|
||||
<!-- setup -->
|
||||
@ -32,10 +40,11 @@
|
||||
import {ref} from "vue";
|
||||
import Header from '@/views/ai/chat/components/Header.vue'
|
||||
import RoleList from './RoleList.vue'
|
||||
import ChatRoleForm from '@/views/ai/model/chatRole/ChatRoleForm.vue'
|
||||
import RoleCategoryList from './RoleCategoryList.vue'
|
||||
import {ChatRoleApi, ChatRolePageReqVO, ChatRoleVO} from '@/api/ai/model/chatRole'
|
||||
import {TabsPaneContext} from "element-plus";
|
||||
import {Search} from "@element-plus/icons-vue";
|
||||
import {Search, User} from "@element-plus/icons-vue";
|
||||
|
||||
// 属性定义
|
||||
const activeRole = ref<string>('my-role') // 选中的角色
|
||||
@ -47,9 +56,10 @@ const myRoleList = ref<ChatRoleVO[]>([]) // my 分页大小
|
||||
const publicPageNo = ref<number>(1) // public 分页下标
|
||||
const publicPageSize = ref<number>(50) // public 分页大小
|
||||
const publicRoleList = ref<ChatRoleVO[]>([]) // public 分页大小
|
||||
const activeCategory = ref<string>('writing') // 选择中的分类
|
||||
const activeCategory = ref<string>('') // 选择中的分类
|
||||
const categoryList = ref<string[]>([]) // 角色分类类别
|
||||
|
||||
/** 添加/修改操作 */
|
||||
const formRef = ref()
|
||||
// tabs 点击
|
||||
const handleTabsClick = async (tab: TabsPaneContext) => {
|
||||
// 设置切换状态
|
||||
@ -109,6 +119,31 @@ const handlerCategoryClick = async (category: string) => {
|
||||
await getActiveTabsRole()
|
||||
}
|
||||
|
||||
// 添加角色
|
||||
const handlerAddRole = async () => {
|
||||
formRef.value.open('my-create', null, '添加角色')
|
||||
}
|
||||
|
||||
// card 删除
|
||||
const handlerCardDelete = async (role) => {
|
||||
await ChatRoleApi.deleteMy(role.id)
|
||||
// 刷新数据
|
||||
await getActiveTabsRole()
|
||||
}
|
||||
|
||||
// card 编辑
|
||||
const handlerCardEdit = async (role) => {
|
||||
formRef.value.open('my-update', role.id, '编辑角色')
|
||||
}
|
||||
|
||||
// 添加角色成功
|
||||
const handlerAddRoleSuccess = async (e) => {
|
||||
console.log(e)
|
||||
// 刷新数据
|
||||
await getActiveTabsRole()
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
onMounted( async () => {
|
||||
// 获取分类
|
||||
@ -139,14 +174,17 @@ onMounted( async () => {
|
||||
.role-main {
|
||||
position: relative;
|
||||
|
||||
.search-input {
|
||||
width: 240px;
|
||||
.search-container {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 10px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
position: relative;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
<el-form-item label="角色头像" prop="avatar">
|
||||
<UploadImg v-model="formData.avatar" height="60px" width="60px"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="绑定模型" prop="modelId">
|
||||
<el-form-item label="绑定模型" prop="modelId" v-if="!isUser(formType)">
|
||||
<el-select v-model="formData.modelId" placeholder="请选择模型" clearable>
|
||||
<el-option
|
||||
v-for="chatModel in chatModelList"
|
||||
@ -23,7 +23,7 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="角色类别" prop="category">
|
||||
<el-form-item label="角色类别" prop="category" v-if="!isUser(formType)">
|
||||
<el-input v-model="formData.category" placeholder="请输入角色类别"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="角色描述" prop="description">
|
||||
@ -32,7 +32,10 @@
|
||||
<el-form-item label="角色设定" prop="systemMessage">
|
||||
<el-input type="textarea" v-model="formData.systemMessage" placeholder="请输入角色设定" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否公开" prop="publicStatus">
|
||||
<el-form-item label="欢迎语👏🏻" prop="welcomeMessage" v-if="isUser(formType)">
|
||||
<el-input type="textarea" v-model="formData.welcomeMessage" placeholder="请输入欢迎语"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否公开" prop="publicStatus" v-if="!isUser(formType)">
|
||||
<el-radio-group v-model="formData.publicStatus">
|
||||
<el-radio
|
||||
v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
|
||||
@ -43,10 +46,10 @@
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="角色排序" prop="sort">
|
||||
<el-form-item label="角色排序" prop="sort" v-if="!isUser(formType)">
|
||||
<el-input-number v-model="formData.sort" placeholder="请输入角色排序" class="!w-1/1"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="开启状态" prop="status">
|
||||
<el-form-item label="开启状态" prop="status" v-if="!isUser(formType)">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio
|
||||
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
|
||||
@ -89,26 +92,49 @@ const formData = ref({
|
||||
sort: undefined,
|
||||
description: undefined,
|
||||
systemMessage: undefined,
|
||||
welcomeMessage: undefined,
|
||||
publicStatus: true,
|
||||
status: CommonStatusEnum.ENABLE
|
||||
})
|
||||
const formRules = reactive({
|
||||
|
||||
// 是否
|
||||
const isUser = (type: string) => {
|
||||
return (type === 'my-create' || type === 'my-update')
|
||||
}
|
||||
|
||||
const formRules = ref() // reactive(formRulesObj)
|
||||
const formRef = ref() // 表单 Ref
|
||||
const chatModelList = ref([] as ChatModelVO[]) // 聊天模型列表
|
||||
|
||||
const getFormRules = async (type: string) => {
|
||||
let formRulesObj = {
|
||||
name: [{required: true, message: '角色名称不能为空', trigger: 'blur'}],
|
||||
avatar: [{required: true, message: '角色头像不能为空', trigger: 'blur'}],
|
||||
category: [{required: true, message: '角色类别不能为空', trigger: 'blur'}],
|
||||
sort: [{required: true, message: '角色排序不能为空', trigger: 'blur'}],
|
||||
description: [{required: true, message: '角色描述不能为空', trigger: 'blur'}],
|
||||
systemMessage: [{required: true, message: '角色设定不能为空', trigger: 'blur'}],
|
||||
// welcomeMessage: [{ required: true, message: '欢迎语不能为空', trigger: 'blur' }],
|
||||
publicStatus: [{required: true, message: '是否公开不能为空', trigger: 'blur'}]
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
const chatModelList = ref([] as ChatModelVO[]) // 聊天模型列表
|
||||
}
|
||||
|
||||
if (isUser(type)) {
|
||||
formRulesObj['welcomeMessage'] = [{
|
||||
required: true,
|
||||
message: '欢迎语不能为空',
|
||||
trigger: 'blur'
|
||||
}]
|
||||
}
|
||||
|
||||
formRules.value = reactive(formRulesObj)
|
||||
}
|
||||
|
||||
/** 打开弹窗 */
|
||||
const open = async (type: string, id?: number) => {
|
||||
const open = async (type: string, id?: number, title?: string) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = t('action.' + type)
|
||||
dialogTitle.value = title || t('action.' + type)
|
||||
formType.value = type
|
||||
getFormRules(type)
|
||||
resetForm()
|
||||
// 修改时,设置数据
|
||||
if (id) {
|
||||
@ -133,7 +159,17 @@ const submitForm = async () => {
|
||||
formLoading.value = true
|
||||
try {
|
||||
const data = formData.value as unknown as ChatRoleVO
|
||||
if (formType.value === 'create') {
|
||||
|
||||
// tip: my-create、my-update 是 chat 角色仓库调用
|
||||
// tip: create、else 是后台管理调用
|
||||
|
||||
if (formType.value === 'my-create') {
|
||||
await ChatRoleApi.createMy(data)
|
||||
message.success(t('common.createSuccess'))
|
||||
} else if (formType.value === 'my-update') {
|
||||
await ChatRoleApi.updateMy(data)
|
||||
message.success(t('common.updateSuccess'))
|
||||
} else if (formType.value === 'create') {
|
||||
await ChatRoleApi.createChatRole(data)
|
||||
message.success(t('common.createSuccess'))
|
||||
} else {
|
||||
@ -148,6 +184,7 @@ const submitForm = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** 重置表单 */
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
@ -159,6 +196,7 @@ const resetForm = () => {
|
||||
sort: undefined,
|
||||
description: undefined,
|
||||
systemMessage: undefined,
|
||||
welcomeMessage: undefined,
|
||||
publicStatus: true,
|
||||
status: CommonStatusEnum.ENABLE
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user