refactor: 重构微应用集成和组件结构

master
钟良源 1 month ago
parent 570b2664cd
commit 1a1281bcdd

@ -9,10 +9,8 @@ import './style.css'
// 初始化 micro-app
microApp.start({
'disable-sandbox': true,
'disable-scopecss': true,
// 启用虚拟路由系统,隔离子应用路由
// 这样子应用的 React Router 不会受到基座 hash 路由的影响
// 'disable-sandbox': true,
// 'disable-scopecss': true,
})
const app = createApp(App)

@ -3,9 +3,9 @@
<micro-app
iframe
name="label-app"
v-if="baseUrl"
:url="baseUrl"
style="display: block; width: 100%"
:style="{ height: config ? 'fit-content' : '' }"
style="display: block; width: 100%;height: 100%"
@mounted="microAppMounted"
router-mode="pure"
:disable-scopecss="media_type === '视频' && !config"
@ -18,7 +18,7 @@
<!-- 弹窗标签配置 -->
<el-dialog v-model="configDialog.show" title="标签配置" width="60vw">
<!-- 自定义 -->
<TagConfiguration v-if="configDialog.method === 'custom'" :id="configDialog.id" :is-use-canvas="true" />
<TagConfiguration v-if="configDialog.method === 'custom'" :id="configDialog.id" :is-use-canvas="true"/>
<!-- 其他 -->
<div v-else-if="configDialog.method == 'other'">
@ -38,18 +38,18 @@
</template>
<script lang="ts" setup>
import { useMicroApptore } from '@/stores/modules/micro-app';
import { useUserStore } from '@/stores/modules/user';
import {useMicroApptore} from '@/stores/modules/micro-app';
import {useUserStore} from '@/stores/modules/user';
import microAppX from '@micro-zoe/micro-app';
import { useRouter } from 'vue-router';
import { ElMessage } from 'element-plus';
import {useRouter} from 'vue-router';
import {ElMessage} from 'element-plus';
import TagConfiguration from './tag-configuration.vue';
import { tagConfig } from './type';
import {tagConfig} from './type';
const router = useRouter();
const route = useRoute();
const { taskId, sampleId } = route.params;
const { media_type } = route.query;
const {taskId, sampleId} = route.params;
const {media_type} = route.query;
const configDialog = ref<tagConfig>({
method: '',
show: false,
@ -58,7 +58,7 @@ const configDialog = ref<tagConfig>({
});
const config = route.hash;
const { getAppDetail } = useMicroApptore();
const {getAppDetail} = useMicroApptore();
const userStore = useUserStore();
const postData = reactive({
@ -186,7 +186,7 @@ const handleCancel = () => {
};
const handleSubmit = () => {
microAppX.setData('label-app', { type: 'SAVE_TASK_EDIT', timestamp: Date.now() });
microAppX.setData('label-app', {type: 'SAVE_TASK_EDIT', timestamp: Date.now()});
};
onBeforeUnmount(() => {
@ -194,7 +194,7 @@ onBeforeUnmount(() => {
});
const labelingToolCreateSubmission = () => {
microAppX.setData('label-app-editor', { type: 'SAVE_TASK_EDIT', timestamp: Date.now() });
microAppX.setData('label-app-editor', {type: 'SAVE_TASK_EDIT', timestamp: Date.now()});
configDialog.value.show = false;
};
@ -206,6 +206,8 @@ onUnmounted(() => {
<style lang="less" scoped>
.container-canvas {
width: 100%;
height: 100%;
background-color: #fff;
overflow: auto;

@ -35,7 +35,7 @@
<!-- 标签设置图片视频音频 -->
<div v-if="activeStep === 'labelSettings'" class="steps-micro">
<micro-app iframe name="label-app" :url="baseUrl" style="display: block; width: 100%" @mounted="microAppMounted" />
<micro-app iframe name="label-app" :src="baseUrl" style="display: block; width: 100%;height: 100%" @mounted="microAppMounted" />
</div>
<!-- 标签设置文本 -->

@ -3,7 +3,9 @@
<div class="header">
<div class="header-left">
<div class="back-title" @click="goBack">
<el-icon style="margin-right: 6px" size="18"><ArrowLeft /></el-icon>
<el-icon style="margin-right: 6px" size="18">
<ArrowLeft/>
</el-icon>
<span>{{ task.name }}</span>
</div>
<div class="filter-buttons">
@ -22,8 +24,10 @@
</div>
</div>
<div class="action-buttons">
<el-button v-if="task.media_type !== 'qa'" link @click="openTagConfig" :icon="Setting" style="margin-right: 10px"
>标签配置</el-button
<el-button v-if="task.media_type !== 'qa'" link @click="openTagConfig" :icon="Setting"
style="margin-right: 10px"
>标签配置
</el-button
>
<el-button link @click="openExportDialog" :icon="Printer" style="margin-right: 10px">数据导出</el-button>
<el-button type="primary" @click="startMarking"></el-button>
@ -41,7 +45,7 @@
@row-click="handleRowClick"
:row-style="{ cursor: 'pointer' }"
>
<el-table-column align="center" prop="index" label="序号" width="80" fixed />
<el-table-column align="center" prop="index" label="序号" width="80" fixed/>
<el-table-column
prop="name"
label="名称"
@ -64,8 +68,9 @@
<el-table-column label="数据预览">
<template #default="scope">
<audio v-if="task.media_type === 'audio'" :src="scope.row.previewUrl" controls></audio>
<video v-else-if="task.media_type === 'video'" :src="scope.row.previewUrl" controls style="height: 80px"></video>
<img v-else-if="task.media_type == 'image'" :src="scope.row.previewUrl" style="height: 80px" />
<video v-else-if="task.media_type === 'video'" :src="scope.row.previewUrl" controls
style="height: 80px"></video>
<img v-else-if="task.media_type == 'image'" :src="scope.row.previewUrl" style="height: 80px"/>
</template>
</el-table-column>
</template>
@ -77,7 +82,8 @@
</el-tag>
</template>
</el-table-column>
<el-table-column v-if="task.media_type !== 'qa'" align="center" prop="annotated_count" label="标注数量" width="120" />
<el-table-column v-if="task.media_type !== 'qa'" align="center" prop="annotated_count" label="标注数量"
width="120"/>
</el-table>
</div>
@ -99,7 +105,7 @@
<el-form :model="exportForm" :rules="exportRules" ref="exportFormRef" label-width="100px">
<el-form-item label="导出格式" prop="export_type">
<el-select v-model="exportForm.export_type" placeholder="请选择导出格式" style="width: 130px">
<el-option v-for="item in exportTypes" :key="item" :label="item" :value="item" />
<el-option v-for="item in exportTypes" :key="item" :label="item" :value="item"/>
</el-select>
</el-form-item>
</el-form>
@ -112,27 +118,27 @@
</template>
<script setup lang="ts">
import { ArrowLeft, Setting, Printer } from '@element-plus/icons-vue';
import { useGet, usePost } from '../../request';
import { markingApi, baseApi } from '../../request/api/requestApi';
import { parseContent } from '../../utils/parse-first-level';
import { ElMessage } from 'element-plus';
import {ArrowLeft, Setting, Printer} from '@element-plus/icons-vue';
import {useGet, usePost} from '../../request';
import {markingApi, baseApi} from '../../request/api/requestApi';
import {parseContent} from '../../utils/parse-first-level';
import {ElMessage} from 'element-plus';
const router = useRouter();
const route = useRoute();
const id = route.params.id as string;
const media_type = route.params.media_type as string;
const { doGet: taskGet } = useGet({
const {doGet: taskGet} = useGet({
url: markingApi.taskApi.get
});
const { doGet: sampleListGet, loading: sampleListLoading } = useGet({
const {doGet: sampleListGet, loading: sampleListLoading} = useGet({
url: markingApi.sample.page(id)
});
const { doGet: baseConfigGet } = useGet({
const {doGet: baseConfigGet} = useGet({
url: baseApi.config
});
const { doPost: exportPost, loading: exportPostLoading } = usePost({
const {doPost: exportPost, loading: exportPostLoading} = usePost({
url: markingApi.sample.export
});
@ -179,7 +185,7 @@ const exportForm = ref({
export_type: 'JSON'
});
const exportRules = ref({
export_type: [{ required: true, message: '请选择导出类型', trigger: 'blur' }]
export_type: [{required: true, message: '请选择导出类型', trigger: 'blur'}]
});
const exportFormRef = ref<any>();
@ -202,9 +208,9 @@ const handleExportSubmit = async () => {
const openTagConfig = () => {
if (task.value.media_type !== 'plaintext' && task.value.media_type !== 'timeseries') {
router.push({ path: `/data-factory/marking/canvas/${id}`, hash: '#config' });
router.push({path: `/data-factory/marking/canvas/${id}`, hash: '#config'});
} else {
router.push({ path: `/data-factory/marking/plaintextConfiguration/${id}` });
router.push({path: `/data-factory/marking/plaintextConfiguration/${id}`});
}
};
@ -374,30 +380,36 @@ const outputSample = async (activeTxt: string) => {
padding: 20px;
background-color: #ffffff;
border-radius: 4px;
.header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
.header-left {
display: flex;
gap: 60px;
align-items: center;
.back-title {
display: flex;
align-items: center;
font-size: 18px;
cursor: pointer;
}
.filter-buttons {
display: flex;
gap: 15px;
.btn-item {
padding: 5px 15px;
color: rgb(78 89 105 / 100%);
cursor: pointer;
border-radius: 20px;
transition: background-color 0.4s;
&.active {
color: rgb(22 93 255 / 100%);
background: rgb(237 237 237 / 100%);
@ -405,20 +417,24 @@ const outputSample = async (activeTxt: string) => {
}
}
}
.action-buttons {
el-button {
margin-left: 10px;
}
}
}
.table-container {
display: flex;
flex-direction: column;
justify-content: space-between;
height: calc(100% - 40px);
.table-content {
flex: 1;
overflow: auto;
.text-ellipsis {
display: inline-block;
width: 100%;
@ -428,12 +444,14 @@ const outputSample = async (activeTxt: string) => {
vertical-align: middle;
}
}
.pagination-box {
display: flex;
justify-content: flex-end;
padding: 10px 0;
}
}
.dialog-footer {
display: flex;
justify-content: flex-end;

@ -1,111 +1,51 @@
<template>
<div class="flow-app-container">
<micro-app
v-if="baseUrl"
name="flow-app"
:url="baseUrl"
iframe
style="display: block; width: 100%; height: 100%"
@created="onCreated"
@beforemount="onBeforeMount"
@mounted="onMountedHandler"
@error="onError"
/>
<div v-else class="loading-container">
<el-icon class="is-loading"><Loading /></el-icon>
<span>加载中...</span>
</div>
<micro-app name="flow-app" :url="baseUrl" style="display: block; width: 100%;height:100%"/>
</div>
</template>
<script setup lang="ts">
import { Loading } from '@element-plus/icons-vue';
import { useRoute } from 'vue-router';
import { useMicroApptore } from '@/stores/modules/micro-app';
import { ElMessage } from 'element-plus';
import {useRoute} from 'vue-router';
import {useMicroApptore} from '@/stores/modules/micro-app';
import {ElMessage} from 'element-plus';
import microAppX from '@micro-zoe/micro-app';
import { useUserStore } from '@/stores/modules/user';
import {useUserStore} from '@/stores/modules/user';
const userStore = useUserStore();
const { getAppDetail } = useMicroApptore();
const route = useRoute();
const baseUrl = ref('');
const postData = reactive({
userStoreData: userStore.$state
});
// micro-app
const onCreated = () => {
console.log('[flow-app] created');
};
const onBeforeMount = () => {
console.log('[flow-app] beforemount');
};
const onMountedHandler = () => {
console.log('[flow-app] mounted');
};
const onError = (e: CustomEvent) => {
console.error('[flow-app] error:', e.detail);
ElMessage.error('子应用加载失败');
};
const {getAppDetail} = useMicroApptore();
const route = useRoute();
const baseUrl = ref('');
onMounted(() => {
const agentId = route.params.id;
console.log('[flow-app] agentId:', agentId);
const commonUrl = `agent/${route.params.id}`;
if (import.meta.env.VITE_USER_NODE_ENV === 'production') {
const appUrl = getAppDetail('flow-app')?.appUrl;
const appUrl = getAppDetail('flow-app')?.appUrl; // 线
if (!appUrl) {
ElMessage.warning('微应用路径获取失败');
return;
ElMessage({
message: '微应用路径获取失败'
});
}
baseUrl.value = appUrl + 'agent/' + agentId;
microAppX.setData('flow-app', {
...postData,
server_ip: location.origin,
isTemplate: route.query.isTemplate,
agentId
});
// 线
baseUrl.value = appUrl ? appUrl + commonUrl : '';
microAppX.setData('flow-app', {...postData, server_ip: location.origin, isTemplate: route.query.isTemplate}); //
} else {
// 访
baseUrl.value = '/flowapp/agent/' + agentId;
console.log('[flow-app] baseUrl:', baseUrl.value);
nextTick(() => {
microAppX.setData('flow-app', {
...postData,
server_ip: undefined,
isTemplate: route.query.isTemplate,
agentId
});
});
//
baseUrl.value = 'http://localhost:9222/flowapp/' + commonUrl;
microAppX.setData('flow-app', {...postData, server_ip: undefined, isTemplate: route.query.isTemplate}); // 使
}
});
</script>
<style scoped lang="less">
.flow-app-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: auto;
}
.loading-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
gap: 8px;
color: #909399;
font-size: 14px;
}
</style>

@ -56,6 +56,7 @@
}
.process-content {
position: relative;
flex: 1;
overflow: auto;
padding: 16px;

Loading…
Cancel
Save