diff --git a/apps/application/serializers/application_serializers.py b/apps/application/serializers/application_serializers.py index 884b14e7066..35145eee93a 100644 --- a/apps/application/serializers/application_serializers.py +++ b/apps/application/serializers/application_serializers.py @@ -609,7 +609,8 @@ def list_function_lib(self, with_valid=True): if with_valid: self.is_valid(raise_exception=True) application = QuerySet(Application).filter(id=self.data.get("application_id")).first() - return FunctionLibSerializer.Query(data={'user_id': application.user_id}).list(with_valid=True) + return FunctionLibSerializer.Query(data={'user_id': application.user_id, 'is_active': True}).list( + with_valid=True) def get_function_lib(self, function_lib_id, with_valid=True): if with_valid: diff --git a/apps/function_lib/migrations/0002_functionlib_is_active_functionlib_permission_type.py b/apps/function_lib/migrations/0002_functionlib_is_active_functionlib_permission_type.py new file mode 100644 index 00000000000..c665ef22a43 --- /dev/null +++ b/apps/function_lib/migrations/0002_functionlib_is_active_functionlib_permission_type.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.15 on 2024-09-14 11:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('function_lib', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='functionlib', + name='is_active', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='functionlib', + name='permission_type', + field=models.CharField(choices=[('PUBLIC', '公开'), ('PRIVATE', '私有')], default='PRIVATE', max_length=20, verbose_name='权限类型'), + ), + ] diff --git a/apps/function_lib/models/function.py b/apps/function_lib/models/function.py index d41c6e9bbf1..49a0e981bb5 100644 --- a/apps/function_lib/models/function.py +++ b/apps/function_lib/models/function.py @@ -15,6 +15,11 @@ from users.models import User +class PermissionType(models.TextChoices): + PUBLIC = "PUBLIC", '公开' + PRIVATE = "PRIVATE", "私有" + + class FunctionLib(AppModelMixin): id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid1, editable=False, verbose_name="主键id") user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户id") @@ -24,6 +29,9 @@ class FunctionLib(AppModelMixin): input_field_list = ArrayField(verbose_name="输入字段列表", base_field=models.JSONField(verbose_name="输入字段", default=dict) , default=list) + is_active = models.BooleanField(default=True) + permission_type = models.CharField(max_length=20, verbose_name='权限类型', choices=PermissionType.choices, + default=PermissionType.PRIVATE) class Meta: db_table = "function_lib" diff --git a/apps/function_lib/serializers/function_lib_serializer.py b/apps/function_lib/serializers/function_lib_serializer.py index 468b07bd2fc..99866d7bf1d 100644 --- a/apps/function_lib/serializers/function_lib_serializer.py +++ b/apps/function_lib/serializers/function_lib_serializer.py @@ -11,7 +11,7 @@ import uuid from django.core import validators -from django.db.models import QuerySet +from django.db.models import QuerySet, Q from rest_framework import serializers from common.db.search import page_search @@ -27,7 +27,7 @@ class FunctionLibModelSerializer(serializers.ModelSerializer): class Meta: model = FunctionLib - fields = ['id', 'name', 'desc', 'code', 'input_field_list', + fields = ['id', 'name', 'desc', 'code', 'input_field_list', 'permission_type', 'is_active', 'create_time', 'update_time'] @@ -68,6 +68,8 @@ class EditFunctionLib(serializers.Serializer): input_field_list = FunctionLibInputField(required=False, many=True) + is_active = serializers.BooleanField(required=False, error_messages=ErrMessage.char('是否可用')) + class CreateFunctionLib(serializers.Serializer): name = serializers.CharField(required=True, error_messages=ErrMessage.char("函数名称")) @@ -79,6 +81,12 @@ class CreateFunctionLib(serializers.Serializer): input_field_list = FunctionLibInputField(required=True, many=True) + permission_type = serializers.CharField(required=True, error_messages=ErrMessage.char("权限"), validators=[ + validators.RegexValidator(regex=re.compile("^PUBLIC|PRIVATE$"), + message="权限只支持PUBLIC|PRIVATE", code=500) + ]) + is_active = serializers.BooleanField(required=False, error_messages=ErrMessage.char('是否可用')) + class FunctionLibSerializer(serializers.Serializer): class Query(serializers.Serializer): @@ -87,15 +95,19 @@ class Query(serializers.Serializer): desc = serializers.CharField(required=False, allow_null=True, allow_blank=True, error_messages=ErrMessage.char("函数描述")) + is_active = serializers.BooleanField(required=False, error_messages=ErrMessage.char("是否可用")) user_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("用户id")) def get_query_set(self): - query_set = QuerySet(FunctionLib).filter(user_id=self.data.get('user_id')) + query_set = QuerySet(FunctionLib).filter( + (Q(user_id=self.data.get('user_id')) | Q(permission_type='PUBLIC'))) if self.data.get('name') is not None: query_set = query_set.filter(name__contains=self.data.get('name')) if self.data.get('desc') is not None: query_set = query_set.filter(desc__contains=self.data.get('desc')) + if self.data.get('is_active') is not None: + query_set = query_set.filter(is_active=self.data.get('is_active')) query_set = query_set.order_by("-create_time") return query_set @@ -120,7 +132,9 @@ def insert(self, instance, with_valid=True): function_lib = FunctionLib(id=uuid.uuid1(), name=instance.get('name'), desc=instance.get('desc'), code=instance.get('code'), user_id=self.data.get('user_id'), - input_field_list=instance.get('input_field_list')) + input_field_list=instance.get('input_field_list'), + permission_type=instance.get('permission_type'), + is_active=instance.get('is_active', True)) function_lib.save() return FunctionLibModelSerializer(function_lib).data @@ -193,7 +207,7 @@ def edit(self, instance, with_valid=True): if with_valid: self.is_valid(raise_exception=True) EditFunctionLib(data=instance).is_valid(raise_exception=True) - edit_field_list = ['name', 'desc', 'code', 'input_field_list'] + edit_field_list = ['name', 'desc', 'code', 'input_field_list', 'permission_type', 'is_active'] edit_dict = {field: instance.get(field) for field in edit_field_list if ( field in instance and instance.get(field) is not None)} QuerySet(FunctionLib).filter(id=self.data.get('id')).update(**edit_dict) diff --git a/apps/function_lib/swagger_api/function_lib_api.py b/apps/function_lib/swagger_api/function_lib_api.py index ce396c6da3d..9ab7f7cd309 100644 --- a/apps/function_lib/swagger_api/function_lib_api.py +++ b/apps/function_lib/swagger_api/function_lib_api.py @@ -103,6 +103,8 @@ def get_request_body_api(): 'name': openapi.Schema(type=openapi.TYPE_STRING, title="函数名称", description="函数名称"), 'desc': openapi.Schema(type=openapi.TYPE_STRING, title="函数描述", description="函数描述"), 'code': openapi.Schema(type=openapi.TYPE_STRING, title="函数内容", description="函数内容"), + 'permission_type': openapi.Schema(type=openapi.TYPE_STRING, title="权限", description="权限"), + 'is_active': openapi.Schema(type=openapi.TYPE_BOOLEAN, title="是否可用", description="是否可用"), 'input_field_list': openapi.Schema(type=openapi.TYPE_ARRAY, description="输入变量列表", items=openapi.Schema(type=openapi.TYPE_OBJECT, @@ -135,11 +137,13 @@ class Create(ApiMixin): def get_request_body_api(): return openapi.Schema( type=openapi.TYPE_OBJECT, - required=['name', 'code', 'input_field_list'], + required=['name', 'code', 'input_field_list', 'permission_type'], properties={ 'name': openapi.Schema(type=openapi.TYPE_STRING, title="函数名称", description="函数名称"), 'desc': openapi.Schema(type=openapi.TYPE_STRING, title="函数描述", description="函数描述"), 'code': openapi.Schema(type=openapi.TYPE_STRING, title="函数内容", description="函数内容"), + 'permission_type': openapi.Schema(type=openapi.TYPE_STRING, title="权限", description="权限"), + 'is_active': openapi.Schema(type=openapi.TYPE_BOOLEAN, title="是否可用", description="是否可用"), 'input_field_list': openapi.Schema(type=openapi.TYPE_ARRAY, description="输入变量列表", items=openapi.Schema(type=openapi.TYPE_OBJECT, diff --git a/ui/src/api/type/function-lib.ts b/ui/src/api/type/function-lib.ts index ff58d0a7a06..2c5efe25481 100644 --- a/ui/src/api/type/function-lib.ts +++ b/ui/src/api/type/function-lib.ts @@ -1,9 +1,11 @@ interface functionLibData { id?: String - name: String - desc: String + name?: String + desc?: String code?: String + permission_type?: 'PRIVATE' | 'PUBLIC' input_field_list?: Array + is_active?: Boolean } export type { functionLibData } diff --git a/ui/src/views/application/index.vue b/ui/src/views/application/index.vue index 913a4836d5e..839f9b81be3 100644 --- a/ui/src/views/application/index.vue +++ b/ui/src/views/application/index.vue @@ -222,7 +222,7 @@ onMounted(() => { .status-tag { position: absolute; right: 16px; - top: 20px; + top: 13px; } } .dropdown-custom-switch { diff --git a/ui/src/views/dataset/index.vue b/ui/src/views/dataset/index.vue index 4cc16138982..001a1eca441 100644 --- a/ui/src/views/dataset/index.vue +++ b/ui/src/views/dataset/index.vue @@ -198,7 +198,7 @@ onMounted(() => { .delete-button { position: absolute; right: 12px; - top: 18px; + top: 13px; height: auto; } .footer-content { diff --git a/ui/src/views/function-lib/component/FunctionFormDrawer.vue b/ui/src/views/function-lib/component/FunctionFormDrawer.vue index 4d39e60345e..92da6eeb9ca 100644 --- a/ui/src/views/function-lib/component/FunctionFormDrawer.vue +++ b/ui/src/views/function-lib/component/FunctionFormDrawer.vue @@ -19,7 +19,7 @@ placeholder="请输入函数名称" maxlength="64" show-word-limit - @blur="form.name = form.name.trim()" + @blur="form.name = form.name?.trim()" /> @@ -30,9 +30,35 @@ maxlength="128" show-word-limit :autosize="{ minRows: 3 }" - @blur="form.desc = form.desc.trim()" + @blur="form.desc = form.desc?.trim()" /> + + + + + + + + +

