<script lang="ts" setup>
|
import type { FormulaValidation } from '#/api/x/eln/formulas';
|
|
import { computed, onMounted, ref, watch } from 'vue';
|
|
defineOptions({ name: 'ElnFormulaPreview' });
|
|
const props = defineProps<{ validation?: FormulaValidation }>();
|
const previewElement = ref<HTMLElement>();
|
let renderSequence = 0;
|
|
const hasValidationError = computed(() => props.validation?.diagnostics.some((diagnostic) => diagnostic.severity === 'ERROR') || false);
|
const errorText = computed(() =>
|
(props.validation?.diagnostics || [])
|
.filter((diagnostic) => diagnostic.severity === 'ERROR')
|
.map((diagnostic) => diagnostic.message || diagnostic.code || '公式校验失败')
|
.join(';'),
|
);
|
const latex = computed(() => (hasValidationError.value ? null : props.validation?.latex?.trim() || null));
|
|
onMounted(() => void renderPreview());
|
watch(latex, () => void renderPreview(), { flush: 'post' });
|
|
async function renderPreview() {
|
const sequence = ++renderSequence;
|
if (!latex.value || !previewElement.value) {
|
previewElement.value?.replaceChildren();
|
return;
|
}
|
const currentLatex = latex.value;
|
try {
|
const { default: katex } = await import('katex');
|
await import('katex/dist/katex.min.css');
|
if (sequence !== renderSequence || latex.value !== currentLatex || !previewElement.value) return;
|
previewElement.value.replaceChildren();
|
katex.render(currentLatex, previewElement.value, { displayMode: true, strict: 'warn', throwOnError: false, trust: false });
|
} catch {
|
if (sequence === renderSequence) previewElement.value?.replaceChildren();
|
}
|
}
|
</script>
|
|
<template>
|
<div class="formula-preview">
|
<a-alert v-if="errorText" :message="errorText" show-icon type="error" />
|
<div v-else-if="!latex" class="formula-preview__empty">等待公式校验结果</div>
|
<div v-show="latex" ref="previewElement" class="formula-preview__surface"></div>
|
</div>
|
</template>
|
|
<style lang="scss" scoped>
|
.formula-preview {
|
height: 100%;
|
}
|
|
.formula-preview__surface {
|
min-height: 120px;
|
padding: 24px 12px;
|
overflow: auto;
|
}
|
|
.formula-preview__empty {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
min-height: 120px;
|
color: var(--text-color-secondary);
|
}
|
</style>
|