diff --git a/demo/jyExample.js b/demo/jyExample.js new file mode 100644 index 0000000..4302543 --- /dev/null +++ b/demo/jyExample.js @@ -0,0 +1,162 @@ +/* eslint-disable no-nested-ternary,no-restricted-syntax,prefer-const,no-plusplus,max-len */ +import React, { Component } from 'react'; +import { render, Text, Document, Hr, Table } from '../src/index'; +import { TitleStyle, SubTitleStyle, HrStyle, OneTitleStyle, TableHeaderStyle, TableBodyStyle, TextStyle } from './jyStyles'; + +const { values, entries } = Object; + +/** + * 表格 + * @param props + * @returns {*} + * @constructor + */ +function TableComponent(props) { + const { headers, data } = props; + const headerDatas = []; + // 设置表头样式 + headers.forEach((item) => { + const header = {}; + header.value = item; + header.styles = TableHeaderStyle; + headerDatas.push(header); + }); + return ( + + ); +} + + +// 时间数据 +const dateData = { year: 2018, + month: 1, + day: 10, + issue: 1 +}; + +// 表格1数据 +const table1Headers = ['监控名称', '余额', '比上日', '比上月', '比年初', '年增幅']; +const table1Data = [['人民币', '1000.00', '1000.00', '1000.00', '1000.00', '1000.00']]; + +// 贷款汇总 +const lnBal = { sz: 100, pj: -100, gr: 0 }; + +// 净增Top5 +const lnAddTop5 = [{ name: '大连', value: '30' }, + { name: '湖南省', value: '15.24' }, + { name: '厦门', value: '9.26' }, + { name: '湖北省', value: '7.05' }, + { name: '河南省', value: '7.04' }]; + +// 回落Top5 +const lnReduceTop5 = [{ name: '上海市', value: '-12.1' }, + { name: '江西省', value: '-11.74' }, + { name: '山东省', value: '-9.26' }, + { name: '天津市', value: '-7.05' }, + { name: '陕西省', value: '-7.04' }]; + +// 表格2 +const table2Headers = [{ value: '省', styles: { ...TableHeaderStyle } }, + { value: '客户', styles: { ...TableHeaderStyle } }, + { value: '金额', styles: { ...TableHeaderStyle } }, + { value: '行业', styles: { ...TableHeaderStyle } }]; +let table2Data = [['湖南省', '张三', '1000.00', '互联网']]; + +const lnTrade = { count: 3000, amt: 189.12, count5000: 15 }; + +class MyDocument extends Component { + // 副标题 + subTitle() { + const { date } = this.props; + // 生成填充空格 + const tab = ' '.repeat(60); + // 生成文本 + return `${date.year}年${date.month}月${date.day}日${tab}第${date.issue}期`; + } + + // 一级标题1 + oneTitle1() { + const { date } = this.props; + return `一、${date.month}月${date.day}日境内机构数据摘要:`; + } + + // 名字和金额映射 + nameAndValue(topValue) { + let str = ''; + topValue.forEach((item) => { + if (str === '') { + str = `${item.name}(${(item.value >= 0) ? `+${item.value}` : `${item.value}`})`; + } else { + str = `${str}、${item.name}(${(item.value >= 0) ? `+${item.value}` : `${item.value}`})`; + } + }); + return str; + } + + // 第一段 + text1() { + const { date, lnBal, lnAddTop5, lnReduceTop5 } = this.props; + + // 汇总 + let [a, d, r] = [0, 0, 0]; + for (let bal of values(lnBal)) { + (bal > 0) ? a++ : (bal === 0) ? d++ : r++; + } + const numMap = new Map([[1, '一'], [2, '二'], [3, '三']]); // 数字与汉字映射 + let lnTotal = `${(a > 0) ? `${numMap.get(a)}升` : ''}${ + (d > 0) ? `${numMap.get(d)}平` : ''}${ + (r > 0) ? `${numMap.get(r)}降` : ''}`; + + // 各项贷款 + const lnName = new Map([['sz', 'XXXX款'], ['pj', 'XXXX款'], ['gr', 'XXXX款']]); + for (let [key, bal] of entries(lnBal)) { + lnTotal = `${lnTotal},${lnName.get(key)}${ + (bal > 0) ? `增加${bal}亿元` : ''}${ + (bal === 0) ? '持平' : ''}${ + (bal < 0) ? `减少${Math.abs(bal)}亿元` : ''}`; + } + + let str = ` ${date.month}月${date.day}日,`; + str = `${str}境内机构XXXX款、XXXX款、XXXX款较上日表现为${lnTotal}。`; + str = `${str}XXXX款是${this.nameAndValue(lnAddTop5)},`; + str = `${str}较上月末回落较多的省分别是${this.nameAndValue(lnReduceTop5)}。`; + return str; + } + + // 一级标题2 + oneTitle2() { + const { date } = this.props; + return `二、${date.month}月${date.day}日发放情况:`; + } + + // 第二段 + text2() { + const { lnTrade } = this.props; + let str = ` 境内累计发放${lnTrade.count}笔,金额${lnTrade.amt}亿元。`; + str = `${str}5000万元(含)以上发放${lnTrade.count5000}笔,具体见下表。`; + return str; + } + + + render() { + return ( + + 交易情况 + {this.subTitle()} +
+ {this.oneTitle1()} + + {this.text1()} + {this.oneTitle2()} + {this.text2()} +
+ + ); + } +} + +render(, `${__dirname}/jy.docx`); + diff --git a/demo/jyStyles.js b/demo/jyStyles.js new file mode 100644 index 0000000..81cc085 --- /dev/null +++ b/demo/jyStyles.js @@ -0,0 +1,47 @@ +// 标题样式 +const TitleStyle = { + fontSize: 22, + fontFace: '方正小标宋_GBK' +}; +// 副标题 +const SubTitleStyle = { + fontSize: 14, + fontFace: '仿宋_GB2312' +}; +// 横线 +const HrStyle = { + // 样式未实现 +}; +// 一级标题 +const OneTitleStyle = { + fontSize: 14, + fontFace: '仿宋_GB2312', + bold: true +}; +// 表格头 +const TableHeaderStyle = { + bold: true, + size: 21 +}; +// 表格体 +const TableBodyStyle = { + tableColWidth: 4261, // Width of each column + tableSize: 21, // 字体大小 + tableAlign: 'right', // 表格居右 + borders: true +}; +// 正文 +const TextStyle = { + fontSize: 14, + fontFace: '仿宋_GB2312' +}; + +export { + TitleStyle, + SubTitleStyle, + HrStyle, + OneTitleStyle, + TableHeaderStyle, + TableBodyStyle, + TextStyle +}; diff --git a/src/components/Bullet.js b/src/components/Bullet.js index 1c5e95d..60356da 100644 --- a/src/components/Bullet.js +++ b/src/components/Bullet.js @@ -9,7 +9,6 @@ class BulletItem extends Root { super(root, props); this.root = root; this.props = props; - this.adder = this.root.doc.createListOfDots(); } appendChild(child) { @@ -22,6 +21,7 @@ class BulletItem extends Root { } async renderChildren(align, styles) { + this.adder = this.root.doc.createListOfDots(); await renderNodes(align, null, styles, this.adder, this.children, this.props); } diff --git a/src/components/Document.js b/src/components/Document.js index 4b0c3bb..80df2f5 100644 --- a/src/components/Document.js +++ b/src/components/Document.js @@ -4,7 +4,7 @@ import { applyStyles } from '../styles/styles'; /** * This component wraps all the children (string, components) and renders them. * It only takes two props, 'align' for alignment of the document and 'info' for adding - * document information like name of the author and description of the document. + * document information like name of the author and description of the document. */ class Document { @@ -14,10 +14,7 @@ class Document { constructor(root, props) { this.root = root; this.props = props; - // Create a new paragraph - this.adder = this.root.doc.createP(); - // Align the children which are of type string - this.adder.options.align = this.props.align; + // Add document information Object.assign(this.root.doc.options, this.props.info ? this.props.info : {}); // Validate the component props @@ -36,6 +33,10 @@ class Document { async renderChildren() { for (let i = 0; i < this.children.length; i += 1) { if (typeof this.children[i] === 'string') { + // Create a new paragraph + this.adder = this.root.doc.createP(); + // Align the children which are of type string + this.adder.options.align = this.props.align; // If not a component, render it as a paragraph await this.adder.addText( this.children[i], this.props.style ? applyStyles(this.props.style) : {}, diff --git a/src/components/HOC.js b/src/components/HOC.js index bfe9ade..e92d695 100644 --- a/src/components/HOC.js +++ b/src/components/HOC.js @@ -12,7 +12,6 @@ function hoc(component, fn) { constructor(root, props) { this.root = root; this.props = props; - this.adder = fn === 'getHeader' ? this.root.doc.getHeader().createP() : this.root.doc.getFooter().createP(); } appendChild(child) { @@ -25,6 +24,7 @@ function hoc(component, fn) { } async renderChildren(align, styles) { + this.adder = fn === 'getHeader' ? this.root.doc.getHeader().createP() : this.root.doc.getFooter().createP(); await renderNodes(align, this.props.align, styles, this.adder, this.children, this.props); } diff --git a/src/components/Image.js b/src/components/Image.js index 2b71660..2815085 100644 --- a/src/components/Image.js +++ b/src/components/Image.js @@ -19,7 +19,14 @@ class Image extends Root { } async renderImage(align) { - this.adder = this.root.doc.createP(); + // ҳü־ + if (this.props.headFootFlag === 'head') { + this.adder = this.root.doc.getHeader().createP(); + } else if (this.props.headFootFlag === 'foot') { + this.adder = this.root.doc.getFooter().createP(); + } else { + this.adder = this.root.doc.createP(); + } // Align the image with context by Document or through component prop 'align' alignChildren(this.adder, align, this.props.align); diff --git a/src/components/Number.js b/src/components/Number.js index e3fd318..7587cbf 100644 --- a/src/components/Number.js +++ b/src/components/Number.js @@ -9,7 +9,6 @@ class NumberItem extends Root { super(root, props); this.root = root; this.props = props; - this.adder = this.root.doc.createListOfNumbers(); } appendChild(child) { @@ -22,6 +21,7 @@ class NumberItem extends Root { } async renderChildren(align, styles) { + this.adder = this.root.doc.createListOfNumbers(); await renderNodes(align, null, styles, this.adder, this.children, this.props); } diff --git a/src/components/PageBreak.js b/src/components/PageBreak.js index bbbd9ed..a9a94d7 100644 --- a/src/components/PageBreak.js +++ b/src/components/PageBreak.js @@ -7,11 +7,11 @@ class PageBreak extends Root { constructor(root, props) { super(root, props); this.root = root; - this.adder = this.root.doc.putPageBreak(); } async render() { - await this.adder; + + await this.root.doc.putPageBreak(); } } diff --git a/src/components/Text.js b/src/components/Text.js index 727fa98..447710c 100644 --- a/src/components/Text.js +++ b/src/components/Text.js @@ -14,7 +14,6 @@ class Text extends Root { super(root, props); this.root = root; this.props = props; - this.adder = this.root.doc.createP(); validateTextProps(this.props); } @@ -62,8 +61,21 @@ class Text extends Root { } async renderChildren(align, styles) { + // 创建操作对象应该在回调函数进行,在构造方法中创建会导致和其他类型组件一起排版 + // createP should be in a renderChildren function, + // In the constructor to create leads to typeset together with other types of components + this.adder = this.root.doc.createP(); + // 对齐 alignChildren(this.adder, align, this.props.align); + // 段首缩进firstLine:'240' + // 段前间距spacing.before + // 段后间距spacing.after + // 行间距spacing.line + // docx.createP ({firstLine:'240', spacing : {before: '340', after: '330', line: '578'}}); + this.props.firstLine && (this.adder.options.firstLine = this.props.firstLine); + this.props.spacing && (this.adder.options.spacing = this.props.spacing); + for (let i = 0; i < this.children.length; i += 1) { if (typeof this.children[i] === 'string') { await renderText(this.children[i], this.props, styles, this.adder); diff --git a/src/validators/componentValidators.js b/src/validators/componentValidators.js index 8f35f3e..46889cc 100644 --- a/src/validators/componentValidators.js +++ b/src/validators/componentValidators.js @@ -59,7 +59,7 @@ function validateTableProps(props) { function headerValidators(props) { const { headers } = props; const headerSchema = ['value', 'styles']; - const styleSchema = ['bold', 'size', 'color', 'align', 'vAlign', 'fontFamily', 'fill']; + const styleSchema = ['bold', 'size', 'color', 'align', 'vAlign', 'fontFamily', 'fill', 'cellColWidth']; headers.forEach((header) => { Object.keys(header).forEach((key) => { @@ -87,7 +87,7 @@ function headerValidators(props) { function tableStyleValidators(props) { const { style } = props; const styleKeys = Object.keys(style || {}); - const tableStyleSchema = ['tableColWidth', 'tableSize', 'tableColor', 'tableAlign', 'borders']; + const tableStyleSchema = ['tableColWidth', 'tableSize', 'tableColor', 'tableAlign', 'borders', 'tableRowHeight', 'tableRowCantSplit']; styleKeys.forEach((key) => { if (!tableStyleSchema.includes(key)) { @@ -101,7 +101,7 @@ function tableStyleValidators(props) { * @param {Object} props Component props */ function validateTextProps(props) { - const knownProps = ['style', 'align', 'children']; + const knownProps = ['style', 'align', 'children', 'firstLine', 'spacing']; const takesProps = Object.keys(props || {}); takesProps.forEach((prop) => {