Skip to content

Commit 6e19167

Browse files
committed
feat: Support functionlib icon and init_fields
--story=1017947 --user=刘瑞斌 【函数库】- 函数支持配置参数及操作优化 https://www.tapd.cn/57709429/s/1664936
1 parent 7bd1dfb commit 6e19167

File tree

16 files changed

+668
-40
lines changed

16 files changed

+668
-40
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 4.2.15 on 2025-03-07 10:31
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('function_lib', '0002_functionlib_is_active_functionlib_permission_type'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='functionlib',
15+
name='icon',
16+
field=models.CharField(default='/ui/favicon.ico', max_length=256, verbose_name='函数库icon'),
17+
),
18+
migrations.AddField(
19+
model_name='functionlib',
20+
name='init_field_list',
21+
field=models.JSONField(default=list, verbose_name='启动字段列表'),
22+
),
23+
]

apps/function_lib/models/function.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class FunctionLib(AppModelMixin):
2929
input_field_list = ArrayField(verbose_name="输入字段列表",
3030
base_field=models.JSONField(verbose_name="输入字段", default=dict)
3131
, default=list)
32+
init_field_list = models.JSONField(verbose_name="启动字段列表", default=list)
33+
icon = models.CharField(max_length=256, verbose_name="函数库icon", default="/ui/favicon.ico")
3234
is_active = models.BooleanField(default=True)
3335
permission_type = models.CharField(max_length=20, verbose_name='权限类型', choices=PermissionType.choices,
3436
default=PermissionType.PRIVATE)

apps/function_lib/serializers/function_lib_serializer.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,23 @@
1010
import pickle
1111
import re
1212
import uuid
13-
from typing import List
1413

1514
from django.core import validators
1615
from django.db import transaction
1716
from django.db.models import QuerySet, Q
1817
from django.http import HttpResponse
18+
from django.utils.translation import gettext_lazy as _
1919
from rest_framework import serializers, status
2020

2121
from common.db.search import page_search
2222
from common.exception.app_exception import AppApiException
23-
from common.field.common import UploadedFileField
23+
from common.field.common import UploadedFileField, UploadedImageField
2424
from common.response import result
2525
from common.util.field_message import ErrMessage
2626
from common.util.function_code import FunctionExecutor
27+
from dataset.models import Image
2728
from function_lib.models.function import FunctionLib
2829
from smartdoc.const import CONFIG
29-
from django.utils.translation import gettext_lazy as _
3030

3131
function_executor = FunctionExecutor(CONFIG.get('SANDBOX'))
3232

@@ -39,7 +39,7 @@ def __init__(self, function_lib: dict, version: str):
3939
class FunctionLibModelSerializer(serializers.ModelSerializer):
4040
class Meta:
4141
model = FunctionLib
42-
fields = ['id', 'name', 'desc', 'code', 'input_field_list', 'permission_type', 'is_active', 'user_id',
42+
fields = ['id', 'name', 'icon', 'desc', 'code', 'input_field_list','init_field_list', 'permission_type', 'is_active', 'user_id',
4343
'create_time', 'update_time']
4444

4545

@@ -65,6 +65,7 @@ class DebugField(serializers.Serializer):
6565
class DebugInstance(serializers.Serializer):
6666
debug_field_list = DebugField(required=True, many=True)
6767
input_field_list = FunctionLibInputField(required=True, many=True)
68+
init_field_list = serializers.ListField(required=False, default=list)
6869
code = serializers.CharField(required=True, error_messages=ErrMessage.char(_('function content')))
6970

7071

@@ -80,6 +81,8 @@ class EditFunctionLib(serializers.Serializer):
8081

8182
input_field_list = FunctionLibInputField(required=False, many=True)
8283

84+
init_field_list = serializers.ListField(required=False, default=list)
85+
8386
is_active = serializers.BooleanField(required=False, error_messages=ErrMessage.char(_('Is active')))
8487

8588

@@ -93,6 +96,8 @@ class CreateFunctionLib(serializers.Serializer):
9396

9497
input_field_list = FunctionLibInputField(required=True, many=True)
9598

99+
init_field_list = serializers.ListField(required=False, default=list)
100+
96101
permission_type = serializers.CharField(required=True, error_messages=ErrMessage.char(_('permission')), validators=[
97102
validators.RegexValidator(regex=re.compile("^PUBLIC|PRIVATE$"),
98103
message="权限只支持PUBLIC|PRIVATE", code=500)
@@ -148,6 +153,7 @@ def insert(self, instance, with_valid=True):
148153
code=instance.get('code'),
149154
user_id=self.data.get('user_id'),
150155
input_field_list=instance.get('input_field_list'),
156+
init_field_list=instance.get('init_field_list'),
151157
permission_type=instance.get('permission_type'),
152158
is_active=instance.get('is_active', True))
153159
function_lib.save()
@@ -163,12 +169,16 @@ def debug(self, debug_instance, with_valid=True):
163169
input_field_list = debug_instance.get('input_field_list')
164170
code = debug_instance.get('code')
165171
debug_field_list = debug_instance.get('debug_field_list')
172+
init_field_list = debug_instance.get('init_field_list')
173+
init_params = {field.get('field'): field.get('value') if field.get('value', None) is not None else field.get('default_value') for field in init_field_list}
166174
params = {field.get('name'): self.convert_value(field.get('name'), field.get('value'), field.get('type'),
167175
field.get('is_required'))
168176
for field in
169177
[{'value': self.get_field_value(debug_field_list, field.get('name'), field.get('is_required')),
170178
**field} for field in
171179
input_field_list]}
180+
# 合并初始化参数
181+
params = init_params | params
172182
return function_executor.exec_code(code, params)
173183

174184
@staticmethod
@@ -224,7 +234,7 @@ def edit(self, instance, with_valid=True):
224234
if with_valid:
225235
self.is_valid(raise_exception=True)
226236
EditFunctionLib(data=instance).is_valid(raise_exception=True)
227-
edit_field_list = ['name', 'desc', 'code', 'input_field_list', 'permission_type', 'is_active']
237+
edit_field_list = ['name', 'desc', 'code', 'input_field_list', 'init_field_list', 'permission_type', 'is_active']
228238
edit_dict = {field: instance.get(field) for field in edit_field_list if (
229239
field in instance and instance.get(field) is not None)}
230240
QuerySet(FunctionLib).filter(id=self.data.get('id')).update(**edit_dict)
@@ -277,4 +287,23 @@ def import_(self, with_valid=True):
277287
permission_type='PRIVATE',
278288
is_active=function_lib.get('is_active'))
279289
function_lib_model.save()
280-
return True
290+
return True
291+
292+
class IconOperate(serializers.Serializer):
293+
id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid(_("function ID")))
294+
user_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid(_("User ID")))
295+
image = UploadedImageField(required=True, error_messages=ErrMessage.image(_("picture")))
296+
297+
def edit(self, with_valid=True):
298+
if with_valid:
299+
self.is_valid(raise_exception=True)
300+
functionLib = QuerySet(FunctionLib).filter(id=self.data.get('id')).first()
301+
if functionLib is None:
302+
raise AppApiException(500, _('Function does not exist'))
303+
image_id = uuid.uuid1()
304+
image = Image(id=image_id, image=self.data.get('image').read(), image_name=self.data.get('image').name)
305+
image.save()
306+
functionLib.icon = f'/api/image/{image_id}'
307+
functionLib.save()
308+
309+
return functionLib.icon

