You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

439 lines
12 KiB
Vue

5 months ago
<template>
<div>
4 months ago
<!-- {{ options }}-->
<!-- <div style="width: 19vw; display: inline-block">-->
<!-- <span style="font-size: 14px"> 点击插入字段(光标所在位置) </span>-->
<!-- <div class="fieldList">-->
<!-- <div class="fieldListItem" v-for="i in fieldList" @click="insertText(i)">-->
<!-- {{ i.name }}-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<div style="width: 100vw; display: inline-block; vertical-align: top">
<umo-editor v-bind="options" ref="editorRef" />
</div>
</div>
5 months ago
</template>
<script setup>
import { AlignmentType, Document, Footer, Packer, Paragraph, TextRun } from 'docx';
import { UmoEditor } from '@umoteam/editor';
const fieldList = ref([
{
name: '字段1',
value: '字段1'
},
{
name: '字段2',
value: '字段2'
}
]);
const editorRef = ref();
const docData = {
'甲方': '青岛xxx科技有限公司',
'合同表格表头': ['序号', '产品名称', '规格描述', '数量', '单位', '单价', '小记']
};
const createContractTable = () => {
const rows = 3;
const cols = docData['合同表格表头'].length;
const head = docData['合同表格表头'];
return {
type: 'table',
attrs: { id: 'contractTable', style: 'width:100%;border-collapse:collapse;' },
content: [
...Array.from({ length: rows }).map((_, k) => ({
type: 'tableRow',
content:
k === 0
? head.map((i) => ({
type: 'tableHeader',
attrs: { style: 'border:1px solid #ccc;padding:4px;height:40px;' },
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: i }]
}
]
}))
: Array.from({ length: cols }).map((__, kk) => ({
type: 'tableCell',
attrs: { style: 'border:1px solid #ccc;padding:4px;height:40px;' },
content:
kk === 0
? [
{
type: 'paragraph',
content: [{ type: 'text', text: '' + k }]
}
]
: [
{
type: 'paragraph',
content: [{ type: 'text', text: ' ' }]
}
]
}))
})),
{
type: 'tableRow',
content: [
{
type: 'tableCell',
attrs: { colspan: 6 },
content: [
{
type: 'paragraph',
attrs: { textAlign: 'center' },
content: [{ type: 'text', text: '合计' }]
}
]
},
{
type: 'tableCell',
attrs: {},
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: ' ' }]
}
]
}
]
},
{
type: 'tableRow',
content: [
{
type: 'tableCell',
attrs: { colspan: 7 },
content: [
{
type: 'paragraph',
attrs: { textAlign: 'center' },
content: [{ type: 'text', text: '合同总价: ¥ 大写:人民币 整' }]
}
]
}
]
},
{
type: 'tableRow',
content: [
{
type: 'tableCell',
attrs: { colspan: 7 },
content: [
{
type: 'paragraph',
attrs: { textAlign: 'left' },
content: [{ type: 'text', text: '备注:\t1、以上含13%增值税,开具增值税专用发票' }]
},
{
type: 'paragraph',
attrs: { textAlign: 'left' },
content: [{ type: 'text', text: '\t\t2、价格含包装运输费质保期一年。' }]
}
]
}
]
}
]
};
};
const options = ref({
4 months ago
templates: [
{
title: '合同',
description: '合同',
content: [
{
type: 'heading',
attrs: { level: 1, textAlign: 'center' },
content: [{ type: 'text', text: '合 同' }]
},
{
type: 'paragraph',
attrs: { textAlign: 'right' },
content: [{ type: 'text', text: '合同编号111' }]
},
{
type: 'paragraph',
content: [
{
type: 'text',
attrs: { textAlign: 'left' },
text: `\t甲方${docData['甲方']}\t\t乙方青岛海威物联科技有限公司`
}
]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '\t1.产品名称、规格、供货范围和价款 币种:人民币 单位:元' }]
},
createContractTable(),
{
type: 'paragraph',
content: [{ type: 'text', text: '\t2.产品包装' }]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '\t\t2.1所供产品由乙方妥善包装。' }]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '\t3.产品交付' }]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '\t\t3.1交付期合同签订收到预付款后1周内发货。' }]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '\t\t3.2乙方送货至甲方指定场所,运费由乙方承担。' }]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '\t4.验收及质保:货物签收即为验收确认无问题;且自设备验收之日起提供一年质保。' }]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '\t5.付款方式:\t电汇合同签订后7日内支付全额货款。' }]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '\t\t\t\t开户银行交通银行青岛崂山支行' }]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '\t\t\t\t银行账户38200557001801018025' }]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '\t6.知识产权' }]
},
{
type: 'paragraph',
content: [
{
type: 'text',
text: '\t\t与合同产品有关的所有技术资料的知识产权属于乙方所有甲方应当严格保守乙方的技术秘密未经许可不得泄露给第三方。否则甲方应当赔偿由此给乙方造成的一切经济损失。'
}
]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '\t7.不可抗力' }]
},
{
type: 'paragraph',
content: [
{
type: 'text',
text: '\t\t由于战争、严重的大火、水灾、暴风雪、瘟疫和地震等人力不可抗拒事件致使乙方交货延迟或不能交货时责任不在乙方。但乙方应立即将事故证明书以最快的方式交给甲方。在上述情况下乙方仍有采取一切必要措施从速交货的责任。'
}
]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '\t8.争议解决方式' }]
},
{
type: 'paragraph',
content: [
{
type: 'text',
text: '\t\t在本合同执行过程中如发生争议双方友好协商解决。协商不成双方同意由原告所在地人民法院审理。'
}
]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '\t9.其它' }]
},
{
type: 'paragraph',
content: [
{
type: 'text',
text: '\t\t合同自双方盖章起生效。本合同一式二份双方各执一份合同扫描件、复印件、传真件与原件具有同等法律效力。'
}
]
},
{
type: 'paragraph',
content: [{ type: 'text', text: `\t甲方${docData['甲方']}\t\t\t乙方青岛海威物联科技有限公司` }]
},
{
type: 'paragraph',
content: [{ type: 'text', text: `\t授权代表\t\t\t\t\t\t授权代表` }]
},
{
type: 'paragraph',
content: [{ type: 'text', text: `\t日期\t\t\t\t\t\t\t日期` }]
}
]
4 months ago
}
],
document: {
title: '',
content: {
type: 'doc',
content: []
},
placeholder: {
en_US: 'Please enter the document content...',
zh_CN: '请输入文档内容...'
},
enableSpellcheck: true,
enableMarkdown: true,
enableBubbleMenu: true,
enableBlockMenu: true,
readOnly: false,
autofocus: true,
characterLimit: 0,
typographyRules: {},
editorProps: {},
parseOptions: {
preserveWhitespace: 'full'
},
autoSave: {
enabled: true,
interval: 300000
}
},
onSave: async (e) => {
4 months ago
console.log(e);
// const editor = editorRef.value;
// const html = editor.getHTML();
// console.log(html);
// const doc = new Document({
// sections: [{ children: parseHTML(editor.getHTML()) }]
// });
// await download(doc);
},
onChanged: async (e) => {
4 months ago
// const editor = editorRef.value;
// const json = editor.getJSON();
// console.log(json);
// console.log(json.content.find((v) => v.type === 'table' && v.attrs?.id === 'contractTable'));
// json
4 months ago
// editor.setContent(json, { emitUpdate: false });
// const doc = new Document({
// sections: [{ children: prseHTML(editor.getHTML()) }]
// });
// await download(doc);
}
});
function parseHTML(html) {
const div = document.createElement('div');
div.innerHTML = html;
const children = [];
div.childNodes.forEach((node) => {
if (node.nodeType === 3) {
children.push(new Paragraph(node.textContent));
} else if (node.nodeType === 1) {
console.log(node);
console.log(node.tagName);
if (node.tagName === 'H1') {
children.push(new Paragraph({ text: node.textContent, heading: 'Heading1' }));
} else if (node.tagName === 'P') {
const runs = [];
node.childNodes.forEach((n) => {
const props = {};
if (n.tagName === 'B' || n.tagName === 'STRONG') props.bold = true;
if (n.tagName === 'I' || n.tagName === 'EM') props.italics = true;
runs.push(new TextRun({ text: n.textContent, ...props }));
});
children.push(new Paragraph({ children: runs }));
}
}
});
return children;
}
5 months ago
// 创建文档
const doc = new Document({
sections: [
{
properties: {},
children: [
new Paragraph({
text: 'Hello World',
heading: 'Heading1'
}),
new Paragraph({
text: 'This is a simple DOCX file created using DOCX.js.'
})
]
}
]
});
const download = async (doc) => {
const blob = await Packer.toBlob(doc);
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'document.docx';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
// download(doc)
const insertText = (e) => {
const editor = editorRef.value;
console.log(editor);
console.log(editor.getSelectionNode());
console.log(editor.getSelectionText());
// const selection = editor.getSelection();
// editor.insertContent({
// type: 'text',
// text: e.value
// });
// if (selection) {
// editor.focus();
// editor.setSelection(selection.toEnd ? selection.toEnd() : selection);
// }
editor
.chain()
.focus()
.insertContent({
type: 'text',
text: e.value
})
.run();
};
5 months ago
</script>
<style scoped>
.fieldList {
width: 100%;
height: calc(100vh - 30px);
overflow: auto;
&::-webkit-scrollbar {
display: none;
}
.fieldListItem {
line-height: 40px;
font-size: 16px;
}
}
/deep/ .t-button--theme-warning {
border-color: var(--td-warning-color-hover);
background-color: var(--td-warning-color-hover);
}
</style>
<style>
.umo-footer {
position: sticky;
bottom: 0px;
}
</style>