Przeglądaj źródła

fix(report): 1.新增以建设项目、分项项目为统计维度的逻辑 2.新增报表导出的功能逻辑

lishihao 4 lat temu
rodzic
commit
efa16fd79a

Plik diff jest za duży
+ 717 - 59
report/package-lock.json


+ 3 - 1
report/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@sc/report",
-  "version": "3.0.1",
+  "version": "3.0.2",
   "description": "Smartcost Report Relative Module",
   "main": "./dist/index.cjs.js",
   "module": "./dist/index.esm.js",
@@ -43,6 +43,8 @@
     "typescript": "^4.0.5"
   },
   "dependencies": {
+    "fs": "0.0.1-security",
+    "pdfkit": "^0.12.1",
     "stream": "0.0.2",
     "uuid": "^8.3.0"
   }

+ 2 - 1
report/src/core/helper/jpc_helper_area.ts

@@ -1,5 +1,6 @@
 'use strict';
 
+import { IPositionProps } from '../../index';
 import { IArea, IBandDetail } from '../../interface/basic';
 import JV from '../jpc_value_define';
 
@@ -10,7 +11,7 @@ const JpcAreaHelper = {
             Left: 0,
             Right: 0,
             Top: 0,
-            Bottom: 0
+            Bottom: 0,
         },
             maxMultiColumns = 3;
         if (multipleDispCol > 0 && multipleDispCol <= maxMultiColumns) {

+ 1 - 0
report/src/core/helper/jpc_helper_common.ts

@@ -1,5 +1,6 @@
 'use strict';
 
+import { IPositionProps } from '../../index';
 import { IArea, IControlCollection, IControlSubCollection, IRptTpl, IStyles } from '../../interface/basic';
 import JV from '../jpc_value_define';
 

+ 1 - 1
report/src/core/jpc_cross_tab.ts

@@ -24,7 +24,7 @@ import {
     ICrossTab,
     IGroupField
 } from '../interface/basic';
-import { IDataObjProps } from '../interface/enum'
+import { IDataObjProps, IPositionProps } from '../interface/enum'
 class JpcCrossTabClass {
     dispValueIdxLst_Row: number[][];
     dispValueIdxLst_Col: any[];

+ 1 - 1
report/src/core/jpc_ex.ts

@@ -16,7 +16,7 @@ import useReportDate from '../public/ReportDate'
 
 import { IDefProperties, IFormula, IParams, ICurrent_RPT, ICurrent_DATA, ICustomizeCfg, ITargetFields, IRptTpl, IDataObj, IBands, IControlCollection, IStyles, BorderStyle, IFontSubCollection, IControlSubCollection, IPreviewPage, IRstPage, IMergeBand } from '../interface/basic'
 import { IFlowTabClass, IBillTabClass, ICostTabClass } from '../interface/classType';
-import { IControlProps, IFontProps, IPagingOption } from '../interface/enum';
+import { IControlProps, IFontProps, IPagingOption, IPositionProps } from '../interface/enum';
 import { Key } from 'readline';
 const JV=$JV;
 class JpcExClass {

+ 3 - 2
report/src/core/jpc_flow_tab.ts

@@ -37,6 +37,7 @@ import {
     INode,
 
 } from '../interface/basic'
+import { IControlProps, IPositionProps } from '../index';
 
 class JpcFlowTabClass {
     isEx: boolean;
@@ -1439,7 +1440,7 @@ function _addPageValue(ValuedIdxLst: number[][][], sortedSequence: number[], grp
 }
 
 function push_cell(pageCellObj: IPageCellObj, cell: INode, cellIdx: number) {
-    let key = cell.area.Left + '_' + cell.area.Right;
+    let key = cell.area.Left; + '_' + cell.area.Right;
     if (!pageCellObj[key]) {
         pageCellObj[key] = [];
     }
@@ -1497,7 +1498,7 @@ function combineAutoHeightCells(prepareObj: IPageAreaObj | {}, page: number, con
             let sameColCells = (prepareObj as IPageAreaObj).pageCellObj[mergeKey]; //左右位置相同的Cell先放在一起,统一处理
             if (sameColCells.length > 1) {
                 //强转格式,此处是强制把本来是字符串的control属性转化为对象,by lish
-                let firstMergeCell: ICell = { ...sameColCells[0].cell, control: {} as IControlSubCollection };
+                let firstMergeCell = { ...sameColCells[0].cell, control: {} as IControlSubCollection }  as ICell;
                 firstMergeCell.style = firstMergeCell.style.slice(0, firstMergeCell.style.indexOf("_AutoHeightMerge")); //首先还原original style
                 //生成原始对象,并且把对象中的control属性转化为对象
                 let orgCtrl = setupControl(firstMergeCell, controls);

+ 1 - 0
report/src/index.ts

@@ -4,3 +4,4 @@
 export * from './core/index';
 export * from './interface/index';
 export * from './public/index';
+// export * from './pdfUnit/rpt_pdf_util';

+ 18 - 23
report/src/interface/basic.ts

@@ -1,6 +1,6 @@
 // import { IFlowTabClass, IBillTabClass, ICostTabClass } from './classType';
 // eslint-disable-next-line camelcase
-import { IDataObjProps, IEventType } from './enum';
+import { IDataObjProps, IEventType, IPositionProps } from './enum';
 
 export interface IArea {
     Left: number;
@@ -68,7 +68,7 @@ export interface IStyles {
     ID: string;
     CfgDispName: string;
     border_style: BorderStyle[];
-    // [key: string]: any; // 剩下的之后补充
+    [key: string]: any; // 剩下的之后补充
 }
 
 export interface IDefProperties {
@@ -154,7 +154,15 @@ export interface ICell {
     Prefix?: string;
     Suffix?: any;
 }
-
+export interface IStyleCollection {
+    BORDER_ALL_AROUND: IPositionExtent;
+    Default: IPositionExtent;
+    Default_None: IPositionExtent;
+    Default_Normal: IPositionExtent;
+    Label_Topline: IPositionExtent;
+    Label_Underline: IPositionExtent;
+    [key:string]:IPositionExtent;
+}
 export interface IPreviewPage {
     打印页面_信息: {
         报表名称: string;
@@ -173,21 +181,8 @@ export interface IPreviewPage {
             }
         }
     ];
-    MergeBand: {
-        Bottom: number;
-        Left: number;
-        Right: number;
-        Top: number;
-        style: any;
-    };
-    style_collection: {
-        BORDER_ALL_AROUND: IPositionExtent;
-        Default: IPositionExtent;
-        Default_None: IPositionExtent;
-        Default_Normal: IPositionExtent;
-        Label_Topline: IPositionExtent;
-        Label_Underline: IPositionExtent;
-    };
+    MergeBand: IMergeBand;
+    style_collection:IStyleCollection;
 }
 
 interface ISimpleJSONPage {
@@ -391,7 +386,7 @@ export interface IOrgBandDetail {
     band_s?:IOrgBandDetail[]
 }
 
-export interface IBandDetail {
+export interface IBandDetail{
     Alignment: number;
     Bottom: number;
     CalculationType: number;
@@ -603,10 +598,10 @@ export interface IRstPage {
 }
 
 export interface IMergeBand {
-    Bottom: number;
-    Left: number;
-    Right: number;
-    Top: number;
+    Bottom:number;
+    Left:number;
+    Right:number;
+    Top:number;
     style?: any;
 }
 //丢失的interface

+ 1 - 1
report/src/interface/enum.ts

@@ -48,7 +48,7 @@ export enum IFontProps {
 }
 
 export enum IPositionProps {
-   TOP,
+   Top,
    Bottom,
    Left,
    Right

+ 5 - 4
report/src/interface/projectConstsEnum.ts

@@ -44,10 +44,11 @@ let projectConstList = [
 ];
 
 let summaryConstList = [
-    `Construct`,
-    `ConstructDetail`,
-    `Segment`,
-    `SegmentDetail`
+    `'construct'`,
+    `'constructDetail'`,
+    `'segment'`,
+    `'segmentDetail'`,
+    `'costTreeData'`
 ];
 
 let projectFieldConstList = [

+ 2 - 0
report/src/pdfUnit/index.ts

@@ -0,0 +1,2 @@
+export * from './rpt_font_util';
+// export * from './rpt_pdf_util';

+ 26 - 0
report/src/pdfUnit/rpt_font_util.ts

@@ -0,0 +1,26 @@
+/**
+ * Created by Tony on 2018/8/2.
+ */
+
+let fontMapObj:Record<string,string> = {
+    "宋体": "Smart"
+    ,"楷体": "simkai"
+    ,"黑体": "simhei"
+};
+//下划线在option中支持
+//另注意:PDFkit设置字体的时候会检测是否同源,也就是说,如果是同一种字体转换不同的特性(如粗体、斜体),那么在设置的时候会无效
+//      比如前一种是普通的字体,后来想设置这种字体的斜体,实际上这种设置会失效
+
+
+export const getActualFont=(mapName:string, isBold:boolean, isItalic:boolean) =>{
+    let rst = ["Smart"];
+    if (fontMapObj[mapName]) rst[0] = fontMapObj[mapName];
+    if (isBold) {
+        rst.push("_bold");
+    }
+    if (isItalic) {
+        rst.push("_italic");
+    }
+    return rst.join("");
+}
+export default {}

+ 492 - 0
report/src/pdfUnit/rpt_pdf_util.ts

@@ -0,0 +1,492 @@
+
+// const pdf = require('pdfkit');
+// const fs = require('fs');
+// import jpcCmnHelper from '../core/helper/jpc_helper_common';
+// const PDF_SCALE = 0.75;
+
+// const DPI = jpcCmnHelper.getScreenDPI()[0] * PDF_SCALE;
+
+// import JV from '../core/jpc_value_define';
+// import { IMergeBand, IPositionProps, IPreviewPage } from '../index';
+// import {  ICell, IControlCollection, IControlSubCollection, IFontCollection, IFontSubCollection, IStyleCollection, IStyles } from '../interface/basic';
+
+// import {getActualFont} from './rpt_font_util';
+
+
+
+// const getNewName=()=>{
+//   return (new Date()).getTime();
+// }
+// // 目前不支持下划线
+
+// export const exportPdfFile=(pageData:IPreviewPage, paperSize:string, fName:string, callback:any) =>{
+//   const offsetX = 10;
+//   const offsetY = 10;
+//   const doc = new pdf({ autoFirstPage: false });
+//   const newName = getNewName();
+//   const stream = doc.pipe(fs.createWriteStream(`${__dirname.slice(0, __dirname.length - 21)}/tmp/${newName}.pdf`));
+//   const pageObj = pageData;
+//   // doc.rect(5,5,1190,890).lineWidth(1).strokeColor('black').stroke();//边框
+//   const paperSizeIdx = JV.PAGES_SIZE_STR.indexOf(paperSize);
+//   const size = JV.PAGES_SIZE[paperSizeIdx];
+
+//   const newPageMergeBand = {...pageObj.MergeBand};
+//   const privateDrawLine=(cell:any, doc:any, style:any, styleBorderDest:string, startP:[string,string], destP:[string,string], mergedBand:any, styles:any, isNeedMergeBand:boolean)=> {
+//     // doc.beginPath();
+//     let destStyle = style;
+//     if (mergedBand) {
+//       if (
+//         isNeedMergeBand &&
+//         mergedBand[styleBorderDest] === cell.area[styleBorderDest]
+//       ) {
+//         destStyle = styles[mergedBand.style.ID];
+//       }
+//     }
+//     // doc.moveTo(cell.area.[startP[0]] + offsetX, cell.area.[startP[1]] + offsetY);
+//     doc.moveTo(
+//       (cell.area[startP[0]] + offsetX) * PDF_SCALE,
+//       (cell.area[startP[1]] + offsetY) * PDF_SCALE
+//     );
+//     if (destStyle[styleBorderDest] && parseFloat(destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT]) !== 0) {
+//       doc.lineWidth(1.0 * destStyle[styleBorderDest][JV.PROP_LINE_WEIGHT]);
+//       // doc.lineTo(cell.area.[destP[0]] + offsetX, cell.area.[destP[1]] + offsetY);
+//       doc.lineTo(
+//         (cell.area[destP[0]] + offsetX) * PDF_SCALE,
+//         (cell.area[destP[1]] + offsetY) * PDF_SCALE
+//       );
+//       doc.strokeColor(destStyle[styleBorderDest][JV.PROP_COLOR]);
+//     }
+//     doc.stroke();
+//   }
+//   const privateDrawCell=(cell:ICell, fonts:IFontCollection, styles:IStyleCollection, controls:IControlCollection, mergedBand:IMergeBand)=> {
+//     doc.save();
+//     // doc.translate(0.5,0.5); //跟H5的canvas不同,不需要这样切换
+//     const style = styles[cell.style];
+//     if (style) {
+//       const isNeedMergeBand = privateChkIfInMergedBand(mergedBand, cell);
+//       privateDrawLine(
+//         cell,
+//         doc,
+//         style,
+//         'Top',
+//         ['Left', 'Top'],
+//         ['Right',  'Top'],
+//         mergedBand,
+//         styles,
+//         isNeedMergeBand
+//       );
+//       privateDrawLine(
+//         cell,
+//         doc,
+//         style,
+//         'Right',
+//         ['Right', 'Top'],
+//         ['Right', 'Bottom'],
+//         mergedBand,
+//         styles,
+//         isNeedMergeBand
+//       );
+//       privateDrawLine(
+//         cell,
+//         doc,
+//         style,
+//         'Bottom',
+//         ['Right', 'Bottom'],
+//         ['Left','Bottom'],
+//         mergedBand,
+//         styles,
+//         isNeedMergeBand
+//       );
+//       privateDrawLine(
+//         cell,
+//         doc,
+//         style,
+//         'Left',
+//         ['Left', 'Bottom'],
+//         ['Left',  'Top'],
+//         mergedBand,
+//         styles,
+//         isNeedMergeBand
+//       );
+//     }
+//     privateDrawCellText(cell, fonts, controls);
+//     doc.restore();
+//   }
+
+//   if (pageObj && pageObj.items.length > 0) {
+//     for (let i = 0; i < pageObj.items.length; i++) {
+//       if (pageData.打印页面_信息.纸张宽高[0] > pageData.打印页面_信息.纸张宽高[1]) {
+//         doc.addPage({ size: [size[1] * DPI, size[0] * DPI] });
+//       } else {
+//         doc.addPage({ size: [size[0] * DPI, size[1] * DPI] });
+//       }
+//       const page = pageObj.items[i];
+//       const fonts = pageObj.font_collection;
+//       const styles = pageObj.style_collection;
+//       const controls = pageObj.control_collection;
+
+//       if (page.page_merge_border) {
+//         Object.assign(newPageMergeBand,page.page_merge_border);
+//       }
+//       for (let j = 0; j < page.cells.length; j++) {
+//         const cell = page.cells[j];
+//         privateDrawCell(cell, fonts, styles, controls, newPageMergeBand);
+//       }
+//     }
+//   }
+//   doc.end();
+//   stream.on('finish', function () {
+//     console.log(`${newName}.pdf was written.`);
+//     callback(newName);
+//   });
+
+//   const privateChkIfInMergedBand=(mergedBand:IMergeBand, cell:ICell)=> {
+//     let rst = false;
+//     if (mergedBand && cell) {
+//       rst =
+//         mergedBand.Top <= cell.area.Top &&
+//         mergedBand.Bottom >= cell.area.Bottom &&
+//         mergedBand.Right <= cell.area.Right &&
+//         mergedBand.Left >= cell.area.Left;
+//     }
+//     return rst;
+//   }
+
+  
+
+ 
+//   const privateDrawCellText=(cell:ICell, fonts:IFontCollection, controls:IControlCollection) =>{
+//     if (cell.Value) {
+//       const values = `${cell.Value}`.split('|');
+//       // let font = fonts[cell.font];
+//       let font = null;
+//       if (typeof cell.font === 'string') {
+//         font = fonts[cell.font];
+//       } else {
+//         font = cell.font;
+//       }
+//       // let control = controls[cell.control];
+//       let control = null;
+//       if (typeof cell.control === 'string') {
+//         control = controls[cell.control];
+//       } else {
+//         control = cell.control;
+//       }
+//       const height = cell.area.Bottom - cell.area.Top;
+//       const area = [
+//         cell.area.Left + offsetX,
+//         cell.area.Top + offsetY,
+//         cell.area.Right + offsetX,
+//         cell.area.Bottom + offsetY,
+//       ];
+//       let ah = height;
+//       let restTopH = 0;
+//       let restBottomH = 0;
+//       if (control.CloseOutput === 'T') {
+//         ah =
+//           (parseFloat(font.Name) +
+//             JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] +
+//             JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM]) *
+//           values.length;
+//         const restH = height - ah;
+//         if (control.Vertical === 'center') {
+//           restTopH = restH / 2;
+//           restBottomH = restH / 2;
+//         } else if (control.Vertical === 'bottom') {
+//           restBottomH = restH;
+//         } else {
+//           restTopH = restH;
+//         }
+//       }
+//       let spaceIdxArr = [];
+//       for (let i = 0; i < values.length; i++) {
+//         // area[JV.IDX_TOP] = cell.area..Top + i * (height / values.length) + offsetY;
+//         // area[JV.IDX_BOTTOM] = cell.area..Top + (i + 1) * (height / values.length) + offsetY;
+//         area[JV.IDX_TOP] = cell.area.Top  + i * (ah / values.length) + offsetY + restTopH;
+//         area[JV.IDX_BOTTOM] = cell.area.Top  + (i + 1) * (ah / values.length) + offsetY + restBottomH;
+//         if (values[i] === null || values[i] === undefined || values[i] === 'null') {
+//           values[i] = '';
+//         }
+//         // 因pdfkit输出空格只有一半宽度,需要额外加空格补上 -----------------------------
+//         if (typeof values[i] === 'string') {
+//           for (let j = 0; j < values[i].length; j++) {
+//             if (values[i][j] === ' ') spaceIdxArr.push(j);
+//           }
+//         }
+//         for (let j = spaceIdxArr.length - 1; j >= 0; j--) {
+//           values[i] = `${values[i].slice(0, spaceIdxArr[j])} ${values[i].slice(spaceIdxArr[j])}`;
+//         }
+//         // -----------------------------
+//         privateDrawText(values[i], area, font, control);
+//         spaceIdxArr = [];
+//       }
+//     }
+//   }
+//   const privateSplitString=(strVal:string, areaWidth:number, doc: { widthOfString: (arg0: string) => any; })=> {
+//     const rst = [];
+//     if (strVal) {
+//       let preSIdx = 0;
+//       let txtWidth = 0;
+//       let currentW = 0;
+//       const chnW = doc.widthOfString('一');
+//       const otherW = doc.widthOfString('_');
+//       for (let sIdx = 0; sIdx < strVal.length; sIdx++) {
+//         currentW = strVal.charCodeAt(sIdx) > 127 ? chnW : otherW;
+//         txtWidth += currentW;
+//         if (txtWidth > areaWidth) {
+//           if (preSIdx < sIdx) {
+//             rst.push(strVal.substr(preSIdx, sIdx - preSIdx));
+//             preSIdx = sIdx;
+//           } else {
+//             rst.push(strVal.substr(preSIdx, 1));
+//             preSIdx = sIdx + 1;
+//           }
+//           txtWidth = currentW;
+//         }
+//         if (sIdx === strVal.length - 1) {
+//           rst.push(strVal.substr(preSIdx, strVal.length - preSIdx));
+//         }
+//       }
+//     }
+//     if (rst.length === 0) rst.push(''); // 什么都没有,也得整个空串
+//     return rst;
+//   }
+//   const privateDrawText=(val:string, area:number[], font:IFontSubCollection, control:IControlSubCollection)=> {
+//     let dftFontHeight = 12;
+//     const output: number[] = [];
+//     let fontFile = `${__dirname}/pdf_base_files/simkai.ttf`;
+//     if (font) {
+//       dftFontHeight = 1 * font.FontHeight;
+//       fontFile = `${__dirname}/pdf_base_files/${getActualFont(
+//         font.Name,
+//         font.FontBold === 'T',
+//         font.FontItalic === 'T'
+//       )}.ttf`;
+//       doc.fontSize(dftFontHeight);
+//     }
+//     doc.font(fontFile);
+//     const options = {
+//       width:0,
+//       height:0
+//     };
+//     const innerSetupControl = function (inArea:number[], inFontHeight:number, inOutput: number[]) {
+//       if (control) {
+//         privateSetupAreaH(inArea, control.Horizon, font.FontAngle, inFontHeight, inOutput, options);
+//         privateSetupAreaV(inArea, control.Vertical, font.FontAngle, inFontHeight, inOutput);
+//       } else {
+//         privateSetupAreaH(inArea, 'left', parseInt(`${font.FontAngle}`), inFontHeight, inOutput, options);
+//         privateSetupAreaV(inArea, 'bottom', parseInt(`${font.FontAngle}`), inFontHeight, inOutput);
+//       }
+//     };
+//     innerSetupControl(area, dftFontHeight, output);
+//     let validAreaTxtWidth =
+//       area[JV.IDX_RIGHT] -
+//       JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] -
+//       area[JV.IDX_LEFT] -
+//       JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
+//     let validTxtLines = Math.floor(
+//       (area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) /
+//         (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + 4)
+//     );
+//     if (parseInt(`${font.FontAngle}`) !== 0) {
+//       validAreaTxtWidth =
+//         area[JV.IDX_BOTTOM] -
+//         JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] -
+//         area[JV.IDX_TOP] -
+//         JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+//       validTxtLines = Math.floor(
+//         (area[JV.IDX_RIGHT] - area[JV.IDX_LEFT]) /
+//           (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT] + 4)
+//       );
+//     }
+
+//     const privateDrawUnderline=(underLineVal:string, underLineArea:number[])=> {
+//       // A. 暂不支持角度; B. PDF输出时,坐标没有translate
+//       const ctx = doc;
+//       // 1. 计算下划线的相关坐标
+//       let width = ctx.widthOfString(underLineVal);
+//       if (width > underLineArea[JV.IDX_RIGHT] - underLineArea[JV.IDX_LEFT]) {
+//         width = underLineArea[JV.IDX_RIGHT] - underLineArea[JV.IDX_LEFT];
+//       }
+//       const height = dftFontHeight;
+//       let startX = underLineArea[JV.IDX_LEFT];
+//       let startY = underLineArea[JV.IDX_TOP];
+//       let endX = underLineArea[JV.IDX_RIGHT];
+//       let endY = underLineArea[JV.IDX_BOTTOM];
+//       // let startX = 0, startY = 0, endX = width, endY = startY;
+//       if (control.Horizon === 'left') {
+//         startX = Math.round(underLineArea[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.IDX_LEFT]);
+//       } else if (control.Horizon === 'right') {
+//         startX = Math.round(underLineArea[JV.IDX_RIGHT] - width - JV.OUTPUT_OFFSET[JV.IDX_RIGHT]);
+//       } else {
+//         startX = Math.round(
+//           underLineArea[JV.IDX_LEFT] + (underLineArea[JV.IDX_RIGHT] - underLineArea[JV.IDX_LEFT] - width) / 2
+//         );
+//       }
+//       endX = Math.round(startX + width);
+
+//       if (control.Vertical === 'top') {
+//         startY = Math.round(
+//           underLineArea[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM] + height
+//         );
+//       } else if (control.Vertical === 'bottom') {
+//         startY = Math.round(underLineArea[JV.IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM]);
+//       } else {
+//         startY =
+//           Math.round(
+//             underLineArea[JV.IDX_TOP] + (underLineArea[JV.IDX_BOTTOM] - underLineArea[JV.IDX_TOP] + height) / 2
+//           ) +
+//           JV.OUTPUT_OFFSET[JV.IDX_TOP] +
+//           JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+//       }
+//       endY = Math.round(startY);
+//       // 2. 画线
+//       // ctx.save();
+//       if (output[1] !== Math.round(output[1])) {
+//         ctx.translate(0, 0.5);
+//       }
+//       // ctx.beginPath();
+//       // ctx.moveTo(startX, startY);
+//       ctx.moveTo(startX * PDF_SCALE, startY * PDF_SCALE);
+//       ctx.lineWidth(1);
+//       ctx.strokeStyle = 'BLACK';
+//       // ctx.lineTo(endX, endY);
+//       ctx.lineTo(endX * PDF_SCALE, endY * PDF_SCALE);
+//       ctx.stroke();
+//       // ctx.restore();
+//     }
+
+//     let rotateOptions;
+//     // if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
+//     //     privateDrawUnderline(val);
+//     // }
+//     if (parseInt(`${font.FontAngle}`) !== 0) {
+//       if (control) {
+//         rotateOptions = privateSetupAreaRotateOption(area, validAreaTxtWidth, control.Vertical, dftFontHeight, output);
+//       } else {
+//         rotateOptions = privateSetupAreaRotateOption(area, validAreaTxtWidth, 'bottom', dftFontHeight, output);
+//       }
+//       doc.rotate(font.FontAngle, rotateOptions);
+//     }
+//     if (
+//       validAreaTxtWidth >= doc.widthOfString(val) ||
+//       (control && control.Shrink !== 'T' && validTxtLines < privateSplitString(val, validAreaTxtWidth, doc).length)
+//     ) {
+//       options.width = validAreaTxtWidth * PDF_SCALE;
+//       options.height = dftFontHeight * PDF_SCALE;
+//       doc.fontSize(dftFontHeight);
+//       if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(`${font.FontAngle}`) === 0) {
+//         privateDrawUnderline(val, area);
+//       }
+//       doc.fontSize(dftFontHeight * PDF_SCALE);
+//       doc.text(val, output[0] * PDF_SCALE, output[1] * PDF_SCALE, options);
+//       doc.font(`${__dirname}/pdf_base_files/simhei_bold_italic.ttf`);
+//     } else {
+//       while (true) {
+//         //* /
+//         let lines = Math.floor(
+//           (area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) /
+//             (dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + 4)
+//         );
+//         lines = lines === 0 || (control.Shrink === 'T' && control.ShrinkFirst === 'T') ? 1 : lines;
+//         const actLines = privateSplitString(val, validAreaTxtWidth, doc);
+//         if (actLines.length > lines && dftFontHeight >= 6) {
+//           dftFontHeight--;
+//           doc.fontSize(dftFontHeight);
+//           options.width = validAreaTxtWidth * PDF_SCALE;
+//           options.height = dftFontHeight * PDF_SCALE;
+//           // doc.text(val,output[0], output[1], options);
+//         } else {
+//           const aH = dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + 4;
+//           if (aH * actLines.length < area[JV.IDX_BOTTOM] - area[JV.IDX_TOP] && control && control.Vertical !== 'top') {
+//             if (control.Vertical === 'bottom') {
+//               area[JV.IDX_TOP] = area[JV.IDX_BOTTOM] - aH * actLines.length;
+//             } else {
+//               area[JV.IDX_TOP] = (area[JV.IDX_TOP] + area[JV.IDX_BOTTOM]) / 2 - (aH * actLines.length) / 2;
+//               area[JV.IDX_BOTTOM] = area[JV.IDX_TOP] + aH * actLines.length;
+//             }
+//           }
+//           const newArea = [];
+//           const baseTop = area[JV.IDX_TOP];
+//           for (let ai = 0; ai < area.length; ai++) {
+//             newArea[ai] = area[ai];
+//           }
+//           options.width = validAreaTxtWidth * PDF_SCALE;
+//           options.height = dftFontHeight * PDF_SCALE;
+//           for (let lIdx = 0; lIdx < actLines.length; lIdx++) {
+//             newArea[JV.IDX_TOP] = Math.round(aH * lIdx + baseTop);
+//             newArea[JV.IDX_BOTTOM] = Math.round(aH * (lIdx + 1) + baseTop);
+//             innerSetupControl(newArea, dftFontHeight, output);
+//             doc.fontSize(dftFontHeight);
+//             if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(`${font.FontAngle}`) === 0) {
+//               privateDrawUnderline(actLines[lIdx], newArea);
+//             }
+//             doc.fontSize(dftFontHeight * PDF_SCALE);
+//             doc.text(actLines[lIdx], output[0] * PDF_SCALE, output[1] * PDF_SCALE, options);
+//           }
+//           break;
+//         }
+//         /* /
+//                 dftFontHeight--;
+//                 doc.fontSize(dftFontHeight);
+//                 if (validAreaTxtWidth >= doc.widthOfString(val) || dftFontHeight < 6) {
+//                     options.width = validAreaTxtWidth;
+//                     options.height = dftFontHeight;
+//                     doc.text(val,output[0], output[1], options);
+//                     doc.font(__dirname + '/pdf_base_files/simhei_bold_italic.ttf');
+//                     break;
+//                 }
+//                 // */
+//       }
+//     }
+//     // doc.text(val,output[0], output[1], options);
+//     doc.font(`${__dirname}/pdf_base_files/simhei_bold_italic.ttf`);
+//     // doc.restore();
+//   }
+
+//   const privateSetupAreaH=(area: number[], type: string, fontAngle: string | number | undefined, dftFontHeight: number, outputPoint: number[], options: { width?: number; height?: number; align?: any; })=> {
+//     let lType = type;
+//     if (type !== 'left' && type !== 'right' && type !== 'center') lType = 'left';
+//     options.align = lType;
+//     outputPoint[0] = 1 * area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+//   }
+
+//   const privateSetupAreaV=(area: number[], type: string, fontAngle: string | number | undefined, dftFontHeight: number, outputPoint: number[])=> {
+//     let lType = type;
+//     if (type !== 'top' && type !== 'bottom' && type !== 'center') lType = 'top';
+//     switch (lType) {
+//       case 'top':
+//         outputPoint[1] = 1 * area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+//         break;
+//       case 'bottom':
+//         outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] - dftFontHeight;
+//         break;
+//       case 'center':
+//         outputPoint[1] = 1 * area[JV.IDX_TOP] + (1 * area[JV.IDX_BOTTOM] - 1 * area[JV.IDX_TOP] - dftFontHeight) / 2;
+//         break;
+//     }
+//   }
+
+  
+
+//   const privateSetupAreaRotateOption=(area: number[], w: number, type = 'top', dftFontHeight: number, outputPoint: any[]) =>{
+//     const x = (area[JV.IDX_RIGHT] - area[JV.IDX_LEFT]) / 2 + area[JV.IDX_LEFT];
+//     const y = (area[JV.IDX_BOTTOM] - area[JV.IDX_TOP]) / 2 + area[JV.IDX_TOP];
+//     const rotateOptions = { origin: [x, y] };
+//     const h = area[JV.IDX_RIGHT] - area[JV.IDX_LEFT];
+//     outputPoint[0] = x - w / 2 + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+//     switch (type) {
+//       case 'top':
+//         outputPoint[1] = y - h / 2 + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
+//         break;
+//       case 'bottom':
+//         outputPoint[1] = y + h / 2 - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] - dftFontHeight;
+//         break;
+//       case 'center':
+//         outputPoint[1] = y + dftFontHeight / 2;
+//         break;
+//     }
+//     return rotateOptions;
+//   }
+// }
+// export default {}