<script lang="ts" setup>
|
import { nextTick, onMounted, onUnmounted, reactive } from 'vue';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { BasicPopup } from '@jnpf/ui/popup';
|
import { createAsyncComponent } from '@jnpf/utils';
|
|
import { getConfigData, getConfigDataByMenuId } from '#/api/onlineDev/visualDev';
|
import { router } from '#/router';
|
import { onlineUtils } from '#/utils/jnpf';
|
|
const DynamicList = createAsyncComponent(() => import('#/views/common/dynamicModel/list/index.vue'));
|
|
interface OpenListConfig {
|
menuId?: number | string;
|
modelId?: number | string;
|
params?: Record<string, any>;
|
path?: string;
|
query?: Record<string, any>;
|
routeQuery?: Record<string, any>;
|
title?: string;
|
}
|
|
interface ListState {
|
config: any;
|
externalParams: Record<string, any>;
|
key: number;
|
loading: boolean;
|
menuId: string;
|
modelId: string;
|
open: boolean;
|
ready: boolean;
|
title: string;
|
}
|
|
const emitter = onlineUtils.getEmitter();
|
const props = withDefaults(defineProps<{ listenGlobal?: boolean }>(), {
|
listenGlobal: true,
|
});
|
const { createMessage } = useMessage();
|
const state = reactive<ListState>({
|
config: {},
|
externalParams: {},
|
key: Date.now(),
|
loading: false,
|
menuId: '',
|
modelId: '',
|
open: false,
|
ready: false,
|
title: '列表',
|
});
|
|
function parseRouteListQuery(value) {
|
if (!value || typeof value !== 'string') return {};
|
try {
|
const data = JSON.parse(value);
|
return data && typeof data === 'object' && !Array.isArray(data) ? data : {};
|
} catch {
|
return {};
|
}
|
}
|
|
function parsePathQuery(path = '') {
|
const query: Record<string, any> = {};
|
const queryString = path.includes('?') ? path.split('?')[1] : '';
|
if (!queryString) return query;
|
const params = new URLSearchParams(queryString);
|
params.forEach((value, key) => {
|
query[key] = value;
|
});
|
return query;
|
}
|
|
function getRouteInfo(config: OpenListConfig) {
|
const routes = router.getRoutes();
|
let target: any = null;
|
if (config.path) {
|
const path = config.path.split('?')[0];
|
target = routes.find((o) => o.path === path);
|
}
|
if (!target && config.menuId) target = routes.find((o) => String(o.meta?.modelId || '') === String(config.menuId));
|
if (!target && config.modelId) target = routes.find((o) => String(o.meta?.relationId || '') === String(config.modelId));
|
if (!target) return null;
|
return {
|
menuId: String(target.meta?.modelId || config.menuId || ''),
|
modelId: String(target.meta?.relationId || config.modelId || ''),
|
query: target.meta?.query && typeof target.meta.query === 'object' && !Array.isArray(target.meta.query) ? { ...target.meta.query } : {},
|
title: target.meta?.title,
|
};
|
}
|
|
async function getTargetConfig(config: OpenListConfig) {
|
const routeInfo = getRouteInfo(config);
|
if (routeInfo?.modelId) {
|
const res = await getConfigData(routeInfo.modelId, { onlineUtilsOpen: true });
|
return { config: res.data, menuId: routeInfo.menuId, modelId: routeInfo.modelId, query: routeInfo.query, title: routeInfo.title };
|
}
|
if (config.modelId) {
|
const res = await getConfigData(config.modelId, { onlineUtilsOpen: true });
|
return { config: res.data, menuId: String(config.menuId || ''), modelId: String(config.modelId), query: {}, title: '' };
|
}
|
if (config.menuId) {
|
const res = await getConfigDataByMenuId({ menuId: config.menuId, onlineUtilsOpen: true });
|
const data = res.data || {};
|
const modelId = data.id || data.modelId || data.visualId || '';
|
return { config: data, menuId: String(config.menuId), modelId: String(modelId), query: {}, title: '' };
|
}
|
throw new Error('未找到目标列表菜单');
|
}
|
|
function getExternalParams(config: OpenListConfig, menuQuery: Record<string, any> = {}) {
|
const params = config.params || config.query || {};
|
const routeQuery = { ...parsePathQuery(config.path), ...config.routeQuery };
|
const listQueryParams = parseRouteListQuery(routeQuery.jnpfListQuery);
|
delete routeQuery.jnpfListQuery;
|
return { ...menuQuery, ...routeQuery, ...listQueryParams, ...(params && typeof params === 'object' && !Array.isArray(params) ? params : {}) };
|
}
|
|
async function handleOpen(config: OpenListConfig) {
|
if (!config?.path && !config?.menuId && !config?.modelId) {
|
console.error('[onlineUtils.openList] path, menuId or modelId is required');
|
return;
|
}
|
state.open = true;
|
state.ready = false;
|
state.loading = true;
|
state.config = {};
|
state.menuId = '';
|
state.modelId = '';
|
state.externalParams = {};
|
try {
|
const target = await getTargetConfig(config);
|
if (!target.modelId || !target.config) throw new Error('未找到目标列表菜单');
|
if (target.config.webType == '1' || target.config.webType == 1) throw new Error('目标不是列表页面');
|
state.config = target.config;
|
state.modelId = target.modelId;
|
state.menuId = target.menuId;
|
state.title = config.title || target.title || target.config.fullName || '列表';
|
state.externalParams = getExternalParams(config, target.query);
|
state.key = Date.now();
|
state.ready = true;
|
await nextTick();
|
} catch (error: any) {
|
console.error('[onlineUtils.openList] open list modal failed:', error);
|
createMessage.warning(error?.message || '打开列表失败');
|
state.open = false;
|
} finally {
|
state.loading = false;
|
}
|
}
|
|
function handleClose() {
|
state.open = false;
|
state.ready = false;
|
state.config = {};
|
return Promise.resolve(true);
|
}
|
|
onMounted(() => {
|
if (props.listenGlobal) emitter.on('OPEN_LIST_MODAL', handleOpen as any);
|
});
|
|
onUnmounted(() => {
|
if (props.listenGlobal) emitter.off('OPEN_LIST_MODAL', handleOpen as any);
|
});
|
|
defineExpose({ close: handleClose, open: handleOpen });
|
</script>
|
|
<template>
|
<BasicPopup v-bind="$attrs" :open="state.open" destroy-on-close :show-ok-btn="false" :close-func="handleClose" class="full-popup global-list-popup">
|
<template #title>
|
<div class="text-[16px] font-medium">{{ state.title }}</div>
|
</template>
|
<div class="global-list-popup-body">
|
<DynamicList
|
v-if="state.ready"
|
:key="state.key"
|
:config="state.config"
|
:model-id="state.modelId"
|
:menu-id="state.menuId"
|
is-online-utils-open
|
:external-params="state.externalParams" />
|
</div>
|
</BasicPopup>
|
</template>
|
|
<style>
|
.global-list-popup-body {
|
height: 100%;
|
min-height: 0;
|
overflow: hidden;
|
}
|
|
.global-list-popup-body > .jnpf-content-wrapper {
|
height: 100%;
|
}
|
</style>
|