mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
feat(model): add model and delete model
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
Generated
+3
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user