feat(property-marketing): 新增月数据复制功能,优化组件样式布局

This commit is contained in:
林志军
2025-07-10 19:05:38 +08:00
parent 78b21b1bf7
commit a5c92999b1
3 changed files with 336 additions and 0 deletions

View File

@ -0,0 +1,221 @@
<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>

View File

@ -0,0 +1,76 @@
<template>
<div class="app-container">
<h1>我的应用</h1>
<!-- 聊天组件 -->
<CozeChat :bot-id="cozeConfig.botId" :title="cozeConfig.title" :token="authToken" />
<!-- Token刷新按钮示例 -->
<button @click="refreshToken" class="refresh-btn">刷新Token</button>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import CozeChat from './components/CozeChat.vue';
export default {
components: { CozeChat },
setup() {
const cozeConfig = ref({
botId: '7522056630889381923',
title: 'AI客服',
});
// 存储认证令牌
const authToken = ref('');
// 模拟从API获取token
const fetchToken = async () => {
return 'pat_tuIM7jubM1hLXaIWzbWg1U15lBe66AlYwu9BkXMQXInh8VdPszRFTwlTPmdziHwg';
// 实际项目中应调用后端API
// return new Promise((resolve) => {
// setTimeout(() => {
// // 生成模拟token
// const mockToken = 'pat_' + Math.random().toString(36).substring(2, 15);
// resolve(mockToken);
// }, 500);
// });
};
// 刷新token
const refreshToken = async () => {
authToken.value = await fetchToken();
};
// 初始化时获取token
onMounted(async () => {
authToken.value = await fetchToken();
});
},
};
</script>
<style>
.app-container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
font-family: Arial, sans-serif;
}
.refresh-btn {
margin-top: 20px;
padding: 10px 20px;
background: #2ecc71;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background 0.3s;
}
.refresh-btn:hover {
background: #27ae60;
}
</style>