|
|
|
|
@ -1,13 +1,13 @@
|
|
|
|
|
<template>
|
|
|
|
|
<div>
|
|
|
|
|
<div style="width: 100%; display: inline-block; vertical-align: top; height: calc(100vh - 50px - 34px)">
|
|
|
|
|
<umo-editor v-bind="options" ref="editorRef" />
|
|
|
|
|
<umo-editor v-if="editorReady" v-bind="options" ref="editorRef" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { getCurrentInstance, onMounted, ref } from 'vue';
|
|
|
|
|
import { getCurrentInstance, nextTick, onMounted, onUnmounted, ref } from 'vue';
|
|
|
|
|
import { UmoEditor } from '@umoteam/editor';
|
|
|
|
|
import { getPrintTemplate } from '@/api/oa/base/printTemplate';
|
|
|
|
|
import { templateAssign } from '@/api/oa/base/templateVariable';
|
|
|
|
|
@ -16,29 +16,45 @@ import { useRoute } from 'vue-router';
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
const proxy = getCurrentInstance()?.proxy;
|
|
|
|
|
|
|
|
|
|
const editorRef = ref();
|
|
|
|
|
const template = ref<any>({});
|
|
|
|
|
const editorRef = ref();
|
|
|
|
|
const editorReady = ref(false);
|
|
|
|
|
let templateData: Record<string, any> = {};
|
|
|
|
|
let isUnmounted = false;
|
|
|
|
|
const defaultMargin = { left: 2.1, right: 2.1, top: 2.2, bottom: 2.2 };
|
|
|
|
|
|
|
|
|
|
const options = ref({
|
|
|
|
|
document: {
|
|
|
|
|
title: '',
|
|
|
|
|
content: { type: 'doc', content: [] },
|
|
|
|
|
placeholder: { en_US: 'Please enter the document content...', zh_CN: '请输入文档内容...' },
|
|
|
|
|
content: {
|
|
|
|
|
type: 'doc',
|
|
|
|
|
content: []
|
|
|
|
|
},
|
|
|
|
|
placeholder: {
|
|
|
|
|
en_US: 'Please enter the document content...',
|
|
|
|
|
zh_CN: '请输入文档内容...'
|
|
|
|
|
},
|
|
|
|
|
enableSpellcheck: true,
|
|
|
|
|
enableMarkdown: false,
|
|
|
|
|
enableBubbleMenu: true,
|
|
|
|
|
enableBlockMenu: true,
|
|
|
|
|
readOnly: true,
|
|
|
|
|
autofocus: false,
|
|
|
|
|
readOnly: false,
|
|
|
|
|
autofocus: true,
|
|
|
|
|
characterLimit: 0,
|
|
|
|
|
typographyRules: { emDash: false },
|
|
|
|
|
typographyRules: {
|
|
|
|
|
emDash: false
|
|
|
|
|
},
|
|
|
|
|
editorProps: {},
|
|
|
|
|
parseOptions: { preserveWhitespace: 'full' },
|
|
|
|
|
autoSave: { enabled: false }
|
|
|
|
|
parseOptions: {
|
|
|
|
|
preserveWhitespace: 'full'
|
|
|
|
|
},
|
|
|
|
|
autoSave: {
|
|
|
|
|
enabled: false
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
toolbar: {
|
|
|
|
|
menus: ['base', 'export']
|
|
|
|
|
},
|
|
|
|
|
toolbar: { menus: ['export'] },
|
|
|
|
|
disableExtensions: [
|
|
|
|
|
'ordered-list',
|
|
|
|
|
'quote',
|
|
|
|
|
@ -50,11 +66,19 @@ const options = ref({
|
|
|
|
|
'export-image',
|
|
|
|
|
'export-text',
|
|
|
|
|
'share',
|
|
|
|
|
'embed',
|
|
|
|
|
'image',
|
|
|
|
|
'link'
|
|
|
|
|
'embed'
|
|
|
|
|
],
|
|
|
|
|
page: { showBreakMarks: false, defaultMargin }
|
|
|
|
|
page: {
|
|
|
|
|
showBreakMarks: false,
|
|
|
|
|
defaultMargin
|
|
|
|
|
},
|
|
|
|
|
// 这里与合同预览保持同一导出入口配置,避免报价导出在 UMO 内部能力上再次分叉
|
|
|
|
|
onSave: async () => {
|
|
|
|
|
return true;
|
|
|
|
|
},
|
|
|
|
|
onFileUpload: async (file: any) => {
|
|
|
|
|
return file;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 常量赋值
|
|
|
|
|
@ -109,9 +133,9 @@ const hasCaretPattern = (arr: any[]) => {
|
|
|
|
|
// 行数据填充
|
|
|
|
|
const fillRowData = (e: any, index: number) => {
|
|
|
|
|
if (Array.isArray(e.content)) {
|
|
|
|
|
e.content.map((item: any) => fillRowData(item, index));
|
|
|
|
|
e.content.forEach((item: any) => fillRowData(item, index));
|
|
|
|
|
} else {
|
|
|
|
|
e.text = rowRenderTemplate(e.text || '', index);
|
|
|
|
|
e.text = rowRenderTemplate(e.text || ' ', index);
|
|
|
|
|
}
|
|
|
|
|
return e;
|
|
|
|
|
};
|
|
|
|
|
@ -142,19 +166,39 @@ const fillData = (e: any): any => {
|
|
|
|
|
e.content = tableTemplate(e.content);
|
|
|
|
|
} else {
|
|
|
|
|
if (Array.isArray(e.content)) {
|
|
|
|
|
e.content.map((item: any) => fillData(item));
|
|
|
|
|
e.content.forEach((item: any) => fillData(item));
|
|
|
|
|
} else {
|
|
|
|
|
e.text = renderTemplate(e.text || '', templateData);
|
|
|
|
|
e.text = renderTemplate(e.text || ' ', templateData);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return e;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const normalizeQueryValue = (value: unknown) => {
|
|
|
|
|
return Array.isArray(value) ? value[0] : value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const resolvePageMargin = (pageConfig: string | undefined) => {
|
|
|
|
|
const config = JSON.parse(pageConfig || '{}');
|
|
|
|
|
const margin = {
|
|
|
|
|
...defaultMargin,
|
|
|
|
|
...(config.pageMargin || {})
|
|
|
|
|
};
|
|
|
|
|
// UMO 的页边距对象里如果混入 layout 字段,导出时会和合同页表现不一致,这里统一剔除
|
|
|
|
|
delete (margin as Record<string, any>).layout;
|
|
|
|
|
return margin;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
isUnmounted = true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
try {
|
|
|
|
|
const quoteIdParam = Array.isArray(route.query.quoteId) ? route.query.quoteId[0] : route.query.quoteId;
|
|
|
|
|
const templateIdParam = Array.isArray(route.query.templateId) ? route.query.templateId[0] : route.query.templateId;
|
|
|
|
|
const quoteId = quoteIdParam ? Number(quoteIdParam) : undefined;
|
|
|
|
|
const quoteIdParam = normalizeQueryValue(route.query.quoteId);
|
|
|
|
|
const templateIdParam = normalizeQueryValue(route.query.templateId);
|
|
|
|
|
// 报价单ID可能是 Long/雪花ID,前端这里保持字符串透传,避免 Number 转换后发生精度丢失导致串单
|
|
|
|
|
const quoteId = quoteIdParam ? String(quoteIdParam) : undefined;
|
|
|
|
|
const templateId = templateIdParam ? String(templateIdParam) : undefined;
|
|
|
|
|
|
|
|
|
|
if (!quoteId || !templateId) {
|
|
|
|
|
@ -169,21 +213,22 @@ onMounted(async () => {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const tplResp = await getPrintTemplate(templateId);
|
|
|
|
|
if (isUnmounted) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
template.value = tplResp.data;
|
|
|
|
|
const editor = editorRef.value;
|
|
|
|
|
|
|
|
|
|
const pageConfig = JSON.parse(tplResp.data.pageConfig || '{}');
|
|
|
|
|
const margin = pageConfig.pageMargin || defaultMargin;
|
|
|
|
|
options.value.page.defaultMargin = {
|
|
|
|
|
left: margin.left ?? defaultMargin.left,
|
|
|
|
|
right: margin.right ?? defaultMargin.right,
|
|
|
|
|
top: margin.top ?? defaultMargin.top,
|
|
|
|
|
bottom: margin.bottom ?? defaultMargin.bottom
|
|
|
|
|
};
|
|
|
|
|
options.value.page.defaultMargin = resolvePageMargin(tplResp.data.pageConfig);
|
|
|
|
|
|
|
|
|
|
const docData = JSON.parse(tplResp.data.templateData || '{}');
|
|
|
|
|
const dataFilled = fillData(docData);
|
|
|
|
|
editor?.setContent(dataFilled);
|
|
|
|
|
// 先把模板和页边距准备完整再挂载编辑器,避免导出页在快速切换时出现空节点补丁异常
|
|
|
|
|
editorReady.value = true;
|
|
|
|
|
await nextTick();
|
|
|
|
|
if (isUnmounted) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
editorRef.value?.setContent(dataFilled);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('quoteView export init error', error);
|
|
|
|
|
proxy?.$modal.msgError('加载报价模板失败,请稍后重试');
|
|
|
|
|
@ -192,48 +237,22 @@ onMounted(async () => {
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
.title {
|
|
|
|
|
width: 100%;
|
|
|
|
|
line-height: 40px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
color: #666;
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.fieldList {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: calc(100vh - 50px - 34px - 40px);
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
|
|
|
|
.fieldItem {
|
|
|
|
|
width: 80%;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
padding-left: 15px;
|
|
|
|
|
color: #333;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
|
|
.btn {
|
|
|
|
|
padding: 10px;
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
background-color: #eee;
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/deep/ .umo-toolbar-actions.ribbon {
|
|
|
|
|
::deep(.umo-toolbar-actions.ribbon) {
|
|
|
|
|
display: none !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/deep/ .umo-status-bar-left .umo-button:nth-child(4) {
|
|
|
|
|
::deep(.umo-status-bar-left .umo-button:nth-child(4)) {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/deep/ .umo-status-bar-left .umo-button:nth-child(5) {
|
|
|
|
|
::deep(.umo-status-bar-left .umo-button:nth-child(5)) {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
::deep(.t-button--theme-warning) {
|
|
|
|
|
border-color: var(--td-warning-color-hover);
|
|
|
|
|
background-color: var(--td-warning-color-hover);
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
<style>
|
|
|
|
|
.umo-footer {
|
|
|
|
|
|