apps/function_lib/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
path('function_lib/debug', views.FunctionLibView.Debug.as_view()),
99
path('function_lib/<str:id>/export', views.FunctionLibView.Export.as_view()),
1010
path('function_lib/import', views.FunctionLibView.Import.as_view()),
11+
path('function_lib/<str:id>/edit_icon', views.FunctionLibView.EditIcon.as_view()),
1112
path('function_lib/pylint', views.PyLintView.as_view()),
1213
path('function_lib/<str:function_lib_id>', views.FunctionLibView.Operate.as_view()),
1314
path("function_lib/<int:current_page>/<int:page_size>", views.FunctionLibView.Page.as_view(),

apps/function_lib/views/function_lib_views.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,16 @@ class Export(APIView):
136136
@has_permissions(RoleConstants.ADMIN, RoleConstants.USER)
137137
def get(self, request: Request, id: str):
138138
return FunctionLibSerializer.Operate(
139-
data={'id': id, 'user_id': request.user.id}).export()
139+
data={'id': id, 'user_id': request.user.id}).export()
140+
141+
class EditIcon(APIView):
142+
authentication_classes = [TokenAuth]
143+
parser_classes = [MultiPartParser]
144+
145+
@action(methods=['PUT'], detail=False)
146+
@has_permissions(RoleConstants.ADMIN, RoleConstants.USER)
147+
def put(self, request: Request, id: str):
148+
return result.success(
149+
FunctionLibSerializer.IconOperate(
150+
data={'id': id, 'user_id': request.user.id,
151+
'image': request.FILES.get('file')}).edit(request.data))

ui/src/api/function-lib.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,14 @@ const exportFunctionLib = (
112112
)
113113
}
114114

115+
const putFunctionLibIcon: (
116+
id: string,
117+
data: any,
118+
loading?: Ref<boolean>
119+
) => Promise<Result<any>> = (id, data, loading) => {
120+
return put(`${prefix}/${id}/edit_icon`, data, undefined, loading)
121+
}
122+
115123
const importFunctionLib: (data: any, loading?: Ref<boolean>) => Promise<Result<any>> = (
116124
data,
117125
loading
@@ -128,5 +136,6 @@ export default {
128136
getFunctionLibById,
129137
exportFunctionLib,
130138
importFunctionLib,
131-
pylint
139+
pylint,
140+
putFunctionLibIcon
132141
}

ui/src/api/type/function-lib.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
interface functionLibData {
22
id?: String
33
name?: String
4+
icon?: String
45
desc?: String
56
code?: String
67
permission_type?: 'PRIVATE' | 'PUBLIC'
78
input_field_list?: Array<any>
9+
init_field_list?: Array<any>
810
is_active?: Boolean
911
}
1012

ui/src/locales/lang/en-US/common.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ export default {
5252
},
5353
param: {
5454
outputParam: 'Output Parameters',
55-
inputParam: 'Input Parameters'
55+
inputParam: 'Input Parameters',
56+
initParam: 'Startup Parameters',
5657
},
5758

5859
inputPlaceholder: 'Please input',

ui/src/locales/lang/zh-CN/common.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ export default {
5555
content: '内容',
5656
param: {
5757
outputParam: '输出参数',
58-
inputParam:'输入参数'
58+
inputParam: '输入参数',
59+
initParam: '启动参数',
5960
},
6061
rename:'重命名'
6162
}

ui/src/locales/lang/zh-Hant/common.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ export default {
5555
content: '内容',
5656
param: {
5757
outputParam: '輸出參數',
58-
inputParam: '輸入參數'
58+
inputParam: '輸入參數',
59+
initParam: '啟動參數',
5960
},
6061
rename: '重命名'
6162
}

0 commit comments

Comments
 (0)