feat: Simple application version (#3479)

This commit is contained in:
shaohuzhang1 2025-07-04 11:42:31 +08:00 committed by GitHub
parent 77d90e5b46
commit e21d53b746
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 282 additions and 103 deletions

View File

@ -55,7 +55,7 @@ class ApplicationVersionOperateAPI(APIMixin):
def get_parameters(): def get_parameters():
return [ return [
OpenApiParameter( OpenApiParameter(
name="work_flow_version_id", name="application_version_id",
description="工作流版本id", description="工作流版本id",
type=OpenApiTypes.STR, type=OpenApiTypes.STR,
location='path', location='path',

View File

@ -0,0 +1,66 @@
# Generated by Django 5.2.3 on 2025-07-04 03:18
import application.models.application
import django.db.models.deletion
import uuid_utils.compat
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('application', '0003_chat_asker_chat_meta_and_more'),
('users', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='application',
name='publish_time',
field=models.DateTimeField(blank=True, default=None, null=True, verbose_name='发布时间'),
),
migrations.CreateModel(
name='ApplicationVersion',
fields=[
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')),
('id', models.UUIDField(default=uuid_utils.compat.uuid7, editable=False, primary_key=True, serialize=False, verbose_name='主键id')),
('name', models.CharField(default='', max_length=128, verbose_name='版本名称')),
('publish_user_id', models.UUIDField(default=None, null=True, verbose_name='发布者id')),
('publish_user_name', models.CharField(default='', max_length=128, verbose_name='发布者名称')),
('workspace_id', models.CharField(db_index=True, default='default', max_length=64, verbose_name='工作空间id')),
('application_name', models.CharField(max_length=128, verbose_name='应用名称')),
('desc', models.CharField(default='', max_length=512, verbose_name='引用描述')),
('prologue', models.CharField(default='', max_length=40960, verbose_name='开场白')),
('dialogue_number', models.IntegerField(default=0, verbose_name='会话数量')),
('model_id', models.UUIDField(blank=True, null=True, verbose_name='大语言模型')),
('knowledge_setting', models.JSONField(default=application.models.application.get_dataset_setting_dict, verbose_name='数据集参数设置')),
('model_setting', models.JSONField(default=application.models.application.get_model_setting_dict, verbose_name='模型参数相关设置')),
('model_params_setting', models.JSONField(default=dict, verbose_name='模型参数相关设置')),
('tts_model_params_setting', models.JSONField(default=dict, verbose_name='模型参数相关设置')),
('problem_optimization', models.BooleanField(default=False, verbose_name='问题优化')),
('icon', models.CharField(default='./favicon.ico', max_length=256, verbose_name='应用icon')),
('work_flow', models.JSONField(default=dict, verbose_name='工作流数据')),
('type', models.CharField(choices=[('SIMPLE', '简易'), ('WORK_FLOW', '工作流')], default='SIMPLE', max_length=256, verbose_name='应用类型')),
('problem_optimization_prompt', models.CharField(blank=True, default='()里面是用户问题,根据上下文回答揣测用户问题({question}) 要求: 输出一个补全问题,并且放在<data></data>标签中', max_length=102400, null=True, verbose_name='问题优化提示词')),
('tts_model_id', models.UUIDField(blank=True, null=True, verbose_name='文本转语音模型id')),
('stt_model_id', models.UUIDField(blank=True, null=True, verbose_name='语音转文本模型id')),
('tts_model_enable', models.BooleanField(default=False, verbose_name='语音合成模型是否启用')),
('stt_model_enable', models.BooleanField(default=False, verbose_name='语音识别模型是否启用')),
('tts_type', models.CharField(default='BROWSER', max_length=20, verbose_name='语音播放类型')),
('tts_autoplay', models.BooleanField(default=False, verbose_name='自动播放')),
('stt_autosend', models.BooleanField(default=False, verbose_name='自动发送')),
('clean_time', models.IntegerField(default=180, verbose_name='清理时间')),
('file_upload_enable', models.BooleanField(default=False, verbose_name='文件上传是否启用')),
('file_upload_setting', models.JSONField(default=dict, verbose_name='文件上传相关设置')),
('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='application.application')),
('user', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.user')),
],
options={
'db_table': 'application_version',
},
),
migrations.DeleteModel(
name='WorkFlowVersion',
),
]

View File

@ -90,6 +90,7 @@ class Application(AppModelMixin):
tts_autoplay = models.BooleanField(verbose_name="自动播放", default=False) tts_autoplay = models.BooleanField(verbose_name="自动播放", default=False)
stt_autosend = models.BooleanField(verbose_name="自动发送", default=False) stt_autosend = models.BooleanField(verbose_name="自动发送", default=False)
clean_time = models.IntegerField(verbose_name="清理时间", default=180) clean_time = models.IntegerField(verbose_name="清理时间", default=180)
publish_time = models.DateTimeField(verbose_name="发布时间", default=None, null=True, blank=True)
file_upload_enable = models.BooleanField(verbose_name="文件上传是否启用", default=False) file_upload_enable = models.BooleanField(verbose_name="文件上传是否启用", default=False)
file_upload_setting = models.JSONField(verbose_name="文件上传相关设置", default=dict) file_upload_setting = models.JSONField(verbose_name="文件上传相关设置", default=dict)
@ -120,14 +121,43 @@ class ApplicationKnowledgeMapping(AppModelMixin):
db_table = "application_knowledge_mapping" db_table = "application_knowledge_mapping"
class WorkFlowVersion(AppModelMixin): class ApplicationVersion(AppModelMixin):
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id") id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id")
application = models.ForeignKey(Application, on_delete=models.CASCADE) application = models.ForeignKey(Application, on_delete=models.CASCADE)
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
name = models.CharField(verbose_name="版本名称", max_length=128, default="") name = models.CharField(verbose_name="版本名称", max_length=128, default="")
publish_user_id = models.UUIDField(verbose_name="发布者id", max_length=128, default=None, null=True) publish_user_id = models.UUIDField(verbose_name="发布者id", max_length=128, default=None, null=True)
publish_user_name = models.CharField(verbose_name="发布者名称", max_length=128, default="") publish_user_name = models.CharField(verbose_name="发布者名称", max_length=128, default="")
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
application_name = models.CharField(max_length=128, verbose_name="应用名称")
desc = models.CharField(max_length=512, verbose_name="引用描述", default="")
prologue = models.CharField(max_length=40960, verbose_name="开场白", default="")
dialogue_number = models.IntegerField(default=0, verbose_name="会话数量")
user = models.ForeignKey(User, on_delete=models.SET_NULL, db_constraint=False, blank=True, null=True)
model_id = models.UUIDField(verbose_name="大语言模型", blank=True, null=True)
knowledge_setting = models.JSONField(verbose_name="数据集参数设置", default=get_dataset_setting_dict)
model_setting = models.JSONField(verbose_name="模型参数相关设置", default=get_model_setting_dict)
model_params_setting = models.JSONField(verbose_name="模型参数相关设置", default=dict)
tts_model_params_setting = models.JSONField(verbose_name="模型参数相关设置", default=dict)
problem_optimization = models.BooleanField(verbose_name="问题优化", default=False)
icon = models.CharField(max_length=256, verbose_name="应用icon", default="./favicon.ico")
work_flow = models.JSONField(verbose_name="工作流数据", default=dict) work_flow = models.JSONField(verbose_name="工作流数据", default=dict)
type = models.CharField(verbose_name="应用类型", choices=ApplicationTypeChoices.choices,
default=ApplicationTypeChoices.SIMPLE, max_length=256)
problem_optimization_prompt = models.CharField(verbose_name="问题优化提示词", max_length=102400, blank=True,
null=True,
default="()里面是用户问题,根据上下文回答揣测用户问题({question}) 要求: 输出一个补全问题,并且放在<data></data>标签中")
tts_model_id = models.UUIDField(verbose_name="文本转语音模型id",
blank=True, null=True)
stt_model_id = models.UUIDField(verbose_name="语音转文本模型id",
blank=True, null=True)
tts_model_enable = models.BooleanField(verbose_name="语音合成模型是否启用", default=False)
stt_model_enable = models.BooleanField(verbose_name="语音识别模型是否启用", default=False)
tts_type = models.CharField(verbose_name="语音播放类型", max_length=20, default="BROWSER")
tts_autoplay = models.BooleanField(verbose_name="自动播放", default=False)
stt_autosend = models.BooleanField(verbose_name="自动发送", default=False)
clean_time = models.IntegerField(verbose_name="清理时间", default=180)
file_upload_enable = models.BooleanField(verbose_name="文件上传是否启用", default=False)
file_upload_setting = models.JSONField(verbose_name="文件上传相关设置", default=dict)
class Meta: class Meta:
db_table = "application_work_flow_version" db_table = "application_version"

View File

@ -27,7 +27,7 @@ from rest_framework.utils.formatting import lazy_format
from application.flow.common import Workflow from application.flow.common import Workflow
from application.models.application import Application, ApplicationTypeChoices, ApplicationKnowledgeMapping, \ from application.models.application import Application, ApplicationTypeChoices, ApplicationKnowledgeMapping, \
ApplicationFolder, WorkFlowVersion ApplicationFolder, ApplicationVersion
from application.models.application_access_token import ApplicationAccessToken from application.models.application_access_token import ApplicationAccessToken
from common import result from common import result
from common.database_model_manage.database_model_manage import DatabaseModelManage from common.database_model_manage.database_model_manage import DatabaseModelManage
@ -614,6 +614,8 @@ class ApplicationOperateSerializer(serializers.Serializer):
def delete(self, with_valid=True): def delete(self, with_valid=True):
if with_valid: if with_valid:
self.is_valid() self.is_valid()
QuerySet(ApplicationVersion).filter(application_id=self.data.get('application_id')).delete()
QuerySet(ApplicationKnowledgeMapping).filter(application_id=self.data.get('application_id')).delete()
QuerySet(Application).filter(id=self.data.get('application_id')).delete() QuerySet(Application).filter(id=self.data.get('application_id')).delete()
return True return True
@ -644,6 +646,27 @@ class ApplicationOperateSerializer(serializers.Serializer):
except Exception as e: except Exception as e:
return result.error(str(e), response_status=status.HTTP_500_INTERNAL_SERVER_ERROR) return result.error(str(e), response_status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@staticmethod
def reset_application_version(application_version, application):
update_field_dict = {
'application_name': 'name', 'desc': 'desc', 'prologue': 'prologue', 'dialogue_number': 'dialogue_number',
'user_id': 'user_id', 'model_id': 'model_id', 'knowledge_setting': 'knowledge_setting',
'model_setting': 'model_setting', 'model_params_setting': 'model_params_setting',
'tts_model_params_setting': 'tts_model_params_setting',
'problem_optimization': 'problem_optimization', 'icon': 'icon', 'work_flow': 'work_flow',
'problem_optimization_prompt': 'problem_optimization_prompt', 'tts_model_id': 'tts_model_id',
'stt_model_id': 'stt_model_id', 'tts_model_enable': 'tts_model_enable',
'stt_model_enable': 'stt_model_enable', 'tts_type': 'tts_type',
'tts_autoplay': 'tts_autoplay', 'stt_autosend': 'stt_autosend', 'file_upload_enable': 'file_upload_enable',
'file_upload_setting': 'file_upload_setting',
'type': 'type'
}
for (version_field, app_field) in update_field_dict.items():
_v = getattr(application, app_field)
if _v:
setattr(application_version, version_field, _v)
@transaction.atomic @transaction.atomic
def publish(self, instance, with_valid=True): def publish(self, instance, with_valid=True):
if with_valid: if with_valid:
@ -653,25 +676,28 @@ class ApplicationOperateSerializer(serializers.Serializer):
user = QuerySet(User).filter(id=user_id).first() user = QuerySet(User).filter(id=user_id).first()
application = QuerySet(Application).filter(id=self.data.get("application_id"), application = QuerySet(Application).filter(id=self.data.get("application_id"),
workspace_id=workspace_id).first() workspace_id=workspace_id).first()
work_flow = instance.get('work_flow') if application.type == ApplicationTypeChoices.WORK_FLOW:
if work_flow is None: work_flow = application.work_flow
raise AppApiException(500, _("work_flow is a required field")) if work_flow is None:
Workflow.new_instance(work_flow).is_valid() raise AppApiException(500, _("work_flow is a required field"))
base_node = get_base_node_work_flow(work_flow) Workflow.new_instance(work_flow).is_valid()
if base_node is not None: base_node = get_base_node_work_flow(work_flow)
node_data = base_node.get('properties').get('node_data') if base_node is not None:
if node_data is not None: node_data = base_node.get('properties').get('node_data')
application.name = node_data.get('name') if node_data is not None:
application.desc = node_data.get('desc') application.name = node_data.get('name')
application.prologue = node_data.get('prologue') application.desc = node_data.get('desc')
application.work_flow = work_flow application.prologue = node_data.get('prologue')
application.work_flow = work_flow
application.publish_time = datetime.datetime.now()
application.is_publish = True application.is_publish = True
application.save() application.save()
work_flow_version = WorkFlowVersion(work_flow=work_flow, application=application, work_flow_version = ApplicationVersion(work_flow=application.work_flow, application=application,
name=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), name=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
publish_user_id=user_id, publish_user_id=user_id,
publish_user_name=user.username, publish_user_name=user.username,
workspace_id=workspace_id) workspace_id=workspace_id)
self.reset_application_version(work_flow_version, application)
work_flow_version.save() work_flow_version.save()
return self.one(with_valid=False) return self.one(with_valid=False)

View File

@ -12,7 +12,7 @@ from django.db.models import QuerySet
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from application.models import WorkFlowVersion, Application from application.models import Application, ApplicationVersion
from common.db.search import page_search from common.db.search import page_search
from common.exception.app_exception import AppApiException from common.exception.app_exception import AppApiException
@ -25,7 +25,7 @@ class ApplicationVersionQuerySerializer(serializers.Serializer):
class ApplicationVersionModelSerializer(serializers.ModelSerializer): class ApplicationVersionModelSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = WorkFlowVersion model = ApplicationVersion
fields = ['id', 'name', 'workspace_id', 'application_id', 'work_flow', 'publish_user_id', 'publish_user_name', fields = ['id', 'name', 'workspace_id', 'application_id', 'work_flow', 'publish_user_id', 'publish_user_name',
'create_time', 'create_time',
'update_time'] 'update_time']
@ -43,11 +43,11 @@ class ApplicationVersionSerializer(serializers.Serializer):
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID")) workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
def get_query_set(self, query): def get_query_set(self, query):
query_set = QuerySet(WorkFlowVersion).filter(application_id=query.get('application_id')) query_set = QuerySet(ApplicationVersion).filter(application_id=query.get('application_id'))
if 'name' in query and query.get('name') is not None: if 'name' in query and query.get('name') is not None:
query_set = query_set.filter(name__contains=query.get('name')) query_set = query_set.filter(name__contains=query.get('name'))
if 'workspace_id' in self.data and self.data.get('workspace_id') is not None: if 'workspace_id' in self.data and self.data.get('workspace_id') is not None:
query_set = query_set.filter(workspace_id=self.data.get('workspace_id').get('name')) query_set = query_set.filter(workspace_id=self.data.get('workspace_id'))
return query_set.order_by("-create_time") return query_set.order_by("-create_time")
def list(self, query, with_valid=True): def list(self, query, with_valid=True):
@ -67,8 +67,8 @@ class ApplicationVersionSerializer(serializers.Serializer):
class Operate(serializers.Serializer): class Operate(serializers.Serializer):
workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID")) workspace_id = serializers.CharField(required=False, allow_null=True, allow_blank=True, label=_("Workspace ID"))
application_id = serializers.UUIDField(required=True, label=_("Application ID")) application_id = serializers.UUIDField(required=True, label=_("Application ID"))
work_flow_version_id = serializers.UUIDField(required=True, application_version_id = serializers.UUIDField(required=True,
label=_("Workflow version id")) label=_("Application version ID"))
def is_valid(self, *, raise_exception=False): def is_valid(self, *, raise_exception=False):
super().is_valid(raise_exception=True) super().is_valid(raise_exception=True)
@ -82,10 +82,11 @@ class ApplicationVersionSerializer(serializers.Serializer):
def one(self, with_valid=True): def one(self, with_valid=True):
if with_valid: if with_valid:
self.is_valid(raise_exception=True) self.is_valid(raise_exception=True)
work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=self.data.get('application_id'), application_version = QuerySet(ApplicationVersion).filter(application_id=self.data.get('application_id'),
id=self.data.get('work_flow_version_id')).first() id=self.data.get(
if work_flow_version is not None: 'application_version_id')).first()
return ApplicationVersionModelSerializer(work_flow_version).data if application_version is not None:
return ApplicationVersionModelSerializer(application_version).data
else: else:
raise AppApiException(500, _('Workflow version does not exist')) raise AppApiException(500, _('Workflow version does not exist'))
@ -93,13 +94,14 @@ class ApplicationVersionSerializer(serializers.Serializer):
if with_valid: if with_valid:
self.is_valid(raise_exception=True) self.is_valid(raise_exception=True)
ApplicationVersionEditSerializer(data=instance).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'), application_version = QuerySet(ApplicationVersion).filter(application_id=self.data.get('application_id'),
id=self.data.get('work_flow_version_id')).first() id=self.data.get(
if work_flow_version is not None: 'application_version_id')).first()
if application_version is not None:
name = instance.get('name', None) name = instance.get('name', None)
if name is not None and len(name) > 0: if name is not None and len(name) > 0:
work_flow_version.name = name application_version.name = name
work_flow_version.save() application_version.save()
return ApplicationVersionModelSerializer(work_flow_version).data return ApplicationVersionModelSerializer(application_version).data
else: else:
raise AppApiException(500, _('Workflow version does not exist')) raise AppApiException(500, _('Workflow version does not exist'))

View File

@ -14,8 +14,9 @@ from django.db.models import QuerySet
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from application.chat_pipeline.step.chat_step.i_chat_step import PostResponseHandler from application.chat_pipeline.step.chat_step.i_chat_step import PostResponseHandler
from application.models import Application, WorkFlowVersion, ChatRecord, Chat from application.models import Application, ChatRecord, Chat, ApplicationVersion
from common.constants.cache_version import Cache_Version from common.constants.cache_version import Cache_Version
from common.exception.app_exception import ChatException
from models_provider.models import Model from models_provider.models import Model
from models_provider.tools import get_model_credential from models_provider.tools import get_model_credential
@ -28,8 +29,6 @@ class ChatInfo:
knowledge_id_list: List[str], knowledge_id_list: List[str],
exclude_document_id_list: list[str], exclude_document_id_list: list[str],
application_id: str, application_id: str,
application: Application,
work_flow_version: WorkFlowVersion = None,
debug=False): debug=False):
""" """
:param chat_id: 对话id :param chat_id: 对话id
@ -38,18 +37,16 @@ class ChatInfo:
:param knowledge_id_list: 知识库列表 :param knowledge_id_list: 知识库列表
:param exclude_document_id_list: 排除的文档 :param exclude_document_id_list: 排除的文档
:param application_id 应用id :param application_id 应用id
:param application: 应用信息
:param debug 是否是调试 :param debug 是否是调试
""" """
self.chat_id = chat_id self.chat_id = chat_id
self.chat_user_id = chat_user_id self.chat_user_id = chat_user_id
self.chat_user_type = chat_user_type self.chat_user_type = chat_user_type
self.application = application
self.knowledge_id_list = knowledge_id_list self.knowledge_id_list = knowledge_id_list
self.exclude_document_id_list = exclude_document_id_list self.exclude_document_id_list = exclude_document_id_list
self.application_id = application_id self.application_id = application_id
self.chat_record_list: List[ChatRecord] = [] self.chat_record_list: List[ChatRecord] = []
self.work_flow_version = work_flow_version self.application = None
self.debug = debug self.debug = debug
@staticmethod @staticmethod
@ -63,10 +60,24 @@ class ChatInfo:
no_references_setting['value'] = no_references_prompt if len(no_references_prompt) > 0 else "{question}" no_references_setting['value'] = no_references_prompt if len(no_references_prompt) > 0 else "{question}"
return no_references_setting return no_references_setting
def get_application(self):
if self.debug:
application = QuerySet(Application).filter(id=self.application_id).first()
if not application:
raise ChatException(500, _('The application does not exist'))
else:
application = QuerySet(ApplicationVersion).filter(application_id=self.application_id).order_by(
'-create_time')[0:1].first()
if not application:
raise ChatException(500, _("The application has not been published. Please use it after publishing."))
self.application = application
return application
def to_base_pipeline_manage_params(self): def to_base_pipeline_manage_params(self):
self.get_application()
knowledge_setting = self.application.knowledge_setting knowledge_setting = self.application.knowledge_setting
model_setting = self.application.model_setting model_setting = self.application.model_setting
model_id = self.application.model.id if self.application.model is not None else None model_id = self.application.model_id
model_params_setting = None model_params_setting = None
if model_id is not None: if model_id is not None:
model = QuerySet(Model).filter(id=model_id).first() model = QuerySet(Model).filter(id=model_id).first()
@ -127,7 +138,7 @@ class ChatInfo:
self.chat_record_list.append(chat_record) self.chat_record_list.append(chat_record)
if not self.debug: if not self.debug:
if not QuerySet(Chat).filter(id=self.chat_id).exists(): if not QuerySet(Chat).filter(id=self.chat_id).exists():
Chat(id=self.chat_id, application_id=self.application.id, abstract=chat_record.problem_text[0:1024], Chat(id=self.chat_id, application_id=self.application_id, abstract=chat_record.problem_text[0:1024],
chat_user_id=self.chat_user_id, chat_user_type=self.chat_user_type).save() chat_user_id=self.chat_user_id, chat_user_type=self.chat_user_type).save()
else: else:
QuerySet(Chat).filter(id=self.chat_id).update(update_time=datetime.now()) QuerySet(Chat).filter(id=self.chat_id).update(update_time=datetime.now())

