Skip to content

Commit 90e136d

Browse files
feat: model
1 parent 5d6c606 commit 90e136d

42 files changed

Lines changed: 1292 additions & 470 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎ui/src/api/admin/workspace/model/model.ts‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { del, get, post, put } from '../../core/request'
2-
import type { Dict, ModelPayload, ModelItem } from '@/api/types'
2+
import type { Dict, DynamicFormField, ModelPayload, ModelItem } from '@/api/types'
33
import { getWorkspaceId } from '@/utils/workspace-context'
44

55
const getPrefix = () => {
@@ -36,8 +36,15 @@ const getModelMeta = (modelId: string) => {
3636
const deleteModel = (modelId: string) => {
3737
return del<undefined, boolean>(`${getPrefix()}/${modelId}`)
3838
}
39+
40+
/** 获取模型参数表单。 */
3941
const getModelParamsForm = (modelId: string) => {
40-
return get<ModelItem>(`${getPrefix()}/${modelId}/model_params_form`)
42+
return get<DynamicFormField[]>(`${getPrefix()}/${modelId}/model_params_form`)
43+
}
44+
45+
/** 保存模型参数表单。 */
46+
const putModelParamsForm = (modelId: string, payload: DynamicFormField[]) => {
47+
return put<DynamicFormField[], boolean>(`${getPrefix()}/${modelId}/model_params_form`, payload)
4148
}
4249

4350
/** 暂停本地模型下载。 */
@@ -50,8 +57,9 @@ export default {
5057
getModelDetail,
5158
getModelList,
5259
getModelMeta,
60+
getModelParamsForm,
5361
postModel,
5462
putModel,
63+
putModelParamsForm,
5564
putPauseModelDownload,
56-
getModelParamsForm,
5765
}

‎ui/src/api/admin/workspace/model/provider.ts‎

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { get } from '../../core/request'
2-
import type { BaseModelOption, DynamicFormField, ModelProviderItem, ModelTypeOption } from '@/api/types'
2+
import type {
3+
BaseModelOption,
4+
DynamicFormField,
5+
ModelProviderItem,
6+
ModelTypeOption,
7+
} from '@/api/types'
38

49
const prefix = '/provider'
510

@@ -22,6 +27,16 @@ const getModelCreateForm = (provider: string, modelType: string, modelName: stri
2227
})
2328
}
2429

30+
/** 获取基础模型的动态参数表单。 */
31+
const getBaseModelParamsForm = (provider: string, modelType: string, modelName: string) => {
32+
return get<DynamicFormField[]>(`${prefix}/model_params_form`, {
33+
model_name: modelName,
34+
model_type: modelType,
35+
provider,
36+
})
37+
}
38+
39+
2540
/** 获取供应商支持的模型类型。 */
2641
const getModelTypeList = (provider: string) => {
2742
return get<ModelTypeOption[]>(`${prefix}/model_type_list`, { provider })
@@ -35,15 +50,6 @@ const getBaseModelList = (provider: string, modelType: string) => {
3550
})
3651
}
3752

