feat(webui): WebUI 管理后台新增 AII 管理栏目

在 WebUI NyaHome 管理后台中实现 AII 管理栏目,用于在线修改模型设置。
同时在后端补全了两个路由端点。
This commit is contained in:
2026-06-01 20:42:16 +08:00
parent 45e255856a
commit 7df66bbc61
13 changed files with 571 additions and 109 deletions
+7 -4
View File
@@ -9,7 +9,7 @@ import ChatControlPanel from '@/components/chatroom/ChatControlPanel.vue'
import ChatroomCard from '@/components/chatroom/ChatroomCard.vue'
import ChatTable from '@/components/chatroom/ChatTable.vue'
import { api } from '@/tools/web.ts'
import type { AiiTokenInfo } from '@/types/aii.ts'
import type { AiiModelPublic, AiiTokenInfo } from '@/types/aii.ts'
import type { Chatroom } from '@/types/chatroom.ts'
import type { ReturnDto } from '@/types/response.ts'
import { SEE_YOU_TOMORROW } from '@/types/syt.ts'
@@ -26,7 +26,8 @@ const MESSAGE = useMessage()
const chatroom = ref<Chatroom | null>(null)
const selectedModel = ref<number | null>(null)
const selectedModelId = ref<number | null>(null)
const selectedModel = ref<AiiModelPublic | null>(null)
const quickerPrompt = ref('')
const inputMessage = ref<string>('')
const inputMode = ref<'continue' | 'expand'>('expand')
@@ -67,7 +68,7 @@ watch(
)
function chat() {
if (!selectedModel.value) {
if (!selectedModelId.value) {
MESSAGE.warning('未选择模型,无法开始创作喵!')
return
}
@@ -91,7 +92,7 @@ function chat() {
message: inputMessage.value,
prefix: quickerPrompt.value,
mode: inputMode.value,
model_id: selectedModel.value,
model_id: selectedModelId.value,
}),
openWhenHidden: true, // 此开关控制在浏览器失去焦点时是否保持连接开启。默认为 false 会导致焦点转移时流式传输中断然后重连,很怪
@@ -249,6 +250,7 @@ function enableSidebar() {
:aii-thinking
:aii-message
:aii-token-info
:model="selectedModel"
v-model:message="inputMessage"
v-model:mode="inputMode"
:on-send-message="chat"
@@ -265,6 +267,7 @@ function enableSidebar() {
:chatroom="chatroom"
:load-page="load"
v-model:quicker-prompt="quickerPrompt"
v-model:select-model-id="selectedModelId"
v-model:select-model="selectedModel"
/>
<div id="sidebar-toggle" @click="disableSidebar" />
+6 -5
View File
@@ -5,6 +5,7 @@ import { ref } from 'vue'
import ConfigCard from '@/components/admin/ConfigCard.vue'
import InDev from '@/components/InDev.vue'
import AdminAii from '@/pages/nyahome/AdminAii.vue'
import { api } from '@/tools/web.ts'
import type { ReturnDto } from '@/types/response.ts'
@@ -101,6 +102,10 @@ function sendTestMail() {
</config-card>
</n-tab-pane>
<n-tab-pane name="aii" tab="AII" display-directive="show">
<admin-aii />
</n-tab-pane>
<n-tab-pane name="site_info" tab="站点信息" display-directive="show">
<n-flex vertical>
<config-card title="基本信息">
@@ -233,8 +238,4 @@ function sendTestMail() {
<n-empty size="large" v-else description="请尝试手动获取设置..." />
</template>
<style scoped>
.in-form-alert {
margin-bottom: 16px;
}
</style>
<style scoped></style>
+199
View File
@@ -0,0 +1,199 @@
<script setup lang="ts">
import { type DataTableColumns, NButton, NTag } from 'naive-ui'
import { h, onMounted, ref } from 'vue'
import ConfigCard from '@/components/admin/ConfigCard.vue'
import AiiModelAddModal from '@/components/aii/AiiModelAddModal.vue'
import AiiModelEditModal from '@/components/aii/AiiModelEditModal.vue'
import AiiProviderAddModal from '@/components/aii/AiiProviderAddModal.vue'
import AiiProviderEditModal from '@/components/aii/AiiProviderEditModal.vue'
import { api } from '@/tools/web.ts'
import type { AiiModelPublic, AiiProviderPublicWithoutKey } from '@/types/aii.ts'
const showProviderAddModal = ref(false)
const showProviderEditModal = ref(false)
const showModelAddModal = ref(false)
const showModelEditModal = ref(false)
function createProviderColumns(): DataTableColumns<AiiProviderPublicWithoutKey> {
return [
{
title: 'ID',
key: 'id',
render(row) {
return h(
NTag,
{
type: 'error',
round: true,
},
row.id,
)
},
},
{
title: '提供商名称',
key: 'name',
},
{
title: 'Base URL',
key: 'base_url',
},
{
title: '操作',
key: 'action',
render(row) {
return h(
NButton,
{
type: 'warning',
secondary: true,
round: true,
onClick() {
selectedProvider.value = row
showProviderEditModal.value = true
},
},
'修改',
)
},
},
]
}
function createModelColumns(): DataTableColumns<AiiModelPublic> {
return [
{
title: 'ID',
key: 'id',
render(row) {
return h(
NTag,
{
type: 'primary',
round: true,
},
row.id,
)
},
},
{
title: '模型名称',
key: 'model_name',
},
{
title: '最大上下文长度(k',
key: 'max_context_length',
},
{
title: '支持思考',
key: 'reasonable',
render(row) {
return h(
NTag,
{
type: 'info',
round: true,
},
row.reasonable ? '思考' : '非思考',
)
},
},
{
title: '所属提供商',
key: 'provider_id',
render(row) {
return h(
NTag,
{
type: 'error',
round: true,
},
row.provider_id,
)
},
},
{
title: '操作',
key: 'action',
render(row) {
return h(
NButton,
{
type: 'warning',
secondary: true,
round: true,
onClick() {
selectedModel.value = row
showModelEditModal.value = true
},
},
'修改',
)
},
},
]
}
const providerColumns = createProviderColumns()
const modelColumns = createModelColumns()
const providers = ref<AiiProviderPublicWithoutKey[]>([])
const models = ref<AiiModelPublic[]>([])
const selectedModel = ref<AiiModelPublic | null>(null)
const selectedProvider = ref<AiiProviderPublicWithoutKey | null>(null)
function load() {
api
.get('/aii/provider/')
.then((res) => res.data as AiiProviderPublicWithoutKey[])
.then((data) => (providers.value = data))
api
.get('/aii/model/')
.then((res) => res.data as AiiModelPublic[])
.then((data) => (models.value = data))
}
onMounted(() => {
load()
})
</script>
<template>
<n-flex vertical align="center">
<n-card>
<n-flex>
<n-h4 style="margin: 0">刷新本页信息如果你正在从其他地方修改</n-h4>
<n-button style="margin-left: auto" type="info" @click="load()">更新</n-button>
</n-flex>
</n-card>
<config-card title="模型提供商">
<template #extra>
<n-button round type="info" @click="showProviderAddModal = true">添加</n-button>
</template>
<n-data-table :columns="providerColumns" :data="providers" />
</config-card>
<config-card title="模型">
<template #extra>
<n-button round type="info" @click="showModelAddModal = true">添加</n-button>
</template>
<n-data-table :columns="modelColumns" :data="models" />
</config-card>
<aii-provider-add-modal v-model:show-modal="showProviderAddModal" :reload="load" />
<aii-model-add-modal v-model:show-modal="showModelAddModal" no-add-provider :reload="load" />
<aii-provider-edit-modal
:provider="selectedProvider"
v-model:show-modal="showProviderEditModal"
:reload="load"
/>
<aii-model-edit-modal
:model="selectedModel"
v-model:show-modal="showModelEditModal"
:reload="load"
/>
</n-flex>
</template>
<style scoped></style>