View File

@ -10,7 +10,8 @@ from (select application."id"::text,
application."user_id", application."user_id",
"user"."nick_name" as "nick_name", "user"."nick_name" as "nick_name",
application."create_time", application."create_time",
application."update_time" application."update_time",
application."publish_time"
from application left join "user" on user_id = "user".id from application left join "user" on user_id = "user".id
${application_custom_sql} ${application_custom_sql}
UNION UNION
@ -25,6 +26,7 @@ from (select application."id"::text,
application_folder."user_id", application_folder."user_id",
"user"."nick_name" as "nick_name", "user"."nick_name" as "nick_name",
application_folder."create_time", application_folder."create_time",
application_folder."update_time" application_folder."update_time",
null as "publish_time"
from application_folder left join "user" on user_id = "user".id ${folder_query_set}) temp from application_folder left join "user" on user_id = "user".id ${folder_query_set}) temp
${application_query_set} ${application_query_set}

View File

@ -10,7 +10,8 @@ from (select application."id"::text,
application."user_id", application."user_id",
"user"."nick_name" as "nick_name", "user"."nick_name" as "nick_name",
application."create_time", application."create_time",
application."update_time" application."update_time",
application."publish_time"
from application left join "user" on user_id = "user".id from application left join "user" on user_id = "user".id
where application."id" in (select target where application."id" in (select target
from workspace_user_resource_permission from workspace_user_resource_permission
@ -28,6 +29,7 @@ from (select application."id"::text,
application_folder."user_id", application_folder."user_id",
"user"."nick_name" as "nick_name", "user"."nick_name" as "nick_name",
application_folder."create_time", application_folder."create_time",
application_folder."update_time" application_folder."update_time",
null as "publish_time"
from application_folder left join "user" on user_id = "user".id ${folder_query_set}) temp from application_folder left join "user" on user_id = "user".id ${folder_query_set}) temp
${application_query_set} ${application_query_set}

View File

@ -10,7 +10,8 @@ from (select application."id"::text,
application."user_id", application."user_id",
"user"."nick_name" as "nick_name", "user"."nick_name" as "nick_name",
application."create_time", application."create_time",
application."update_time" application."update_time",
application."publish_time"
from application left join "user" on user_id = "user".id from application left join "user" on user_id = "user".id
where "application".id in (select target where "application".id in (select target
from workspace_user_resource_permission from workspace_user_resource_permission
@ -41,6 +42,7 @@ from (select application."id"::text,
application_folder."user_id", application_folder."user_id",
"user"."nick_name" as "nick_name", "user"."nick_name" as "nick_name",
application_folder."create_time", application_folder."create_time",
application_folder."update_time" application_folder."update_time",
null as "publish_time"
from application_folder left join "user" on user_id = "user".id ${folder_query_set}) temp from application_folder left join "user" on user_id = "user".id ${folder_query_set}) temp
${application_query_set} ${application_query_set}

View File

@ -15,7 +15,7 @@ urlpatterns = [
path('workspace/<str:workspace_id>/application/<str:application_id>/application_stats', views.ApplicationStats.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/application_stats', views.ApplicationStats.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/application_key/<str:api_key_id>', views.ApplicationKey.Operate.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/application_key/<str:api_key_id>', views.ApplicationKey.Operate.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/export', views.ApplicationAPI.Export.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/export', views.ApplicationAPI.Export.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/work_flow_version', views.ApplicationVersionView.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/application_version', views.ApplicationVersionView.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/access_token', views.AccessToken.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/access_token', views.AccessToken.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/add_knowledge', views.ApplicationChatRecordAddKnowledge.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/add_knowledge', views.ApplicationChatRecordAddKnowledge.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/chat', views.ApplicationChat.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/chat', views.ApplicationChat.as_view()),
@ -27,8 +27,8 @@ urlpatterns = [
path('workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record/<str:chat_record_id>/improve', views.ApplicationChatRecordImprove.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record/<str:chat_record_id>/improve', views.ApplicationChatRecordImprove.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record/<str:chat_record_id>/knowledge/<str:knowledge_id>/document/<str:document_id>/improve', views.ApplicationChatRecordImproveParagraph.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record/<str:chat_record_id>/knowledge/<str:knowledge_id>/document/<str:document_id>/improve', views.ApplicationChatRecordImproveParagraph.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record/<str:chat_record_id>/knowledge/<str:knowledge_id>/document/<str:document_id>/paragraph/<str:paragraph_id>/improve', views.ApplicationChatRecordImproveParagraph.Operate.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/chat/<str:chat_id>/chat_record/<str:chat_record_id>/knowledge/<str:knowledge_id>/document/<str:document_id>/paragraph/<str:paragraph_id>/improve', views.ApplicationChatRecordImproveParagraph.Operate.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/work_flow_version/<int:current_page>/<int:page_size>', views.ApplicationVersionView.Page.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/application_version/<int:current_page>/<int:page_size>', views.ApplicationVersionView.Page.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/work_flow_version/<str:work_flow_version_id>', views.ApplicationVersionView.Operate.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/application_version/<str:application_version_id>', views.ApplicationVersionView.Operate.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/open', views.OpenView.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/open', views.OpenView.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/text_to_speech', views.TextToSpeech.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/text_to_speech', views.TextToSpeech.as_view()),
path('workspace/<str:workspace_id>/application/<str:application_id>/speech_to_text', views.SpeechToText.as_view()), path('workspace/<str:workspace_id>/application/<str:application_id>/speech_to_text', views.SpeechToText.as_view()),

View File

@ -132,7 +132,8 @@ class ApplicationAPI(APIView):
@has_permissions(PermissionConstants.APPLICATION_EXPORT.get_workspace_application_permission(), @has_permissions(PermissionConstants.APPLICATION_EXPORT.get_workspace_application_permission(),
PermissionConstants.APPLICATION_EXPORT.get_workspace_permission_workspace_manage_role(), PermissionConstants.APPLICATION_EXPORT.get_workspace_permission_workspace_manage_role(),
ViewPermission([RoleConstants.USER.get_workspace_role()], ViewPermission([RoleConstants.USER.get_workspace_role()],
[PermissionConstants.APPLICATION.get_workspace_application_permission()],CompareConstants.AND), [PermissionConstants.APPLICATION.get_workspace_application_permission()],
CompareConstants.AND),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role()) RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
@log(menu='Application', operate="Export Application", @log(menu='Application', operate="Export Application",
get_operation_object=lambda r, k: get_application_operation_object(k.get('application_id')), get_operation_object=lambda r, k: get_application_operation_object(k.get('application_id')),
@ -227,7 +228,7 @@ class ApplicationAPI(APIView):
summary=_("Publishing an application"), summary=_("Publishing an application"),
operation_id=_("Publishing an application"), # type: ignore operation_id=_("Publishing an application"), # type: ignore
parameters=ApplicationOperateAPI.get_parameters(), parameters=ApplicationOperateAPI.get_parameters(),
request=ApplicationEditAPI.get_request(), request=None,
responses=result.DefaultResultSerializer, responses=result.DefaultResultSerializer,
tags=[_('Application')] # type: ignore tags=[_('Application')] # type: ignore
) )

View File

@ -89,11 +89,11 @@ class ApplicationVersionView(APIView):
[PermissionConstants.APPLICATION.get_workspace_application_permission()], [PermissionConstants.APPLICATION.get_workspace_application_permission()],
CompareConstants.AND), CompareConstants.AND),
RoleConstants.WORKSPACE_MANAGE.get_workspace_role()) RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
def get(self, request: Request, workspace_id: str, application_id: str, work_flow_version_id: str): def get(self, request: Request, workspace_id: str, application_id: str, application_version_id: str):
return result.success( return result.success(
ApplicationVersionSerializer.Operate( ApplicationVersionSerializer.Operate(
data={'user_id': request.user, 'workspace_id': workspace_id, data={'user_id': request.user, 'workspace_id': workspace_id,
'application_id': application_id, 'work_flow_version_id': work_flow_version_id}).one()) 'application_id': application_id, 'application_version_id': application_version_id}).one())
@extend_schema( @extend_schema(
methods=['PUT'], methods=['PUT'],
@ -114,10 +114,10 @@ class ApplicationVersionView(APIView):
@log(menu='Application', operate="Modify application version information", @log(menu='Application', operate="Modify application version information",
get_operation_object=lambda r, k: get_application_operation_object(k.get('application_id')), get_operation_object=lambda r, k: get_application_operation_object(k.get('application_id')),
) )
def put(self, request: Request, workspace_id: str, application_id: str, work_flow_version_id: str): def put(self, request: Request, workspace_id: str, application_id: str, application_version_id: str):
return result.success( return result.success(
ApplicationVersionSerializer.Operate( ApplicationVersionSerializer.Operate(
data={'application_id': application_id, 'workspace_id': workspace_id, data={'application_id': application_id, 'workspace_id': workspace_id,
'work_flow_version_id': work_flow_version_id, 'application_version_id': application_version_id,
'user_id': request.user.id}).edit( 'user_id': request.user.id}).edit(
request.data)) request.data))

View File

@ -25,8 +25,8 @@ from application.chat_pipeline.step.search_dataset_step.impl.base_search_dataset
from application.flow.common import Answer, Workflow from application.flow.common import Answer, Workflow
from application.flow.i_step_node import WorkFlowPostHandler from application.flow.i_step_node import WorkFlowPostHandler
from application.flow.workflow_manage import WorkflowManage from application.flow.workflow_manage import WorkflowManage
from application.models import Application, ApplicationTypeChoices, WorkFlowVersion, ApplicationKnowledgeMapping, \ from application.models import Application, ApplicationTypeChoices, ApplicationKnowledgeMapping, \
ChatUserType, ApplicationChatUserStats, ApplicationAccessToken, ChatRecord, Chat ChatUserType, ApplicationChatUserStats, ApplicationAccessToken, ChatRecord, Chat, ApplicationVersion
from application.serializers.application import ApplicationOperateSerializer from application.serializers.application import ApplicationOperateSerializer
from application.serializers.common import ChatInfo from application.serializers.common import ChatInfo
from common.exception.app_exception import AppApiException, AppChatNumOutOfBoundsFailed, ChatException from common.exception.app_exception import AppApiException, AppChatNumOutOfBoundsFailed, ChatException
@ -124,7 +124,7 @@ class ChatSerializers(serializers.Serializer):
def is_valid_chat_id(self, chat_info: ChatInfo): def is_valid_chat_id(self, chat_info: ChatInfo):
if self.data.get('application_id') is not None and self.data.get('application_id') != str( if self.data.get('application_id') is not None and self.data.get('application_id') != str(
chat_info.application.id): chat_info.application_id):
raise ChatException(500, _("Conversation does not exist")) raise ChatException(500, _("Conversation does not exist"))
def is_valid_intraday_access_num(self): def is_valid_intraday_access_num(self):
@ -148,10 +148,10 @@ class ChatSerializers(serializers.Serializer):
def is_valid_application_simple(self, *, chat_info: ChatInfo, raise_exception=False): def is_valid_application_simple(self, *, chat_info: ChatInfo, raise_exception=False):
self.is_valid_intraday_access_num() self.is_valid_intraday_access_num()
model = chat_info.application.model model_id = chat_info.application.model_id
if model is None: if model_id is None:
return chat_info return chat_info
model = QuerySet(Model).filter(id=model.id).first() model = QuerySet(Model).filter(id=model_id).first()
if model is None: if model is None:
return chat_info return chat_info
if model.status == Status.ERROR: if model.status == Status.ERROR:
@ -226,10 +226,7 @@ class ChatSerializers(serializers.Serializer):
if chat_record_id is not None: if chat_record_id is not None:
chat_record = self.get_chat_record(chat_info, chat_record_id) chat_record = self.get_chat_record(chat_info, chat_record_id)
history_chat_record = [r for r in chat_info.chat_record_list if str(r.id) != chat_record_id] history_chat_record = [r for r in chat_info.chat_record_list if str(r.id) != chat_record_id]
if not debug: work_flow = chat_info.application.work_flow
work_flow = chat_info.work_flow_version.work_flow
else:
work_flow = chat_info.application.work_flow
work_flow_manage = WorkflowManage(Workflow.new_instance(work_flow), work_flow_manage = WorkflowManage(Workflow.new_instance(work_flow),
{'history_chat_record': history_chat_record, 'question': message, {'history_chat_record': history_chat_record, 'question': message,
'chat_id': chat_info.chat_id, 'chat_record_id': str( 'chat_id': chat_info.chat_id, 'chat_record_id': str(
@ -252,6 +249,7 @@ class ChatSerializers(serializers.Serializer):
super().is_valid(raise_exception=True) super().is_valid(raise_exception=True)
ChatMessageSerializers(data=instance).is_valid(raise_exception=True) ChatMessageSerializers(data=instance).is_valid(raise_exception=True)
chat_info = self.get_chat_info() chat_info = self.get_chat_info()
chat_info.get_application()
self.is_valid_chat_id(chat_info) self.is_valid_chat_id(chat_info)
if chat_info.application.type == ApplicationTypeChoices.SIMPLE: if chat_info.application.type == ApplicationTypeChoices.SIMPLE:
self.is_valid_application_simple(raise_exception=True, chat_info=chat_info) self.is_valid_application_simple(raise_exception=True, chat_info=chat_info)
@ -301,14 +299,13 @@ class ChatSerializers(serializers.Serializer):
return chat_info return chat_info
def re_open_chat_work_flow(self, chat_id, application): def re_open_chat_work_flow(self, chat_id, application):
work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=application.id).order_by( application_version = QuerySet(ApplicationVersion).filter(application_id=application.id).order_by(
'-create_time')[0:1].first() '-create_time')[0:1].first()
if work_flow_version is None: if application_version is None:
raise ChatException(500, _("The application has not been published. Please use it after publishing.")) raise ChatException(500, _("The application has not been published. Please use it after publishing."))
chat_info = ChatInfo(chat_id, self.data.get('chat_user_id'), self.data.get('chat_user_type'), [], [], chat_info = ChatInfo(chat_id, self.data.get('chat_user_id'), self.data.get('chat_user_type'), [], [],
application.id, application.id)
application, work_flow_version)
chat_record_list = list(QuerySet(ChatRecord).filter(chat_id=chat_id).order_by('-create_time')[0:5]) chat_record_list = list(QuerySet(ChatRecord).filter(chat_id=chat_id).order_by('-create_time')[0:5])
chat_record_list.sort(key=lambda r: r.create_time) chat_record_list.sort(key=lambda r: r.create_time)
for chat_record in chat_record_list: for chat_record in chat_record_list:
@ -349,18 +346,16 @@ class OpenChatSerializers(serializers.Serializer):
chat_user_type = self.data.get("chat_user_type") chat_user_type = self.data.get("chat_user_type")
debug = self.data.get("debug") debug = self.data.get("debug")
chat_id = str(uuid.uuid7()) chat_id = str(uuid.uuid7())
work_flow_version = None
if not debug: if not debug:
work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=application_id).order_by( application_version = QuerySet(ApplicationVersion).filter(application_id=application_id).order_by(
'-create_time')[0:1].first() '-create_time')[0:1].first()
if work_flow_version is None: if application_version is None:
raise AppApiException(500, raise AppApiException(500,
gettext( gettext(
"The application has not been published. Please use it after publishing.")) "The application has not been published. Please use it after publishing."))
ChatInfo(chat_id, chat_user_id, chat_user_type, [], ChatInfo(chat_id, chat_user_id, chat_user_type, [],
[], [],
application_id, application_id, debug).set_cache()
application, work_flow_version, debug).set_cache()
return chat_id return chat_id
def open_simple(self, application): def open_simple(self, application):
@ -378,7 +373,7 @@ class OpenChatSerializers(serializers.Serializer):
knowledge_id__in=knowledge_id_list, knowledge_id__in=knowledge_id_list,
is_active=False)], is_active=False)],
application_id, application_id,
application, debug=debug).set_cache() debug=debug).set_cache()
return chat_id return chat_id

View File

@ -15,7 +15,7 @@ from django.utils.translation import gettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from application.models import ApplicationAccessToken, ChatUserType, Application, ApplicationTypeChoices, \ from application.models import ApplicationAccessToken, ChatUserType, Application, ApplicationTypeChoices, \
WorkFlowVersion ApplicationVersion
from application.serializers.application import ApplicationSerializerModel from application.serializers.application import ApplicationSerializerModel
from common.auth.common import ChatUserToken, ChatAuthentication from common.auth.common import ChatUserToken, ChatAuthentication
from common.constants.authentication_type import AuthenticationType from common.constants.authentication_type import AuthenticationType
@ -79,6 +79,25 @@ class AuthProfileSerializer(serializers.Serializer):
class ApplicationProfileSerializer(serializers.Serializer): class ApplicationProfileSerializer(serializers.Serializer):
application_id = serializers.UUIDField(required=True, label=_("Application ID")) application_id = serializers.UUIDField(required=True, label=_("Application ID"))
@staticmethod
def reset_application(application, application_version):
update_field_dict = {
'application_name': 'name', 'desc': 'desc', 'prologue': 'prologue', 'dialogue_number': 'dialogue_number',
'user_id': 'user_id', 'model_id': 'model_id', 'knowledge_setting': 'knowledge_setting',
'model_setting': 'model_setting', 'model_params_setting': 'model_params_setting',
'tts_model_params_setting': 'tts_model_params_setting',
'problem_optimization': 'problem_optimization', 'icon': 'icon', 'work_flow': 'work_flow',
'problem_optimization_prompt': 'problem_optimization_prompt', 'tts_model_id': 'tts_model_id',
'stt_model_id': 'stt_model_id', 'tts_model_enable': 'tts_model_enable',
'stt_model_enable': 'stt_model_enable', 'tts_type': 'tts_type',
'tts_autoplay': 'tts_autoplay', 'stt_autosend': 'stt_autosend', 'file_upload_enable': 'file_upload_enable',
'file_upload_setting': 'file_upload_setting'
}
for (version_field, app_field) in update_field_dict.items():
_v = getattr(application_version, version_field)
if _v:
setattr(application, app_field, _v)
def profile(self, with_valid=True): def profile(self, with_valid=True):
if with_valid: if with_valid:
self.is_valid() self.is_valid()
@ -88,12 +107,10 @@ class ApplicationProfileSerializer(serializers.Serializer):
if application_access_token is None: if application_access_token is None:
raise AppUnauthorizedFailed(500, _("Illegal User")) raise AppUnauthorizedFailed(500, _("Illegal User"))
application_setting_model = DatabaseModelManage.get_model('application_setting') application_setting_model = DatabaseModelManage.get_model('application_setting')
if application.type == ApplicationTypeChoices.WORK_FLOW: application_version = QuerySet(ApplicationVersion).filter(application_id=application.id).order_by(
work_flow_version = QuerySet(WorkFlowVersion).filter(application_id=application.id).order_by( '-create_time')[0:1].first()
'-create_time')[0:1].first() if application_version is not None:
if work_flow_version is not None: self.reset_application(application, application_version)
application.work_flow = work_flow_version.work_flow
license_is_valid = cache.get(Cache_Version.SYSTEM.get_key(key='license_is_valid'), license_is_valid = cache.get(Cache_Version.SYSTEM.get_key(key='license_is_valid'),
version=Cache_Version.SYSTEM.get_version()) version=Cache_Version.SYSTEM.get_version())
application_setting_dict = {} application_setting_dict = {}

View File

@ -18,7 +18,7 @@ const getWorkFlowVersion: (
application_id: string, application_id: string,
loading?: Ref<boolean>, loading?: Ref<boolean>,
) => Promise<Result<any>> = (application_id, loading) => { ) => Promise<Result<any>> = (application_id, loading) => {
return get(`${prefix.value}/${application_id}/work_flow_version`, undefined, loading) return get(`${prefix.value}/${application_id}/application_version`, undefined, loading)
} }
/** /**
@ -30,7 +30,7 @@ const getWorkFlowVersionDetail: (
loading?: Ref<boolean>, loading?: Ref<boolean>,
) => Promise<Result<any>> = (application_id, application_version_id, loading) => { ) => Promise<Result<any>> = (application_id, application_version_id, loading) => {
return get( return get(
`${prefix.value}/${application_id}/work_flow_version/${application_version_id}`, `${prefix.value}/${application_id}/application_version/${application_version_id}`,
undefined, undefined,
loading, loading,
) )
@ -45,7 +45,7 @@ const putWorkFlowVersion: (
loading?: Ref<boolean>, loading?: Ref<boolean>,
) => Promise<Result<any>> = (application_id, application_version_id, data, loading) => { ) => Promise<Result<any>> = (application_id, application_version_id, data, loading) => {
return put( return put(
`${prefix.value}/${application_id}/work_flow_version/${application_version_id}`, `${prefix.value}/${application_id}/application_version/${application_version_id}`,
data, data,
undefined, undefined,
loading, loading,

View File

@ -114,7 +114,8 @@ export default {
}, },
}, },
buttons: { buttons: {
publish: '保存并发布', save: '保存',
publish: '发布',
addModel: '添加模型', addModel: '添加模型',
}, },

View File

@ -281,7 +281,10 @@ const publish = () => {
return return
} }
applicationApi applicationApi
.publish(id, { work_flow: workflow }, loading) .putApplication(id, { work_flow: workflow }, loading)
.then((ok) => {
return applicationApi.publish(id, {}, loading)
})
.then((ok: any) => { .then((ok: any) => {
detail.value.name = ok.data.name detail.value.name = ok.data.name
MsgSuccess(t('views.applicationWorkflow.tip.publicSuccess')) MsgSuccess(t('views.applicationWorkflow.tip.publicSuccess'))

View File

@ -4,14 +4,24 @@
<h3> <h3>
{{ $t('common.setting') }} {{ $t('common.setting') }}
</h3> </h3>
<el-button <div>
type="primary" <el-button
@click="submit(applicationFormRef)" type="primary"
:disabled="loading" @click="submit(applicationFormRef)"
v-if="permissionPrecise.edit(id)" :disabled="loading"
> v-if="permissionPrecise.edit(id)"
{{ $t('views.application.buttons.publish') }} >
</el-button> {{ $t('views.application.buttons.save') }}
</el-button>
<el-button
type="primary"
@click="publish(applicationFormRef)"
:disabled="loading"
v-if="permissionPrecise.edit(id)"
>
{{ $t('views.application.buttons.publish') }}
</el-button>
</div>
</div> </div>
<el-card style="--el-card-padding: 0"> <el-card style="--el-card-padding: 0">
<el-row v-loading="loading"> <el-row v-loading="loading">
@ -444,7 +454,7 @@ import { t } from '@/locales'
import TTSModeParamSettingDialog from './component/TTSModeParamSettingDialog.vue' import TTSModeParamSettingDialog from './component/TTSModeParamSettingDialog.vue'
import ReasoningParamSettingDialog from './component/ReasoningParamSettingDialog.vue' import ReasoningParamSettingDialog from './component/ReasoningParamSettingDialog.vue'
import permissionMap from '@/permission' import permissionMap from '@/permission'
import ApplicationAPI from '@/api/application/application'
const route = useRoute() const route = useRoute()
const apiType = computed<'workspace'>(() => { const apiType = computed<'workspace'>(() => {
@ -549,7 +559,18 @@ function submitReasoningDialog(val: any) {
...val, ...val,
} }
} }
const publish = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.validate().then(() => {
return ApplicationAPI.putApplication(id, applicationForm.value, loading)
.then((ok) => {
return ApplicationAPI.publish(id, {}, loading)
})
.then((res) => {
MsgSuccess(t('common.saveSuccess'))
})
})
}
const submit = async (formEl: FormInstance | undefined) => { const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
await formEl.validate((valid, fields) => { await formEl.validate((valid, fields) => {