@@ -137,7 +163,7 @@ import functionLibApi from '@/api/function-lib' import type { FormInstance } from 'element-plus' import { MsgSuccess, MsgConfirm } from '@/utils/message' import { cloneDeep } from 'lodash' - +import { PermissionType, PermissionDesc } from '@/enums/model' const props = defineProps({ title: String }) @@ -158,7 +184,8 @@ const form = ref({ name: '', desc: '', code: '', - input_field_list: [] + input_field_list: [], + permission_type: 'PRIVATE' }) const dialogVisible = ref(false) @@ -173,13 +200,15 @@ watch(visible, (bool) => { name: '', desc: '', code: '', - input_field_list: [] + input_field_list: [], + permission_type: 'PRIVATE' } } }) const rules = reactive({ - name: [{ required: true, message: '请输入函数名称', trigger: 'blur' }] + name: [{ required: true, message: '请输入函数名称', trigger: 'blur' }], + permission_type: [{ required: true, message: '请选择', trigger: 'change' }] }) function openCodemirrorDialog() { diff --git a/ui/src/views/function-lib/index.vue b/ui/src/views/function-lib/index.vue index 636a8433420..8f1cee66426 100644 --- a/ui/src/views/function-lib/index.vue +++ b/ui/src/views/function-lib/index.vue @@ -11,7 +11,11 @@ clearable />

-
+
- +
+ 公用 + 私有 +
@@ -89,6 +107,7 @@ const paginationConfig = reactive({ const searchValue = ref('') const title = ref('') +const changeStateloading = ref(false) function openCreateDialog(data?: any) { title.value = data ? '编辑函数' : '创建函数' @@ -102,6 +121,33 @@ function searchHandle() { getList() } +function changeState(bool: Boolean, row: any) { + if (!bool) { + MsgConfirm( + `是否禁用函数:${row.name} ?`, + `禁用后,引用了该函数的应用提问时会报错 ,请谨慎操作。`, + { + confirmButtonText: '禁用', + confirmButtonClass: 'danger' + } + ) + .then(() => { + const obj = { + is_active: bool + } + functionLibApi.putFunctionLib(row.id, obj, changeStateloading).then((res) => {}) + }) + .catch(() => { + row.is_active = true + }) + } else { + const obj = { + is_active: bool + } + functionLibApi.putFunctionLib(row.id, obj, changeStateloading).then((res) => {}) + } +} + function deleteFunctionLib(row: any) { MsgConfirm( `是否删除函数:${row.name} ?`, @@ -155,4 +201,13 @@ onMounted(() => { getList() }) - +