mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
feat: 分享对话
This commit is contained in:
parent
b71ce75b3a
commit
112e4b568d
|
|
@ -32,6 +32,7 @@
|
|||
"pinia": "^2.1.6",
|
||||
"pinyin-pro": "^3.18.2",
|
||||
"vue": "^3.3.4",
|
||||
"vue-clipboard3": "^2.0.0",
|
||||
"vue-router": "^4.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -29,32 +29,6 @@ const getApplication: (param: pageRequest) => Promise<Result<any>> = (param) =>
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得临时回话Id
|
||||
* @param 参数
|
||||
* {
|
||||
"model_id": "string",
|
||||
"multiple_rounds_dialogue": true,
|
||||
"dataset_id_list": [
|
||||
"string"
|
||||
]
|
||||
}
|
||||
*/
|
||||
const postChatOpen: (data: ApplicationFormType) => Promise<Result<any>> = (data) => {
|
||||
return post(`${prefix}/chat/open`, data)
|
||||
}
|
||||
/**
|
||||
* 对话
|
||||
* @param 参数
|
||||
* chat_id: string
|
||||
* {
|
||||
"message": "string",
|
||||
}
|
||||
*/
|
||||
const postChatMessage: (chat_id: string, message: string) => Promise<any> = (chat_id, message) => {
|
||||
return postStream(`/api/${prefix}/chat_message/${chat_id}`, { message })
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建应用
|
||||
* @param 参数
|
||||
|
|
@ -156,16 +130,85 @@ const getAccessToken: (applicaiton_id: string, loading?: Ref<boolean>) => Promis
|
|||
return get(`${prefix}/${applicaiton_id}/access_token`, undefined, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用认证
|
||||
* @param 参数
|
||||
{
|
||||
"access_token": "string"
|
||||
}
|
||||
*/
|
||||
const postAppAuthentication: (access_token: string, loading?: Ref<boolean>) => Promise<any> = (
|
||||
access_token,
|
||||
loading
|
||||
) => {
|
||||
return post(`${prefix}/authentication`, { access_token }, undefined, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 对话获取应用相关信息
|
||||
* @param 参数
|
||||
{
|
||||
"access_token": "string"
|
||||
}
|
||||
*/
|
||||
const getProfile: (loading?: Ref<boolean>) => Promise<any> = (loading) => {
|
||||
return get(`${prefix}/profile`, undefined, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得临时回话Id
|
||||
* @param 参数
|
||||
* {
|
||||
"model_id": "string",
|
||||
"multiple_rounds_dialogue": true,
|
||||
"dataset_id_list": [
|
||||
"string"
|
||||
]
|
||||
}
|
||||
*/
|
||||
const postChatOpen: (data: ApplicationFormType) => Promise<Result<any>> = (data) => {
|
||||
return post(`${prefix}/chat/open`, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 正式回话Id
|
||||
* @param 参数
|
||||
* {
|
||||
"model_id": "string",
|
||||
"multiple_rounds_dialogue": true,
|
||||
"dataset_id_list": [
|
||||
"string"
|
||||
]
|
||||
}
|
||||
*/
|
||||
const getChatOpen: (applicaiton_id: String) => Promise<Result<any>> = (applicaiton_id) => {
|
||||
return get(`${prefix}/${applicaiton_id}/chat/open`)
|
||||
}
|
||||
/**
|
||||
* 对话
|
||||
* @param 参数
|
||||
* chat_id: string
|
||||
* {
|
||||
"message": "string",
|
||||
}
|
||||
*/
|
||||
const postChatMessage: (chat_id: string, message: string) => Promise<any> = (chat_id, message) => {
|
||||
return postStream(`/api/${prefix}/chat_message/${chat_id}`, { message })
|
||||
}
|
||||
|
||||
export default {
|
||||
getAllAppilcation,
|
||||
getApplication,
|
||||
postApplication,
|
||||
putApplication,
|
||||
postChatOpen,
|
||||
getChatOpen,
|
||||
postChatMessage,
|
||||
delApplication,
|
||||
getApplicationDetail,
|
||||
getApplicationDataset,
|
||||
getAPIKey,
|
||||
getAccessToken
|
||||
getAccessToken,
|
||||
postAppAuthentication,
|
||||
getProfile
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,14 +107,21 @@
|
|||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, nextTick, onUpdated, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import applicationApi from '@/api/application'
|
||||
import { ChatManagement, type chatType } from '@/api/type/application'
|
||||
import { randomId } from '@/utils/utils'
|
||||
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { accessToken }
|
||||
} = route as any
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
appId: String
|
||||
})
|
||||
|
||||
const scrollDiv = ref()
|
||||
|
|
@ -125,7 +132,7 @@ const chartOpenId = ref('')
|
|||
const chatList = ref<chatType[]>([])
|
||||
|
||||
const isDisabledChart = computed(
|
||||
() => !(inputValue.value && props.data?.name && props.data?.model_id)
|
||||
() => !(inputValue.value && (props.appId || (props.data?.name && props.data?.model_id)))
|
||||
)
|
||||
|
||||
function quickProblemHandel(val: string) {
|
||||
|
|
@ -160,15 +167,27 @@ function getChartOpenId() {
|
|||
dataset_id_list: props.data.dataset_id_list,
|
||||
multiple_rounds_dialogue: props.data.multiple_rounds_dialogue
|
||||
}
|
||||
applicationApi
|
||||
.postChatOpen(obj)
|
||||
.then((res) => {
|
||||
chartOpenId.value = res.data
|
||||
chatMessage()
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
if (props.appId) {
|
||||
applicationApi
|
||||
.getChatOpen(props.appId)
|
||||
.then((res) => {
|
||||
chartOpenId.value = res.data
|
||||
chatMessage()
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
} else {
|
||||
applicationApi
|
||||
.postChatOpen(obj)
|
||||
.then((res) => {
|
||||
chartOpenId.value = res.data
|
||||
chatMessage()
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
function chatMessage() {
|
||||
loading.value = true
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export default {
|
|||
app.component(ReadWrite.name, ReadWrite)
|
||||
app.component(TagEllipsis.name, TagEllipsis)
|
||||
app.component(CommonList.name, CommonList)
|
||||
app.component(dynamicsForm.name, dynamicsForm)
|
||||
app.component(MarkdownRenderer.name, MarkdownRenderer)
|
||||
app.component(dynamicsForm.name, dynamicsForm)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,14 +7,13 @@ import {
|
|||
type RouteRecordRaw,
|
||||
type RouteRecordName
|
||||
} from 'vue-router'
|
||||
import useStore from '@/stores';
|
||||
import useStore from '@/stores'
|
||||
import { routes } from '@/router/routes'
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: routes
|
||||
})
|
||||
|
||||
|
||||
// 路由前置拦截器
|
||||
router.beforeEach(
|
||||
async (to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => {
|
||||
|
|
@ -22,8 +21,8 @@ router.beforeEach(
|
|||
next()
|
||||
return
|
||||
}
|
||||
const { user } = useStore();
|
||||
const notAuthRouteNameList = ['register', 'login', 'forgot_password', 'reset_password']
|
||||
const { user } = useStore()
|
||||
const notAuthRouteNameList = ['register', 'login', 'forgot_password', 'reset_password', 'Chat']
|
||||
|
||||
if (!notAuthRouteNameList.includes(to.name ? to.name.toString() : '')) {
|
||||
const token = user.getToken()
|
||||
|
|
|
|||
|
|
@ -45,6 +45,20 @@ const useApplicationStore = defineStore({
|
|||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
async asyncAppAuthentication(token: string, loading?: Ref<boolean>) {
|
||||
return new Promise((resolve, reject) => {
|
||||
applicationApi
|
||||
.postAppAuthentication(token, loading)
|
||||
.then((res) => {
|
||||
localStorage.setItem('accessToken', res.data)
|
||||
resolve(res)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import type { User } from '@/api/type/user'
|
|||
import UserApi from '@/api/user'
|
||||
|
||||
export interface userStateTypes {
|
||||
userType: number // 1 系统操作者 2 对话用户
|
||||
userInfo: User | null
|
||||
token: any
|
||||
}
|
||||
|
|
@ -10,6 +11,7 @@ export interface userStateTypes {
|
|||
const useUserStore = defineStore({
|
||||
id: 'user',
|
||||
state: (): userStateTypes => ({
|
||||
userType: 1,
|
||||
userInfo: null,
|
||||
token: ''
|
||||
}),
|
||||
|
|
@ -18,7 +20,9 @@ const useUserStore = defineStore({
|
|||
if (this.token) {
|
||||
return this.token
|
||||
}
|
||||
return localStorage.getItem('token')
|
||||
return this.userType === 1
|
||||
? localStorage.getItem('token')
|
||||
: localStorage.getItem('accessToken')
|
||||
},
|
||||
|
||||
getPermissions() {
|
||||
|
|
@ -35,7 +39,9 @@ const useUserStore = defineStore({
|
|||
return ''
|
||||
}
|
||||
},
|
||||
|
||||
changeUserType(num: number) {
|
||||
this.userType = num
|
||||
},
|
||||
async profile() {
|
||||
return UserApi.profile().then((ok) => {
|
||||
this.userInfo = ok.data
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
import Clipboard from 'vue-clipboard3'
|
||||
import { MsgSuccess, MsgError } from '@/utils/message'
|
||||
/*
|
||||
复制粘贴
|
||||
*/
|
||||
export async function copyClick(info: string) {
|
||||
const { toClipboard } = Clipboard()
|
||||
try {
|
||||
await toClipboard(info)
|
||||
MsgSuccess('复制成功')
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
MsgError('复制失败')
|
||||
}
|
||||
}
|
||||
|
|
@ -49,3 +49,4 @@ export function realatedObject(list: any, val: string | number, attr: string) {
|
|||
const filterData: any = list.filter((item: any) => item[attr] === val)?.[0]
|
||||
return filterData || null
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
{{ shareUrl }}
|
||||
</span>
|
||||
|
||||
<el-button type="primary" text>
|
||||
<el-button type="primary" text @click="copyClick(shareUrl)">
|
||||
<el-icon style="font-size: 13px"><CopyDocument /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
|
|
@ -56,12 +56,12 @@
|
|||
</el-col> -->
|
||||
</el-row>
|
||||
<div class="mt-16">
|
||||
<el-button type="primary"> 演示 </el-button>
|
||||
<el-button type="primary"><a :href="shareUrl" target="_blank">演示</a></el-button>
|
||||
<el-button @click="openDialog"> 嵌入第三方 </el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<EmbedDialog ref="EmbedDialogRef" />
|
||||
<EmbedDialog ref="EmbedDialogRef" :accessToken="accessToken" />
|
||||
</LayoutContainer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
|
|
@ -69,6 +69,7 @@ import { reactive, ref, watch, onMounted } from 'vue'
|
|||
import { useRouter, useRoute } from 'vue-router'
|
||||
import applicationApi from '@/api/application'
|
||||
import EmbedDialog from './components/EmbedDialog.vue'
|
||||
import { copyClick } from '@/utils/clipboard'
|
||||
import useStore from '@/stores'
|
||||
const { application } = useStore()
|
||||
const router = useRouter()
|
||||
|
|
@ -76,6 +77,7 @@ const route = useRoute()
|
|||
|
||||
const EmbedDialogRef = ref()
|
||||
const shareUrl = ref('')
|
||||
const accessToken = ref('')
|
||||
const detail = ref<any>(null)
|
||||
const apiKey = ref<any>(null)
|
||||
const {
|
||||
|
|
@ -89,6 +91,7 @@ function openDialog() {
|
|||
}
|
||||
function getAccessToken() {
|
||||
application.asyncGetAccessToken(id, loading).then((res) => {
|
||||
accessToken.value = res?.data?.access_token
|
||||
shareUrl.value = application.location + res?.data?.access_token
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<div class="code border-t p-16">
|
||||
<div class="flex-between">
|
||||
<span class="bold">复制以下代码进行嵌入</span>
|
||||
<el-button text>
|
||||
<el-button text @click="copyClick(source1)">
|
||||
<el-icon style="font-size: 13px"><CopyDocument /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
<div class="code border-t p-16">
|
||||
<div class="flex-between">
|
||||
<span class="bold">复制以下代码进行嵌入</span>
|
||||
<el-button text>
|
||||
<el-button text @click="copyClick(source2)">
|
||||
<el-icon style="font-size: 13px"><CopyDocument /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
|
|
@ -38,20 +38,20 @@
|
|||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import { copyClick } from '@/utils/clipboard'
|
||||
import useStore from '@/stores'
|
||||
const { application } = useStore()
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array<any>,
|
||||
default: () => []
|
||||
}
|
||||
accessToken: String
|
||||
})
|
||||
|
||||
const emit = defineEmits(['addData'])
|
||||
|
||||
const loading = ref(false)
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
|
||||
const source1 = ref(`<iframe
|
||||
src="https://udify.app/chatbot/ASkyzvhN5Z1h6k7g"
|
||||
src="${application.location + props.accessToken}"
|
||||
style="width: 100%; height: 100%;"
|
||||
frameborder="0"
|
||||
allow="microphone">
|
||||
|
|
@ -59,11 +59,11 @@ allow="microphone">
|
|||
`)
|
||||
|
||||
const source2 = ref(`<script> window.difyChatbotConfig = {
|
||||
token: '85FfbbzTpXzzr40X'
|
||||
token: "${props.accessToken}"
|
||||
}
|
||||
<\/script>
|
||||
<script src="https://udify.app/embed.min.js"
|
||||
id="85FfbbzTpXzzr40X"
|
||||
id="${props.accessToken}"
|
||||
defer>
|
||||
<\/script>
|
||||
`)
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
<template #footer>
|
||||
<div class="footer-content">
|
||||
<el-tooltip effect="dark" content="演示" placement="top">
|
||||
<el-button text @click.stop>
|
||||
<el-button text @click.stop @click="getAccessToken(item.id)">
|
||||
<AppIcon iconName="app-view"></AppIcon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
|
|
@ -71,7 +71,9 @@
|
|||
<span>运行中</span>
|
||||
<!-- <el-switch v-model="item.status" @change="changeState($event, item)" /> -->
|
||||
</div>
|
||||
<el-dropdown-item divided @click="deleteApplication(item)">删除</el-dropdown-item>
|
||||
<el-dropdown-item divided @click="deleteApplication(item)"
|
||||
>删除</el-dropdown-item
|
||||
>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
|
|
@ -88,8 +90,10 @@
|
|||
import { ref, onMounted, reactive } from 'vue'
|
||||
import applicationApi from '@/api/application'
|
||||
import type { pageRequest } from '@/api/type/common'
|
||||
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
||||
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
||||
import { useRouter } from 'vue-router'
|
||||
import useStore from '@/stores'
|
||||
const { application } = useStore()
|
||||
const router = useRouter()
|
||||
|
||||
const loading = ref(false)
|
||||
|
|
@ -109,29 +113,31 @@ function search() {
|
|||
getList()
|
||||
}
|
||||
|
||||
function deleteApplication(row: any) {
|
||||
MsgConfirm(
|
||||
`是否删除应用:${row.name} ?`,
|
||||
`删除后该应用将不再提供服务,请谨慎操作。`,
|
||||
{
|
||||
confirmButtonText: '删除',
|
||||
confirmButtonClass: 'danger'
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
loading.value = true
|
||||
applicationApi
|
||||
.delApplication(row.id)
|
||||
.then(() => {
|
||||
MsgSuccess('删除成功')
|
||||
getList()
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
function getAccessToken(id: string) {
|
||||
application.asyncGetAccessToken(id, loading).then((res) => {
|
||||
window.open(application.location + res?.data?.access_token)
|
||||
})
|
||||
}
|
||||
|
||||
function deleteApplication(row: any) {
|
||||
MsgConfirm(`是否删除应用:${row.name} ?`, `删除后该应用将不再提供服务,请谨慎操作。`, {
|
||||
confirmButtonText: '删除',
|
||||
confirmButtonClass: 'danger'
|
||||
})
|
||||
.then(() => {
|
||||
loading.value = true
|
||||
applicationApi
|
||||
.delApplication(row.id)
|
||||
.then(() => {
|
||||
MsgSuccess('删除成功')
|
||||
getList()
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
// function changeState(bool: Boolean, row: any) {
|
||||
// const obj = {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,44 @@
|
|||
<template>
|
||||
<div class="chat">
|
||||
<div class="chat__header">
|
||||
<div class="chat-width"><h2 class="ml-24">111</h2></div>
|
||||
<div class="chat-width">
|
||||
<h2 class="ml-24">{{ applicationDetail?.name }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat__main chat-width" v-loading="loading">
|
||||
<AiDialog :data="applicationDetail" :appId="applicationDetail?.id"></AiDialog>
|
||||
</div>
|
||||
<div class="chat__main chat-width"><AiDialog></AiDialog></div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, watch, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import AiDialog from '@/components/ai-dialog/index.vue'
|
||||
import applicationApi from '@/api/application'
|
||||
import useStore from '@/stores'
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { accessToken }
|
||||
} = route as any
|
||||
|
||||
const { application, user } = useStore()
|
||||
|
||||
const loading = ref(false)
|
||||
const applicationDetail = ref<any>({})
|
||||
|
||||
function getAccessToken(token: string) {
|
||||
application.asyncAppAuthentication(token, loading).then((res) => {})
|
||||
}
|
||||
function getProfile() {
|
||||
applicationApi.getProfile(loading).then((res) => {
|
||||
applicationDetail.value = res.data
|
||||
})
|
||||
}
|
||||
onMounted(() => {
|
||||
user.changeUserType(2)
|
||||
getAccessToken(accessToken)
|
||||
getProfile()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.chat {
|
||||
|
|
|
|||
Loading…
Reference in New Issue