feat: 优化插件弹窗加载速度

This commit is contained in:
jxxghp
2025-02-27 12:44:39 +08:00
parent 3d64382c9b
commit 5cd021ea85
6 changed files with 222 additions and 220 deletions

View File

@@ -0,0 +1,109 @@
<script setup lang="ts">
import { useDisplay } from 'vuetify'
import type { Plugin } from '@/api/types'
import { isNullOrEmptyObject } from '@/@core/utils'
import api from '@/api'
import { useToast } from 'vue-toast-notification'
import FormRender from '../render/FormRender.vue'
import ProgressDialog from '../dialog/ProgressDialog.vue'
// 输入参数
const props = defineProps({
plugin: {
type: Object as PropType<Plugin>,
},
})
// 定义事件
const emit = defineEmits(['close', 'save', 'switch'])
// 显示器宽度
const display = useDisplay()
// 插件配置表单数据
const pluginConfigForm = ref({})
// 插件表单配置项
let pluginFormItems = reactive([])
// 进度框
const progressDialog = ref(false)
// 进度文字
const progressText = ref('')
// 提示框
const $toast = useToast()
// 是否刷新
const isRefreshed = ref(false)
// 调用API读取表单页面
async function loadPluginForm() {
try {
const result: { [key: string]: any } = await api.get(`plugin/form/${props.plugin?.id}`)
if (result) {
pluginFormItems = result.conf
if (result.model) pluginConfigForm.value = result.model
}
} catch (error) {
console.error(error)
}
isRefreshed.value = true
}
// 调用API读取配置数据
async function loadPluginConf() {
try {
const result: { [key: string]: any } = await api.get(`plugin/${props.plugin?.id}`)
if (!isNullOrEmptyObject(result)) pluginConfigForm.value = result
} catch (error) {
console.error(error)
}
isRefreshed.value = true
}
// 调用API保存配置数据
async function savePluginConf() {
// 显示等待提示框
progressDialog.value = true
progressText.value = `正在保存 ${props.plugin?.plugin_name} 配置...`
try {
const result: { [key: string]: any } = await api.put(`plugin/${props.plugin?.id}`, pluginConfigForm.value)
if (result.success) {
progressDialog.value = false
$toast.success(`插件 ${props.plugin?.plugin_name} 配置已保存`)
// 通知父组件刷新
emit('save')
} else {
progressDialog.value = false
$toast.error(`插件 ${props.plugin?.plugin_name} 配置保存失败:${result.message}}`)
}
} catch (error) {
console.error(error)
}
}
onBeforeMount(async () => {
await loadPluginForm()
await loadPluginConf()
})
</script>
<template>
<VDialog scrollable max-width="60rem" :fullscreen="!display.mdAndUp.value">
<VCard :title="`${props.plugin?.plugin_name} - 配置`" class="rounded-t">
<DialogCloseBtn @click="emit('close')" />
<VDivider />
<VCardText v-if="isRefreshed">
<FormRender v-for="(item, index) in pluginFormItems" :key="index" :config="item" :model="pluginConfigForm" />
</VCardText>
<VCardActions class="pt-3">
<VBtn v-if="props.plugin?.has_page" @click="emit('switch')" variant="outlined" color="info"> 查看数据 </VBtn>
<VSpacer />
<VBtn @click="savePluginConf" variant="elevated" prepend-icon="mdi-content-save" class="px-5"> 保存 </VBtn>
</VCardActions>
</VCard>
<!-- 进度框 -->
<ProgressDialog v-if="progressDialog" v-model="progressDialog" :text="progressText" />
</VDialog>
</template>

View File

@@ -0,0 +1,63 @@
<script setup lang="ts">
import { useDisplay } from 'vuetify'
import type { Plugin } from '@/api/types'
import PageRender from '@/components/render/PageRender.vue'
import api from '@/api'
// 输入参数
const props = defineProps({
plugin: {
type: Object as PropType<Plugin>,
},
})
// 定义事件
const emit = defineEmits(['close', 'save', 'switch'])
// 显示器宽度
const display = useDisplay()
// APP
const appMode = inject('pwaMode') && display.mdAndDown.value
// 是否刷新
const isRefreshed = ref(false)
// 插件数据页面配置项
let pluginPageItems = ref([])
// 调用API读取数据页面
async function loadPluginPage() {
try {
const result: [] = await api.get(`plugin/page/${props.plugin?.id}`)
if (result) pluginPageItems.value = result
} catch (error) {
console.error(error)
}
isRefreshed.value = true
}
onMounted(() => {
loadPluginPage()
})
</script>
<template>
<VDialog scrollable max-width="80rem" :fullscreen="!display.mdAndUp.value">
<VCard :title="`${props.plugin?.plugin_name}`" class="rounded-t">
<DialogCloseBtn @click="emit('close')" />
<LoadingBanner v-if="!isRefreshed" class="mt-5" />
<VCardText v-else class="min-h-40">
<PageRender @action="loadPluginPage" v-for="(item, index) in pluginPageItems" :key="index" :config="item" />
</VCardText>
<VFab
icon="mdi-cog"
location="bottom"
size="x-large"
fixed
app
appear
@click="emit('switch')"
:class="{ 'mb-10': appMode }"
/>
</VCard>
</VDialog>
</template>

View File

@@ -6,54 +6,15 @@ import useDragAndDrop from '@core/utils/workflow'
import { Workflow } from '@/api/types'
import { useToast } from 'vue-toast-notification'
import api from '@/api'
import { useConfirm } from 'vuetify-use-dialog'
import Sidebar from '../workflow/Sidebar.vue'
import DropzoneBackground from '../workflow/DropzoneBackground.vue'
const { onConnect, addEdges, nodes, edges, onNodesChange, applyNodeChanges, onEdgesChange, applyEdgeChanges } =
useVueFlow()
const { onConnect, addEdges, nodes, edges } = useVueFlow()
const { onDragOver, onDrop, onDragLeave, isDragOver } = useDragAndDrop()
onConnect(addEdges)
onNodesChange(async (changes: any) => {
const nextChanges = []
for (const change of changes) {
if (change.type === 'remove') {
const isConfirmed = await createConfirm({
title: '确认',
content: `确定要删除该节点吗?`,
})
if (!isConfirmed) {
nextChanges.push(change)
}
} else {
nextChanges.push(change)
}
}
applyNodeChanges(nextChanges)
})
onEdgesChange(async (changes: any) => {
const nextChanges = []
for (const change of changes) {
if (change.type === 'remove') {
const isConfirmed = await createConfirm({
title: '确认',
content: `确定要删除该节点吗?`,
})
if (isConfirmed) {
nextChanges.push(change)
}
} else {
nextChanges.push(change)
}
}
applyEdgeChanges(nextChanges)
})
// 定义输入参数
const props = defineProps({
workflow: Object as PropType<Workflow>,
@@ -68,9 +29,6 @@ const workflowForm = ref<any>(props.workflow || {})
// 提示框
const $toast = useToast()
// 确认框
const createConfirm = useConfirm()
// 调用API 编辑任务
async function updateWorkflow() {
// 更新节点和流程
@@ -119,7 +77,13 @@ onMounted(() => {
</div>
<VCardText class="px-0 py-0">
<div class="dnd-flow" @drop="onDrop">
<VueFlow :nodes="nodes" :edges="edges" @dragover="onDragOver" @dragleave="onDragLeave">
<VueFlow
:nodes="nodes"
:edges="edges"
:default-edge-options="{ type: 'animation', animated: true }"
@dragover="onDragOver"
@dragleave="onDragLeave"
>
<MiniMap />
<DropzoneBackground
:style="{