2025-03-18 16:44:01 +08:00

205 lines
5.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { getCurrentInstance, onMounted, ref, watch } from 'vue';
import { useQuery } from '@tanstack/vue-query';
import { jsonp, request } from '@vtj/utils';
import { createProvider } from '@vtj/web';
import { ElLoading, ElMessage } from 'element-plus';
import { getFile } from './io';
import { LowCodeService } from './service';
console.log('window', window);
const rawWindow = window;
console.log('window.$wujie', window.$wujie);
// 定义 wujie props 的类型
interface WujieProps {
accessToken?: string;
applicationId?: number | string;
fileId?: string;
name?: string;
projectId?: number | string;
[key: string]: any;
}
// 从 wujie props 获取数据,提供默认值
const wujieProps: WujieProps = window.$wujie?.props || {};
console.log('wujie props:', wujieProps);
// 响应式状态
const renderer = ref();
const lowCodeService = new LowCodeService();
const isLoading = ref(false);
const provider = ref(null);
const loadingInstance = ref(null);
// 初始化请求配置
const initRequestConfig = (token: string) => {
if (!token) return;
request.useRequest((req) => {
req.headers.set('Authorization', `Bearer ${token}`);
return req;
});
};
// 显示加载中
const showLoading = (text = '低代码文件加载中...') => {
if (loadingInstance.value) return;
loadingInstance.value = ElLoading.service({ text });
};
// 隐藏加载中
const hideLoading = () => {
if (loadingInstance.value) {
loadingInstance.value.close();
loadingInstance.value = null;
}
};
// 初始化低代码引擎 - 只初始化一次
const initLowCodeEngine = async () => {
// 如果已经初始化过,直接返回
if (provider.value) return provider.value;
// 初始化请求配置
initRequestConfig(wujieProps.accessToken);
try {
const { provider: lowCodeProvider, onReady } = createProvider({
nodeEnv: import.meta.env.NODE_ENV,
service: lowCodeService,
project: { id: Number(wujieProps.projectId) },
adapter: {
request,
jsonp,
},
});
provider.value = { provider: lowCodeProvider, onReady };
return { provider: lowCodeProvider, onReady };
} catch (error) {
console.error('初始化低代码引擎失败:', error);
ElMessage.error('初始化低代码引擎失败');
return Promise.reject(error);
}
};
// 获取渲染组件
const getRenderComponent = async () => {
isLoading.value = true;
showLoading();
try {
// 1. 确保低代码引擎已初始化
const { provider: lowCodeProvider, onReady } = await initLowCodeEngine();
// 2. 获取渲染组件
return new Promise<any>((resolve) => {
onReady(async () => {
const instance = getCurrentInstance();
instance?.appContext.app.use(lowCodeProvider);
try {
const file = await getFile(wujieProps.fileId);
const { renderer } = await lowCodeProvider.createDslRenderer(
file.published_dsl,
{
// window: rawWindow,
},
);
console.log('渲染组件获取成功');
resolve(renderer);
} catch (error) {
console.error('获取渲染组件失败:', error);
ElMessage.error('获取渲染组件失败');
resolve(null);
}
});
});
} catch (error) {
console.error('获取渲染组件过程出错:', error);
return null;
} finally {
isLoading.value = false;
hideLoading();
}
};
// 使用 useQuery 管理渲染组件
const { data: rendererComponent, isError } = useQuery({
queryKey: ['getRenderer', wujieProps.fileId, wujieProps.projectId],
queryFn: getRenderComponent,
enabled: false, // 初始不自动执行
retry: 1, // 失败后重试一次
staleTime: 1000 * 60 * 5, // 5分钟内不重新获取
});
// 当组件挂载时,将渲染器组件赋值给 renderer
watch(rendererComponent, (newVal) => {
if (newVal) {
renderer.value = newVal;
console.log('渲染器组件已更新');
}
});
// 向父应用发送状态消息
const notifyParent = (event: string, data?: any) => {
if (window.$wujie?.bus) {
window.$wujie.bus.$emit(event, data);
}
};
// 组件挂载后执行初始化
onMounted(async () => {
// 通知父应用已准备就绪
notifyParent('ready', 'y-code-renderer is ready');
try {
await initLowCodeEngine();
const component = await getRenderComponent();
if (component) {
renderer.value = component;
notifyParent('render-success');
} else {
notifyParent('render-fail', 'Failed to get component');
}
} catch (error) {
console.error('初始化过程出错:', error);
notifyParent('render-fail', error);
}
});
</script>
<template>
<div class="renderer-container">
<component :is="renderer" v-if="renderer" :wujie-props="wujieProps" />
<div v-else-if="!isLoading && isError" class="error-message">
组件加载失败请检查参数和网络连接
</div>
<div v-else-if="!isLoading" class="error-message">
组件加载失败请检查控制台日志
</div>
</div>
</template>
<style scoped>
.renderer-container {
padding: 20px;
height: 100%;
width: 100%;
}
.error-message {
margin-top: 50px;
color: red;
text-align: center;
}
</style>