From ec30340b430b4b1eba5021009284f4acc29cbd78 Mon Sep 17 00:00:00 2001 From: xie7654 <765462425@qq.com> Date: Fri, 11 Jul 2025 11:00:37 +0800 Subject: [PATCH] add api tool --- .../0003_tool_alter_aimodel_options.py | 105 +++++++++++++ backend/ai/models.py | 15 ++ backend/ai/urls.py | 2 +- backend/ai/views/__init__.py | 4 +- backend/ai/views/tool.py | 24 +++ .../commands/tpl/frontend_list.vue.tpl | 2 +- .../web-antd/src/locales/langs/en-US/ai.json | 12 +- .../web-antd/src/locales/langs/zh-CN/ai.json | 4 + web/apps/web-antd/src/models/ai/tool.ts | 22 +++ web/apps/web-antd/src/views/ai/tool/data.ts | 131 ++++++++++++++++ web/apps/web-antd/src/views/ai/tool/list.vue | 141 ++++++++++++++++++ .../src/views/ai/tool/modules/form.vue | 79 ++++++++++ 12 files changed, 534 insertions(+), 7 deletions(-) create mode 100644 backend/ai/migrations/0003_tool_alter_aimodel_options.py create mode 100644 backend/ai/views/tool.py create mode 100644 web/apps/web-antd/src/models/ai/tool.ts create mode 100644 web/apps/web-antd/src/views/ai/tool/data.ts create mode 100644 web/apps/web-antd/src/views/ai/tool/list.vue create mode 100644 web/apps/web-antd/src/views/ai/tool/modules/form.vue diff --git a/backend/ai/migrations/0003_tool_alter_aimodel_options.py b/backend/ai/migrations/0003_tool_alter_aimodel_options.py new file mode 100644 index 0000000..6ab662c --- /dev/null +++ b/backend/ai/migrations/0003_tool_alter_aimodel_options.py @@ -0,0 +1,105 @@ +# Generated by Django 5.2.1 on 2025-07-11 02:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("ai", "0002_alter_aiapikey_api_key_alter_aiapikey_create_time_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="Tool", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "remark", + models.CharField( + blank=True, + db_comment="备注", + help_text="备注", + max_length=256, + null=True, + verbose_name="备注", + ), + ), + ( + "creator", + models.CharField( + blank=True, + db_comment="创建人", + help_text="创建人", + max_length=64, + null=True, + verbose_name="创建人", + ), + ), + ( + "modifier", + models.CharField( + blank=True, + db_comment="修改人", + help_text="修改人", + max_length=64, + null=True, + verbose_name="修改人", + ), + ), + ( + "update_time", + models.DateTimeField( + auto_now=True, + db_comment="修改时间", + help_text="修改时间", + null=True, + verbose_name="修改时间", + ), + ), + ( + "create_time", + models.DateTimeField( + auto_now_add=True, + db_comment="创建时间", + help_text="创建时间", + null=True, + verbose_name="创建时间", + ), + ), + ( + "is_deleted", + models.BooleanField( + db_comment="是否软删除", + default=False, + verbose_name="是否软删除", + ), + ), + ("name", models.CharField(max_length=128, verbose_name="工具名称")), + ( + "description", + models.CharField( + blank=True, max_length=256, null=True, verbose_name="工具描述" + ), + ), + ("status", models.SmallIntegerField(verbose_name="状态")), + ], + options={ + "verbose_name": "AI 工具", + "verbose_name_plural": "AI 工具", + "db_table": "ai_tool", + }, + ), + migrations.AlterModelOptions( + name="aimodel", + options={"verbose_name": "模型配置", "verbose_name_plural": "模型配置"}, + ), + ] diff --git a/backend/ai/models.py b/backend/ai/models.py index f99a125..2278402 100644 --- a/backend/ai/models.py +++ b/backend/ai/models.py @@ -59,3 +59,18 @@ class AIModel(CoreModel): def __str__(self): return self.name + + +class Tool(CoreModel): + """ AI 工具表 """ + name = models.CharField(max_length=128, verbose_name="工具名称") + description = models.CharField(max_length=256, null=True, blank=True, verbose_name="工具描述") + status = models.SmallIntegerField(verbose_name="状态") + + class Meta: + db_table = "ai_tool" + verbose_name = "AI 工具" + verbose_name_plural = verbose_name + + def __str__(self): + return self.name \ No newline at end of file diff --git a/backend/ai/urls.py b/backend/ai/urls.py index da7f3a0..3da09a7 100644 --- a/backend/ai/urls.py +++ b/backend/ai/urls.py @@ -6,8 +6,8 @@ from . import views router = routers.DefaultRouter() router.register(r'ai_api_key', views.AIApiKeyViewSet) router.register(r'ai_model', views.AIModelViewSet) +router.register(r'tool', views.ToolViewSet) urlpatterns = [ path('', include(router.urls)), - ] \ No newline at end of file diff --git a/backend/ai/views/__init__.py b/backend/ai/views/__init__.py index 0d4de63..92691aa 100644 --- a/backend/ai/views/__init__.py +++ b/backend/ai/views/__init__.py @@ -1,7 +1,9 @@ __all__ = [ 'AIApiKeyViewSet', 'AIModelViewSet', + 'ToolViewSet', ] from ai.views.ai_api_key import AIApiKeyViewSet -from ai.views.ai_model import AIModelViewSet \ No newline at end of file +from ai.views.ai_model import AIModelViewSet +from ai.views.tool import ToolViewSet \ No newline at end of file diff --git a/backend/ai/views/tool.py b/backend/ai/views/tool.py new file mode 100644 index 0000000..9f79093 --- /dev/null +++ b/backend/ai/views/tool.py @@ -0,0 +1,24 @@ +from ai.models import Tool +from utils.serializers import CustomModelSerializer +from utils.custom_model_viewSet import CustomModelViewSet + +class ToolSerializer(CustomModelSerializer): + """ + AI 工具 序列化器 + """ + class Meta: + model = Tool + fields = '__all__' + read_only_fields = ['id', 'create_time', 'update_time'] + + +class ToolViewSet(CustomModelViewSet): + """ + AI 工具 视图集 + """ + queryset = Tool.objects.filter(is_deleted=False).order_by('-id') + serializer_class = ToolSerializer + filterset_fields = ['id', 'remark', 'creator', 'modifier', 'is_deleted', 'name', 'description', 'status'] + search_fields = ['name'] # 根据实际字段调整 + ordering_fields = ['create_time', 'id'] + ordering = ['-create_time'] diff --git a/backend/system/management/commands/tpl/frontend_list.vue.tpl b/backend/system/management/commands/tpl/frontend_list.vue.tpl index a70d2f2..8df2fb1 100644 --- a/backend/system/management/commands/tpl/frontend_list.vue.tpl +++ b/backend/system/management/commands/tpl/frontend_list.vue.tpl @@ -133,7 +133,7 @@ function refreshGrid() { v-permission="'${app_name}:${model_name_snake}:create'" > - {{ $t('ui.actionTitle.create') }} + {{ $$t('ui.actionTitle.create') }} diff --git a/web/apps/web-antd/src/locales/langs/en-US/ai.json b/web/apps/web-antd/src/locales/langs/en-US/ai.json index 43d6c48..1a6b41a 100644 --- a/web/apps/web-antd/src/locales/langs/en-US/ai.json +++ b/web/apps/web-antd/src/locales/langs/en-US/ai.json @@ -1,11 +1,15 @@ { "title": "AI Management", "ai_api_key": { - "title": "API KEY", - "name": "API KEY" + "title": "KEY Management", + "name": "KEY Management" }, "ai_model": { - "title": "MODEL CONFIG", - "name": "MODEL CONFIG" + "title": "MODEL Management", + "name": "MODEL Management" + }, + "tool": { + "title": "TOOL Management", + "name": "TOOL Management" } } diff --git a/web/apps/web-antd/src/locales/langs/zh-CN/ai.json b/web/apps/web-antd/src/locales/langs/zh-CN/ai.json index b2dc137..f093252 100644 --- a/web/apps/web-antd/src/locales/langs/zh-CN/ai.json +++ b/web/apps/web-antd/src/locales/langs/zh-CN/ai.json @@ -7,5 +7,9 @@ "ai_model": { "title": "模型配置", "name": "模型配置" + }, + "tool": { + "title": "工具管理", + "name": "工具管理" } } diff --git a/web/apps/web-antd/src/models/ai/tool.ts b/web/apps/web-antd/src/models/ai/tool.ts new file mode 100644 index 0000000..0958a21 --- /dev/null +++ b/web/apps/web-antd/src/models/ai/tool.ts @@ -0,0 +1,22 @@ +import { BaseModel } from '#/models/base'; + +export namespace AiToolApi { + export interface AiTool { + id: number; + remark: string; + creator: string; + modifier: string; + update_time: string; + create_time: string; + is_deleted: boolean; + name: string; + description: string; + status: number; + } +} + +export class AiToolModel extends BaseModel { + constructor() { + super('/ai/tool/'); + } +} diff --git a/web/apps/web-antd/src/views/ai/tool/data.ts b/web/apps/web-antd/src/views/ai/tool/data.ts new file mode 100644 index 0000000..6606746 --- /dev/null +++ b/web/apps/web-antd/src/views/ai/tool/data.ts @@ -0,0 +1,131 @@ +import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; + +import type { VbenFormSchema } from '#/adapter/form'; +import type { OnActionClickFn } from '#/adapter/vxe-table'; +import type { AiToolApi } from '#/models/ai/tool'; + +import { z } from '#/adapter/form'; +import { $t } from '#/locales'; +import { op } from '#/utils/permission'; + +/** + * 获取编辑表单的字段配置 + */ +export function useSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'name', + label: '工具名称', + rules: z + .string() + .min(1, $t('ui.formRules.required', ['工具名称'])) + .max(100, $t('ui.formRules.maxLength', ['工具名称', 100])), + }, + { + component: 'Input', + fieldName: 'description', + label: '工具描述', + }, + { + component: 'RadioGroup', + componentProps: { + buttonStyle: 'solid', + options: [ + { label: $t('common.enabled'), value: 1 }, + { label: $t('common.disabled'), value: 0 }, + ], + optionType: 'button', + }, + defaultValue: 1, + fieldName: 'status', + label: $t('system.status'), + }, + { + component: 'Input', + fieldName: 'remark', + label: '备注', + }, + ]; +} + +/** + * 获取编辑表单的字段配置 + */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'name', + label: '工具名称', + }, + { + component: 'Input', + fieldName: 'description', + label: '工具描述', + }, + { + component: 'Select', + fieldName: 'status', + label: '状态', + componentProps: { + allowClear: true, + options: [ + { label: '启用', value: 1 }, + { label: '禁用', value: 0 }, + ], + }, + }, + ]; +} + +/** + * 获取表格列配置 + * @description 使用函数的形式返回列数据而不是直接export一个Array常量,是为了响应语言切换时重新翻译表头 + * @param onActionClick 表格操作按钮点击事件 + */ +export function useColumns( + onActionClick?: OnActionClickFn, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: 'ID', + }, + { + field: 'name', + title: '工具名称', + }, + { + field: 'description', + title: '工具描述', + }, + { + cellRender: { + name: 'CellTag', + }, + field: 'status', + title: '状态', + }, + { + field: 'remark', + title: '备注', + }, + { + align: 'center', + cellRender: { + attrs: { + nameField: 'name', + nameTitle: $t('ai.tool.name'), + onClick: onActionClick, + }, + name: 'CellOperation', + options: [op('ai:tool:edit', 'edit'), op('ai:tool:delete', 'delete')], + }, + field: 'action', + fixed: 'right', + title: '操作', + width: 120, + }, + ]; +} diff --git a/web/apps/web-antd/src/views/ai/tool/list.vue b/web/apps/web-antd/src/views/ai/tool/list.vue new file mode 100644 index 0000000..a2757de --- /dev/null +++ b/web/apps/web-antd/src/views/ai/tool/list.vue @@ -0,0 +1,141 @@ + + + diff --git a/web/apps/web-antd/src/views/ai/tool/modules/form.vue b/web/apps/web-antd/src/views/ai/tool/modules/form.vue new file mode 100644 index 0000000..f7df8dc --- /dev/null +++ b/web/apps/web-antd/src/views/ai/tool/modules/form.vue @@ -0,0 +1,79 @@ + + + +