Commit 8a629996 authored by 高如斌's avatar 高如斌

1

parent 8bcd41e5
......@@ -202,6 +202,9 @@ frontend/.env.development.local
frontend/.env.test.local
frontend/.env.production.local
# Kiro IDE files
.kiro/
# OS generated files
Thumbs.db
.DS_Store
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -19,6 +19,7 @@
"highlight.js": "^11.9.0",
"marked": "^17.0.1",
"pako": "^2.1.0",
"pangea-ui": "^0.14.2-beta.9",
"pinia": "^2.1.7",
"snabbdom": "^3.6.3",
"vue": "^3.4.0",
......@@ -26,11 +27,13 @@
"vue-router": "^4.3.0"
},
"devDependencies": {
"@arco-design/web-vue": "^2.55.3",
"@types/dompurify": "^3.0.5",
"@types/node": "^20.10.0",
"@vitejs/plugin-vue": "^5.0.0",
"eslint": "^8.55.0",
"eslint-plugin-vue": "^9.19.0",
"less": "^4.2.0",
"terser": "^5.44.1",
"typescript": "^5.9.3",
"vite": "^5.0.0",
......
This diff is collapsed.
<template>
<hi-page-template
ref="templateRef"
:json="json"
:open-intl="false"
></hi-page-template>
<div class="button-wrap">
<a-button type="primary" @click="submit">提交</a-button>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import HiPageTemplate from "pangea-ui/hi-page-template";
const templateRef = ref();
const submit = () => {
templateRef.value?.ctx.validate(1, (res, data) => {
console.log(res, data);
});
};
const json = {
pages: [
{
key: 0,
type: "default",
name: "默认页",
code: "",
display: "",
props: {
margin: "16px",
padding: "12px",
backgroundColor: "white",
display: {},
},
bindProps: {},
coms: [
{
key: 1,
type: "node",
name: "表单容器",
code: "HiFormContainer",
display: "",
props: {
status: "default",
backgroundColor: "transparent",
layout: "horizontal",
size: "medium",
labelAlign: "right",
display: {},
borderRadius: {},
boxShadow: {},
loop: {
data: [],
},
},
bindProps: {},
coms: [
{
key: 1766473421208,
name: "输入框",
code: "HiInput",
props: {
title: "输入框",
status: "default",
placeholder: "请输入",
name: "INPUT_6CP8HIBK",
},
bindProps: {},
coms: [],
},
{
key: 1766476676439,
name: "日期",
code: "HiDatePicker",
props: {
title: "日期",
type: "date",
format: "YYYY-MM-DD",
status: "default",
name: "DATE_PA9TUPQQ",
},
bindProps: {},
},
],
},
],
},
],
params: [],
apis: [],
funcs: [],
pageTemplate: {},
};
</script>
<style scoped>
.button-wrap {
display: flex;
justify-content: center;
}
</style>
<template>
<div class="work-area">
<el-tabs v-model="activeTab" class="work-tabs">
<el-tab-pane label="表单" name="form">
<form-render ref="formRender" />
</el-tab-pane>
<el-tab-pane label="📋 时间轴" name="timeline">
<timeline-container ref="timelineContainerRef" />
</el-tab-pane>
......@@ -12,108 +15,121 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import TimelineContainer from './TimelineContainer.vue'
import WebpageBrowser from './WebpageBrowser.vue'
import { TimelineService } from '../services/TimelineService'
import { ref, onMounted, onUnmounted } from "vue";
import FormRender from "./FormRender.vue";
import TimelineContainer from "./TimelineContainer.vue";
import WebpageBrowser from "./WebpageBrowser.vue";
import { TimelineService } from "../services/TimelineService";
const activeTab = ref('timeline')
const timelineContainerRef = ref<InstanceType<typeof TimelineContainer> | null>(null)
const webBrowser = ref()
let timelineService: TimelineService | null = null
const activeTab = ref("form");
const formRender = ref();
const timelineContainerRef = ref<InstanceType<typeof TimelineContainer> | null>(
null
);
const webBrowser = ref();
let timelineService: TimelineService | null = null;
// 添加事件到时间轴
const addEvent = (event: any): void => {
timelineContainerRef.value?.addEvent(event)
}
timelineContainerRef.value?.addEvent(event);
};
// 初始化Timeline服务
const initTimelineService = () => {
if (timelineContainerRef.value) {
timelineService = new TimelineService((event: any) => {
addEvent(event)
})
timelineService.connectSSE()
addEvent(event);
});
timelineService.connectSSE();
}
}
};
// 清除时间轴
const clearTimeline = (): void => {
timelineContainerRef.value?.clearTimeline()
}
timelineContainerRef.value?.clearTimeline();
};
// 定义embed事件的详细信息类型
interface EmbedEventDetail {
url: string
type: string
title: string
htmlContent?: string
url: string;
type: string;
title: string;
htmlContent?: string;
}
// 监听embed事件
const handleEmbedEvent = (e: Event) => {
const customEvent = e as CustomEvent<EmbedEventDetail>
const { url, type, title, htmlContent } = customEvent.detail
const customEvent = e as CustomEvent<EmbedEventDetail>;
const { url, type, title, htmlContent } = customEvent.detail;
// 验证URL有效性
if (!url || typeof url !== 'string' || url.trim() === '') {
console.error('[WorkArea] embed事件URL验证失败:', {
if (!url || typeof url !== "string" || url.trim() === "") {
console.error("[WorkArea] embed事件URL验证失败:", {
url: url,
type: typeof url,
isEmpty: url?.trim() === '',
detail: customEvent.detail
})
return
isEmpty: url?.trim() === "",
detail: customEvent.detail,
});
return;
}
// 自动切换到浏览器标签页
activeTab.value = 'browser'
activeTab.value = "browser";
// 调用WebpageBrowser的导航方法,传递完整信息
if (webBrowser.value && typeof webBrowser.value.navigateToUrl === 'function') {
if (
webBrowser.value &&
typeof webBrowser.value.navigateToUrl === "function"
) {
webBrowser.value.navigateToUrl(url, {
htmlContent: htmlContent,
embedType: type,
embedTitle: title
})
embedTitle: title,
});
} else {
console.error('[WorkArea] webBrowser引用无效或navigateToUrl方法不存在', {
console.error("[WorkArea] webBrowser引用无效或navigateToUrl方法不存在", {
hasWebBrowser: !!webBrowser.value,
hasFn: webBrowser.value ? typeof webBrowser.value.navigateToUrl : 'undefined'
})
hasFn: webBrowser.value
? typeof webBrowser.value.navigateToUrl
: "undefined",
});
}
}
};
onMounted(() => {
// 监听embed事件
window.addEventListener('embed-event', handleEmbedEvent as EventListener)
window.addEventListener("embed-event", handleEmbedEvent as EventListener);
// 初始化Timeline服务
initTimelineService()
})
initTimelineService();
});
onUnmounted(() => {
// 移除事件监听
window.removeEventListener('embed-event', handleEmbedEvent as EventListener)
window.removeEventListener("embed-event", handleEmbedEvent as EventListener);
// 清理Timeline服务
if (timelineService) {
timelineService.cleanup()
timelineService.cleanup();
}
})// 暴露方法供父组件调用
}); // 暴露方法供父组件调用
defineExpose({
formRender,
timelineContainerRef,
webBrowser,
activeTab,
// 提供切换tab的方法
switchToForm: () => {
activeTab.value = "form";
},
switchToTimeline: () => {
activeTab.value = 'timeline'
activeTab.value = "timeline";
},
switchToBrowser: () => {
activeTab.value = 'browser'
activeTab.value = "browser";
},
// 提供时间轴操作方法
addEvent,
clearTimeline
})
clearTimeline,
});
</script>
<style scoped>
......
......@@ -4,6 +4,9 @@ import router from './router'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import ArcoVue from "@arco-design/web-vue";
import ArcoVueIcon from "@arco-design/web-vue/es/icon";
import '@arco-design/web-vue/dist/arco.less';
import 'highlight.js/styles/atom-one-dark.css'
import './styles/variables.css'
import './styles/global.css'
......@@ -17,6 +20,8 @@ const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(ElementPlus)
app.use(ArcoVue)
app.use(ArcoVueIcon)
// 全局注册所有Element Plus图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment