feat(model): add model and delete model

This commit is contained in:
Quicy
2026-01-20 14:12:54 +08:00
parent cb11ac2708
commit 42372ddea3
8 changed files with 140 additions and 49 deletions
+1
View File
@@ -17,6 +17,7 @@
"@tailwindcss/vite": "^4.1.18",
"@tanstack/vue-table": "^8.21.3",
"@vee-validate/zod": "^4.15.1",
"@vueuse/core": "^14.1.0",
"axios": "^1.13.2",
"dotenv": "^17.2.3",
"pinia": "^3.0.4",
@@ -3,7 +3,7 @@
<Dialog v-model:open="open">
<DialogTrigger as-child>
<Button variant="default">
Open Dialog
添加Model
</Button>
</DialogTrigger>
<DialogContent class="sm:max-w-106.25">
@@ -132,7 +132,7 @@
</FormField>
<FormField
v-slot="{ componentField }"
name="role"
name="type"
>
<FormItem>
<FormLabel class="mb-2">
@@ -145,14 +145,10 @@
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
value="chat"
>
<SelectItem value="chat">
Chat
</SelectItem>
<SelectItem
value="embedding"
>
<SelectItem value="embedding">
embedding
</SelectItem>
</SelectGroup>
@@ -206,40 +202,65 @@ import {
FormMessage
} from '@memoh/ui'
import { useForm } from 'vee-validate'
import { ref } from 'vue'
import { inject, watch, type Ref,ref } from 'vue'
import { toTypedSchema } from '@vee-validate/zod'
import z from 'zod'
import request from '@/utils/request'
import { useMutation,useQueryCache } from '@pinia/colada'
import { useMutation, useQueryCache } from '@pinia/colada'
const formSchema = toTypedSchema(z.object({
modelId:z.string().min(1),
baseUrl: z.string().min(1),
apiKey: z.string().min(1),
clientType: z.string().min(1),
name: z.string().min(1),
role: z.string().min(1),
type: z.string().min(1),
}))
const form = useForm({
validationSchema: formSchema
})
const queryCache=useQueryCache()
const queryCache = useQueryCache()
type ModelInfoType= Parameters<(Parameters<typeof form.handleSubmit>)[0]>[0]
const { mutate: createModel } = useMutation({
mutation: (modelInfo: Parameters<(Parameters<typeof form.handleSubmit>)[0]>[0]) => request({
mutation: (modelInfo:ModelInfoType ) => request({
url: '/model',
data: {
...modelInfo,
modelId:'fwoi0fjwfiwefwjfiowefoi'
...modelInfo,
},
method:'post'
method: 'post'
}),
onSettled: () => queryCache.invalidateQueries({ key: ['models'], exact: true })
})
const addModel = form.handleSubmit(async (modelInfo) => {
createModel(modelInfo)
onSettled: () => { open.value = false; queryCache.invalidateQueries({ key: ['models'], exact: true })}
})
const open = ref(false)
const { mutate: updateModel } = useMutation({
mutation: (modelInfo: ModelInfoType) => request({
url: `/model/${editInfo.value?.id}`,
data: {
...modelInfo,
},
method: 'PUT'
}),
onSettled: () => { open.value = false; queryCache.invalidateQueries({ key: ['models'], exact: true }) }
})
const addModel = form.handleSubmit(async (modelInfo) => {
if (editInfo.value?.id) {
updateModel(modelInfo)
} else {
createModel(modelInfo)
}
})
const open = inject<Ref<boolean>>('open',ref(false))
const editInfo = inject('editModelInfo',ref<null|(ModelInfoType&{id:string})>(null))
watch(open, () => {
if (open.value && editInfo?.value) {
form.setValues(editInfo.value)
}
}, {
immediate:true
})
</script>
@@ -5,7 +5,6 @@ import {
getCoreRowModel,
useVueTable,
} from '@tanstack/vue-table'
import {
Table,
TableBody,
@@ -25,7 +24,6 @@ const table = useVueTable({
get columns() { return props.columns },
getCoreRowModel: getCoreRowModel(),
})
console.log(table.getHeaderGroups())
</script>
<template>
+1 -1
View File
@@ -119,7 +119,7 @@ import { toTypedSchema } from '@vee-validate/zod'
import { useForm } from 'vee-validate'
import * as z from 'zod'
import request from '@/utils/request'
import { useUserStore } from '@/store/user'
import { useUserStore } from '@/store/User.ts'
import { ref } from 'vue'
const router = useRouter()
+73 -21
View File
@@ -1,37 +1,69 @@
<script setup lang="ts">
// import type { Payment } from '@/components/columns'
import { watch, h, computed } from 'vue'
import { h, computed, ref, provide, watch } from 'vue'
import CreateModel from '@/components/CreateModel/index.vue'
import { useQuery } from '@pinia/colada'
import { useQuery,useMutation,useQueryCache } from '@pinia/colada'
import {
Button,
} from '@memoh/ui'
import DataTable from '@/components/DataTable/index.vue'
import request from '@/utils/request'
import {type ColumnDef } from '@tanstack/vue-table'
import { type ColumnDef } from '@tanstack/vue-table'
interface ModelType {
apiKey:string,
apiKey: string,
baseUrl: string,
clientType: 'OpenAI'|'Anthropic'|'Google',
modelId:string,
name:string,
type:'chat'|'embedding'
clientType: 'OpenAI' | 'Anthropic' | 'Google',
modelId: string,
name: string,
type: 'chat' | 'embedding',
id:string
}
const columns:ColumnDef<ModelType>[] = [
const openDialogModel = ref(false)
const editModelInfo = ref<ModelType & {id:string} |null>(null)
provide('open', openDialogModel)
provide('editModelInfo', editModelInfo)
watch(openDialogModel, () => {
if (!openDialogModel.value) {
editModelInfo.value=null
}
}, {
immediate:true
})
const cacheQuery=useQueryCache()
const {
mutate: deleteModel,
} = useMutation({
mutation: (id: string) =>
request({
url: `model/${id}`,
method: 'DELETE'
}),
onSettled: () => {
cacheQuery.invalidateQueries({
key:['models']
})
}
})
const columns: ColumnDef<ModelType>[] = [
{
accessorKey: 'modelId',
header: () => h('div', { class: 'text-left py-4' }, 'Name'),
cell({row}) {
return h('div',{ class: 'text-left py-4' },row.getValue('modelId'))
cell({ row }) {
return h('div', { class: 'text-left py-4' }, row.getValue('modelId'))
}
},
{
accessorKey: 'baseUrl',
header: () => h('div', { class: 'text-left' }, 'Base Url'),
},
{
accessorKey: 'apiKey',
header: () => h('div', { class: 'text-left' }, 'Api Key'),
@@ -41,16 +73,30 @@ const columns:ColumnDef<ModelType>[] = [
header: () => h('div', { class: 'text-left' }, 'Client Type'),
},
{
accessorKey: 'Name',
accessorKey: 'name',
header: () => h('div', { class: 'text-left' }, 'Name'),
},
{
accessorKey: 'type',
header: () => h('div', { class: 'text-left' }, 'Type'),
},
{
accessorKey: 'control',
header: () => h('div', { class: 'text-center' }, '操作'),
cell: ({row}) => h('div', { class: ' w-full flex justify-around' }, [h(Button, {
'onClick': () => {
editModelInfo.value=row.original
openDialogModel.value = true
}
}, () => '编辑'), h(Button, {
variant: 'destructive', onClick() {
deleteModel(row.original.id)
}},()=>'删除')])
}
]
const {data:modelData}=useQuery({
const { data: modelData } = useQuery({
key: ['models'],
query() {
return request({
@@ -58,20 +104,26 @@ const {data:modelData}=useQuery({
})
}
})
const displayFormat = computed(() => {
return modelData.value?.data?.items?.map((currentModel:{model: ModelType,id:'string' })=>currentModel.model)??[]
return modelData.value?.data?.items?.map((currentModel: { model: Omit<ModelType,'id'>, id: 'string' }) => ({id:currentModel.id,...currentModel.model})) ?? []
})
</script>
<template>
<div class="w-full py-10 mx-auto">
<div class="flex mb-4">
<CreateModel />
</div>
<div class="[&_td:last-child]:w-45">
<DataTable
:columns="columns"
:data="displayFormat"
/>
</div>
<DataTable
:columns="columns"
:data="displayFormat"
/>
</div>
</template>
+1 -1
View File
@@ -1,6 +1,5 @@
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
@@ -72,6 +71,7 @@ const router = createRouter({
})
router.beforeEach((to) => {
const token = localStorage.getItem('token')
if (to.fullPath !== '/login') {
return token ? true : { name: 'Login' }
} else {
+19 -3
View File
@@ -1,5 +1,7 @@
import { defineStore } from 'pinia'
import { reactive } from 'vue'
import { reactive,watch } from 'vue'
import { useLocalStorage } from '@vueuse/core'
import { useRouter } from 'vue-router'
type user={
@@ -8,6 +10,8 @@ type user={
'role': string,
'displayName': string
}
export const useUserStore = defineStore('user', () => {
const userInfo = reactive<user>({
'id': '',
@@ -16,20 +20,32 @@ export const useUserStore = defineStore('user', () => {
'displayName': ''
})
const localToken=useLocalStorage('token','')
const login = (userData: user,token:string) => {
localStorage.setItem('token',token)
localToken.value=token
for (const key of Object.keys(userData) as (keyof user)[]) {
userInfo[key] = userData[key]
}
}
const exitLogin = () => {
localStorage.removeItem('token')
localToken.value=''
for (const key of Object.keys(userInfo) as (keyof user)[]) {
userInfo[key]=''
}
}
const router=useRouter()
watch(localToken, () => {
if (!localToken.value) {
exitLogin()
router.replace({name:'Login'})
}
}, {
immediate: true
})
return {
userInfo,
login,
+3
View File
@@ -252,6 +252,9 @@ importers:
'@vee-validate/zod':
specifier: ^4.15.1
version: 4.15.1(vue@3.5.26(typescript@5.9.3))(zod@4.3.5)
'@vueuse/core':
specifier: ^14.1.0
version: 14.1.0(vue@3.5.26(typescript@5.9.3))
axios:
specifier: ^1.13.2
version: 1.13.2