refactor: 对话秘钥校验 (#1430)
This commit is contained in:
parent
5973957037
commit
23c7269231
@ -36,7 +36,7 @@ from common.db.sql_execute import select_list
|
|||||||
from common.exception.app_exception import AppApiException, NotFound404, AppUnauthorizedFailed
|
from common.exception.app_exception import AppApiException, NotFound404, AppUnauthorizedFailed
|
||||||
from common.field.common import UploadedImageField
|
from common.field.common import UploadedImageField
|
||||||
from common.models.db_model_manage import DBModelManage
|
from common.models.db_model_manage import DBModelManage
|
||||||
from common.util.common import valid_license
|
from common.util.common import valid_license, password_encrypt
|
||||||
from common.util.field_message import ErrMessage
|
from common.util.field_message import ErrMessage
|
||||||
from common.util.file_util import get_file_content
|
from common.util.file_util import get_file_content
|
||||||
from dataset.models import DataSet, Document, Image
|
from dataset.models import DataSet, Document, Image
|
||||||
@ -264,7 +264,9 @@ class ApplicationSerializer(serializers.Serializer):
|
|||||||
if work_flow is not None:
|
if work_flow is not None:
|
||||||
for node in work_flow.get('nodes', []):
|
for node in work_flow.get('nodes', []):
|
||||||
if node['id'] == 'base-node':
|
if node['id'] == 'base-node':
|
||||||
input_field_list = node.get('properties', {}).get('api_input_field_list', node.get('properties', {}).get('input_field_list', []))
|
input_field_list = node.get('properties', {}).get('api_input_field_list',
|
||||||
|
node.get('properties', {}).get(
|
||||||
|
'input_field_list', []))
|
||||||
if input_field_list is not None:
|
if input_field_list is not None:
|
||||||
for field in input_field_list:
|
for field in input_field_list:
|
||||||
if field['assignment_method'] == 'api_input' and field['variable'] in params:
|
if field['assignment_method'] == 'api_input' and field['variable'] in params:
|
||||||
@ -352,6 +354,8 @@ class ApplicationSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
class Authentication(serializers.Serializer):
|
class Authentication(serializers.Serializer):
|
||||||
access_token = serializers.CharField(required=True, error_messages=ErrMessage.char("access_token"))
|
access_token = serializers.CharField(required=True, error_messages=ErrMessage.char("access_token"))
|
||||||
|
authentication_value = serializers.JSONField(required=False, allow_null=True,
|
||||||
|
error_messages=ErrMessage.char("认证信息"))
|
||||||
|
|
||||||
def auth(self, request, with_valid=True):
|
def auth(self, request, with_valid=True):
|
||||||
token = request.META.get('HTTP_AUTHORIZATION')
|
token = request.META.get('HTTP_AUTHORIZATION')
|
||||||
@ -366,21 +370,47 @@ class ApplicationSerializer(serializers.Serializer):
|
|||||||
self.is_valid(raise_exception=True)
|
self.is_valid(raise_exception=True)
|
||||||
access_token = self.data.get("access_token")
|
access_token = self.data.get("access_token")
|
||||||
application_access_token = QuerySet(ApplicationAccessToken).filter(access_token=access_token).first()
|
application_access_token = QuerySet(ApplicationAccessToken).filter(access_token=access_token).first()
|
||||||
|
authentication_value = self.data.get('authentication_value', None)
|
||||||
|
authentication = {}
|
||||||
if application_access_token is not None and application_access_token.is_active:
|
if application_access_token is not None and application_access_token.is_active:
|
||||||
if token_details is not None and 'client_id' in token_details and token_details.get(
|
if token_details is not None and 'client_id' in token_details and token_details.get(
|
||||||
'client_id') is not None:
|
'client_id') is not None:
|
||||||
client_id = token_details.get('client_id')
|
client_id = token_details.get('client_id')
|
||||||
|
authentication = {'type': token_details.get('type'),
|
||||||
|
'value': token_details.get('value')}
|
||||||
else:
|
else:
|
||||||
client_id = str(uuid.uuid1())
|
client_id = str(uuid.uuid1())
|
||||||
|
if authentication_value is not None:
|
||||||
|
# 认证用户token
|
||||||
|
self.auth_authentication_value(authentication_value, str(application_access_token.application_id))
|
||||||
|
authentication = {'type': authentication_value.get('type'),
|
||||||
|
'value': password_encrypt(authentication_value.get('value'))}
|
||||||
token = signing.dumps({'application_id': str(application_access_token.application_id),
|
token = signing.dumps({'application_id': str(application_access_token.application_id),
|
||||||
'user_id': str(application_access_token.application.user.id),
|
'user_id': str(application_access_token.application.user.id),
|
||||||
'access_token': application_access_token.access_token,
|
'access_token': application_access_token.access_token,
|
||||||
'type': AuthenticationType.APPLICATION_ACCESS_TOKEN.value,
|
'type': AuthenticationType.APPLICATION_ACCESS_TOKEN.value,
|
||||||
'client_id': client_id})
|
'client_id': client_id
|
||||||
|
, **authentication})
|
||||||
return token
|
return token
|
||||||
else:
|
else:
|
||||||
raise NotFound404(404, "无效的access_token")
|
raise NotFound404(404, "无效的access_token")
|
||||||
|
|
||||||
|
def auth_authentication_value(self, authentication_value, application_id):
|
||||||
|
application_setting_model = DBModelManage.get_model('application_setting')
|
||||||
|
xpack_cache = DBModelManage.get_model('xpack_cache')
|
||||||
|
X_PACK_LICENSE_IS_VALID = False if xpack_cache is None else xpack_cache.get('XPACK_LICENSE_IS_VALID', False)
|
||||||
|
if application_setting_model is not None and X_PACK_LICENSE_IS_VALID:
|
||||||
|
application_setting = QuerySet(application_setting_model).filter(application_id=application_id).first()
|
||||||
|
if application_setting.authentication and authentication_value is not None:
|
||||||
|
if authentication_value.get('type') == 'password':
|
||||||
|
if not self.auth_password(authentication_value, application_setting.authentication_value):
|
||||||
|
raise AppApiException(1005, "密码错误")
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def auth_password(source_authentication_value, authentication_value):
|
||||||
|
return source_authentication_value.get('value') == authentication_value.get('value')
|
||||||
|
|
||||||
class Edit(serializers.Serializer):
|
class Edit(serializers.Serializer):
|
||||||
name = serializers.CharField(required=False, max_length=64, min_length=1,
|
name = serializers.CharField(required=False, max_length=64, min_length=1,
|
||||||
error_messages=ErrMessage.char("应用名称"))
|
error_messages=ErrMessage.char("应用名称"))
|
||||||
@ -762,6 +792,8 @@ class ApplicationSerializer(serializers.Serializer):
|
|||||||
'avatar': application_setting.avatar,
|
'avatar': application_setting.avatar,
|
||||||
'float_icon': application_setting.float_icon,
|
'float_icon': application_setting.float_icon,
|
||||||
'authentication': application_setting.authentication,
|
'authentication': application_setting.authentication,
|
||||||
|
'authentication_type': application_setting.authentication_value.get(
|
||||||
|
'type', 'password'),
|
||||||
'disclaimer': application_setting.disclaimer,
|
'disclaimer': application_setting.disclaimer,
|
||||||
'disclaimer_value': application_setting.disclaimer_value,
|
'disclaimer_value': application_setting.disclaimer_value,
|
||||||
'custom_theme': application_setting.custom_theme,
|
'custom_theme': application_setting.custom_theme,
|
||||||
|
|||||||
@ -376,7 +376,9 @@ class Application(APIView):
|
|||||||
security=[])
|
security=[])
|
||||||
def post(self, request: Request):
|
def post(self, request: Request):
|
||||||
return result.success(
|
return result.success(
|
||||||
ApplicationSerializer.Authentication(data={'access_token': request.data.get("access_token")}).auth(
|
ApplicationSerializer.Authentication(data={'access_token': request.data.get("access_token"),
|
||||||
|
'authentication_value': request.data.get(
|
||||||
|
'authentication_value')}).auth(
|
||||||
request),
|
request),
|
||||||
headers={"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Credentials": "true",
|
headers={"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Credentials": "true",
|
||||||
"Access-Control-Allow-Methods": "POST",
|
"Access-Control-Allow-Methods": "POST",
|
||||||
@ -539,12 +541,13 @@ class Application(APIView):
|
|||||||
authentication_classes = [TokenAuth]
|
authentication_classes = [TokenAuth]
|
||||||
|
|
||||||
@action(methods=['POST'], detail=False)
|
@action(methods=['POST'], detail=False)
|
||||||
@has_permissions(ViewPermission([RoleConstants.ADMIN, RoleConstants.USER, RoleConstants.APPLICATION_ACCESS_TOKEN],
|
@has_permissions(
|
||||||
[lambda r, keywords: Permission(group=Group.APPLICATION,
|
ViewPermission([RoleConstants.ADMIN, RoleConstants.USER, RoleConstants.APPLICATION_ACCESS_TOKEN],
|
||||||
operate=Operate.USE,
|
[lambda r, keywords: Permission(group=Group.APPLICATION,
|
||||||
dynamic_tag=keywords.get(
|
operate=Operate.USE,
|
||||||
'application_id'))],
|
dynamic_tag=keywords.get(
|
||||||
compare=CompareConstants.AND))
|
'application_id'))],
|
||||||
|
compare=CompareConstants.AND))
|
||||||
def post(self, request: Request, application_id: str):
|
def post(self, request: Request, application_id: str):
|
||||||
return result.success(
|
return result.success(
|
||||||
ApplicationSerializer.Operate(data={'application_id': application_id, 'user_id': request.user.id})
|
ApplicationSerializer.Operate(data={'application_id': application_id, 'user_id': request.user.id})
|
||||||
@ -554,31 +557,33 @@ class Application(APIView):
|
|||||||
authentication_classes = [TokenAuth]
|
authentication_classes = [TokenAuth]
|
||||||
|
|
||||||
@action(methods=['POST'], detail=False)
|
@action(methods=['POST'], detail=False)
|
||||||
@has_permissions(ViewPermission([RoleConstants.ADMIN, RoleConstants.USER, RoleConstants.APPLICATION_ACCESS_TOKEN],
|
@has_permissions(
|
||||||
[lambda r, keywords: Permission(group=Group.APPLICATION,
|
ViewPermission([RoleConstants.ADMIN, RoleConstants.USER, RoleConstants.APPLICATION_ACCESS_TOKEN],
|
||||||
operate=Operate.USE,
|
[lambda r, keywords: Permission(group=Group.APPLICATION,
|
||||||
dynamic_tag=keywords.get(
|
operate=Operate.USE,
|
||||||
'application_id'))],
|
dynamic_tag=keywords.get(
|
||||||
compare=CompareConstants.AND))
|
'application_id'))],
|
||||||
|
compare=CompareConstants.AND))
|
||||||
def post(self, request: Request, application_id: str):
|
def post(self, request: Request, application_id: str):
|
||||||
byte_data = ApplicationSerializer.Operate(
|
byte_data = ApplicationSerializer.Operate(
|
||||||
data={'application_id': application_id, 'user_id': request.user.id}).text_to_speech(
|
data={'application_id': application_id, 'user_id': request.user.id}).text_to_speech(
|
||||||
request.data.get('text'))
|
request.data.get('text'))
|
||||||
return HttpResponse(byte_data, status=200, headers={'Content-Type': 'audio/mp3',
|
return HttpResponse(byte_data, status=200, headers={'Content-Type': 'audio/mp3',
|
||||||
'Content-Disposition': 'attachment; filename="abc.mp3"'})
|
'Content-Disposition': 'attachment; filename="abc.mp3"'})
|
||||||
|
|
||||||
class PlayDemoText(APIView):
|
class PlayDemoText(APIView):
|
||||||
authentication_classes = [TokenAuth]
|
authentication_classes = [TokenAuth]
|
||||||
|
|
||||||
@action(methods=['POST'], detail=False)
|
@action(methods=['POST'], detail=False)
|
||||||
@has_permissions(ViewPermission([RoleConstants.ADMIN, RoleConstants.USER, RoleConstants.APPLICATION_ACCESS_TOKEN],
|
@has_permissions(
|
||||||
[lambda r, keywords: Permission(group=Group.APPLICATION,
|
ViewPermission([RoleConstants.ADMIN, RoleConstants.USER, RoleConstants.APPLICATION_ACCESS_TOKEN],
|
||||||
operate=Operate.USE,
|
[lambda r, keywords: Permission(group=Group.APPLICATION,
|
||||||
dynamic_tag=keywords.get(
|
operate=Operate.USE,
|
||||||
'application_id'))],
|
dynamic_tag=keywords.get(
|
||||||
compare=CompareConstants.AND))
|
'application_id'))],
|
||||||
|
compare=CompareConstants.AND))
|
||||||
def post(self, request: Request, application_id: str):
|
def post(self, request: Request, application_id: str):
|
||||||
byte_data = ApplicationSerializer.Operate(
|
byte_data = ApplicationSerializer.Operate(
|
||||||
data={'application_id': application_id, 'user_id': request.user.id}).play_demo_text(request.data)
|
data={'application_id': application_id, 'user_id': request.user.id}).play_demo_text(request.data)
|
||||||
return HttpResponse(byte_data, status=200, headers={'Content-Type': 'audio/mp3',
|
return HttpResponse(byte_data, status=200, headers={'Content-Type': 'audio/mp3',
|
||||||
'Content-Disposition': 'attachment; filename="abc.mp3"'})
|
'Content-Disposition': 'attachment; filename="abc.mp3"'})
|
||||||
|
|||||||
@ -12,7 +12,9 @@ from application.models.api_key_model import ApplicationAccessToken
|
|||||||
from common.auth.handle.auth_base_handle import AuthBaseHandle
|
from common.auth.handle.auth_base_handle import AuthBaseHandle
|
||||||
from common.constants.authentication_type import AuthenticationType
|
from common.constants.authentication_type import AuthenticationType
|
||||||
from common.constants.permission_constants import RoleConstants, Permission, Group, Operate, Auth
|
from common.constants.permission_constants import RoleConstants, Permission, Group, Operate, Auth
|
||||||
from common.exception.app_exception import AppAuthenticationFailed
|
from common.exception.app_exception import AppAuthenticationFailed, ChatException
|
||||||
|
from common.models.db_model_manage import DBModelManage
|
||||||
|
from common.util.common import password_encrypt
|
||||||
|
|
||||||
|
|
||||||
class PublicAccessToken(AuthBaseHandle):
|
class PublicAccessToken(AuthBaseHandle):
|
||||||
@ -29,6 +31,20 @@ class PublicAccessToken(AuthBaseHandle):
|
|||||||
auth_details = get_token_details()
|
auth_details = get_token_details()
|
||||||
application_access_token = QuerySet(ApplicationAccessToken).filter(
|
application_access_token = QuerySet(ApplicationAccessToken).filter(
|
||||||
application_id=auth_details.get('application_id')).first()
|
application_id=auth_details.get('application_id')).first()
|
||||||
|
application_setting_model = DBModelManage.get_model('application_setting')
|
||||||
|
xpack_cache = DBModelManage.get_model('xpack_cache')
|
||||||
|
X_PACK_LICENSE_IS_VALID = False if xpack_cache is None else xpack_cache.get('XPACK_LICENSE_IS_VALID', False)
|
||||||
|
if application_setting_model is not None and X_PACK_LICENSE_IS_VALID:
|
||||||
|
application_setting = QuerySet(application_setting_model).filter(application_id=str(
|
||||||
|
application_access_token.application_id)).first()
|
||||||
|
if application_setting.authentication:
|
||||||
|
authentication = auth_details.get('authentication', {})
|
||||||
|
if authentication is None:
|
||||||
|
authentication = {}
|
||||||
|
if application_setting.authentication_value.get('type') != authentication.get(
|
||||||
|
'type') or password_encrypt(
|
||||||
|
application_setting.authentication_value.get('value')) != authentication.get('value'):
|
||||||
|
raise ChatException(1002, "身份验证信息不正确")
|
||||||
if application_access_token is None:
|
if application_access_token is None:
|
||||||
raise AppAuthenticationFailed(1002, "身份验证信息不正确")
|
raise AppAuthenticationFailed(1002, "身份验证信息不正确")
|
||||||
if not application_access_token.is_active:
|
if not application_access_token.is_active:
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
@date:2023/10/16 16:42
|
@date:2023/10/16 16:42
|
||||||
@desc:
|
@desc:
|
||||||
"""
|
"""
|
||||||
|
import hashlib
|
||||||
import importlib
|
import importlib
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
@ -62,6 +63,18 @@ def flat_map(array: List[List]):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def password_encrypt(raw_password):
|
||||||
|
"""
|
||||||
|
密码 md5加密
|
||||||
|
:param raw_password: 密码
|
||||||
|
:return: 加密后密码
|
||||||
|
"""
|
||||||
|
md5 = hashlib.md5() # 2,实例化md5() 方法
|
||||||
|
md5.update(raw_password.encode()) # 3,对字符串的字节类型加密
|
||||||
|
result = md5.hexdigest() # 4,加密
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def post(post_function):
|
def post(post_function):
|
||||||
def inner(func):
|
def inner(func):
|
||||||
def run(*args, **kwargs):
|
def run(*args, **kwargs):
|
||||||
|
|||||||
@ -122,11 +122,17 @@ const putAccessToken: (
|
|||||||
"access_token": "string"
|
"access_token": "string"
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
const postAppAuthentication: (access_token: string, loading?: Ref<boolean>) => Promise<any> = (
|
const postAppAuthentication: (
|
||||||
access_token,
|
access_token: string,
|
||||||
loading
|
loading?: Ref<boolean>,
|
||||||
) => {
|
authentication_value?: any
|
||||||
return post(`${prefix}/authentication`, { access_token }, undefined, loading)
|
) => Promise<any> = (access_token, loading, authentication_value) => {
|
||||||
|
return post(
|
||||||
|
`${prefix}/authentication`,
|
||||||
|
{ access_token: access_token, authentication_value },
|
||||||
|
undefined,
|
||||||
|
loading
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -365,8 +365,7 @@ function handleInputFieldList() {
|
|||||||
?.filter((v: any) => v.id === 'base-node')
|
?.filter((v: any) => v.id === 'base-node')
|
||||||
.map((v: any) => {
|
.map((v: any) => {
|
||||||
inputFieldList.value = v.properties.user_input_field_list
|
inputFieldList.value = v.properties.user_input_field_list
|
||||||
? v.properties.user_input_field_list
|
? v.properties.user_input_field_list.map((v: any) => {
|
||||||
.map((v: any) => {
|
|
||||||
switch (v.type) {
|
switch (v.type) {
|
||||||
case 'input':
|
case 'input':
|
||||||
return {
|
return {
|
||||||
@ -404,51 +403,51 @@ function handleInputFieldList() {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
: v.properties.input_field_list ? v.properties.input_field_list
|
: v.properties.input_field_list
|
||||||
.filter((v: any) => v.assignment_method === 'user_input')
|
? v.properties.input_field_list
|
||||||
.map((v: any) => {
|
.filter((v: any) => v.assignment_method === 'user_input')
|
||||||
switch (v.type) {
|
.map((v: any) => {
|
||||||
case 'input':
|
switch (v.type) {
|
||||||
return {
|
case 'input':
|
||||||
field: v.variable,
|
return {
|
||||||
input_type: 'TextInput',
|
field: v.variable,
|
||||||
label: v.name,
|
input_type: 'TextInput',
|
||||||
default_value: default_value[v.variable],
|
label: v.name,
|
||||||
required: v.is_required
|
default_value: default_value[v.variable],
|
||||||
}
|
required: v.is_required
|
||||||
case 'select':
|
|
||||||
return {
|
|
||||||
field: v.variable,
|
|
||||||
input_type: 'SingleSelect',
|
|
||||||
label: v.name,
|
|
||||||
default_value: default_value[v.variable],
|
|
||||||
required: v.is_required,
|
|
||||||
option_list: v.optionList.map((o: any) => {
|
|
||||||
return { key: o, value: o }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
case 'date':
|
|
||||||
return {
|
|
||||||
field: v.variable,
|
|
||||||
input_type: 'DatePicker',
|
|
||||||
label: v.name,
|
|
||||||
default_value: default_value[v.variable],
|
|
||||||
required: v.is_required,
|
|
||||||
attrs: {
|
|
||||||
format: 'YYYY-MM-DD HH:mm:ss',
|
|
||||||
'value-format': 'YYYY-MM-DD HH:mm:ss',
|
|
||||||
type: 'datetime'
|
|
||||||
}
|
}
|
||||||
}
|
case 'select':
|
||||||
default:
|
return {
|
||||||
break
|
field: v.variable,
|
||||||
}
|
input_type: 'SingleSelect',
|
||||||
})
|
label: v.name,
|
||||||
|
default_value: default_value[v.variable],
|
||||||
|
required: v.is_required,
|
||||||
|
option_list: v.optionList.map((o: any) => {
|
||||||
|
return { key: o, value: o }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
case 'date':
|
||||||
|
return {
|
||||||
|
field: v.variable,
|
||||||
|
input_type: 'DatePicker',
|
||||||
|
label: v.name,
|
||||||
|
default_value: default_value[v.variable],
|
||||||
|
required: v.is_required,
|
||||||
|
attrs: {
|
||||||
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
'value-format': 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
type: 'datetime'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
: []
|
: []
|
||||||
|
|
||||||
apiInputFieldList.value = v.properties.api_input_field_list
|
apiInputFieldList.value = v.properties.api_input_field_list
|
||||||
? v.properties.api_input_field_list
|
? v.properties.api_input_field_list.map((v: any) => {
|
||||||
.map((v: any) => {
|
|
||||||
switch (v.type) {
|
switch (v.type) {
|
||||||
case 'input':
|
case 'input':
|
||||||
return {
|
return {
|
||||||
@ -488,45 +487,45 @@ function handleInputFieldList() {
|
|||||||
})
|
})
|
||||||
: v.properties.input_field_list
|
: v.properties.input_field_list
|
||||||
? v.properties.input_field_list
|
? v.properties.input_field_list
|
||||||
.filter((v: any) => v.assignment_method === 'api_input')
|
.filter((v: any) => v.assignment_method === 'api_input')
|
||||||
.map((v: any) => {
|
.map((v: any) => {
|
||||||
switch (v.type) {
|
switch (v.type) {
|
||||||
case 'input':
|
case 'input':
|
||||||
return {
|
return {
|
||||||
field: v.variable,
|
field: v.variable,
|
||||||
input_type: 'TextInput',
|
input_type: 'TextInput',
|
||||||
label: v.name,
|
label: v.name,
|
||||||
default_value: default_value[v.variable],
|
default_value: default_value[v.variable],
|
||||||
required: v.is_required
|
required: v.is_required
|
||||||
}
|
|
||||||
case 'select':
|
|
||||||
return {
|
|
||||||
field: v.variable,
|
|
||||||
input_type: 'SingleSelect',
|
|
||||||
label: v.name,
|
|
||||||
default_value: default_value[v.variable],
|
|
||||||
required: v.is_required,
|
|
||||||
option_list: v.optionList.map((o: any) => {
|
|
||||||
return { key: o, value: o }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
case 'date':
|
|
||||||
return {
|
|
||||||
field: v.variable,
|
|
||||||
input_type: 'DatePicker',
|
|
||||||
label: v.name,
|
|
||||||
default_value: default_value[v.variable],
|
|
||||||
required: v.is_required,
|
|
||||||
attrs: {
|
|
||||||
format: 'YYYY-MM-DD HH:mm:ss',
|
|
||||||
'value-format': 'YYYY-MM-DD HH:mm:ss',
|
|
||||||
type: 'datetime'
|
|
||||||
}
|
}
|
||||||
}
|
case 'select':
|
||||||
default:
|
return {
|
||||||
break
|
field: v.variable,
|
||||||
}
|
input_type: 'SingleSelect',
|
||||||
})
|
label: v.name,
|
||||||
|
default_value: default_value[v.variable],
|
||||||
|
required: v.is_required,
|
||||||
|
option_list: v.optionList.map((o: any) => {
|
||||||
|
return { key: o, value: o }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
case 'date':
|
||||||
|
return {
|
||||||
|
field: v.variable,
|
||||||
|
input_type: 'DatePicker',
|
||||||
|
label: v.name,
|
||||||
|
default_value: default_value[v.variable],
|
||||||
|
required: v.is_required,
|
||||||
|
attrs: {
|
||||||
|
format: 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
'value-format': 'YYYY-MM-DD HH:mm:ss',
|
||||||
|
type: 'datetime'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
: []
|
: []
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -912,7 +911,7 @@ const mediaRecorderStatus = ref(true)
|
|||||||
const startRecording = async () => {
|
const startRecording = async () => {
|
||||||
try {
|
try {
|
||||||
// 取消录音控制台日志
|
// 取消录音控制台日志
|
||||||
Recorder.CLog=function(){}
|
Recorder.CLog = function () {}
|
||||||
mediaRecorderStatus.value = false
|
mediaRecorderStatus.value = false
|
||||||
handleTimeChange()
|
handleTimeChange()
|
||||||
mediaRecorder.value = new Recorder({
|
mediaRecorder.value = new Recorder({
|
||||||
|
|||||||
@ -40,6 +40,9 @@ instance.interceptors.response.use(
|
|||||||
(response: any) => {
|
(response: any) => {
|
||||||
if (response.data) {
|
if (response.data) {
|
||||||
if (response.data.code !== 200 && !(response.data instanceof Blob)) {
|
if (response.data.code !== 200 && !(response.data instanceof Blob)) {
|
||||||
|
if (response.config.url.includes('/application/authentication')) {
|
||||||
|
return Promise.reject(response.data)
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
!response.config.url.includes('/valid') &&
|
!response.config.url.includes('/valid') &&
|
||||||
!response.config.url.includes('/function_lib/debug')
|
!response.config.url.includes('/function_lib/debug')
|
||||||
|
|||||||
@ -89,10 +89,14 @@ const useApplicationStore = defineStore({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async asyncAppAuthentication(token: string, loading?: Ref<boolean>) {
|
async asyncAppAuthentication(
|
||||||
|
token: string,
|
||||||
|
loading?: Ref<boolean>,
|
||||||
|
authentication_value?: any
|
||||||
|
) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
applicationApi
|
applicationApi
|
||||||
.postAppAuthentication(token, loading)
|
.postAppAuthentication(token, loading, authentication_value)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
localStorage.setItem('accessToken', res.data)
|
localStorage.setItem('accessToken', res.data)
|
||||||
sessionStorage.setItem('accessToken', res.data)
|
sessionStorage.setItem('accessToken', res.data)
|
||||||
|
|||||||
83
ui/src/views/chat/auth/component/password.vue
Normal file
83
ui/src/views/chat/auth/component/password.vue
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
:modelValue="show"
|
||||||
|
modal-class="positioned-mask"
|
||||||
|
width="300"
|
||||||
|
title="请输入密码打开链接"
|
||||||
|
custom-class="no-close-button"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
:show-close="false"
|
||||||
|
top="25vh"
|
||||||
|
center
|
||||||
|
:modal="true"
|
||||||
|
>
|
||||||
|
<el-form ref="FormRef" :model="form">
|
||||||
|
<el-form-item prop="value" :rules="rules.value">
|
||||||
|
<el-input show-password v-model="form.value" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-button class="w-full mt-8" type="primary" @click="validator" :loading="loading"
|
||||||
|
>确定</el-button
|
||||||
|
>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import useStore from '@/stores'
|
||||||
|
const route = useRoute()
|
||||||
|
const FormRef = ref()
|
||||||
|
const {
|
||||||
|
params: { accessToken }
|
||||||
|
} = route as any
|
||||||
|
const { application } = useStore()
|
||||||
|
const props = defineProps<{ applicationProfile: any; modelValue: boolean }>()
|
||||||
|
const loading = ref<boolean>(false)
|
||||||
|
const show = computed(() => {
|
||||||
|
if (props.applicationProfile) {
|
||||||
|
if (props.modelValue) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return props.applicationProfile.authentication
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const auth = () => {
|
||||||
|
return application.asyncAppAuthentication(accessToken, loading, form.value).then(() => {
|
||||||
|
emit('update:modelValue', true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const validator_auth = (rule: any, value: string, callback: any) => {
|
||||||
|
if (value === '') {
|
||||||
|
callback(new Error('密码不能为空'))
|
||||||
|
} else {
|
||||||
|
auth().catch(() => {
|
||||||
|
callback(new Error('密码错误'))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const validator = () => {
|
||||||
|
FormRef.value.validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
value: [{ required: true, validator: validator_auth, trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = ref({
|
||||||
|
type: 'password',
|
||||||
|
value: ''
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.positioned-mask {
|
||||||
|
top: var(--app-header-height);
|
||||||
|
height: calc(100% - var(--app-header-height));
|
||||||
|
.el-overlay-dialog {
|
||||||
|
top: var(--app-header-height);
|
||||||
|
height: calc(100% - var(--app-header-height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
56
ui/src/views/chat/auth/index.vue
Normal file
56
ui/src/views/chat/auth/index.vue
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<div class="chat-pc__header">
|
||||||
|
<div class="flex align-center">
|
||||||
|
<div class="mr-12 ml-24 flex">
|
||||||
|
<AppAvatar
|
||||||
|
v-if="isAppIcon(application_profile?.icon)"
|
||||||
|
shape="square"
|
||||||
|
:size="32"
|
||||||
|
style="background: none"
|
||||||
|
>
|
||||||
|
<img :src="application_profile?.icon" alt="" />
|
||||||
|
</AppAvatar>
|
||||||
|
<AppAvatar
|
||||||
|
v-else-if="application_profile?.name"
|
||||||
|
:name="application_profile?.name"
|
||||||
|
pinyinColor
|
||||||
|
shape="square"
|
||||||
|
:size="32"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<h4>{{ application_profile?.name }}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<component
|
||||||
|
:is="auth_components[`/src/views/chat/auth/component/${auth_type}.vue`].default"
|
||||||
|
v-model="is_auth"
|
||||||
|
:applicationProfile="application_profile"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { isAppIcon } from '@/utils/application'
|
||||||
|
const auth_components: any = import.meta.glob('@/views/chat/auth/component/*.vue', {
|
||||||
|
eager: true
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{ modelValue: boolean; application_profile: any; auth_type?: string }>(),
|
||||||
|
{
|
||||||
|
auth_type: 'password'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const is_auth = computed({
|
||||||
|
get: () => {
|
||||||
|
return props.modelValue
|
||||||
|
},
|
||||||
|
set: (v) => {
|
||||||
|
emit('update:modelValue', v)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss"></style>
|
||||||
@ -34,49 +34,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
|
||||||
import { isAppIcon } from '@/utils/application'
|
import { isAppIcon } from '@/utils/application'
|
||||||
import useStore from '@/stores'
|
import useStore from '@/stores'
|
||||||
const route = useRoute()
|
|
||||||
const {
|
|
||||||
params: { accessToken }
|
|
||||||
} = route as any
|
|
||||||
|
|
||||||
const { application, user } = useStore()
|
const { user } = useStore()
|
||||||
|
|
||||||
const isDefaultTheme = computed(() => {
|
const isDefaultTheme = computed(() => {
|
||||||
return user.isDefaultTheme()
|
return user.isDefaultTheme()
|
||||||
})
|
})
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const applicationDetail = ref<any>({})
|
const props = defineProps<{
|
||||||
const applicationAvailable = ref<boolean>(true)
|
application_profile: any
|
||||||
|
applicationAvailable: boolean
|
||||||
function getAccessToken(token: string) {
|
}>()
|
||||||
application
|
const applicationDetail = computed({
|
||||||
.asyncAppAuthentication(token, loading)
|
get: () => {
|
||||||
.then(() => {
|
return props.application_profile
|
||||||
getAppProfile()
|
},
|
||||||
})
|
set: (v) => {}
|
||||||
.catch(() => {
|
|
||||||
applicationAvailable.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
function getAppProfile() {
|
|
||||||
application
|
|
||||||
.asyncGetAppProfile(loading)
|
|
||||||
.then((res: any) => {
|
|
||||||
applicationDetail.value = res.data
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
applicationAvailable.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
user.changeUserType(2)
|
|
||||||
getAccessToken(accessToken)
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@ -1,31 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="chat-embed layout-bg" v-loading="loading">
|
<div class="chat-embed layout-bg" v-loading="loading">
|
||||||
<el-dialog
|
|
||||||
v-model="isPasswordDialogVisible"
|
|
||||||
width="300"
|
|
||||||
title="请输入密码打开链接"
|
|
||||||
custom-class="no-close-button"
|
|
||||||
:close-on-click-modal="false"
|
|
||||||
:close-on-press-escape="false"
|
|
||||||
:show-close="false"
|
|
||||||
align-center
|
|
||||||
center
|
|
||||||
:modal="true"
|
|
||||||
>
|
|
||||||
<el-form ref="FormRef" :model="form" :rules="rules" v-loading="validateLoading">
|
|
||||||
<el-form-item prop="password">
|
|
||||||
<el-input
|
|
||||||
v-model="form.password"
|
|
||||||
:placeholder="$t('login.ldap.passwordPlaceholder')"
|
|
||||||
show-password
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-button class="w-full mt-8" type="primary" @click="submitHandle(FormRef)"
|
|
||||||
>确定</el-button
|
|
||||||
>
|
|
||||||
</el-form>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<div class="chat-embed__header" :class="!isDefaultTheme ? 'custom-header' : ''">
|
<div class="chat-embed__header" :class="!isDefaultTheme ? 'custom-header' : ''">
|
||||||
<div class="chat-width flex align-center">
|
<div class="chat-width flex align-center">
|
||||||
<div class="mr-12 ml-24 flex">
|
<div class="mr-12 ml-24 flex">
|
||||||
@ -49,7 +23,7 @@
|
|||||||
<h4>{{ applicationDetail?.name }}</h4>
|
<h4>{{ applicationDetail?.name }}</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isAuthenticated">
|
<div>
|
||||||
<div class="chat-embed__main">
|
<div class="chat-embed__main">
|
||||||
<AiChat
|
<AiChat
|
||||||
ref="AiChatRef"
|
ref="AiChatRef"
|
||||||
@ -128,16 +102,11 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, reactive, nextTick, computed } from 'vue'
|
import { ref, onMounted, reactive, nextTick, computed } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
|
||||||
import { isAppIcon } from '@/utils/application'
|
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
|
||||||
import useStore from '@/stores'
|
|
||||||
const route = useRoute()
|
|
||||||
const {
|
|
||||||
params: { accessToken }
|
|
||||||
} = route as any
|
|
||||||
|
|
||||||
const { application, user, log } = useStore()
|
import { isAppIcon } from '@/utils/application'
|
||||||
|
import useStore from '@/stores'
|
||||||
|
|
||||||
|
const { user, log } = useStore()
|
||||||
|
|
||||||
const isDefaultTheme = computed(() => {
|
const isDefaultTheme = computed(() => {
|
||||||
return user.isDefaultTheme()
|
return user.isDefaultTheme()
|
||||||
@ -146,47 +115,19 @@ const isDefaultTheme = computed(() => {
|
|||||||
const AiChatRef = ref()
|
const AiChatRef = ref()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const left_loading = ref(false)
|
const left_loading = ref(false)
|
||||||
const applicationDetail = ref<any>({})
|
|
||||||
const applicationAvailable = ref<boolean>(true)
|
|
||||||
const chatLogeData = ref<any[]>([])
|
const chatLogeData = ref<any[]>([])
|
||||||
const show = ref(false)
|
const show = ref(false)
|
||||||
|
const props = defineProps<{
|
||||||
const FormRef = ref()
|
application_profile: any
|
||||||
|
applicationAvailable: boolean
|
||||||
const isPasswordDialogVisible = ref(false)
|
}>()
|
||||||
const validateLoading = ref(false)
|
const applicationDetail = computed({
|
||||||
|
get: () => {
|
||||||
const form = ref({
|
return props.application_profile
|
||||||
password: ''
|
},
|
||||||
|
set: (v) => {}
|
||||||
})
|
})
|
||||||
|
|
||||||
const isAuthenticated = ref(false)
|
|
||||||
|
|
||||||
const validateName = (rule: any, value: string, callback: any) => {
|
|
||||||
if (value === '') {
|
|
||||||
callback(new Error('密码不能为空'))
|
|
||||||
} else {
|
|
||||||
application
|
|
||||||
.validatePassword(applicationDetail?.value.id, form.value.password, validateLoading)
|
|
||||||
.then((res: any) => {
|
|
||||||
if (res?.data.is_valid) {
|
|
||||||
isAuthenticated.value = true
|
|
||||||
isPasswordDialogVisible.value = false
|
|
||||||
} else {
|
|
||||||
callback(new Error('密码错误'))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const rules = reactive({
|
|
||||||
password: [{ required: true, validator: validateName, trigger: 'blur' }]
|
|
||||||
})
|
|
||||||
|
|
||||||
const submitHandle = async (formEl: FormInstance | undefined) => {
|
|
||||||
if (!formEl) return
|
|
||||||
await formEl.validate((valid) => {})
|
|
||||||
}
|
|
||||||
|
|
||||||
const paginationConfig = reactive({
|
const paginationConfig = reactive({
|
||||||
current_page: 1,
|
current_page: 1,
|
||||||
page_size: 20,
|
page_size: 20,
|
||||||
@ -237,38 +178,6 @@ function newChat() {
|
|||||||
currentChatId.value = 'new'
|
currentChatId.value = 'new'
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAccessToken(token: string) {
|
|
||||||
application
|
|
||||||
.asyncAppAuthentication(token, loading)
|
|
||||||
.then(() => {
|
|
||||||
setTimeout(() => {
|
|
||||||
getAppProfile()
|
|
||||||
}, 500)
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
applicationAvailable.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
function getAppProfile() {
|
|
||||||
application
|
|
||||||
.asyncGetAppProfile(loading)
|
|
||||||
.then((res: any) => {
|
|
||||||
applicationDetail.value = res.data
|
|
||||||
if (user.isEnterprise()) {
|
|
||||||
isPasswordDialogVisible.value = applicationDetail?.value.authentication
|
|
||||||
}
|
|
||||||
if (!isPasswordDialogVisible.value) {
|
|
||||||
isAuthenticated.value = true
|
|
||||||
}
|
|
||||||
if (res.data?.show_history || !user.isEnterprise()) {
|
|
||||||
getChatLog(applicationDetail.value.id)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
applicationAvailable.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function getChatLog(id: string) {
|
function getChatLog(id: string) {
|
||||||
const page = {
|
const page = {
|
||||||
current_page: 1,
|
current_page: 1,
|
||||||
@ -324,10 +233,16 @@ function refresh(id: string) {
|
|||||||
getChatLog(applicationDetail.value.id)
|
getChatLog(applicationDetail.value.id)
|
||||||
currentChatId.value = id
|
currentChatId.value = id
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*初始化历史对话记录
|
||||||
|
*/
|
||||||
|
const init = () => {
|
||||||
|
if (applicationDetail.value.show_history || !user.isEnterprise()) {
|
||||||
|
getChatLog(applicationDetail.value.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
user.changeUserType(2)
|
init()
|
||||||
getAccessToken(accessToken)
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@ -1,20 +1,36 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="currentTemplate" :key="route.fullPath" />
|
<component
|
||||||
|
v-if="chat_show"
|
||||||
|
:applicationAvailable="applicationAvailable"
|
||||||
|
:is="currentTemplate"
|
||||||
|
:application_profile="application_profile"
|
||||||
|
:key="route.fullPath"
|
||||||
|
v-loading="loading"
|
||||||
|
/>
|
||||||
|
<Auth
|
||||||
|
v-else
|
||||||
|
:application_profile="application_profile"
|
||||||
|
:auth_type="application_profile.authentication_type"
|
||||||
|
v-model="is_auth"
|
||||||
|
></Auth>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import useStore from '@/stores'
|
import useStore from '@/stores'
|
||||||
|
import Auth from '@/views/chat/auth/index.vue'
|
||||||
|
const route = useRoute()
|
||||||
const { application, user } = useStore()
|
const { application, user } = useStore()
|
||||||
|
|
||||||
const components: any = import.meta.glob('@/views/chat/**/index.vue', {
|
const components: any = import.meta.glob('@/views/chat/**/index.vue', {
|
||||||
eager: true
|
eager: true
|
||||||
})
|
})
|
||||||
const route = useRoute()
|
|
||||||
const {
|
|
||||||
query: { mode }
|
|
||||||
} = route as any
|
|
||||||
|
|
||||||
|
const {
|
||||||
|
query: { mode },
|
||||||
|
params: { accessToken }
|
||||||
|
} = route as any
|
||||||
|
const is_auth = ref<boolean>(false)
|
||||||
const currentTemplate = computed(() => {
|
const currentTemplate = computed(() => {
|
||||||
let modeName = ''
|
let modeName = ''
|
||||||
if (mode && mode === 'embed') {
|
if (mode && mode === 'embed') {
|
||||||
@ -22,26 +38,57 @@ const currentTemplate = computed(() => {
|
|||||||
} else {
|
} else {
|
||||||
modeName = show_history.value || !user.isEnterprise() ? 'pc' : 'base'
|
modeName = show_history.value || !user.isEnterprise() ? 'pc' : 'base'
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = `/src/views/chat/${modeName}/index.vue`
|
const name = `/src/views/chat/${modeName}/index.vue`
|
||||||
return components[name].default
|
return components[name].default
|
||||||
})
|
})
|
||||||
|
/**
|
||||||
|
* 是否显示对话
|
||||||
|
*/
|
||||||
|
const chat_show = computed(() => {
|
||||||
|
if (init_data_end.value) {
|
||||||
|
if (!applicationAvailable.value) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (application_profile.value) {
|
||||||
|
if (application_profile.value.authentication && is_auth.value) {
|
||||||
|
return true
|
||||||
|
} else if (!application_profile.value.authentication) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
|
||||||
const show_history = ref(false)
|
const show_history = ref(false)
|
||||||
|
|
||||||
|
const application_profile = ref<any>({})
|
||||||
|
/**
|
||||||
|
|
||||||
|
* 初始化结束
|
||||||
|
*/
|
||||||
|
const init_data_end = ref<boolean>(false)
|
||||||
|
|
||||||
|
const applicationAvailable = ref<boolean>(true)
|
||||||
function getAppProfile() {
|
function getAppProfile() {
|
||||||
application.asyncGetAppProfile(loading).then((res: any) => {
|
return application.asyncGetAppProfile(loading).then((res: any) => {
|
||||||
show_history.value = res.data?.show_history
|
show_history.value = res.data?.show_history
|
||||||
|
application_profile.value = res.data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
function getAccessToken(token: string) {
|
||||||
onMounted(() => {
|
return application.asyncAppAuthentication(token, loading).then(() => {
|
||||||
user.asyncGetProfile().then(() => {
|
getAppProfile()
|
||||||
if (user.isEnterprise()) {
|
|
||||||
getAppProfile()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
Promise.all([user.changeUserType(2), getAccessToken(accessToken)])
|
||||||
|
.catch(() => {
|
||||||
|
applicationAvailable.value = false
|
||||||
|
})
|
||||||
|
.finally(() => (init_data_end.value = true))
|
||||||
|
user.asyncGetProfile()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss"></style>
|
<style lang="scss"></style>
|
||||||
|
|||||||
@ -1,30 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="chat-pc layout-bg" :class="classObj" v-loading="loading">
|
<div class="chat-pc layout-bg" :class="classObj" v-loading="loading">
|
||||||
<el-dialog
|
|
||||||
v-model="isPasswordDialogVisible"
|
|
||||||
width="480"
|
|
||||||
title="请输入密码打开链接"
|
|
||||||
custom-class="no-close-button"
|
|
||||||
:close-on-click-modal="false"
|
|
||||||
:close-on-press-escape="false"
|
|
||||||
:show-close="false"
|
|
||||||
align-center
|
|
||||||
center
|
|
||||||
:modal="true"
|
|
||||||
>
|
|
||||||
<el-form ref="FormRef" :model="form" :rules="rules" v-loading="validateLoading">
|
|
||||||
<el-form-item prop="password">
|
|
||||||
<el-input
|
|
||||||
v-model="form.password"
|
|
||||||
:placeholder="$t('login.ldap.passwordPlaceholder')"
|
|
||||||
show-password
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-button class="w-full mt-8" type="primary" @click="submitHandle(FormRef)"
|
|
||||||
>确定</el-button
|
|
||||||
>
|
|
||||||
</el-form>
|
|
||||||
</el-dialog>
|
|
||||||
<div class="chat-pc__header" :class="!isDefaultTheme ? 'custom-header' : ''">
|
<div class="chat-pc__header" :class="!isDefaultTheme ? 'custom-header' : ''">
|
||||||
<div class="flex align-center">
|
<div class="flex align-center">
|
||||||
<div class="mr-12 ml-24 flex">
|
<div class="mr-12 ml-24 flex">
|
||||||
@ -47,7 +22,7 @@
|
|||||||
<h4>{{ applicationDetail?.name }}</h4>
|
<h4>{{ applicationDetail?.name }}</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isAuthenticated">
|
<div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="chat-pc__left border-r">
|
<div class="chat-pc__left border-r">
|
||||||
<div class="p-24 pb-0">
|
<div class="p-24 pb-0">
|
||||||
@ -149,65 +124,22 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref, onMounted, nextTick, computed } from 'vue'
|
import { ref, onMounted, nextTick, computed } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
|
||||||
import { marked } from 'marked'
|
import { marked } from 'marked'
|
||||||
import { saveAs } from 'file-saver'
|
import { saveAs } from 'file-saver'
|
||||||
import { isAppIcon } from '@/utils/application'
|
import { isAppIcon } from '@/utils/application'
|
||||||
import useStore from '@/stores'
|
import useStore from '@/stores'
|
||||||
import useResize from '@/layout/hooks/useResize'
|
import useResize from '@/layout/hooks/useResize'
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
|
||||||
import { t } from '@/locales'
|
|
||||||
useResize()
|
useResize()
|
||||||
|
|
||||||
const route = useRoute()
|
const { user, log, common } = useStore()
|
||||||
|
|
||||||
const {
|
|
||||||
params: { accessToken }
|
|
||||||
} = route as any
|
|
||||||
|
|
||||||
const { application, user, log, common } = useStore()
|
|
||||||
|
|
||||||
const isDefaultTheme = computed(() => {
|
const isDefaultTheme = computed(() => {
|
||||||
return user.isDefaultTheme()
|
return user.isDefaultTheme()
|
||||||
})
|
})
|
||||||
|
|
||||||
const FormRef = ref()
|
|
||||||
|
|
||||||
const isCollapse = ref(false)
|
const isCollapse = ref(false)
|
||||||
const isPasswordDialogVisible = ref(false)
|
|
||||||
const validateLoading = ref(false)
|
|
||||||
|
|
||||||
const form = ref({
|
|
||||||
password: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
const isAuthenticated = ref(false)
|
|
||||||
|
|
||||||
const validateName = (rule: any, value: string, callback: any) => {
|
|
||||||
if (value === '') {
|
|
||||||
callback(new Error('密码不能为空'))
|
|
||||||
} else {
|
|
||||||
application
|
|
||||||
.validatePassword(applicationDetail?.value.id, form.value.password, validateLoading)
|
|
||||||
.then((res: any) => {
|
|
||||||
if (res?.data.is_valid) {
|
|
||||||
isAuthenticated.value = true
|
|
||||||
isPasswordDialogVisible.value = false
|
|
||||||
} else {
|
|
||||||
callback(new Error('密码错误'))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const rules = reactive({
|
|
||||||
password: [{ required: true, validator: validateName, trigger: 'blur' }]
|
|
||||||
})
|
|
||||||
|
|
||||||
const submitHandle = async (formEl: FormInstance | undefined) => {
|
|
||||||
if (!formEl) return
|
|
||||||
await formEl.validate((valid) => {})
|
|
||||||
}
|
|
||||||
|
|
||||||
const classObj = computed(() => {
|
const classObj = computed(() => {
|
||||||
return {
|
return {
|
||||||
@ -221,12 +153,21 @@ const newObj = {
|
|||||||
id: 'new',
|
id: 'new',
|
||||||
abstract: '新建对话'
|
abstract: '新建对话'
|
||||||
}
|
}
|
||||||
|
const props = defineProps<{
|
||||||
|
application_profile: any
|
||||||
|
applicationAvailable: boolean
|
||||||
|
}>()
|
||||||
const AiChatRef = ref()
|
const AiChatRef = ref()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const left_loading = ref(false)
|
const left_loading = ref(false)
|
||||||
const applicationDetail = ref<any>({})
|
|
||||||
const applicationAvailable = ref<boolean>(true)
|
const applicationDetail = computed({
|
||||||
|
get: () => {
|
||||||
|
return props.application_profile
|
||||||
|
},
|
||||||
|
set: (v) => {}
|
||||||
|
})
|
||||||
|
|
||||||
const chatLogeData = ref<any[]>([])
|
const chatLogeData = ref<any[]>([])
|
||||||
|
|
||||||
const paginationConfig = ref({
|
const paginationConfig = ref({
|
||||||
@ -270,37 +211,6 @@ function handleScroll(event: any) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAccessToken(token: string) {
|
|
||||||
application
|
|
||||||
.asyncAppAuthentication(token, loading)
|
|
||||||
.then(() => {
|
|
||||||
getAppProfile()
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
applicationAvailable.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAppProfile() {
|
|
||||||
application
|
|
||||||
.asyncGetAppProfile(loading)
|
|
||||||
.then((res: any) => {
|
|
||||||
applicationDetail.value = res.data
|
|
||||||
if (user.isEnterprise()) {
|
|
||||||
isPasswordDialogVisible.value = applicationDetail?.value.authentication
|
|
||||||
}
|
|
||||||
if (!isPasswordDialogVisible.value) {
|
|
||||||
isAuthenticated.value = true
|
|
||||||
}
|
|
||||||
if (res.data?.show_history || !user.isEnterprise()) {
|
|
||||||
getChatLog(applicationDetail.value.id)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
applicationAvailable.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function newChat() {
|
function newChat() {
|
||||||
if (!chatLogeData.value.some((v) => v.id === 'new')) {
|
if (!chatLogeData.value.some((v) => v.id === 'new')) {
|
||||||
paginationConfig.value.current_page = 1
|
paginationConfig.value.current_page = 1
|
||||||
@ -403,9 +313,19 @@ async function exportHTML(): Promise<void> {
|
|||||||
saveAs(blob, suggestedName)
|
saveAs(blob, suggestedName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*初始化历史对话记录
|
||||||
|
*/
|
||||||
|
const init = () => {
|
||||||
|
if (
|
||||||
|
(applicationDetail.value.show_history || !user.isEnterprise()) &&
|
||||||
|
props.applicationAvailable
|
||||||
|
) {
|
||||||
|
getChatLog(applicationDetail.value.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
user.changeUserType(2)
|
init()
|
||||||
getAccessToken(accessToken)
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user