<script lang="ts" setup>
|
import { ref, watch } from 'vue';
|
|
import { createAsyncComponent } from '@jnpf/utils';
|
|
import { Button, Result, Spin } from 'ant-design-vue';
|
import { cloneDeep } from 'lodash-es';
|
|
import { getConfigData, getDataChange } from '#/api/onlineDev/visualDev';
|
import { onlineUtils } from '#/utils/jnpf';
|
import { processDetailData } from '#/views/common/dynamicModel/list/detail/detailData';
|
|
import type { FormDetailTab } from './types';
|
|
const DetailParser = createAsyncComponent(() => import('#/views/common/dynamicModel/list/detail/Parser.vue'));
|
|
const props = defineProps<{
|
tab: FormDetailTab;
|
}>();
|
|
const loading = ref(false);
|
const error = ref('');
|
const formConf = ref<Record<string, any> | null>(null);
|
const formData = ref<Record<string, any>>({});
|
const renderKey = ref(0);
|
let requestId = 0;
|
|
function fillFormData(form: Record<string, any>, data: Record<string, any>) {
|
const loop = (list: any[]) => {
|
if (!Array.isArray(list)) return;
|
for (const item of list) {
|
const config = item.__config__;
|
if (!config) continue;
|
|
if (item.__vModel__) {
|
if (config.jnpfKey === 'relationForm' || config.jnpfKey === 'popupSelect') {
|
config.defaultValue = data[`${item.__vModel__}_id`];
|
item.name = data[item.__vModel__] || '';
|
} else if (Object.prototype.hasOwnProperty.call(data, item.__vModel__)) {
|
config.defaultValue = data[item.__vModel__];
|
}
|
} else if (['popupAttr', 'relationFormAttr'].includes(config.jnpfKey)) {
|
config.defaultValue = data[`${item.relationField.split('_jnpfTable_')[0]}_${item.showField}`];
|
}
|
|
if (Array.isArray(config.children)) loop(config.children);
|
}
|
};
|
|
loop(form.fields);
|
}
|
|
async function loadDetail() {
|
const currentRequestId = ++requestId;
|
const { modelId, id } = props.tab;
|
if (!modelId || !id) {
|
error.value = '缺少表单详情参数';
|
formConf.value = null;
|
formData.value = {};
|
loading.value = false;
|
return;
|
}
|
|
loading.value = true;
|
error.value = '';
|
|
try {
|
const detailQuery: Record<string, any> = { id };
|
if (props.tab.menuId) detailQuery.menuId = props.tab.menuId;
|
if (props.tab.propsValue) detailQuery.propsValue = props.tab.propsValue;
|
const [configRes, modelRes] = await Promise.all([getConfigData(modelId), getDataChange(modelId, detailQuery)]);
|
const configData = configRes.data || {};
|
if (!configData.formData) throw new Error('目标表单配置异常');
|
const parsedFormConf = JSON.parse(configData.formData);
|
const dataForm = modelRes?.data || {};
|
const dataId = dataForm.id || id;
|
const nextFormConf = cloneDeep(parsedFormConf);
|
const sourceFormData = dataForm.data ? { ...JSON.parse(dataForm.data), id: dataId } : { id: dataId };
|
const nextFormData = await processDetailData(nextFormConf, sourceFormData, onlineUtils);
|
fillFormData(nextFormConf, nextFormData);
|
|
if (currentRequestId !== requestId) return;
|
formConf.value = nextFormConf;
|
formData.value = nextFormData;
|
renderKey.value = Date.now();
|
} catch (err) {
|
if (currentRequestId !== requestId) return;
|
console.error('[ReportFormDetailPane] 加载表单详情失败:', err);
|
error.value = '加载表单详情失败';
|
formConf.value = null;
|
formData.value = {};
|
} finally {
|
if (currentRequestId !== requestId) return;
|
loading.value = false;
|
}
|
}
|
|
watch(() => [props.tab.modelId, props.tab.id], loadDetail, { immediate: true });
|
|
defineExpose({ reload: loadDetail });
|
</script>
|
|
<template>
|
<div class="report-form-detail-pane">
|
<div v-if="loading" class="loading-state">
|
<Spin size="large" tip="加载表单详情中..." />
|
</div>
|
|
<div v-else-if="error" class="error-state">
|
<Result status="error" :title="error">
|
<template #extra>
|
<Button type="primary" @click="loadDetail">重新加载</Button>
|
</template>
|
</Result>
|
</div>
|
|
<DetailParser v-else-if="formConf" :key="renderKey" :form-conf="formConf" :form-data="formData" />
|
</div>
|
</template>
|
|
<style lang="scss" scoped>
|
.report-form-detail-pane {
|
min-height: 400px;
|
padding: 10px;
|
|
.loading-state {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
min-height: 400px;
|
}
|
}
|
</style>
|