完成模版9个表格

master
lynn 6 months ago
parent c2f045a2a0
commit 5bd4abb345

@ -19,6 +19,7 @@
"core-js": "3.6.5",
"docx": "^9.4.1",
"docx-parser": "^0.2.1",
"docx-preview": "^0.1.14",
"docx2html": "^1.3.2",
"docxtemplater": "^3.61.1",
"echarts": "^5.6.0",

@ -26,15 +26,7 @@
</div>
<div class="preview-container" v-if="formatType === 1" v-html="previewContent"></div>
<div class="preview-container" v-else>
<iframe
v-if="docxUrl"
:src="docxUrl"
frameborder="0"
style="width: 100%; height: 100%;"
></iframe>
<div v-else class="no-preview">
请上传文档进行预览
</div>
<div v-html="previewContent"></div>
</div>
</div>
@ -159,15 +151,7 @@
>
<div class="modal-preview-container" v-if="formatType === 1" v-html="previewContent"></div>
<div class="modal-preview-container" v-else>
<iframe
v-if="docxUrl"
:src="docxUrl"
frameborder="0"
style="width: 100%; height: 100%;"
></iframe>
<div v-else class="no-preview">
请上传文档进行预览
</div>
<div v-html="previewContent"></div>
</div>
</el-dialog>
</div>
@ -189,7 +173,7 @@ export default {
previewContent: '', //
showEditDrawer: false,
showPreviewModal: false, //
currentTemplateIndex: 1,
currentTemplateIndex: 0,
editForm: {
field: '', // Renamed from name to field
name: '', // Renamed from label to name (Chinese name)
@ -201,6 +185,10 @@ export default {
docxUrl: null,
templateFile: null,
templates: [
{
name:'',
content:''
},
{
name: '资金划拨审批单',
content: `
@ -866,15 +854,21 @@ export default {
this.loadTemplate(newVal);
}
},
formatType: {
immediate: true,
handler(val) {
if (val === 1) {
this.loadTemplate(this.currentTemplateIndex);
} else {
this.codeContent = '<?xml version="1.0" encoding="UTF-8"?>\n<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">\n <!-- 这里将显示生成的DOCX代码 -->\n</w:document>'
this.previewContent = ''
formatType(newVal) {
if (newVal === 1) {
// HTML
if (this.$refs.codeEditor) {
this.$refs.codeEditor.setValue(this.codeContent)
}
this.previewContent = this.codeContent
this.handleRefresh()
} else if (newVal === 2) {
// DOCX
if (this.$refs.codeEditor) {
this.$refs.codeEditor.setValue(this.codeContent)
}
this.previewContent = this.codeContent
this.handleRefresh()
}
}
},
@ -916,68 +910,21 @@ export default {
this.previewContent = processedContent;
},
handleUpload() {
//
const input = document.createElement('input');
input.type = 'file';
input.accept = '.docx';
//
const input = document.createElement('input')
input.type = 'file'
input.accept = '.docx'
input.onchange = async (e) => {
const file = e.target.files[0];
e.preventDefault() //
const file = e.target.files[0]
if (file) {
//
if (!file.name.endsWith('.docx')) {
this.$message.error('请选择docx格式的文件');
return;
}
try {
// URL
const blobUrl = URL.createObjectURL(file);
// 使 Microsoft Office Online Viewer
this.docxUrl = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(blobUrl)}`;
//
this.codeContent = '';
// ArrayBuffer
const arrayBuffer = await this.readFileAsArrayBuffer(file);
// 使mammothdocxHTML
const result = await mammoth.convertToHtml({
arrayBuffer,
transformDocument: (document) => {
return document;
}
});
//
const variables = this.extractVariables(result.value);
// HTML
this.codeContent = result.value;
//
this.updateFieldMetadata(variables);
} catch (error) {
console.error('处理文档失败:', error);
this.$message.error('处理文档失败,请重试');
this.$message.error('请选择docx格式的文件')
return
}
await this.convertDocxToHtml(file)
}
};
//
input.click();
},
readFileAsArrayBuffer(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (event) => resolve(event.target.result);
reader.onerror = (error) => reject(error);
reader.readAsArrayBuffer(file);
});
}
input.click()
},
handleEditField(field) {
this.editForm = { ...field };
@ -1189,7 +1136,132 @@ export default {
extractAndUpdateFields() {
const variables = this.extractVariables(this.codeContent) // variables are field names
this.updateFieldMetadata(variables) // Pass field names
}
},
async convertDocxToHtml(file) {
try {
//
const fileName = file.name.replace(/\.[^/.]+$/, "")
this.formName = fileName
const reader = new FileReader()
const arrayBuffer = await new Promise((resolve, reject) => {
reader.onload = (e) => resolve(e.target.result)
reader.onerror = (e) => reject(e)
reader.readAsArrayBuffer(file)
})
const result = await mammoth.convertToHtml({
arrayBuffer,
convertImage: mammoth.images.imgElement(function(image) {
return image.read("base64").then(function(imageBuffer) {
return {
src: "data:" + image.contentType + ";base64," + imageBuffer
};
});
}),
styleMap: [
"p[style-name='Normal'] => p:style='margin: 0; padding: 0;'",
"p[style-name='Heading 1'] => h1:style='font-size: 24px; font-weight: bold; margin: 0 0 20px 0;'",
"p[style-name='Heading 2'] => h2:style='font-size: 20px; font-weight: bold; margin: 0 0 16px 0;'",
"p[style-name='Heading 3'] => h3:style='font-size: 18px; font-weight: bold; margin: 0 0 14px 0;'",
"p[style-name='Heading 4'] => h4:style='font-size: 16px; font-weight: bold; margin: 0 0 12px 0;'",
"p[style-name='Heading 5'] => h5:style='font-size: 14px; font-weight: bold; margin: 0 0 10px 0;'",
"p[style-name='Heading 6'] => h6:style='font-size: 12px; font-weight: bold; margin: 0 0 8px 0;'",
"p[style-name='List Paragraph'] => p:style='margin: 0; padding: 0; list-style-type: disc;'",
"p[style-name='Quote'] => blockquote:style='margin: 0 0 16px 0; padding: 10px 20px; border-left: 4px solid #ccc;'",
"p[style-name='Intense Quote'] => blockquote:style='margin: 0 0 16px 0; padding: 10px 20px; border-left: 4px solid #666; background: #f5f5f5;'",
"r[style-name='Strong'] => strong:style='font-weight: bold;'",
"r[style-name='Emphasis'] => em:style='font-style: italic;'",
"r[style-name='Code'] => code:style='font-family: monospace; background: #f5f5f5; padding: 2px 4px;'",
"table => table:style='width: 100%; border-collapse: collapse; margin: 0 0 16px 0;'",
"tr => tr:style='border-bottom: 1px solid #ddd;'",
"td => td:style='padding: 8px; border: 1px solid #ddd; text-align: center; vertical-align: middle;'",
"th => th:style='padding: 8px; border: 1px solid #ddd; font-weight: bold; text-align: center; vertical-align: middle;'",
"table[style-name='Table Grid'] => table:style='width: 100%; border-collapse: collapse; margin: 0 0 16px 0; border: 1px solid #000;'",
"table[style-name='Table Grid Light'] => table:style='width: 100%; border-collapse: collapse; margin: 0 0 16px 0; border: 1px solid #ddd;'",
"table[style-name='Table Grid Dark'] => table:style='width: 100%; border-collapse: collapse; margin: 0 0 16px 0; border: 1px solid #000;'",
"table[style-name='Table Grid Medium'] => table:style='width: 100%; border-collapse: collapse; margin: 0 0 16px 0; border: 1px solid #666;'"
],
transformDocument: function(document) {
return document;
}
})
// HTML
let html = result.value
//
html = html.replace(/<table/g, (match) => {
if (match.includes('style-name="Table Grid"')) {
return '<table style="width: 100%; border-collapse: collapse; margin: 0 0 16px 0; border: 1px solid #000;"'
} else if (match.includes('style-name="Table Grid Light"')) {
return '<table style="width: 100%; border-collapse: collapse; margin: 0 0 16px 0; border: 1px solid #ddd;"'
} else if (match.includes('style-name="Table Grid Dark"')) {
return '<table style="width: 100%; border-collapse: collapse; margin: 0 0 16px 0; border: 1px solid #000;"'
} else if (match.includes('style-name="Table Grid Medium"')) {
return '<table style="width: 100%; border-collapse: collapse; margin: 0 0 16px 0; border: 1px solid #666;"'
}
return '<table style="width: 100%; border-collapse: collapse; margin: 0 0 16px 0;"'
})
//
html = html.replace(/<td/g, (match) => {
let style = 'padding: 8px; border: 1px solid #ddd; text-align: center; vertical-align: middle;'
if (match.includes('style-name="Table Grid"')) {
style = 'padding: 8px; border: 1px solid #000; text-align: center; vertical-align: middle;'
} else if (match.includes('style-name="Table Grid Light"')) {
style = 'padding: 8px; border: 1px solid #ddd; text-align: center; vertical-align: middle;'
} else if (match.includes('style-name="Table Grid Dark"')) {
style = 'padding: 8px; border: 1px solid #000; text-align: center; vertical-align: middle;'
} else if (match.includes('style-name="Table Grid Medium"')) {
style = 'padding: 8px; border: 1px solid #666; text-align: center; vertical-align: middle;'
}
return `<td style="${style}"`
})
//
html = html.replace(/<th/g, (match) => {
let style = 'padding: 8px; border: 1px solid #ddd; font-weight: bold; text-align: center; vertical-align: middle;'
if (match.includes('style-name="Table Grid"')) {
style = 'padding: 8px; border: 1px solid #000; font-weight: bold; text-align: center; vertical-align: middle;'
} else if (match.includes('style-name="Table Grid Light"')) {
style = 'padding: 8px; border: 1px solid #ddd; font-weight: bold; text-align: center; vertical-align: middle;'
} else if (match.includes('style-name="Table Grid Dark"')) {
style = 'padding: 8px; border: 1px solid #000; font-weight: bold; text-align: center; vertical-align: middle;'
} else if (match.includes('style-name="Table Grid Medium"')) {
style = 'padding: 8px; border: 1px solid #666; font-weight: bold; text-align: center; vertical-align: middle;'
}
return `<th style="${style}"`
})
//
html = html.replace(/<p>/g, '<p style="margin: 0; padding: 0; display: flex; align-items: center; justify-content: center; height: 100%;">')
//
html = html.replace(/<img/g, '<img style="max-width: 100%; height: auto;"')
//
this.codeContent = html
//
const variables = this.extractVariables(html)
this.updateFieldMetadata(variables)
//
this.$nextTick(() => {
//
if (this.$refs.codeEditor) {
this.$refs.codeEditor.setValue(html)
}
//
this.previewContent = html
this.handleRefresh()
})
} catch (error) {
console.error('转换失败:', error)
this.$message.error('文件转换失败')
}
},
},
// URL
beforeDestroy() {

Loading…
Cancel
Save