refactor(Agent/Chat): 使用 cozeInfo 替代 botId 获取聊天记录
- 移除了 HistoryChat 组件中的 botId属性 - 使用 cozeInfo.bot_id 替代 botId 获取历史聊天数据
This commit is contained in:
137
src/components/upload/FileUpload.vue
Normal file
137
src/components/upload/FileUpload.vue
Normal file
@ -0,0 +1,137 @@
|
||||
<template>
|
||||
<a-upload
|
||||
:custom-request="customRequest"
|
||||
action="/"
|
||||
:limit="limit"
|
||||
:fileList="fileList"
|
||||
@change="onChange"
|
||||
@success="handleSuccess"
|
||||
@error="handleError"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { fetchImageUploadFile, fetchUploadFile } from '@/api/all';
|
||||
import axios from 'axios';
|
||||
|
||||
const fileList = ref([]);
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: [Array, String],
|
||||
default: '',
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 0, // 0 表示不限制
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
const handleSuccess = (fileItem) => {
|
||||
let response = fileItem.response;
|
||||
response = JSON.parse(response);
|
||||
if (response && response.data.file_url) {
|
||||
if (props.limit === 1) {
|
||||
emit('update:modelValue', response.data.file_url);
|
||||
} else {
|
||||
emit('update:modelValue', [...props.modelValue, response.data.file_url]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
async (value) => {
|
||||
console.log(value, 'value');
|
||||
if (value) {
|
||||
fileList.value =
|
||||
props.limit == 1
|
||||
? [
|
||||
{
|
||||
name: '',
|
||||
url: props.modelValue as string,
|
||||
},
|
||||
]
|
||||
: (props.modelValue as string[]).map((item) => {
|
||||
return {
|
||||
name: '',
|
||||
url: item,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
fileList.value = [];
|
||||
}
|
||||
},
|
||||
{ once: true },
|
||||
);
|
||||
|
||||
let previousFileListLength = 0;
|
||||
//删除图片
|
||||
const onChange = (fileList) => {
|
||||
if (fileList.length < previousFileListLength) {
|
||||
if (props.limit === 1) {
|
||||
if (fileList.length === 0) {
|
||||
emit('update:modelValue', '');
|
||||
}
|
||||
} else {
|
||||
if (fileList.length === 0) {
|
||||
emit('update:modelValue', []);
|
||||
} else {
|
||||
let image_data = fileList.map((item) => item.url);
|
||||
emit('update:modelValue', image_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
previousFileListLength = fileList.length;
|
||||
};
|
||||
|
||||
const beforeUpload = (file, files) => {
|
||||
if (props.limit > 0 && files.length >= props.limit) {
|
||||
Message.warning(`最多只能上传 ${props.limit} 张图片`);
|
||||
return false; // 阻止上传
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleError = (error) => {
|
||||
Message.error('上传失败');
|
||||
console.error(error);
|
||||
};
|
||||
|
||||
const customRequest = async (option) => {
|
||||
const { onProgress, onError, onSuccess, fileItem, name } = option;
|
||||
try {
|
||||
// 1. 获取预签名上传URL
|
||||
const response = await fetchUploadFile({ suffix: getFileExtension(fileItem.file.name) });
|
||||
const preSignedUrl = response?.data?.upload_url;
|
||||
|
||||
if (!preSignedUrl) {
|
||||
throw new Error('未能获取有效的预签名上传地址');
|
||||
}
|
||||
console.log('preSignedUrl', preSignedUrl);
|
||||
// 2. 使用预签名URL上传文件
|
||||
const blob = new Blob([fileItem.file], { type: fileItem.file.type });
|
||||
await axios.put(preSignedUrl, blob, {
|
||||
headers: { 'Content-Type': fileItem.file.type },
|
||||
});
|
||||
|
||||
onSuccess(JSON.stringify(response));
|
||||
} catch (error) {
|
||||
onError(error);
|
||||
}
|
||||
};
|
||||
|
||||
function getFileExtension(filename: string): string {
|
||||
const match = filename.match(/\.([^.]+)$/);
|
||||
return match ? match[1].toLowerCase() : '';
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 添加一些样式 */
|
||||
</style>
|
||||
@ -38,7 +38,18 @@ export const router = createRouter({
|
||||
{
|
||||
path: '/agent/chat',
|
||||
name: 'Chat',
|
||||
component: () => import('@/views/Agent/chat'),
|
||||
component: () => import('@/views/agent/chat'),
|
||||
meta: {
|
||||
hideSidebar: true,
|
||||
requiresAuth: false,
|
||||
requireLogin: true,
|
||||
id: MENU_GROUP_IDS.WORK_BENCH_ID,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/agent/workFlow',
|
||||
name: 'WorkFlow',
|
||||
component: () => import('@/views/agent/work-flow'),
|
||||
meta: {
|
||||
hideSidebar: true,
|
||||
requiresAuth: false,
|
||||
|
||||
@ -4,42 +4,31 @@ import { MENU_GROUP_IDS } from '@/router/constants';
|
||||
import IconRepository from '@/assets/svg/icon-repository.svg';
|
||||
|
||||
const COMPONENTS: AppRouteRecordRaw[] = [
|
||||
{
|
||||
path: '/agent',
|
||||
name: 'Agent',
|
||||
redirect: 'agent/index',
|
||||
meta: {
|
||||
locale: '扣子智能体',
|
||||
icon: IconRepository,
|
||||
requiresAuth: true,
|
||||
requireLogin: true,
|
||||
roles: ['*'],
|
||||
id: MENU_GROUP_IDS.PROPERTY_ID,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
name: 'AgentIndex',
|
||||
component: () => import('@/views/agent/index'),
|
||||
meta: {
|
||||
requiresAuth: false,
|
||||
requireLogin: true,
|
||||
id: MENU_GROUP_IDS.WORK_BENCH_ID,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'chat',
|
||||
name: 'Chat',
|
||||
component: () => import('@/views/agent/chat'),
|
||||
meta: {
|
||||
hideSidebar: true,
|
||||
requiresAuth: false,
|
||||
requireLogin: true,
|
||||
id: MENU_GROUP_IDS.WORK_BENCH_ID,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// path: '/agent',
|
||||
// name: 'Agent',
|
||||
// redirect: 'agent/index',
|
||||
// meta: {
|
||||
// locale: '扣子智能体',
|
||||
// icon: IconRepository,
|
||||
// requiresAuth: true,
|
||||
// requireLogin: true,
|
||||
// roles: ['*'],
|
||||
// id: MENU_GROUP_IDS.AGENT,
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// path: 'index',
|
||||
// name: 'AgentIndex',
|
||||
// component: () => import('@/views/agent/index'),
|
||||
// meta: {
|
||||
// requiresAuth: false,
|
||||
// requireLogin: true,
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// ],
|
||||
// },
|
||||
];
|
||||
|
||||
export default COMPONENTS;
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
<template>
|
||||
<a-layout-content style="padding: 24px; background: #fff; min-height: 280px;">
|
||||
<div style="text-align: center; margin-bottom: 20px">
|
||||
<img src="@/assets/chatbot-icon.png" alt="Chatbot Icon" style="width: 60px" />
|
||||
<h3>舆情脉络整理</h3>
|
||||
</div>
|
||||
<a-card :bordered="false">
|
||||
<p>
|
||||
您好,我是舆情脉络整理助手,可以帮您梳理事件发展脉络,提取核心观点,分析情绪倾向,快速生成舆情摘要与应对建议。
|
||||
</p>
|
||||
</a-card>
|
||||
<div style="margin-top: 20px">
|
||||
<a-input-search
|
||||
v-model:value="message"
|
||||
placeholder="发送消息..."
|
||||
enter-button
|
||||
@search="onSearch"
|
||||
>
|
||||
<template #enterButton>
|
||||
<a-button type="primary">
|
||||
<!-- <template #icon><SendOutlined /></template>-->
|
||||
</a-button>
|
||||
</template>
|
||||
</a-input-search>
|
||||
</div>
|
||||
<small style="display: block; text-align: center; margin-top: 10px">
|
||||
内容由AI生成,无法确保真实准确,仅供参考。
|
||||
</small>
|
||||
</a-layout-content>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineComponent, ref } from 'vue';
|
||||
// import { SendOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
</script>
|
||||
@ -1,217 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 聊天容器 -->
|
||||
<div ref="chatContainer" class="coze-chat-container"></div>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="loading" class="loading-state">
|
||||
<div class="spinner"></div>
|
||||
<p>正在加载聊天服务...</p>
|
||||
</div>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<div v-if="error" class="error-state">
|
||||
<p>⚠️ 聊天服务加载失败</p>
|
||||
<button @click="retry">重新加载</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
botId: {
|
||||
type: String,
|
||||
default: '7522056630889381923',
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: 'Coze助手',
|
||||
},
|
||||
token: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const chatContainer = ref(null);
|
||||
const loading = ref(true);
|
||||
const error = ref(false);
|
||||
let chatClient = null;
|
||||
let scriptLoaded = false;
|
||||
|
||||
// 加载SDK脚本
|
||||
const loadSDK = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 检查是否已加载
|
||||
if (window.CozeWebSDK) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否正在加载
|
||||
if (document.querySelector('script[src*="coze.cn"]')) {
|
||||
const checkInterval = setInterval(() => {
|
||||
if (window.CozeWebSDK) {
|
||||
clearInterval(checkInterval);
|
||||
resolve();
|
||||
}
|
||||
}, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建新脚本
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://lf-cdn.coze.cn/obj/unpkg/flow-platform/chat-app-sdk/1.2.0-beta.10/libs/cn/index.js';
|
||||
script.onload = () => {
|
||||
scriptLoaded = true;
|
||||
resolve();
|
||||
};
|
||||
script.onerror = (err) => {
|
||||
console.error('SDK加载失败:', err);
|
||||
reject(new Error('无法加载聊天SDK'));
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
};
|
||||
|
||||
// 初始化聊天
|
||||
const initChat = () => {
|
||||
try {
|
||||
if (!window.CozeWebSDK) {
|
||||
throw new Error('SDK未加载');
|
||||
}
|
||||
|
||||
chatClient = new window.CozeWebSDK.WebChatClient({
|
||||
container: chatContainer.value,
|
||||
config: {
|
||||
bot_id: props.botId,
|
||||
},
|
||||
componentProps: {
|
||||
title: props.title,
|
||||
// 可选配置
|
||||
// theme: 'light',
|
||||
// welcome_message: '您好!需要什么帮助?',
|
||||
// input_placeholder: '输入您的问题...'
|
||||
},
|
||||
auth: {
|
||||
type: 'token',
|
||||
token: props.token,
|
||||
onRefreshToken: () => {
|
||||
// 实际项目中应从API获取新token
|
||||
console.log('Token刷新');
|
||||
return props.token;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
loading.value = false;
|
||||
} catch (err) {
|
||||
console.error('聊天初始化失败:', err);
|
||||
error.value = true;
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const retry = async () => {
|
||||
error.value = false;
|
||||
loading.value = true;
|
||||
try {
|
||||
await loadSDK();
|
||||
initChat();
|
||||
} catch (err) {
|
||||
console.error('重试失败:', err);
|
||||
error.value = true;
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await loadSDK();
|
||||
initChat();
|
||||
} catch (err) {
|
||||
console.error('初始化失败:', err);
|
||||
error.value = true;
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (chatClient && typeof chatClient.destroy === 'function') {
|
||||
chatClient.destroy();
|
||||
}
|
||||
|
||||
if (scriptLoaded) {
|
||||
const scripts = document.querySelectorAll('script[src*="coze.cn"]');
|
||||
scripts.forEach((script) => script.remove());
|
||||
window.CozeWebSDK = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
chatContainer,
|
||||
loading,
|
||||
error,
|
||||
retry,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.coze-chat-container {
|
||||
height: 600px;
|
||||
width: 100%;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
.loading-state,
|
||||
.error-state {
|
||||
height: 600px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #f9f9f9;
|
||||
border-radius: 12px;
|
||||
border: 1px dashed #ddd;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
border: 4px solid rgba(0, 0, 0, 0.1);
|
||||
border-left-color: #3498db;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.error-state button {
|
||||
margin-top: 16px;
|
||||
padding: 8px 16px;
|
||||
background: #3498db;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.error-state button:hover {
|
||||
background: #2980b9;
|
||||
}
|
||||
</style>
|
||||
@ -1,217 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 聊天容器 -->
|
||||
<div ref="chatContainer" class="coze-chat-container"></div>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="loading" class="loading-state">
|
||||
<div class="spinner"></div>
|
||||
<p>正在加载聊天服务...</p>
|
||||
</div>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<div v-if="error" class="error-state">
|
||||
<p>⚠️ 聊天服务加载失败</p>
|
||||
<button @click="retry">重新加载</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
botId: {
|
||||
type: String,
|
||||
default: '7522056630889381923',
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: 'Coze助手',
|
||||
},
|
||||
token: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const chatContainer = ref(null);
|
||||
const loading = ref(true);
|
||||
const error = ref(false);
|
||||
let chatClient = null;
|
||||
let scriptLoaded = false;
|
||||
|
||||
// 加载SDK脚本
|
||||
const loadSDK = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 检查是否已加载
|
||||
if (window.CozeWebSDK) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否正在加载
|
||||
if (document.querySelector('script[src*="coze.cn"]')) {
|
||||
const checkInterval = setInterval(() => {
|
||||
if (window.CozeWebSDK) {
|
||||
clearInterval(checkInterval);
|
||||
resolve();
|
||||
}
|
||||
}, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建新脚本
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://lf-cdn.coze.cn/obj/unpkg/flow-platform/chat-app-sdk/1.2.0-beta.10/libs/cn/index.js';
|
||||
script.onload = () => {
|
||||
scriptLoaded = true;
|
||||
resolve();
|
||||
};
|
||||
script.onerror = (err) => {
|
||||
console.error('SDK加载失败:', err);
|
||||
reject(new Error('无法加载聊天SDK'));
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
};
|
||||
|
||||
// 初始化聊天
|
||||
const initChat = () => {
|
||||
try {
|
||||
if (!window.CozeWebSDK) {
|
||||
throw new Error('SDK未加载');
|
||||
}
|
||||
|
||||
chatClient = new window.CozeWebSDK.WebChatClient({
|
||||
container: chatContainer.value,
|
||||
config: {
|
||||
bot_id: props.botId,
|
||||
},
|
||||
componentProps: {
|
||||
title: props.title,
|
||||
// 可选配置
|
||||
// theme: 'light',
|
||||
// welcome_message: '您好!需要什么帮助?',
|
||||
// input_placeholder: '输入您的问题...'
|
||||
},
|
||||
auth: {
|
||||
type: 'token',
|
||||
token: props.token,
|
||||
onRefreshToken: () => {
|
||||
// 实际项目中应从API获取新token
|
||||
console.log('Token刷新');
|
||||
return props.token;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
loading.value = false;
|
||||
} catch (err) {
|
||||
console.error('聊天初始化失败:', err);
|
||||
error.value = true;
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const retry = async () => {
|
||||
error.value = false;
|
||||
loading.value = true;
|
||||
try {
|
||||
await loadSDK();
|
||||
initChat();
|
||||
} catch (err) {
|
||||
console.error('重试失败:', err);
|
||||
error.value = true;
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await loadSDK();
|
||||
initChat();
|
||||
} catch (err) {
|
||||
console.error('初始化失败:', err);
|
||||
error.value = true;
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (chatClient && typeof chatClient.destroy === 'function') {
|
||||
chatClient.destroy();
|
||||
}
|
||||
|
||||
if (scriptLoaded) {
|
||||
const scripts = document.querySelectorAll('script[src*="coze.cn"]');
|
||||
scripts.forEach((script) => script.remove());
|
||||
window.CozeWebSDK = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
chatContainer,
|
||||
loading,
|
||||
error,
|
||||
retry,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.coze-chat-container {
|
||||
height: 600px;
|
||||
width: 100%;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
.loading-state,
|
||||
.error-state {
|
||||
height: 600px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #f9f9f9;
|
||||
border-radius: 12px;
|
||||
border: 1px dashed #ddd;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
border: 4px solid rgba(0, 0, 0, 0.1);
|
||||
border-left-color: #3498db;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.error-state button {
|
||||
margin-top: 16px;
|
||||
padding: 8px 16px;
|
||||
background: #3498db;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.error-state button:hover {
|
||||
background: #2980b9;
|
||||
}
|
||||
</style>
|
||||
@ -27,7 +27,7 @@ import { useRouter } from 'vue-router';
|
||||
const router = useRouter();
|
||||
|
||||
// 存储认证令牌
|
||||
const authToken = ref('pat_tuIM7jubM1hLXaIWzbWg1U15lBe66AlYwu9BkXMQXInh8VdPszRFTwlTPmdziHwg');
|
||||
const authToken = ref('');
|
||||
|
||||
// 模拟从API获取token
|
||||
const fetchToken = async () => {
|
||||
@ -89,9 +89,8 @@ const initChat = async () => {
|
||||
};
|
||||
|
||||
const cozeWebSdkConfig = (botId, name, auth) => {
|
||||
console.log(name, 'title');
|
||||
auth.onRefreshToken = function () {
|
||||
return 'pat_tuIM7jubM1hLXaIWzbWg1U15lBe66AlYwu9BkXMQXInh8VdPszRFTwlTPmdziHwg';
|
||||
return '';
|
||||
};
|
||||
let config = {
|
||||
config: {
|
||||
@ -105,6 +104,9 @@ const cozeWebSdkConfig = (botId, name, auth) => {
|
||||
title: name,
|
||||
isNeedFunctionCallMessage: true,
|
||||
},
|
||||
footer:{
|
||||
expressionText:"内容由AI生成,无法确保真实准确,仅供参考。",
|
||||
},
|
||||
},
|
||||
auth: auth,
|
||||
base: {
|
||||
@ -2,7 +2,7 @@
|
||||
<div class="agent-wrap">
|
||||
<a-input
|
||||
style="float: right; width: 300px"
|
||||
v-model="query.title"
|
||||
v-model="query.name"
|
||||
@blur="getData()"
|
||||
placeholder="搜索智能体"
|
||||
size="medium"
|
||||
@ -57,7 +57,7 @@ const getData = async () => {
|
||||
};
|
||||
|
||||
const query = reactive({
|
||||
title: '',
|
||||
name: '',
|
||||
});
|
||||
const goDetail = (type: number, id: number) => {
|
||||
if (type === 1) {
|
||||
@ -4,16 +4,30 @@
|
||||
<a-form-item
|
||||
v-for="(field, index) in formFields"
|
||||
:key="index"
|
||||
:label="field.label"
|
||||
:field="field.key"
|
||||
:rules="field.rules"
|
||||
:label="field.props.label"
|
||||
:field="field.props.name"
|
||||
:rules="field.props.rules"
|
||||
>
|
||||
<a-input v-if="field.type === 'input'" v-model="formData[field.key]" :placeholder="field.placeholder" />
|
||||
<a-textarea v-if="field.type === 'textarea'" v-model="formData[field.key]" :placeholder="field.placeholder" />
|
||||
<ImageUpload v-if="field.type == 'upload'" v-model="formData[field.key]" :limit="1"></ImageUpload>
|
||||
|
||||
<a-select v-else-if="field.type === 'select'" v-model="formData[field.key]" :placeholder="field.placeholder">
|
||||
<a-option v-for="(option, optIndex) in field.options" :key="optIndex" :value="option.value">
|
||||
<a-input
|
||||
allowClear
|
||||
v-if="field.type === 'input'"
|
||||
v-model="formData[field.props.name]"
|
||||
:placeholder="field?.props?.placeholder"
|
||||
/>
|
||||
<a-textarea
|
||||
v-if="field.type === 'textarea'"
|
||||
style="width: 500px; height: 200px;"
|
||||
v-model="formData[field.props.name]"
|
||||
:placeholder="field?.props?.placeholder"
|
||||
/>
|
||||
<ImageUpload v-if="field.type == 'upload_image'" v-model="formData[field.props.name]" :limit="field.props.limit"></ImageUpload>
|
||||
<FileUpload v-if="field.type == 'upload_file'" v-model="formData[field.props.name]" :limit="field.props.limit"></FileUpload>
|
||||
<a-select
|
||||
v-else-if="field.type === 'select'"
|
||||
v-model="formData[field.props.name]"
|
||||
:placeholder="field.placeholder"
|
||||
>
|
||||
<a-option v-for="(option, optIndex) in field.props.options" :key="optIndex" :value="option.value">
|
||||
{{ option.label }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
@ -25,6 +39,7 @@
|
||||
<script setup>
|
||||
import { defineProps, defineEmits } from 'vue';
|
||||
import ImageUpload from '@/components/upload/ImageUpload.vue';
|
||||
import FileUpload from '@/components/upload/FileUpload.vue';
|
||||
|
||||
const props = defineProps({
|
||||
formFields: {
|
||||
@ -45,7 +60,7 @@ const formRef = ref(null);
|
||||
const handleSubmit = async () => {
|
||||
const errors = await formRef.value.validate();
|
||||
if (errors) return;
|
||||
|
||||
console.log(props.formFields, 'props.formFields');
|
||||
emit('submit', props.formData);
|
||||
};
|
||||
</script>
|
||||
@ -5,11 +5,10 @@
|
||||
</div>
|
||||
<a-menu mode="inline" theme="light">
|
||||
<a-menu-item key="1">
|
||||
<span>{{ cozeInfo.title }}</span>
|
||||
<span>{{ cozeInfo.name }}</span>
|
||||
<span style="color: #8492ff; font-size: 12px">{{ cozeInfo.type == 1 ? '智能体' : '对话式' }}</span>
|
||||
<span style="float: right">{{ cozeInfo.views }}次使用</span>
|
||||
<span style="float: right">{{ cozeInfo.views }}次使用 </span>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="2">历史对话</a-menu-item>
|
||||
|
||||
</a-menu>
|
||||
</a-layout-sider>
|
||||
@ -28,15 +27,8 @@ const props = defineProps({
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
console.log(props.cozeInfo, 'cozeInfo');
|
||||
const getHistoryChat = async () => {
|
||||
const { code, data } = await getHistoryChat({ botId: props.botId });
|
||||
console.log(data, 'data');
|
||||
// 获取历史对话
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getHistoryChat();
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -13,9 +13,8 @@
|
||||
</a-layout-sider>
|
||||
<a-layout-content ref="contentRef" class="content-container">
|
||||
<a-spin v-if="loading" class="spin-center" tip="生成中。。。" />
|
||||
<div class="work-res">
|
||||
<span > {{ workFlowRes?.output }}</span>
|
||||
</div>
|
||||
<div v-if="workFlowRes?.output != ''" class="work-res" v-html="renderedMarkdown"></div>
|
||||
<NoData v-else />
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
@ -26,9 +25,11 @@
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import HistoryChat from './components/historyChat.vue';
|
||||
import { executeWorkFlow, getWorkFlowInfo } from '@/api/all/agent';
|
||||
import DynamicForm from './components/DynamicForm.vue';
|
||||
import { executeWorkFlow, getWorkFlowInfo } from '@/api/all/agent';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { marked } from 'marked';
|
||||
import DOMPurify from 'dompurify';
|
||||
|
||||
const formFields = ref([]);
|
||||
|
||||
@ -49,7 +50,7 @@ const goChatIndex = async () => {
|
||||
const loading = ref(false);
|
||||
|
||||
const cozeInfo = reactive({
|
||||
title: '',
|
||||
name: '',
|
||||
description: '',
|
||||
icon_url: '',
|
||||
workflow_id: '',
|
||||
@ -59,11 +60,22 @@ const getData = async () => {
|
||||
Object.assign(cozeInfo, data.info);
|
||||
formFields.value = data.form_config;
|
||||
};
|
||||
const workFlowRes = reactive({});
|
||||
const workFlowRes = reactive({
|
||||
output: '',
|
||||
});
|
||||
|
||||
// 渲染 Markdown 的计算属性
|
||||
const renderedMarkdown = computed(() => {
|
||||
if (workFlowRes?.output) {
|
||||
const rawHtml = marked.parse(workFlowRes.output || '');
|
||||
return DOMPurify.sanitize(rawHtml); // 防止 XSS 攻击
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async (formData) => {
|
||||
console.log(formData, 'formData');
|
||||
|
||||
try {
|
||||
const param = { form_data: formData, workflow_id: cozeInfo.workflow_id };
|
||||
loading.value = true;
|
||||
Reference in New Issue
Block a user