38-
/** 获取基础模型的参数表单。 */
39-
const getBaseModelParamsForm = (provider: string, modelType: string, modelName: string) => {
40-
return get<DynamicFormField[]>(`${prefix}/model_params_form`, {
41-
model_name: modelName,
42-
model_type: modelType,
43-
provider,
44-
})
45-
}
46-
4753
export default {
4854
getBaseModelList,
4955
getBaseModelParamsForm,

‎ui/src/api/types/model.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export interface DynamicFormField {
4444
attrs?: Record<string, unknown>
4545
default_value?: unknown
4646
field: string
47-
input_type?: string
47+
input_type: string
4848
label: string | DynamicFormLabel
4949
option_list?: Record<string, unknown>[]
5050
required?: boolean
@@ -58,6 +58,7 @@ export interface DynamicFormLabel {
5858
tooltip?: string
5959
[key: string]: unknown
6060
}
61+
input_type: string
6162
label: string
6263
type?: string
6364
}
-52.7 KB
Loading

‎ui/src/components/COMPONENT_README.md‎

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ Element Plus 使用 `ElOnlyChild` 处理浮层触发器。`el-tooltip`、`el-pop
176176
带标题触发器和展开过渡动画的内容折叠组件。组件内部维护展开状态,`default-expanded` 设置初始
177177
状态且默认为 `true`;点击标题行会切换状态,不向外回传展开状态。默认插槽放置折叠内容,标题
178178
默认使用 `title` 属性,也可通过 `label` 插槽自定义;标题触发层可通过 `trigger-class` 和
179-
`trigger-style` 自定义 class 和行内样式。
179+
`trigger-style` 自定义 class 和行内样式。指示图标默认显示在标题前,通过
180+
`indicator-position="after"` 可改为显示在标题后的线性上、下箭头。
180181

181182
```vue
182183
<MkCollapse title="系统管理员">
@@ -189,6 +190,11 @@ Element Plus 使用 `ElOnlyChild` 处理浮层触发器。`el-tooltip`、`el-pop
189190
</template>
190191
<div>折叠内容</div>
191192
</MkCollapse>
193+
194+
<MkCollapse indicator-position="after">
195+
<template #label><h6>高级设置</h6></template>
196+
<div>高级设置内容</div>
197+
</MkCollapse>
192198
```
193199

194200
### MkEmpty
@@ -343,16 +349,18 @@ Element Plus Dropdown 属性和事件通过 `$attrs` 传入,并暴露 `handleO
343349
### MkViewLayout
344350

345351
路由页面的通用内容结构,统一提供满高弹性布局及可选左侧栏。标题优先使用 `title` Prop,未传入
346-
时读取当前路由的 `meta.title`。`aside` 和默认作用域插槽都提供 `title` 与对应区域的 `Header`
347-
包装组件;插槽未渲染 `Header` 时,组件会自动显示当前标题,页面需要添加操作区或自定义标题时
348-
再显式渲染 `Header`。Header 固定在主内容区顶部,其余默认插槽内容由组件统一放入
352+
时读取当前路由的 `meta.title`。`aside` 作用域插槽提供 `title` 和对应区域的 `Header` 包装组件,
353+
默认作用域插槽另外提供主内容区的 `Footer` 包装组件;插槽未渲染 `Header` 时,组件会自动显示当前
354+
标题,页面需要添加操作区或自定义标题时再显式渲染 `Header`。Header 固定在主内容区顶部,其余
355+
默认插槽内容由组件统一放入
349356
`el-scrollbar`,页面不要再为整个主内容区嵌套滚动容器;Tabs、树或其他局部区域需要独立滚动时
350-
仍可自行使用 `el-scrollbar`。页面可以在同一个插槽中组织标题、内容和空状态,并只写一次业务
351-
状态判断。传入 `aside` 插槽后才会渲染左侧栏;左右结构上方的独立内容放入 `top` 插槽。页面加载状态通过
352-
`loading` Prop 传入,由组件将 Element Plus Loading 遮罩绑定到整个布局根节点。默认插槽没有
353-
渲染 `Header` 时会自动显示当前标题;显式渲染后则由页面控制标题内容。`collapsible` 默认为
354-
`false`;传入后,展开状态仅在鼠标移入侧栏或焦点进入侧栏时显示收起按钮,收起状态始终显示展开
355-
按钮。收起时释放侧栏宽度,页面不需要自行维护折叠状态。
357+
仍可自行使用 `el-scrollbar`。渲染 `Footer` 后固定在主内容区底部,不占用左侧栏空间,适合放置页面
358+
或全高 Drawer 右侧内容的操作按钮。页面可以在同一个插槽中组织标题、内容、底栏和空状态,并只写
359+
一次业务状态判断。传入 `aside` 插槽后才会渲染左侧栏;左右结构上方的独立内容放入 `top` 插槽。
360+
页面加载状态通过 `loading` Prop 传入,由组件将 Element Plus Loading 遮罩绑定到整个布局根节点。
361+
默认插槽没有渲染 `Header` 时会自动显示当前标题;显式渲染后则由页面控制标题内容。`collapsible`
362+
默认为 `false`;传入后,展开状态仅在鼠标移入侧栏或焦点进入侧栏时显示收起按钮,收起状态始终显示
363+
展开按钮。收起时释放侧栏宽度,页面不需要自行维护折叠状态。
356364

357365
主内容区固定保留 `px-6` 水平留白。内置滚动容器会抵消两侧留白,再为滚动内容补回 `24px`
358366
水平间距,使滚动条贴齐主区域右边界,并允许 `MkTable` 的底部操作栏延伸至完整主区域宽度。
@@ -371,12 +379,16 @@ Element Plus Dropdown 属性和事件通过 `$attrs` 传入,并暴露 `handleO
371379
</component>
372380
左侧列表
373381
</template>
374-
<template #default="{ title, Header }">
382+
<template #default="{ title, Footer, Header }">
375383
<template v-if="selectedItem">
376384
<component :is="Header">
377385
<h4>{{ title }}</h4>
378386
</component>
379387
右侧内容
388+
<component :is="Footer">
389+
<el-button>取消</el-button>
390+
<el-button type="primary">保存</el-button>
391+
</component>
380392
</template>
381393
<MkEmpty v-else />
382394
</template>
@@ -493,8 +505,10 @@ const paginationConfig = ref({
493505
`maxTableHeight` 表示窗口中除表格外需要扣除的高度,默认为 `250`;组件会在窗口尺寸变化时
494506
重新计算 `max-height`。传入 `resizable` 后启用列宽拖拽,并隐藏为拖拽借用的原生边框视觉。
495507
`resizable` 采用白名单式启用:只有需求明确指定的页面级表格才能开启;未明确指定的表格,以及
496-
Dialog、Drawer、Popover、嵌套区域等其他大、小表格均禁止开启。需要显示 Element Plus 原生边框
497-
时直接使用 `el-table`。
508+
Dialog、Drawer、Popover、嵌套区域等其他大、小表格均禁止开启。
509+
510+
传入 `size="small"` 时,组件会为内部 `el-table` 添加 `small` class;组件仅提供该样式钩子,
511+
不内置对应样式。
498512

499513
表头需要多选筛选时使用 `MkTableFilter`。`label` 设置表头文案,`options` 接收
500514
`OptionItem<string>[]`,`v-model` 绑定已选值;初始不选择任何选项,确认或重置后通过 `change`

‎ui/src/components/business/workspace-relation-tags/index.vue‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const tableData = computed(() => {
2323
<MkTagGroup :tags="tags" popover-disabled class="cursor-pointer" />
2424
</template>
2525
<div class="p-6">
26-
<MkTable :data="tableData" max-height="300">
26+
<MkTable :data="tableData" max-height="300" size="small">
2727
<template v-for="(label, prop) in tableRenderParams" :key="prop">
2828
<el-table-column
2929
:label="label"

‎ui/src/components/global/mk-collapse/index.vue‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,20 @@ defineOptions({ name: 'MkCollapse' })
77
const props = withDefaults(
88
defineProps<{
99
defaultExpanded?: boolean
10+
indicatorPosition?: 'after' | 'before'
1011
title?: string
1112
triggerClass?: HTMLAttributes['class']
1213
triggerStyle?: HTMLAttributes['style']
1314
}>(),
1415
{
1516
defaultExpanded: true,
17+
indicatorPosition: 'before',
1618
},
1719
)
1820
1921
defineSlots<{
20-
label(): unknown
21-
default(): unknown
22+
default?: () => unknown
23+
label?: () => unknown
2224
}>()
2325
2426
const expanded = ref(props.defaultExpanded)
@@ -29,6 +31,7 @@ const expanded = ref(props.defaultExpanded)
2931
<div class="py-2" :class="triggerClass" :style="triggerStyle" @click="expanded = !expanded">
3032
<div class="flex w-full cursor-pointer items-center gap-2 text-left">
3133
<MkIcon
34+
v-if="indicatorPosition === 'before'"
3235
:icon="CaretBottom"
3336
:size="14"
3437
class="transition-transform text-N600!"
@@ -37,6 +40,14 @@ const expanded = ref(props.defaultExpanded)
3740
<slot name="label">
3841
<span>{{ title }}</span>
3942
</slot>
43+
44+
<MkIcon
45+
v-if="indicatorPosition === 'after'"
46+
name="icon_down_outlined"
47+
:size="16"
48+
class="transition-transform text-N600!"
49+
:class="{ '-rotate-180': expanded }"
50+
/>
4051
</div>
4152
</div>
4253
<el-collapse-transition>

‎ui/src/components/global/mk-dialog/index.vue‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<script setup lang="ts">
22
defineOptions({ name: 'MkDialog', inheritAttrs: false })
33
4+
const props = defineProps<{
5+
contentClass?: string
6+
}>()
7+
48
const visible = defineModel<boolean>({ default: false })
59
610
defineSlots<{
@@ -36,7 +40,7 @@ defineSlots<{
3640
</template>
3741

3842
<el-scrollbar>
39-
<div style="max-height: calc(100vh - 272px)">
43+
<div class="px-6" :class="props.contentClass" style="max-height: calc(100vh - 272px)">
4044
<slot />
4145
</div>
4246
</el-scrollbar>

‎ui/src/components/global/mk-table/index.vue‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const props = withDefaults(
1919
maxTableHeight?: number
2020
paginationConfig?: PaginationConfig
2121
resizable?: boolean // 非指定表格禁止开启
22+
size?: 'small'
2223
}>(),
2324
{
2425
data: () => [],
@@ -109,7 +110,10 @@ defineExpose({ clearSelection, tableRef })
109110
<div class="mk-table relative flex w-full min-h-0 flex-1 flex-col">
110111
<el-table
111112
ref="tableRef"
112-
:class="{ 'mk-table__resizable--borderless': props.resizable }"
113+
:class="{
114+
'mk-table__resizable--borderless': props.resizable,
115+
small: props.size === 'small',
116+
}"
113117
:data="props.data"
114118
:max-height="tableHeight"
115119
row-key="id"

‎ui/src/components/global/mk-view-layout/index.vue‎

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ const props = withDefaults(
2020
2121
defineSlots<{
2222
aside?: (props: { Header: FunctionalComponent; title: string }) => unknown
23-
default?: (props: { Header: FunctionalComponent; title: string }) => unknown
23+
default?: (props: {
24+
Footer: FunctionalComponent
25+
Header: FunctionalComponent
26+
title: string
27+
}) => unknown
2428
top?: () => unknown
2529
}>()
2630
@@ -41,12 +45,22 @@ function flattenSlotNodes(children: unknown): VNode[] {
4145
const LayoutHeader: FunctionalComponent = (_, { slots }) =>
4246
h('header', { class: 'flex-between shrink-0 py-4 gap-4' }, slots.default?.())
4347
48+
const LayoutFooter: FunctionalComponent = (_, { slots }) =>
49+
h(
50+
'footer',
51+
{ class: '-mx-6 -mb-6 flex shrink-0 justify-end border-t px-6 py-4' },
52+
slots.default?.(),
53+
)
54+
4455
const LayoutContent: FunctionalComponent = () => {
4556
const contentNodes = flattenSlotNodes(
46-
slots.default?.({ Header: LayoutHeader, title: title.value }),
57+
slots.default?.({ Footer: LayoutFooter, Header: LayoutHeader, title: title.value }),
4758
)
4859
const customHeaderNodes = contentNodes.filter((node) => node.type === LayoutHeader)
49-
const bodyNodes = contentNodes.filter((node) => node.type !== LayoutHeader)
60+
const customFooterNodes = contentNodes.filter((node) => node.type === LayoutFooter)
61+
const bodyNodes = contentNodes.filter(
62+
(node) => node.type !== LayoutHeader && node.type !== LayoutFooter,
63+
)
5064
const headerNodes = customHeaderNodes.length
5165
? customHeaderNodes
5266
: title.value
@@ -58,11 +72,12 @@ const LayoutContent: FunctionalComponent = () => {
5872
h(
5973
ElScrollbar,
6074
{
61-
class: '-mx-6 -mb-6 min-h-0 flex-1',
75+
class: ['-mx-6 min-h-0 flex-1', customFooterNodes.length ? '' : '-mb-6'],
6276
viewClass: 'flex min-h-full flex-col px-6 pb-6',
6377
},
6478
{ default: () => bodyNodes },
6579
),
80+
...customFooterNodes,
6681
]
6782
}
6883
</script>
@@ -80,7 +95,7 @@ const LayoutContent: FunctionalComponent = () => {
8095
</template>
8196
</LayoutAside>
8297

83-
<main class="mb-6 flex min-w-0 flex-1 flex-col px-6 min-h-0">
98+
<main class="mb-6 flex min-h-0 min-w-0 flex-1 flex-col px-6">
8499
<LayoutContent />
85100
</main>
86101
</div>

0 commit comments

Comments
 (0)