feat: 工作流版本管理 (#1386)

This commit is contained in:
shaohuzhang1 2024-10-23 17:01:19 +08:00 committed by GitHub
parent 0c6e4b73b8
commit 36998c804e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 653 additions and 26 deletions

View File

@ -0,0 +1,33 @@
# 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', '0017_application_tts_model_params_setting'),
]
operations = [
migrations.AddField(
model_name='workflowversion',
name='name',
field=models.CharField(default='', max_length=128, verbose_name='版本名称'),
),
migrations.RunSQL(sql),
migrations.AddField(
model_name='workflowversion',
name='publish_user_id',
field=models.UUIDField(default=None, null=True, verbose_name='发布者id'),
),
migrations.AddField(
model_name='workflowversion',
name='publish_user_name',
field=models.CharField(default='', max_length=128, verbose_name='发布者名称'),
),
]

View File

@ -88,6 +88,9 @@ class Application(AppModelMixin):
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="")
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="")
work_flow = models.JSONField(verbose_name="工作流数据", default=dict)
class Meta:

View File

@ -6,6 +6,7 @@
@date2023/11/7 10:02
@desc:
"""
import datetime
import hashlib
import json
import os
@ -50,6 +51,7 @@ from setting.models_provider.constants.model_provider_constants import ModelProv
from setting.models_provider.tools import get_model_instance_by_model_user_id
from setting.serializers.provider_serializers import ModelSerializer
from smartdoc.conf import PROJECT_DIR
from users.models import User
chat_cache = cache.caches['chat_cache']
@ -684,6 +686,8 @@ class ApplicationSerializer(serializers.Serializer):
def publish(self, instance, with_valid=True):
if with_valid:
self.is_valid()
user_id = self.data.get('user_id')
user = QuerySet(User).filter(id=user_id).first()
application = QuerySet(Application).filter(id=self.data.get("application_id")).first()
work_flow = instance.get('work_flow')
if work_flow is None:
@ -703,7 +707,10 @@ class ApplicationSerializer(serializers.Serializer):
application.save()
# 插入知识库关联关系
self.save_application_mapping(application_dataset_id_list, dataset_id_list, application.id)
work_flow_version = WorkFlowVersion(work_flow=work_flow, application=application)
work_flow_version = WorkFlowVersion(work_flow=work_flow, application=application,
name=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
publish_user_id=user_id,
publish_user_name=user.username)
chat_cache.clear_by_application_id(str(application.id))
work_flow_version.save()
return True
@ -1002,6 +1009,7 @@ class ApplicationSerializer(serializers.Serializer):
if application.tts_model_enable:
model = get_model_instance_by_model_user_id(application.tts_model_id, application.user_id,
**application.tts_model_params_setting)
return model.text_to_speech(text)
def play_demo_text(self, form_data, with_valid=True):

View File

@ -0,0 +1,84 @@
# coding=utf-8
"""
@project: MaxKB
@Author
@file application_version_serializers.py
@date2024/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', 'publish_user_id', 'publish_user_name', '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.order_by("-create_time")
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, '不存在的工作流版本')

View File

@ -0,0 +1,69 @@
# coding=utf-8
"""
@project: MaxKB
@Author
@file application_version_api.py
@date2024/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="版本名称")
}
)

View File

@ -70,7 +70,12 @@ urlpatterns = [
name='application/audio'),
path('application/<str:application_id>/text_to_speech', views.Application.TextToSpeech.as_view(),
name='application/audio'),
path('application/<str:application_id>/work_flow_version', views.ApplicationVersionView.as_view()),
path('application/<str:application_id>/work_flow_version/<int:current_page>/<int:page_size>',
views.ApplicationVersionView.Page.as_view()),
path('application/<str:application_id>/work_flow_version/<str:work_flow_version_id>',
views.ApplicationVersionView.Operate.as_view()),
path('application/<str:application_id>/play_demo_text', views.Application.PlayDemoText.as_view(),
name='application/audio'),
name='application/audio')
]

View File

@ -8,3 +8,4 @@
"""
from .application_views import *
from .chat_views import *
from .application_version_views import *

View File

