Files
loveKeyAdmin/src/views/keyboard/aicompanion/index.vue
2026-04-16 13:16:44 +08:00

340 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="角色头像" prop="avatarUrl">
<el-input v-model="queryParams.avatarUrl" placeholder="请输入角色头像URL" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="角色封面图" prop="coverImageUrl">
<el-input v-model="queryParams.coverImageUrl" placeholder="请输入角色封面图URL" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-input v-model="queryParams.gender" placeholder="male / female / other" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="年龄段" prop="ageRange">
<el-input v-model="queryParams.ageRange" placeholder="如20s、25-30" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="性格标签" prop="personalityTags">
<el-input v-model="queryParams.personalityTags" placeholder="如:温柔、黏人、治愈" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="说话风格" prop="speakingStyle">
<el-input v-model="queryParams.speakingStyle" placeholder="如:撒娇型、理性型、活泼型" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="系统Prompt" prop="systemPrompt">
<el-input v-model="queryParams.systemPrompt" placeholder="定义角色核心人设" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable class="!w-240px">
<el-option label="上线" value="1" />
<el-option label="下线" value="0" />
</el-select>
</el-form-item>
<el-form-item label="可见性" prop="visibility">
<el-select v-model="queryParams.visibility" placeholder="请选择可见性" clearable class="!w-240px">
<el-option label="公开" value="1" />
<el-option label="内测" value="2" />
<el-option label="隐藏" value="3" />
</el-select>
</el-form-item>
<el-form-item label="排序权重" prop="sortOrder">
<el-input v-model="queryParams.sortOrder" placeholder="数值越大排序越靠前" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="热度评分" prop="popularityScore">
<el-input v-model="queryParams.popularityScore" placeholder="用于推荐排序" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="创建时间" prop="createdAt">
<el-date-picker v-model="queryParams.createdAt" value-format="YYYY-MM-DD" type="date" placeholder="选择创建时间"
clearable class="!w-240px" />
</el-form-item>
<el-form-item label="更新时间" prop="updatedAt">
<el-date-picker v-model="queryParams.updatedAt" value-format="YYYY-MM-DD" type="date" placeholder="选择更新时间"
clearable class="!w-240px" />
</el-form-item>
<el-form-item label="开场白" prop="prologue">
<el-input v-model="queryParams.prologue" placeholder="请输入开场白" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="开场白音频" prop="prologueAudio">
<el-input v-model="queryParams.prologueAudio" placeholder="请输入开场白音频URL" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="音频Id" prop="voiceId">
<el-input v-model="queryParams.voiceId" placeholder="请输入音频Id" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['keyboard:ai-companion:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['keyboard:ai-companion:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
<el-button type="danger" plain :disabled="isEmpty(checkedIds)" @click="handleDeleteBatch"
v-hasPermi="['keyboard:ai-companion:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table row-key="id" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"
highlight-current-row @current-change="handleCurrentChange" @selection-change="handleRowCheckboxChange">
<el-table-column type="selection" width="55" />
<el-table-column label="ID" align="center" prop="id" width="80px" />
<el-table-column label="角色头像" align="center" prop="avatarUrl" width="100px">
<template #default="scope">
<el-image v-if="scope.row.avatarUrl" :src="scope.row.avatarUrl" fit="contain" class="avatar-image"
:preview-src-list="[scope.row.avatarUrl]" preview-teleported />
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="角色封面图" align="center" prop="coverImageUrl" width="120px">
<template #default="scope">
<el-image v-if="scope.row.coverImageUrl" :src="scope.row.coverImageUrl" fit="contain" class="cover-image"
:preview-src-list="[scope.row.coverImageUrl]" preview-teleported />
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="性别" align="center" prop="gender" width="100px" />
<el-table-column label="年龄段" align="center" prop="ageRange" width="100px" />
<el-table-column label="性格标签" align="center" prop="personalityTags" width="150px" />
<el-table-column label="说话风格" align="center" prop="speakingStyle" width="120px" />
<el-table-column label="系统Prompt" align="center" prop="systemPrompt" min-width="200px" />
<el-table-column label="状态" align="center" prop="status" width="80px">
<template #default="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">
{{ scope.row.status === 1 ? '上线' : '下线' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="可见性" align="center" prop="visibility" width="100px">
<template #default="scope">
<el-tag :type="scope.row.visibility === 1 ? 'success' : scope.row.visibility === 2 ? 'warning' : 'info'">
{{ scope.row.visibility === 1 ? '公开' : scope.row.visibility === 2 ? '内测' : '隐藏' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="排序权重" align="center" prop="sortOrder" width="100px" />
<el-table-column label="热度评分" align="center" prop="popularityScore" width="100px" />
<!-- <el-table-column label="创建时间" align="center" prop="createdAt" :formatter="dateFormatter" width="180px" />
<el-table-column label="更新时间" align="center" prop="updatedAt" :formatter="dateFormatter" width="180px" /> -->
<!-- <el-table-column label="开场白" align="center" prop="prologue" min-width="150px" />
<el-table-column label="开场白音频" align="center" prop="prologueAudio" min-width="150px" /> -->
<el-table-column label="音频Id" align="center" prop="voiceId" width="120px" />
<el-table-column label="操作" align="center" min-width="120px">
<template #default="scope">
<el-button link type="primary" @click="openForm('update', scope.row.id)"
v-hasPermi="['keyboard:ai-companion:update']">
编辑
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)"
v-hasPermi="['keyboard:ai-companion:delete']">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<AiCompanionForm ref="formRef" @success="getList" />
<!-- 子表的列表 -->
<ContentWrap>
<el-tabs model-value="aiCompanionI18n">
<el-tab-pane label="AI陪聊角色国际化表用于存储不同语言下的角色名称、一句话描述和详细介绍" name="aiCompanionI18n">
<AiCompanionI18nList :id="currentRow.id" />
</el-tab-pane>
</el-tabs>
</ContentWrap>
</template>
<script setup lang="ts">
import { isEmpty } from '@/utils/is'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { AiCompanionApi, AiCompanion } from '@/api/keyboard/aicompanion'
import AiCompanionForm from './AiCompanionForm.vue'
import AiCompanionI18nList from './components/AiCompanionI18nList.vue'
/** AI陪聊角色表用于定义恋爱/陪伴型虚拟角色的基础信息与人设 列表 */
defineOptions({ name: 'KeyboardAiCompanion' })
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中
const list = ref<AiCompanion[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
avatarUrl: undefined,
coverImageUrl: undefined,
gender: undefined,
ageRange: undefined,
personalityTags: undefined,
speakingStyle: undefined,
systemPrompt: undefined,
status: undefined,
visibility: undefined,
sortOrder: undefined,
popularityScore: undefined,
createdAt: undefined,
createdAt: [],
updatedAt: undefined,
updatedAt: [],
prologue: undefined,
prologueAudio: undefined,
voiceId: undefined
})
const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) // 导出的加载中
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await AiCompanionApi.getAiCompanionPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
// 删除的二次确认
await message.delConfirm()
// 发起删除
await AiCompanionApi.deleteAiCompanion(id)
message.success(t('common.delSuccess'))
currentRow.value = {}
// 刷新列表
await getList()
} catch { }
}
/** 批量删除AI陪聊角色表用于定义恋爱/陪伴型虚拟角色的基础信息与人设 */
const handleDeleteBatch = async () => {
try {
// 删除的二次确认
await message.delConfirm()
await AiCompanionApi.deleteAiCompanionList(checkedIds.value);
checkedIds.value = [];
message.success(t('common.delSuccess'))
await getList();
} catch { }
}
const checkedIds = ref<number[]>([])
const handleRowCheckboxChange = (records: AiCompanion[]) => {
checkedIds.value = records.map((item) => item.id!);
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
// 导出的二次确认
await message.exportConfirm()
// 发起导出
exportLoading.value = true
const data = await AiCompanionApi.exportAiCompanion(queryParams)
download.excel(data, 'AI陪聊角色表用于定义恋爱/陪伴型虚拟角色的基础信息与人设.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 选中行操作 */
const currentRow = ref({}) // 选中行
const handleCurrentChange = (row) => {
currentRow.value = row
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>
<style scoped>
/* 头像和封面图样式 */
.avatar-image {
width: 56px;
height: 56px;
border-radius: 8px;
border: 1px solid var(--el-border-color-light);
background-color: var(--el-fill-color-light);
padding: 4px;
cursor: pointer;
}
.cover-image {
width: 96px;
height: 64px;
border-radius: 4px;
border: 1px solid var(--el-border-color-light);
background-color: var(--el-fill-color-light);
padding: 4px;
cursor: pointer;
}
/* 按钮间距 */
.el-button {
margin-right: 8px;
margin-bottom: 8px;
}
/* 表格样式优化 */
.el-table {
margin-top: 16px;
}
/* 操作按钮间距 */
.el-table-column__content .el-button {
margin-right: 4px;
}
</style>