From 8d94b5927928e83a3bfc32a23712ea476b877a1b Mon Sep 17 00:00:00 2001 From: shaohuzhang1 Date: Wed, 16 Oct 2024 15:22:50 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=E5=B7=A5=E4=BD=9C=E6=B5=81?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0017_workflowversion_name.py | 23 +++++ apps/application/models/application.py | 1 + .../application_version_serializers.py | 83 +++++++++++++++++ .../swagger_api/application_version_api.py | 69 ++++++++++++++ apps/application/urls.py | 5 ++ apps/application/views/__init__.py | 1 + .../views/application_version_views.py | 89 +++++++++++++++++++ 7 files changed, 271 insertions(+) create mode 100644 apps/application/migrations/0017_workflowversion_name.py create mode 100644 apps/application/serializers/application_version_serializers.py create mode 100644 apps/application/swagger_api/application_version_api.py create mode 100644 apps/application/views/application_version_views.py diff --git a/apps/application/migrations/0017_workflowversion_name.py b/apps/application/migrations/0017_workflowversion_name.py new file mode 100644 index 00000000000..e70f84bea21 --- /dev/null +++ b/apps/application/migrations/0017_workflowversion_name.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.15 on 2024-10-16 15:17 + +from django.db import migrations, models + +sql = """ +UPDATE "public".application_work_flow_version +SET "name" = TO_CHAR(create_time, 'YYYY-MM-DD HH24:MI:SS'); +""" + + +class Migration(migrations.Migration): + dependencies = [ + ('application', '0016_alter_chatrecord_problem_text'), + ] + + operations = [ + migrations.AddField( + model_name='workflowversion', + name='name', + field=models.CharField(default='', max_length=128, verbose_name='版本名称'), + ), + migrations.RunSQL(sql) + ] diff --git a/apps/application/models/application.py b/apps/application/models/application.py index ba4c03e2669..c6850de8a82 100644 --- a/apps/application/models/application.py +++ b/apps/application/models/application.py @@ -87,6 +87,7 @@ class Meta: class WorkFlowVersion(AppModelMixin): id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid1, editable=False, verbose_name="主键id") application = models.ForeignKey(Application, on_delete=models.CASCADE) + name = models.CharField(verbose_name="版本名称", max_length=128, default="") work_flow = models.JSONField(verbose_name="工作流数据", default=dict) class Meta: diff --git a/apps/application/serializers/application_version_serializers.py b/apps/application/serializers/application_version_serializers.py new file mode 100644 index 00000000000..f0aa3cfe71d --- /dev/null +++ b/apps/application/serializers/application_version_serializers.py @@ -0,0 +1,83 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎 + @file: application_version_serializers.py + @date:2024/10/15 16:42 + @desc: +""" +from typing import Dict + +from django.db.models import QuerySet +from rest_framework import serializers + +from application.models import WorkFlowVersion +from common.db.search import page_search +from common.exception.app_exception import AppApiException +from common.util.field_message import ErrMessage + + +class ApplicationVersionModelSerializer(serializers.ModelSerializer): + class Meta: + model = WorkFlowVersion + fields = ['id', 'name', 'application_id', 'work_flow', 'create_time', 'update_time'] + + +class ApplicationVersionEditSerializer(serializers.Serializer): + name = serializers.CharField(required=False, max_length=128, allow_null=True, allow_blank=True, + error_messages=ErrMessage.char("版本名称")) + + +class ApplicationVersionSerializer(serializers.Serializer): + class Query(serializers.Serializer): + application_id = serializers.UUIDField(required=True, error_messages=ErrMessage.char("应用id")) + name = serializers.CharField(required=False, allow_null=True, allow_blank=True, + error_messages=ErrMessage.char("摘要")) + + def get_query_set(self): + query_set = QuerySet(WorkFlowVersion).filter(application_id=self.data.get('application_id')) + if 'name' in self.data and self.data.get('name') is not None: + query_set = query_set.filter(name__contains=self.data.get('name')) + return query_set + + def list(self, with_valid=True): + if with_valid: + self.is_valid(raise_exception=True) + query_set = self.get_query_set() + return [ApplicationVersionModelSerializer(v).data for v in query_set] + + def page(self, current_page, page_size, with_valid=True): + if with_valid: + self.is_valid(raise_exception=True) + return page_search(current_page, page_size, + self.get_query_set(), + post_records_handler=lambda v: ApplicationVersionModelSerializer(v).data) + + class Operate(serializers.Serializer): + application_id = serializers.UUIDField(required=True, error_messages=ErrMessage.char("应用id")) + work_flow_version_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("工作流版本id")) + + def one(self, with_valid=True): + if with_valid: + self.is_valid(raise_exception=True) + work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=self.data.get('application_id'), + id=self.data.get('work_flow_version_id')).first() + if work_flow_version is not None: + return ApplicationVersionModelSerializer(work_flow_version).data + else: + raise AppApiException(500, '不存在的工作流版本') + + def edit(self, instance: Dict, with_valid=True): + if with_valid: + self.is_valid(raise_exception=True) + ApplicationVersionEditSerializer(data=instance).is_valid(raise_exception=True) + work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=self.data.get('application_id'), + id=self.data.get('work_flow_version_id')).first() + if work_flow_version is not None: + name = instance.get('name', None) + if name is not None and len(name) > 0: + work_flow_version.name = name + work_flow_version.save() + return ApplicationVersionModelSerializer(work_flow_version).data + else: + raise AppApiException(500, '不存在的工作流版本') diff --git a/apps/application/swagger_api/application_version_api.py b/apps/application/swagger_api/application_version_api.py new file mode 100644 index 00000000000..5335e1a87c3 --- /dev/null +++ b/apps/application/swagger_api/application_version_api.py @@ -0,0 +1,69 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎 + @file: application_version_api.py + @date:2024/10/15 17:18 + @desc: +""" +from drf_yasg import openapi + +from common.mixins.api_mixin import ApiMixin + + +class ApplicationVersionApi(ApiMixin): + @staticmethod + def get_response_body_api(): + return openapi.Schema( + type=openapi.TYPE_OBJECT, + required=['id', 'name', 'work_flow', 'create_time', 'update_time'], + properties={ + 'id': openapi.Schema(type=openapi.TYPE_NUMBER, title="主键id", + description="主键id"), + 'name': openapi.Schema(type=openapi.TYPE_NUMBER, title="版本名称", + description="版本名称"), + 'work_flow': openapi.Schema(type=openapi.TYPE_STRING, title="工作流数据", description='工作流数据'), + 'create_time': openapi.Schema(type=openapi.TYPE_STRING, title="创建时间", description='创建时间'), + 'update_time': openapi.Schema(type=openapi.TYPE_STRING, title="修改时间", description='修改时间') + } + ) + + class Query(ApiMixin): + @staticmethod + def get_request_params_api(): + return [openapi.Parameter(name='application_id', + in_=openapi.IN_PATH, + type=openapi.TYPE_STRING, + required=True, + description='应用id'), + openapi.Parameter(name='name', + in_=openapi.IN_QUERY, + type=openapi.TYPE_STRING, + required=False, + description='版本名称')] + + class Operate(ApiMixin): + @staticmethod + def get_request_params_api(): + return [openapi.Parameter(name='application_id', + in_=openapi.IN_PATH, + type=openapi.TYPE_STRING, + required=True, + description='应用id'), + openapi.Parameter(name='work_flow_version_id', + in_=openapi.IN_PATH, + type=openapi.TYPE_STRING, + required=True, + description='应用版本id'), ] + + class Edit(ApiMixin): + @staticmethod + def get_request_body_api(): + return openapi.Schema( + type=openapi.TYPE_OBJECT, + required=[], + properties={ + 'name': openapi.Schema(type=openapi.TYPE_STRING, title="版本名称", + description="版本名称") + } + ) diff --git a/apps/application/urls.py b/apps/application/urls.py index 2555b7dcdde..c17b5218b7b 100644 --- a/apps/application/urls.py +++ b/apps/application/urls.py @@ -70,5 +70,10 @@ name='application/audio'), path('application//text_to_speech', views.Application.TextToSpeech.as_view(), name='application/audio'), + path('application//work_flow_version', views.ApplicationVersionView.as_view()), + path('application//work_flow_version//', + views.ApplicationVersionView.Page.as_view()), + path('application//work_flow_version/', + views.ApplicationVersionView.Operate.as_view()) ] diff --git a/apps/application/views/__init__.py b/apps/application/views/__init__.py index 52d004041eb..24569c17e3b 100644 --- a/apps/application/views/__init__.py +++ b/apps/application/views/__init__.py @@ -8,3 +8,4 @@ """ from .application_views import * from .chat_views import * +from .application_version_views import * diff --git a/apps/application/views/application_version_views.py b/apps/application/views/application_version_views.py new file mode 100644 index 00000000000..105f280b0ed --- /dev/null +++ b/apps/application/views/application_version_views.py @@ -0,0 +1,89 @@ +# coding=utf-8 +""" + @project: MaxKB + @Author:虎 + @file: application_version_views.py + @date:2024/10/15 16:49 + @desc: +""" +from drf_yasg.utils import swagger_auto_schema +from rest_framework.decorators import action +from rest_framework.request import Request +from rest_framework.views import APIView + +from application.serializers.application_version_serializers import ApplicationVersionSerializer +from application.swagger_api.application_version_api import ApplicationVersionApi +from common.auth import has_permissions, TokenAuth +from common.constants.permission_constants import PermissionConstants, CompareConstants, ViewPermission, RoleConstants, \ + Permission, Group, Operate +from common.response import result + + +class ApplicationVersionView(APIView): + authentication_classes = [TokenAuth] + + @action(methods=['GET'], detail=False) + @swagger_auto_schema(operation_summary="获取应用列表", + operation_id="获取应用列表", + manual_parameters=ApplicationVersionApi.Query.get_request_params_api(), + responses=result.get_api_array_response(ApplicationVersionApi.get_response_body_api()), + tags=['应用/版本']) + @has_permissions(PermissionConstants.APPLICATION_READ, compare=CompareConstants.AND) + def get(self, request: Request, application_id: str): + return result.success( + ApplicationVersionSerializer.Query( + data={'name': request.query_params.get('name'), 'user_id': request.user.id, + 'application_id': application_id}).list()) + + class Page(APIView): + authentication_classes = [TokenAuth] + + @action(methods=['GET'], detail=False) + @swagger_auto_schema(operation_summary="分页获取应用版本列表", + operation_id="分页获取应用版本列表", + manual_parameters=result.get_page_request_params( + ApplicationVersionApi.Query.get_request_params_api()), + responses=result.get_page_api_response(ApplicationVersionApi.get_response_body_api()), + tags=['应用/版本']) + @has_permissions(PermissionConstants.APPLICATION_READ, compare=CompareConstants.AND) + def get(self, request: Request, application_id: str, current_page: int, page_size: int): + return result.success( + ApplicationVersionSerializer.Query( + data={'name': request.query_params.get('name'), 'user_id': request.user, + 'application_id': application_id}).page( + current_page, page_size)) + + class Operate(APIView): + authentication_classes = [TokenAuth] + + @action(methods=['GET'], detail=False) + @swagger_auto_schema(operation_summary="获取应用版本详情", + operation_id="获取应用版本详情", + manual_parameters=ApplicationVersionApi.Operate.get_request_params_api(), + responses=result.get_api_response(ApplicationVersionApi.get_response_body_api()), + tags=['应用/版本']) + @has_permissions(PermissionConstants.APPLICATION_READ, compare=CompareConstants.AND) + def get(self, request: Request, application_id: str, work_flow_version_id: str): + return result.success( + ApplicationVersionSerializer.Operate( + data={'user_id': request.user, + 'application_id': application_id, 'work_flow_version_id': work_flow_version_id}).one()) + + @action(methods=['PUT'], detail=False) + @swagger_auto_schema(operation_summary="修改应用版本信息", + operation_id="修改应用版本信息", + manual_parameters=ApplicationVersionApi.Operate.get_request_params_api(), + request_body=ApplicationVersionApi.Edit.get_request_body_api(), + responses=result.get_api_response(ApplicationVersionApi.get_response_body_api()), + tags=['应用/版本']) + @has_permissions(ViewPermission( + [RoleConstants.ADMIN, RoleConstants.USER], + [lambda r, keywords: Permission(group=Group.APPLICATION, operate=Operate.MANAGE, + dynamic_tag=keywords.get('application_id'))], + compare=CompareConstants.AND)) + def put(self, request: Request, application_id: str, work_flow_version_id: str): + return result.success( + ApplicationVersionSerializer.Operate( + data={'application_id': application_id, 'work_flow_version_id': work_flow_version_id, + 'user_id': request.user.id}).edit( + request.data)) From 10f66a4134effb332f9a2527e04d90c79439e5f6 Mon Sep 17 00:00:00 2001 From: shaohuzhang1 Date: Tue, 22 Oct 2024 14:54:45 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E5=B7=A5=E4=BD=9C=E6=B5=81?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...017_workflowversion_name.py => 0018_workflowversion_name.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename apps/application/migrations/{0017_workflowversion_name.py => 0018_workflowversion_name.py} (88%) diff --git a/apps/application/migrations/0017_workflowversion_name.py b/apps/application/migrations/0018_workflowversion_name.py similarity index 88% rename from apps/application/migrations/0017_workflowversion_name.py rename to apps/application/migrations/0018_workflowversion_name.py index e70f84bea21..7b80b5e7191 100644 --- a/apps/application/migrations/0017_workflowversion_name.py +++ b/apps/application/migrations/0018_workflowversion_name.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): dependencies = [ - ('application', '0016_alter_chatrecord_problem_text'), + ('application', '0017_application_tts_model_params_setting'), ] operations = [ From e4d9a490ea0019ee11bd93cd2bf6f9e2ab72e13f Mon Sep 17 00:00:00 2001 From: wangdan-fit2cloud Date: Tue, 22 Oct 2024 19:12:22 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20=E5=8E=86=E5=8F=B2=E7=89=88?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/src/api/application.ts | 46 ++++++- ui/src/components/common-list/index.vue | 11 +- ui/src/components/icons/index.ts | 23 +++- ui/src/styles/app.scss | 5 +- .../component/PublishHistory.vue | 130 ++++++++++++++++++ ui/src/views/application-workflow/index.vue | 109 ++++++++++++++- ui/src/views/chat/embed/index.vue | 8 +- ui/src/views/chat/pc/index.vue | 14 +- 8 files changed, 326 insertions(+), 20 deletions(-) create mode 100644 ui/src/views/application-workflow/component/PublishHistory.vue diff --git a/ui/src/api/application.ts b/ui/src/api/application.ts index c32f232df98..2ca88c464d2 100644 --- a/ui/src/api/application.ts +++ b/ui/src/api/application.ts @@ -397,6 +397,47 @@ const validatePassword: (application_id: string, password: string) => Promise +) => Promise> = (application_id, loading) => { + return get(`/application/${application_id}/work_flow_version`, undefined, loading) +} + +/** + * workflow历史版本详情 + */ +const getWorkFlowVersionDetail: ( + application_id: string, + application_version_id: string, + loading?: Ref +) => Promise> = (application_id, application_version_id, loading) => { + return get( + `/application/${application_id}/work_flow_version/${application_version_id}`, + undefined, + loading + ) +} +/** + * 修改workflow历史版本 + */ +const putWorkFlowVersion: ( + application_id: string, + application_version_id: string, + data: any, + loading?: Ref +) => Promise> = (application_id, application_version_id, data, loading) => { + return put( + `/application/${application_id}/work_flow_version/${application_version_id}`, + data, + undefined, + loading + ) +} + export default { getAllAppilcation, getApplication, @@ -429,5 +470,8 @@ export default { getPlatformConfig, updatePlatformConfig, updatePlatformStatus, - validatePassword + validatePassword, + getWorkFlowVersion, + getWorkFlowVersionDetail, + putWorkFlowVersion } diff --git a/ui/src/components/common-list/index.vue b/ui/src/components/common-list/index.vue index 5912efe33df..6641cac4572 100644 --- a/ui/src/components/common-list/index.vue +++ b/ui/src/components/common-list/index.vue @@ -6,8 +6,8 @@ @click.prevent="clickHandle(item, index)" :class="current === item[props.valueKey] ? 'active' : ''" class="cursor" - @mouseenter="mouseenter(item)" - @mouseleave="mouseleave()" + @mouseenter.stop="mouseenter(item)" + @mouseleave.stop="mouseleave()" > @@ -71,6 +71,13 @@ function clickHandle(row: any, index: number) { border-radius: 4px; color: var(--el-color-primary); font-weight: 500; + &:hover { + background: var(--el-color-primary-light-9); + } + } + &:hover { + border-radius: 4px; + background: var(--app-text-color-light-1); } } } diff --git a/ui/src/components/icons/index.ts b/ui/src/components/icons/index.ts index 590806840f1..35e94fafdd1 100644 --- a/ui/src/components/icons/index.ts +++ b/ui/src/components/icons/index.ts @@ -1227,5 +1227,26 @@ export const iconMap: any = { ) ]) } - } + }, + // 'app-history-outlined': { + // iconReader: () => { + // return h('i', [ + // h( + // 'svg', + // { + // style: { height: '100%', width: '100%' }, + // viewBox: '0 0 1024 1024', + // version: '1.1', + // xmlns: 'http://www.w3.org/2000/svg' + // }, + // [ + // h('path', { + // d: 'M955.733333 512c0 235.648-191.018667 426.666667-426.666666 426.666667a425.898667 425.898667 0 0 1-334.677334-162.005334l67.797334-51.84a341.333333 341.333333 0 1 0-69.717334-269.653333h30.08c18.176-0.042667 29.013333 20.181333 18.944 35.328L170.24 597.333333a22.741333 22.741333 0 0 1-37.888 0l-71.253333-106.88a22.741333 22.741333 0 0 1 18.944-35.413333h26.112C133.973333 246.4 312.746667 85.333333 529.066667 85.333333c235.648 0 426.666667 191.018667 426.666666 426.666667z" p-id="16742"> +

发布历史

+
+ +
+ + + + + +
+
+
+ + + + diff --git a/ui/src/views/application-workflow/index.vue b/ui/src/views/application-workflow/index.vue index 83650835998..4d359ba694a 100644 --- a/ui/src/views/application-workflow/index.vue +++ b/ui/src/views/application-workflow/index.vue @@ -6,11 +6,24 @@ @click="router.push({ path: `/application/${id}/WORK_FLOW/overview` })" >

{{ detail?.name }}

- + 预览版本: + {{ currentVersion.name || datetimeFormat(currentVersion.create_time) }} + + 保存时间:{{ datetimeFormat(saveTime) }} -
+
+ 恢复版本 + + + + +
+
添加组件 @@ -21,6 +34,27 @@ 保存 发布 + + + + + + +
@@ -90,6 +124,10 @@ + + + +