From fc6a467e6317611622c3599422f0b900ffa59280 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 26 Oct 2025 16:32:52 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E3=80=90ele=E3=80=91=E3=80=90ai?= =?UTF-8?q?=E3=80=91modal=20=E9=83=A8=E5=88=86=E7=9A=84=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web-ele/src/views/ai/model/apiKey/data.ts | 147 +++++++++ .../src/views/ai/model/apiKey/index.vue | 128 ++++++++ .../views/ai/model/apiKey/modules/form.vue | 82 +++++ .../src/views/ai/model/chatRole/data.ts | 310 ++++++++++++++++++ .../src/views/ai/model/chatRole/index.vue | 129 ++++++++ .../views/ai/model/chatRole/modules/form.vue | 88 +++++ apps/web-ele/src/views/ai/model/model/data.ts | 275 ++++++++++++++++ .../src/views/ai/model/model/index.vue | 129 ++++++++ .../src/views/ai/model/model/modules/form.vue | 83 +++++ apps/web-ele/src/views/ai/model/tool/data.ts | 122 +++++++ .../web-ele/src/views/ai/model/tool/index.vue | 132 ++++++++ .../src/views/ai/model/tool/modules/form.vue | 82 +++++ 12 files changed, 1707 insertions(+) create mode 100644 apps/web-ele/src/views/ai/model/apiKey/data.ts create mode 100644 apps/web-ele/src/views/ai/model/apiKey/index.vue create mode 100644 apps/web-ele/src/views/ai/model/apiKey/modules/form.vue create mode 100644 apps/web-ele/src/views/ai/model/chatRole/data.ts create mode 100644 apps/web-ele/src/views/ai/model/chatRole/index.vue create mode 100644 apps/web-ele/src/views/ai/model/chatRole/modules/form.vue create mode 100644 apps/web-ele/src/views/ai/model/model/data.ts create mode 100644 apps/web-ele/src/views/ai/model/model/index.vue create mode 100644 apps/web-ele/src/views/ai/model/model/modules/form.vue create mode 100644 apps/web-ele/src/views/ai/model/tool/data.ts create mode 100644 apps/web-ele/src/views/ai/model/tool/index.vue create mode 100644 apps/web-ele/src/views/ai/model/tool/modules/form.vue diff --git a/apps/web-ele/src/views/ai/model/apiKey/data.ts b/apps/web-ele/src/views/ai/model/apiKey/data.ts new file mode 100644 index 000000000..1c307ed55 --- /dev/null +++ b/apps/web-ele/src/views/ai/model/apiKey/data.ts @@ -0,0 +1,147 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { CommonStatusEnum, DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { z } from '#/adapter/form'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'platform', + label: '所属平台', + component: 'Select', + componentProps: { + placeholder: '请选择所属平台', + options: getDictOptions(DICT_TYPE.AI_PLATFORM, 'string'), + allowClear: true, + }, + rules: 'required', + }, + { + component: 'Input', + fieldName: 'name', + label: '名称', + rules: 'required', + componentProps: { + placeholder: '请输入名称', + }, + }, + { + component: 'Input', + fieldName: 'apiKey', + label: '密钥', + rules: 'required', + componentProps: { + placeholder: '请输入密钥', + }, + }, + { + component: 'Input', + fieldName: 'url', + label: '自定义 API URL', + componentProps: { + placeholder: '请输入自定义 API URL', + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '名称', + component: 'Input', + componentProps: { + placeholder: '请输入名称', + allowClear: true, + }, + }, + { + fieldName: 'platform', + label: '平台', + component: 'Select', + componentProps: { + allowClear: true, + placeholder: '请选择平台', + options: getDictOptions(DICT_TYPE.AI_PLATFORM, 'string'), + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + allowClear: true, + placeholder: '请选择状态', + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'platform', + title: '所属平台', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.AI_PLATFORM }, + }, + minWidth: 100, + }, + { + field: 'name', + title: '名称', + minWidth: 120, + }, + { + field: 'apiKey', + title: '密钥', + minWidth: 140, + }, + { + field: 'url', + title: '自定义 API URL', + minWidth: 180, + }, + { + field: 'status', + title: '状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + minWidth: 80, + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-ele/src/views/ai/model/apiKey/index.vue b/apps/web-ele/src/views/ai/model/apiKey/index.vue new file mode 100644 index 000000000..a6b5181ad --- /dev/null +++ b/apps/web-ele/src/views/ai/model/apiKey/index.vue @@ -0,0 +1,128 @@ + + + diff --git a/apps/web-ele/src/views/ai/model/apiKey/modules/form.vue b/apps/web-ele/src/views/ai/model/apiKey/modules/form.vue new file mode 100644 index 000000000..c7e5388ea --- /dev/null +++ b/apps/web-ele/src/views/ai/model/apiKey/modules/form.vue @@ -0,0 +1,82 @@ + + + diff --git a/apps/web-ele/src/views/ai/model/chatRole/data.ts b/apps/web-ele/src/views/ai/model/chatRole/data.ts new file mode 100644 index 000000000..58ceaf02b --- /dev/null +++ b/apps/web-ele/src/views/ai/model/chatRole/data.ts @@ -0,0 +1,310 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { AiModelTypeEnum, CommonStatusEnum, DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { z } from '#/adapter/form'; +import { getSimpleKnowledgeList } from '#/api/ai/knowledge/knowledge'; +import { getModelSimpleList } from '#/api/ai/model/model'; +import { getToolSimpleList } from '#/api/ai/model/tool'; + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + component: 'Input', + fieldName: 'formType', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + component: 'Input', + fieldName: 'name', + label: '角色名称', + rules: 'required', + componentProps: { + placeholder: '请输入角色名称', + }, + }, + { + component: 'ImageUpload', + fieldName: 'avatar', + label: '角色头像', + rules: 'required', + }, + { + fieldName: 'modelId', + label: '绑定模型', + component: 'ApiSelect', + componentProps: { + placeholder: '请选择绑定模型', + api: () => getModelSimpleList(AiModelTypeEnum.CHAT), + labelField: 'name', + valueField: 'id', + allowClear: true, + }, + dependencies: { + triggerFields: ['formType'], + show: (values) => { + return values.formType === 'create' || values.formType === 'update'; + }, + }, + }, + { + component: 'Input', + fieldName: 'category', + label: '角色类别', + rules: 'required', + componentProps: { + placeholder: '请输入角色类别', + }, + dependencies: { + triggerFields: ['formType'], + show: (values) => { + return values.formType === 'create' || values.formType === 'update'; + }, + }, + }, + { + component: 'Textarea', + fieldName: 'description', + label: '角色描述', + componentProps: { + placeholder: '请输入角色描述', + }, + rules: 'required', + }, + { + fieldName: 'systemMessage', + label: '角色设定', + component: 'Textarea', + componentProps: { + placeholder: '请输入角色设定', + }, + rules: 'required', + }, + { + fieldName: 'knowledgeIds', + label: '引用知识库', + component: 'ApiSelect', + componentProps: { + placeholder: '请选择引用知识库', + api: getSimpleKnowledgeList, + labelField: 'name', + mode: 'multiple', + valueField: 'id', + allowClear: true, + }, + }, + { + fieldName: 'toolIds', + label: '引用工具', + component: 'ApiSelect', + componentProps: { + placeholder: '请选择引用工具', + api: getToolSimpleList, + mode: 'multiple', + labelField: 'name', + valueField: 'id', + allowClear: true, + }, + }, + { + fieldName: 'mcpClientNames', + label: '引用 MCP', + component: 'Select', + componentProps: { + placeholder: '请选择 MCP', + options: getDictOptions(DICT_TYPE.AI_MCP_CLIENT_NAME, 'string'), + mode: 'multiple', + allowClear: true, + }, + }, + { + fieldName: 'publicStatus', + label: '是否公开', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), }, + defaultValue: true, + dependencies: { + triggerFields: ['formType'], + show: (values) => { + return values.formType === 'create' || values.formType === 'update'; + }, + }, + rules: 'required', + }, + { + fieldName: 'sort', + label: '角色排序', + component: 'InputNumber', + componentProps: { + placeholder: '请输入角色排序', + controlsPosition: 'right', + class: 'w-full', + }, + dependencies: { + triggerFields: ['formType'], + show: (values) => { + return values.formType === 'create' || values.formType === 'update'; + }, + }, + rules: 'required', + }, + { + fieldName: 'status', + label: '开启状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), }, + dependencies: { + triggerFields: ['formType'], + show: (values) => { + return values.formType === 'create' || values.formType === 'update'; + }, + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '角色名称', + component: 'Input', + }, + { + fieldName: 'category', + label: '角色类别', + component: 'Input', + }, + { + fieldName: 'publicStatus', + label: '是否公开', + component: 'Select', + componentProps: { + placeholder: '请选择是否公开', + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), + allowClear: true, + }, + defaultValue: true, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'name', + title: '角色名称', + minWidth: 100, + }, + { + title: '绑定模型', + field: 'modelName', + minWidth: 100, + }, + { + title: '角色头像', + field: 'avatar', + minWidth: 140, + cellRender: { + name: 'CellImage', + props: { + width: 40, + height: 40, + }, + }, + }, + { + title: '角色类别', + field: 'category', + minWidth: 100, + }, + { + title: '角色描述', + field: 'description', + minWidth: 100, + }, + { + title: '角色设定', + field: 'systemMessage', + minWidth: 100, + }, + { + title: '知识库', + field: 'knowledgeIds', + minWidth: 100, + formatter: ({ cellValue }) => { + return !cellValue || cellValue.length === 0 + ? '-' + : `引用${cellValue.length}个`; + }, + }, + { + title: '工具', + field: 'toolIds', + minWidth: 100, + formatter: ({ cellValue }) => { + return !cellValue || cellValue.length === 0 + ? '-' + : `引用${cellValue.length}个`; + }, + }, + { + title: 'MCP', + field: 'mcpClientNames', + minWidth: 100, + formatter: ({ cellValue }) => { + return !cellValue || cellValue.length === 0 + ? '-' + : `引用${cellValue.length}个`; + }, + }, + { + field: 'publicStatus', + title: '是否公开', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + minWidth: 80, + }, + { + field: 'status', + title: '状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + minWidth: 80, + }, + { + title: '角色排序', + field: 'sort', + minWidth: 80, + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-ele/src/views/ai/model/chatRole/index.vue b/apps/web-ele/src/views/ai/model/chatRole/index.vue new file mode 100644 index 000000000..89d14b41e --- /dev/null +++ b/apps/web-ele/src/views/ai/model/chatRole/index.vue @@ -0,0 +1,129 @@ + + + diff --git a/apps/web-ele/src/views/ai/model/chatRole/modules/form.vue b/apps/web-ele/src/views/ai/model/chatRole/modules/form.vue new file mode 100644 index 000000000..d6a430f38 --- /dev/null +++ b/apps/web-ele/src/views/ai/model/chatRole/modules/form.vue @@ -0,0 +1,88 @@ + + + diff --git a/apps/web-ele/src/views/ai/model/model/data.ts b/apps/web-ele/src/views/ai/model/model/data.ts new file mode 100644 index 000000000..db8e12cac --- /dev/null +++ b/apps/web-ele/src/views/ai/model/model/data.ts @@ -0,0 +1,275 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { AiModelApiKeyApi } from '#/api/ai/model/apiKey'; + +import { AiModelTypeEnum, CommonStatusEnum, DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { z } from '#/adapter/form'; +import { getApiKeySimpleList } from '#/api/ai/model/apiKey'; + +let apiKeyList: AiModelApiKeyApi.ApiKey[] = []; +async function getApiKeyList() { + apiKeyList = await getApiKeySimpleList(); +} + +getApiKeyList(); + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'platform', + label: '所属平台', + component: 'Select', + componentProps: { + placeholder: '请选择所属平台', + options: getDictOptions(DICT_TYPE.AI_PLATFORM, 'string'), + allowClear: true, + }, + rules: 'required', + }, + { + fieldName: 'type', + label: '模型类型', + component: 'Select', + componentProps: (values) => { + return { + placeholder: '请输入模型类型', + disabled: !!values.id, + options: getDictOptions(DICT_TYPE.AI_MODEL_TYPE, 'number'), + allowClear: true, + }; + }, + rules: 'required', + }, + { + fieldName: 'keyId', + label: 'API 秘钥', + component: 'ApiSelect', + componentProps: { + placeholder: '请选择 API 秘钥', + api: getApiKeySimpleList, + labelField: 'name', + valueField: 'id', + allowClear: true, + }, + rules: 'required', + }, + { + component: 'Input', + fieldName: 'name', + label: '模型名字', + rules: 'required', + componentProps: { + placeholder: '请输入模型名字', + }, + }, + { + component: 'Input', + fieldName: 'model', + label: '模型标识', + rules: 'required', + componentProps: { + placeholder: '请输入模型标识', + }, + }, + { + fieldName: 'sort', + label: '模型排序', + component: 'InputNumber', + componentProps: { + placeholder: '请输入模型排序', + controlsPosition: 'right', + class: '!w-full', + }, + rules: 'required', + }, + { + fieldName: 'status', + label: '开启状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + { + fieldName: 'temperature', + label: '温度参数', + component: 'InputNumber', + componentProps: { + placeholder: '请输入温度参数', + controlsPosition: 'right', + class: '!w-full', + min: 0, + max: 2, + }, + dependencies: { + triggerFields: ['type'], + show: (values) => { + return [AiModelTypeEnum.CHAT].includes(values.type); + }, + }, + rules: 'required', + }, + { + fieldName: 'maxTokens', + label: '回复数 Token 数', + component: 'InputNumber', + componentProps: { + min: 0, + max: 8192, + placeholder: '请输入回复数 Token 数', + controlsPosition: 'right', + class: '!w-full', + }, + dependencies: { + triggerFields: ['type'], + show: (values) => { + return [AiModelTypeEnum.CHAT].includes(values.type); + }, + }, + rules: 'required', + }, + { + fieldName: 'maxContexts', + label: '上下文数量', + component: 'InputNumber', + componentProps: { + min: 0, + max: 20, + placeholder: '请输入上下文数量', + controlsPosition: 'right', + class: '!w-full', + }, + dependencies: { + triggerFields: ['type'], + show: (values) => { + return [AiModelTypeEnum.CHAT].includes(values.type); + }, + }, + rules: 'required', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '模型名字', + component: 'Input', + componentProps: { + placeholder: '请输入模型名字', + allowClear: true, + }, + }, + { + fieldName: 'model', + label: '模型标识', + component: 'Input', + componentProps: { + placeholder: '请输入模型标识', + allowClear: true, + }, + }, + { + fieldName: 'platform', + label: '模型平台', + component: 'Input', + componentProps: { + placeholder: '请输入模型平台', + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'platform', + title: '所属平台', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.AI_PLATFORM }, + }, + minWidth: 100, + }, + { + field: 'type', + title: '模型类型', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.AI_MODEL_TYPE }, + }, + minWidth: 100, + }, + { + field: 'name', + title: '模型名字', + minWidth: 180, + }, + { + title: '模型标识', + field: 'model', + minWidth: 180, + }, + { + title: 'API 秘钥', + field: 'keyId', + formatter: ({ cellValue }) => { + return ( + apiKeyList.find((apiKey) => apiKey.id === cellValue)?.name || '-' + ); + }, + minWidth: 140, + }, + { + title: '排序', + field: 'sort', + minWidth: 80, + }, + { + field: 'status', + title: '状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + minWidth: 80, + }, + { + field: 'temperature', + title: '温度参数', + minWidth: 100, + }, + { + title: '回复数 Token 数', + field: 'maxTokens', + minWidth: 140, + }, + { + title: '上下文数量', + field: 'maxContexts', + minWidth: 120, + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-ele/src/views/ai/model/model/index.vue b/apps/web-ele/src/views/ai/model/model/index.vue new file mode 100644 index 000000000..eb58f3013 --- /dev/null +++ b/apps/web-ele/src/views/ai/model/model/index.vue @@ -0,0 +1,129 @@ + + + diff --git a/apps/web-ele/src/views/ai/model/model/modules/form.vue b/apps/web-ele/src/views/ai/model/model/modules/form.vue new file mode 100644 index 000000000..893028fb5 --- /dev/null +++ b/apps/web-ele/src/views/ai/model/model/modules/form.vue @@ -0,0 +1,83 @@ + + + diff --git a/apps/web-ele/src/views/ai/model/tool/data.ts b/apps/web-ele/src/views/ai/model/tool/data.ts new file mode 100644 index 000000000..4eae03859 --- /dev/null +++ b/apps/web-ele/src/views/ai/model/tool/data.ts @@ -0,0 +1,122 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; + +import { CommonStatusEnum, DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { getRangePickerDefaultProps } from '#/utils'; +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + + { + component: 'Input', + fieldName: 'name', + label: '工具名称', + rules: 'required', + componentProps: { + placeholder: '请输入工具名称', + }, + }, + { + component: 'Textarea', + fieldName: 'description', + label: '工具描述', + componentProps: { + placeholder: '请输入工具描述', + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), }, + defaultValue: CommonStatusEnum.ENABLE, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '工具名称', + component: 'Input', + componentProps: { + placeholder: '请输入工具名称', + allowClear: true, + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + placeholder: '请选择状态', + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '工具编号', + minWidth: 100, + }, + { + field: 'name', + title: '工具名称', + minWidth: 120, + }, + { + field: 'description', + title: '工具描述', + minWidth: 140, + }, + { + field: 'status', + title: '状态', + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + minWidth: 80, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-ele/src/views/ai/model/tool/index.vue b/apps/web-ele/src/views/ai/model/tool/index.vue new file mode 100644 index 000000000..7b0c47a1c --- /dev/null +++ b/apps/web-ele/src/views/ai/model/tool/index.vue @@ -0,0 +1,132 @@ + + + diff --git a/apps/web-ele/src/views/ai/model/tool/modules/form.vue b/apps/web-ele/src/views/ai/model/tool/modules/form.vue new file mode 100644 index 000000000..520563a92 --- /dev/null +++ b/apps/web-ele/src/views/ai/model/tool/modules/form.vue @@ -0,0 +1,82 @@ + + +