290 lines
7.5 KiB
Vue
290 lines
7.5 KiB
Vue
<script lang="ts" setup>
|
|
import { ref, watch } from 'vue';
|
|
|
|
import { Download, Printer } from '@vben/icons';
|
|
import { $t } from '@vben/locales';
|
|
import { ReportDialogHeader, ZqUniverPrint } from '@zq/univer';
|
|
import '@zq/univer/style';
|
|
|
|
import UniverHost from '../univer-host.vue';
|
|
|
|
import { ElButton, ElDialog, ElMessage, ElMessageBox } from 'element-plus';
|
|
|
|
import {
|
|
exportReportDesignExcelApi,
|
|
previewReportDesignApi,
|
|
} from '#/api/online-dev/report-manager';
|
|
import { useReportQuery } from '#/components/report-design/hooks/useReportQuery';
|
|
import ReportQueryForm from '#/components/report-design/modules/report-query-form.vue';
|
|
import { countSnapshotImages } from '#/components/report-design/utils/report-media-url';
|
|
import { showPreviewWarnings } from '#/components/report-design/utils/preview-warnings';
|
|
|
|
const visible = defineModel<boolean>('visible', { default: false });
|
|
|
|
const props = defineProps<{
|
|
versionId: string;
|
|
reportCode?: string;
|
|
reportName?: string;
|
|
queryList: any[];
|
|
getDraftPayload?: () => Record<string, any> | null | undefined;
|
|
}>();
|
|
|
|
const loading = ref(false);
|
|
const exportLoading = ref(false);
|
|
const allowExport = ref(true);
|
|
const allowPrint = ref(true);
|
|
const printRef = ref<InstanceType<typeof ZqUniverPrint> | null>(null);
|
|
const previewReady = ref(false);
|
|
const previewSessionKey = ref(0);
|
|
const previewSnapshot = ref<Record<string, any>>({});
|
|
const previewCells = ref<Record<string, any>>({});
|
|
const previewChartData = ref<any[]>([]);
|
|
const previewWatermark = ref<{ show?: boolean; config?: Record<string, any> }>({
|
|
show: false,
|
|
config: {},
|
|
});
|
|
|
|
const { searchSchemas, formValues, setQueryList, getDefaultParams, setFormValues } =
|
|
useReportQuery();
|
|
|
|
watch(
|
|
() => props.queryList,
|
|
(list) => setQueryList(list || []),
|
|
{ immediate: true },
|
|
);
|
|
|
|
function resetPreviewState() {
|
|
previewReady.value = false;
|
|
allowExport.value = true;
|
|
allowPrint.value = true;
|
|
previewSnapshot.value = {};
|
|
previewCells.value = {};
|
|
previewChartData.value = [];
|
|
previewWatermark.value = { show: false, config: {} };
|
|
}
|
|
|
|
watch(visible, async (v) => {
|
|
if (!v) {
|
|
resetPreviewState();
|
|
return;
|
|
}
|
|
if (!props.versionId) return;
|
|
|
|
resetPreviewState();
|
|
await runPreview();
|
|
previewSessionKey.value += 1;
|
|
previewReady.value = true;
|
|
});
|
|
|
|
function buildDraftPayload() {
|
|
const draft = props.getDraftPayload?.();
|
|
if (!draft) return undefined;
|
|
return {
|
|
snapshot: draft.snapshot,
|
|
cells: draft.cells,
|
|
queryList: draft.queryList,
|
|
sortList: draft.sortList,
|
|
columnList: draft.columnList,
|
|
fenceList: draft.fenceList,
|
|
convertConfig: draft.convertConfig,
|
|
};
|
|
}
|
|
|
|
async function runPreview() {
|
|
if (!props.versionId) return;
|
|
loading.value = true;
|
|
try {
|
|
const res = await previewReportDesignApi(
|
|
props.versionId,
|
|
getDefaultParams(),
|
|
buildDraftPayload(),
|
|
);
|
|
previewSnapshot.value = res.snapshot || {};
|
|
previewCells.value = res.cells || {};
|
|
previewChartData.value = Array.isArray(res.chartData)
|
|
? res.chartData
|
|
: [];
|
|
previewWatermark.value =
|
|
res.watermark && typeof res.watermark === 'object'
|
|
? res.watermark
|
|
: {
|
|
show: !!res.allowWatermark,
|
|
config: res.watermarkConfig || {},
|
|
};
|
|
allowExport.value = res.allowExport !== false;
|
|
allowPrint.value = res.allowPrint !== false;
|
|
showPreviewWarnings(Array.isArray(res.warnings) ? res.warnings : []);
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
async function handleExportExcel() {
|
|
if (exportLoading.value || !props.versionId) return;
|
|
if (!allowExport.value) {
|
|
ElMessage.warning($t('report-manager.export.notAllowed'));
|
|
return;
|
|
}
|
|
exportLoading.value = true;
|
|
try {
|
|
const blob = await exportReportDesignExcelApi(
|
|
props.versionId,
|
|
getDefaultParams(),
|
|
buildDraftPayload(),
|
|
);
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = `${props.reportCode || props.reportName || 'report'}.xlsx`;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
ElMessage.success($t('report-manager.export.success'));
|
|
} catch (error: any) {
|
|
ElMessage.error(error?.message || $t('report-manager.export.failed'));
|
|
} finally {
|
|
exportLoading.value = false;
|
|
}
|
|
}
|
|
|
|
async function handlePrint() {
|
|
if (!allowPrint.value) {
|
|
ElMessage.warning($t('report-manager.print.notAllowed'));
|
|
return;
|
|
}
|
|
if (!previewSnapshot.value || !Object.keys(previewSnapshot.value).length) {
|
|
ElMessage.warning($t('report-manager.render.empty'));
|
|
return;
|
|
}
|
|
|
|
const imageCount = countSnapshotImages(previewSnapshot.value, previewCells.value);
|
|
if (imageCount > 100) {
|
|
try {
|
|
await ElMessageBox.confirm(
|
|
$t('report-manager.print.imageWarn', { count: imageCount }),
|
|
$t('report-manager.print.title'),
|
|
{ type: 'warning' },
|
|
);
|
|
} catch {
|
|
return;
|
|
}
|
|
}
|
|
|
|
printRef.value?.handleCreatePrintUnit?.({
|
|
snapshot: previewSnapshot.value as any,
|
|
watermarkConfig: previewWatermark.value,
|
|
reportName: props.reportName,
|
|
reportCode: props.reportCode,
|
|
});
|
|
}
|
|
|
|
function handleClose() {
|
|
visible.value = false;
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<ElDialog
|
|
v-model="visible"
|
|
class="report-preview-dialog"
|
|
fullscreen
|
|
append-to-body
|
|
destroy-on-close
|
|
:show-close="false"
|
|
:close-on-click-modal="false"
|
|
>
|
|
<div class="bg-background flex h-full min-h-0 flex-col">
|
|
<ReportDialogHeader
|
|
:report-name="reportName"
|
|
:report-code="reportCode"
|
|
:fallback-title="$t('report-manager.preview.title')"
|
|
>
|
|
<template #actions>
|
|
<ElButton
|
|
v-if="allowExport"
|
|
:icon="Download"
|
|
:loading="exportLoading"
|
|
@click="handleExportExcel"
|
|
>
|
|
{{ $t('report-manager.export.title') }}
|
|
</ElButton>
|
|
<ElButton v-if="allowPrint" :icon="Printer" @click="handlePrint">
|
|
{{ $t('report-manager.print.title') }}
|
|
</ElButton>
|
|
<ElButton @click="handleClose">
|
|
{{ $t('common.close') }}
|
|
</ElButton>
|
|
</template>
|
|
</ReportDialogHeader>
|
|
|
|
<main
|
|
v-loading="loading"
|
|
class="report-preview-dialog__content m-3 min-h-0 min-w-0 flex-1 overflow-hidden rounded-lg"
|
|
>
|
|
<ReportQueryForm
|
|
:schemas="searchSchemas"
|
|
:model-value="formValues"
|
|
:loading="loading"
|
|
@update:model-value="setFormValues"
|
|
@search="runPreview"
|
|
/>
|
|
<div class="report-preview-dialog__sheet">
|
|
<UniverHost
|
|
v-if="previewReady"
|
|
:key="previewSessionKey"
|
|
mode="preview"
|
|
readonly
|
|
class="h-full w-full"
|
|
:snapshot="previewSnapshot"
|
|
:cells="previewCells"
|
|
:chart-data="previewChartData"
|
|
:watermark="previewWatermark"
|
|
/>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</ElDialog>
|
|
|
|
<Teleport to="body">
|
|
<ZqUniverPrint ref="printRef" />
|
|
</Teleport>
|
|
</template>
|
|
|
|
<style lang="scss">
|
|
.report-preview-dialog.el-dialog {
|
|
display: flex;
|
|
flex-direction: column;
|
|
margin: 0;
|
|
padding: 0;
|
|
|
|
.el-dialog__header {
|
|
display: none;
|
|
}
|
|
|
|
.el-dialog__body {
|
|
display: flex;
|
|
flex: 1;
|
|
flex-direction: column;
|
|
min-height: 0;
|
|
overflow: hidden;
|
|
padding: 0;
|
|
}
|
|
}
|
|
|
|
.report-preview-dialog__content {
|
|
display: flex;
|
|
flex: 1;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
min-height: 0;
|
|
min-width: 0;
|
|
}
|
|
|
|
.report-preview-dialog__sheet {
|
|
flex: 1;
|
|
min-height: 0;
|
|
width: 100%;
|
|
overflow: hidden;
|
|
border-radius: 8px;
|
|
}
|
|
</style>
|