@ -0,0 +1,89 @@
# coding=utf-8
"""
@project: MaxKB
@Author
@file application_version_views.py
@date2024/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))

View File

@ -1,3 +1,4 @@
from typing import Dict, List
from langchain_core.embeddings import Embeddings
@ -34,3 +35,7 @@ class TencentEmbeddingModel(MaxKBBaseModel, Embeddings):
secret_key=model_credential.get('SecretKey'),
model_name=model_name,
)
def _generate_auth_token(self):
# Example method to generate an authentication token for the model API
return f"{self.secret_id}:{self.secret_key}"

View File

@ -415,6 +415,47 @@ const validatePassword: (
return get(`/application/${application_id}/auth/${password}`, undefined, loading)
}
/**
* workflow历史版本
*/
const getWorkFlowVersion: (
application_id: string,
loading?: Ref<boolean>
) => Promise<Result<any>> = (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<boolean>
) => Promise<Result<any>> = (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<boolean>
) => Promise<Result<any>> = (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,
@ -448,5 +489,8 @@ export default {
updatePlatformConfig,
updatePlatformStatus,
validatePassword,
getWorkFlowVersion,
getWorkFlowVersionDetail,
putWorkFlowVersion,
playDemoText
}

View File

@ -3,11 +3,11 @@
<ul v-if="data.length > 0">
<template v-for="(item, index) in data" :key="index">
<li
@click.prevent="clickHandle(item, index)"
@click.stop="clickHandle(item, index)"
:class="current === item[props.valueKey] ? 'active' : ''"
class="cursor"
@mouseenter="mouseenter(item)"
@mouseleave="mouseleave()"
@mouseenter.stop="mouseenter(item)"
@mouseleave.stop="mouseleave()"
>
<slot :row="item" :index="index"> </slot>
</li>
@ -78,6 +78,13 @@ defineExpose({
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);
}
}
}

View File

@ -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"></path><path d="M554.666667 497.792V364.074667A22.741333 22.741333 0 0 0 531.925333 341.333333h-39.850666a22.741333 22.741333 0 0 0-22.741334 22.741334v196.266666c0 12.586667 10.197333 22.784 22.741334 22.784H674.133333a22.741333 22.741333 0 0 0 22.741334-22.784V520.533333a22.741333 22.741333 0 0 0-22.741334-22.741333H554.666667z',
// fill: 'currentColor'
// })
// ]
// )
// ])
// }
// }
}

View File

@ -65,25 +65,44 @@ const props = defineProps({
trigger: {
type: String,
default: 'default',
validator: (value: string) => ['default', 'dblclick'].includes(value)
validator: (value: string) => ['default', 'dblclick', 'manual'].includes(value)
},
write: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['change'])
const emit = defineEmits(['change', 'close'])
const inputRef = ref()
const isEdit = ref(false)
const writeValue = ref('')
const loading = ref(false)
watch(isEdit, (bool) => {
console.log(bool)
if (!bool) {
writeValue.value = ''
emit('close')
} else {
nextTick(() => {
inputRef.value?.focus()
})
setTimeout(() => {
nextTick(() => {
inputRef.value?.focus()
})
}, 200)
}
})
watch(
() => props.write,
(bool) => {
if (bool && props.trigger === 'manual') {
editNameHandle()
} else {
isEdit.value = false
}
}
)
function dblclick() {
if (props.trigger === 'dblclick') {
editNameHandle()

View File

@ -380,7 +380,7 @@ h5 {
/* tag */
.default-tag {
background: var(--el-color-primary-light-7);
background: var(--el-color-primary-light-8);
color: var(--el-color-primary);
border: none;
}
@ -492,6 +492,9 @@ h5 {
.avatar-green {
background: #34c724;
}
.avatar-grey {
background: #bbbfc4;
}
.success {
color: var(--el-color-success);

View File

@ -0,0 +1,141 @@
<template>
<div class="workflow-publish-history border-l">
<h4 class="border-b p-16-24">发布历史</h4>
<div class="left-height pt-0">
<el-scrollbar>
<div class="p-8 pt-0">
<common-list
:data="LogData"
class="mt-8"
v-loading="loading"
@click.stop="clickListHandle"
@mouseenter="mouseenter"
@mouseleave="mouseId = ''"
>
<template #default="{ row, index }">
<div class="flex-between">
<div style="max-width: 80%">
<h5 :class="index === 0 ? 'primary' : ''" class="flex">
<ReadWrite
@change="editName($event, row)"
:data="row.name || datetimeFormat(row.update_time)"
trigger="manual"
:write="row.writeStatus"
@close="closeWrite(row)"
/>
<el-tag v-if="index === 0" class="default-tag ml-4">最近发布</el-tag>
</h5>
<el-text type="info" class="color-secondary flex mt-8">
<AppAvatar :size="20" class="avatar-grey mr-4">
<el-icon><UserFilled /></el-icon>
</AppAvatar>
{{ row.publish_user_name }}
</el-text>
</div>
<div @click.stop v-show="mouseId === row.id">
<el-dropdown trigger="click" :teleported="false">
<el-button text>
<el-icon><MoreFilled /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click.stop="openEditVersion(row)">
<el-icon><EditPen /></el-icon>
编辑
</el-dropdown-item>
<el-dropdown-item @click="refreshVersion(row)">
<el-icon><RefreshLeft /></el-icon>
恢复此版本
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</template>
<template #empty>
<div class="text-center">
<el-text type="info">暂无历史记录</el-text>
</div>
</template>
</common-list>
</div>
</el-scrollbar>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
import { useRoute } from 'vue-router'
import applicationApi from '@/api/application'
import { datetimeFormat } from '@/utils/time'
import { MsgSuccess, MsgError } from '@/utils/message'
const route = useRoute()
const {
params: { id }
} = route as any
const emit = defineEmits(['click', 'refreshVersion'])
const loading = ref(false)
const LogData = ref<any[]>([])
const mouseId = ref('')
function mouseenter(row: any) {
mouseId.value = row.id
}
function clickListHandle(item: any) {
emit('click', item)
}
function refreshVersion(item: any) {
emit('refreshVersion', item)
}
function openEditVersion(item: any) {
item['writeStatus'] = true
}
function closeWrite(item: any) {
item['writeStatus'] = false
}
function editName(val: string, item: any) {
if (val) {
const obj = {
name: val
}
applicationApi.putWorkFlowVersion(id as string, item.id, obj, loading).then(() => {
MsgSuccess('修改成功')
item['writeStatus'] = false
getList()
})
} else {
MsgError('名字不能为空!')
}
}
function getList() {
applicationApi.getWorkFlowVersion(id, loading).then((res: any) => {
LogData.value = res.data
})
}
onMounted(() => {
getList()
})
</script>
<style lang="scss" scoped>
.workflow-publish-history {
width: 320px;
position: absolute;
right: 0;
top: 57px;
background: #ffffff;
height: calc(100vh - 57px);
z-index: 9;
}
</style>

View File

@ -6,11 +6,24 @@
@click="router.push({ path: `/application/${id}/WORK_FLOW/overview` })"
></back-button>
<h4>{{ detail?.name }}</h4>
<el-text type="info" class="ml-16 color-secondary" v-if="saveTime"
<div v-if="showHistory && disablePublic">
<el-text type="info" class="ml-16 color-secondary"
>预览版本
{{ currentVersion.name || datetimeFormat(currentVersion.update_time) }}</el-text
>
</div>
<el-text type="info" class="ml-16 color-secondary" v-else-if="saveTime"
>保存时间{{ datetimeFormat(saveTime) }}</el-text
>
</div>
<div>
<div v-if="showHistory && disablePublic">
<el-button type="primary" class="mr-8" @click="refreshVersion()"> 恢复版本 </el-button>
<el-divider direction="vertical" />
<el-button text @click="closeHistory">
<el-icon><Close /></el-icon>
</el-button>
</div>
<div v-else>
<el-button icon="Plus" @click="showPopover = !showPopover"> 添加组件 </el-button>
<el-button @click="clickShowDebug" :disabled="showDebug">
<AppIcon iconName="app-play-outlined" class="mr-4"></AppIcon>
@ -21,6 +34,27 @@
保存
</el-button>
<el-button type="primary" @click="publicHandle"> 发布 </el-button>
<el-dropdown trigger="click">
<el-button text @click.stop class="ml-8 mt-4">
<el-icon class="rotate-90"><MoreFilled /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="openHistory">
<AppIcon iconName="app-history-outlined"></AppIcon>
发布历史
</el-dropdown-item>
<el-dropdown-item>
<AppIcon iconName="app-save-outlined"></AppIcon>
自动保存
<div @click.stop class="ml-4">
<el-switch size="small" v-model="isSave" @change="changeSave" />
</div>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
<!-- 下拉框 -->
@ -90,6 +124,13 @@
</div>
</div>
</el-collapse-transition>
<!-- 发布历史 -->
<PublishHistory
v-if="showHistory"
@click="checkVersion"
v-click-outside="clickoutsideHistory"
@refreshVersion="refreshVersion"
/>
</div>
</template>
<script setup lang="ts">
@ -97,6 +138,7 @@ import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import Workflow from '@/workflow/index.vue'
import DropdownMenu from '@/views/application-workflow/component/DropdownMenu.vue'
import PublishHistory from '@/views/application-workflow/component/PublishHistory.vue'
import applicationApi from '@/api/application'
import { isAppIcon } from '@/utils/application'
import { MsgSuccess, MsgConfirm, MsgError } from '@/utils/message'
@ -126,6 +168,57 @@ const showPopover = ref(false)
const showDebug = ref(false)
const enlarge = ref(false)
const saveTime = ref<any>('')
const isSave = ref(false)
const showHistory = ref(false)
const disablePublic = ref(false)
const currentVersion = ref<any>({})
function clickoutsideHistory() {
if (!disablePublic.value) {
showHistory.value = false
}
}
function refreshVersion(item?: any) {
if (item) {
getHistortyDetail(item.id)
}
initInterval()
showHistory.value = false
disablePublic.value = false
}
function checkVersion(item: any) {
disablePublic.value = true
getHistortyDetail(item.id)
currentVersion.value = item
closeInterval()
}
function getHistortyDetail(versionId: string) {
applicationApi.getWorkFlowVersionDetail(id, versionId, loading).then((res: any) => {
res.data?.work_flow['nodes'].map((v: any) => {
v['properties']['noRender'] = true
})
detail.value.stt_model_id = res.data.stt_model
detail.value.tts_model_id = res.data.tts_model
detail.value.tts_type = res.data.tts_type
saveTime.value = res.data?.update_time
})
}
function closeHistory() {
getDetail()
showHistory.value = false
}
function openHistory() {
showHistory.value = true
}
function changeSave(bool: boolean) {
bool ? initInterval() : closeInterval()
localStorage.setItem('workflowAutoSave', bool.toString())
}
function clickNodes(item: any) {
// workflowRef.value?.addNode(item)
@ -136,6 +229,7 @@ function onmousedown(item: any) {
// workflowRef.value?.onmousedown(item)
showPopover.value = false
}
function clickoutside() {
showPopover.value = false
}
@ -256,9 +350,10 @@ const closeInterval = () => {
onMounted(() => {
getDetail()
const workflowAutoSave = localStorage.getItem('workflowAutoSave')
isSave.value = workflowAutoSave === 'true' ? true : false
//
if (hasPermission(`APPLICATION:MANAGE:${id}`, 'AND')) {
if (hasPermission(`APPLICATION:MANAGE:${id}`, 'AND') && workflowAutoSave) {
initInterval()
}
})

View File

@ -64,7 +64,7 @@
<el-scrollbar max-height="300">
<div class="p-8">
<common-list
:data="chatLogeData"
:data="chatLogData"
v-loading="left_loading"
:defaultActive="currentChatId"
@click="clickListHandle"
@ -90,7 +90,7 @@
</template>
</common-list>
</div>
<div v-if="chatLogeData.length" class="gradient-divider lighter mt-8">
<div v-if="chatLogData.length" class="gradient-divider lighter mt-8">
<span>仅显示最近 20 条对话</span>
</div>
</el-scrollbar>
@ -115,7 +115,6 @@ const isDefaultTheme = computed(() => {
const AiChatRef = ref()
const loading = ref(false)
const left_loading = ref(false)
const chatLogeData = ref<any[]>([])
const show = ref(false)
const props = defineProps<{
@ -185,7 +184,7 @@ function getChatLog(id: string) {
}
log.asyncGetChatLogClient(id, page, left_loading).then((res: any) => {
chatLogeData.value = res.data.records
chatLogData.value = res.data.records
})
}

View File

@ -38,7 +38,7 @@
<el-scrollbar>
<div class="p-8 pt-0">
<common-list
:data="chatLogeData"
:data="chatLogData"
class="mt-8"
v-loading="left_loading"
:defaultActive="currentChatId"
@ -66,7 +66,7 @@
</template>
</common-list>
</div>
<div v-if="chatLogeData.length" class="gradient-divider lighter mt-8">
<div v-if="chatLogData.length" class="gradient-divider lighter mt-8">
<span>仅显示最近 20 条对话</span>
</div>
</el-scrollbar>
@ -161,6 +161,7 @@ const AiChatRef = ref()
const loading = ref(false)
const left_loading = ref(false)
const applicationDetail = computed({
get: () => {
return props.application_profile
@ -212,11 +213,11 @@ function handleScroll(event: any) {
}
function newChat() {
if (!chatLogeData.value.some((v) => v.id === 'new')) {
if (!chatLogData.value.some((v) => v.id === 'new')) {
paginationConfig.value.current_page = 1
paginationConfig.value.total = 0
currentRecordList.value = []
chatLogeData.value.unshift(newObj)
chatLogData.value.unshift(newObj)
} else {
paginationConfig.value.current_page = 1
paginationConfig.value.total = 0
@ -236,9 +237,9 @@ function getChatLog(id: string, refresh?: boolean) {
}
log.asyncGetChatLogClient(id, page, left_loading).then((res: any) => {
chatLogeData.value = res.data.records
chatLogData.value = res.data.records
if (refresh) {
currentChatName.value = chatLogeData.value[0].abstract
currentChatName.value = chatLogData.value[0].abstract
}
})
}