Ver código fonte

Merge branch 'master' of http://192.168.1.41:3000/SmartCost/SCCommon

zhangweicheng 4 anos atrás
pai
commit
69c8b01c15

+ 1 - 1
handsontable/handsontable.d.ts

@@ -2334,7 +2334,7 @@ declare namespace Handsontable {
     time: cellTypes.Time;
 
     // 自定义添加
-    registerCellType:(name:string, type:{editor: any; renderer: Handsontable.renderers.Base})=> void
+    registerCellType:(name:string, type:{editor: any; renderer: Handsontable.renderers.Base; validator?: (value: any, callback: (valid: boolean) => void) => void;})=> void
   }
 
   interface Editors {

+ 1 - 0
handsontable/package.json

@@ -59,6 +59,7 @@
     "data-spreadsheet"
   ],
   "dependencies": {
+    "@sc/util": "^1.0.7",
     "moment": "2.20.1",
     "numbro": "^2.0.6",
     "pikaday": "1.5.1"

+ 7 - 1
handsontable/src/plugins/copyPaste/copyPaste.js

@@ -1,3 +1,4 @@
+import { roundForObj, isNumber } from '@sc/util';
 import BasePlugin from './../_base';
 import Hooks from './../../pluginHooks';
 import SheetClip from './../../../lib/SheetClip/SheetClip';
@@ -280,17 +281,22 @@ class CopyPaste extends BasePlugin {
     return rawData;
   }
 
-  // 粘贴key - value 的dropdown 时 返回 value
+  // 粘贴数据预处理
   preparePaseData(column, value) {
     const settings = this.hot.getSettings();
     if (settings && settings.columns) {
       const colMeta = settings.columns[column];
       if (colMeta && colMeta.source && colMeta.source.length > 0) {
+        // 粘贴key - value 的dropdown 时 返回 value
         if (typeof colMeta.source[0] === 'object') {
           colMeta.source.forEach((option) => {
             if (option.key === value) value = option.value;
           });
         }
+      } else if (isNumber(value) && ['number', 'function'].includes(typeof colMeta.decimal)) {
+        // 粘贴数值字符串时,将其转换为number并根据小数位数进行四舍五入
+        const decimalNum = typeof colMeta.decimal === 'function' ? colMeta.decimal() : colMeta.decimal;
+        value = roundForObj(value, decimalNum);
       }
     }
     return value;

Diferenças do arquivo suprimidas por serem muito extensas
+ 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 {}

+ 5 - 0
util/README.md

@@ -1,7 +1,12 @@
 ### 开始
+所有项目通用的工具包
 
+## math
 统一 4 舍 5 入算法,防止浮点数计算不精确问题。
 
+## reg
+常用的正则表达式
+
 ### 初始化
 
 npm install

+ 2 - 2
util/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@sc/util",
-  "version": "1.0.6",
-  "description": "用的工具包",
+  "version": "1.0.7",
+  "description": "用的工具包",
   "main": "./dist/index.cjs.js",
   "module": "./dist/index.esm.js",
   "browser": "./dist/index.min.js",

+ 0 - 3
util/src/index.ts

@@ -1,5 +1,2 @@
 export * from './math';
-export * from './bill';
-export * from './rationAss';
 export * from './reg';
-export * from './glj';

+ 1 - 0
wise-cost-util/.eslintignore

@@ -0,0 +1 @@
+/dist

+ 41 - 0
wise-cost-util/.eslintrc.js

@@ -0,0 +1,41 @@
+module.exports = {
+  env: {
+    browser: true,
+    es2021: true,
+    node: true,
+  },
+  extends: ['airbnb-base', 'plugin:@typescript-eslint/recommended', 'prettier'],
+  parser: '@typescript-eslint/parser',
+  parserOptions: {
+    ecmaVersion: 12,
+    sourceType: 'module',
+  },
+  plugins: ['@typescript-eslint', 'prettier'],
+  rules: {
+    'prettier/prettier': 'error',
+    'import/extensions': [
+      'error',
+      {
+        js: 'never',
+        jsx: 'never',
+        ts: 'never',
+        tsx: 'never',
+        json: 'always',
+      },
+    ],
+    'import/no-unresolved': 'off',
+    '@typescript-eslint/no-empty-function': 'off',
+    '@typescript-eslint/no-explicit-any': 'off',
+    '@typescript-eslint/explicit-module-boundary-types': 'off',
+    'no-unused-expressions': [
+      'error',
+      {
+        allowShortCircuit: true,
+      },
+    ],
+    'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
+    'no-restricted-syntax': 'off',
+    'no-shadow': 'off',
+    '@typescript-eslint/no-shadow': 'error',
+  },
+};

+ 22 - 0
wise-cost-util/.gitignore

@@ -0,0 +1,22 @@
+.DS_Store
+node_modules
+dist
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

+ 6 - 0
wise-cost-util/.huskyrc.js

@@ -0,0 +1,6 @@
+module.exports = {
+  hooks: {
+    'pre-commit': 'lint-staged',
+    'commit-msg': 'commitlint -E HUSKY_GIT_PARAMS',
+  },
+};

+ 21 - 0
wise-cost-util/README.md

@@ -0,0 +1,21 @@
+### 开始
+
+wise-cost项目前后端业务通用工具包
+
+### 初始化
+
+npm install
+
+### 构建
+
+npm run build
+
+### 代码风格
+
+ESLint + Airbnb config
+
+### 发布
+
+发布
+
+`npm publish`

+ 29 - 0
wise-cost-util/commitlint.config.js

@@ -0,0 +1,29 @@
+module.exports = {
+  ignores: [commit => commit.includes('init')],
+  extends: ['@commitlint/config-conventional'],
+  rules: {
+    'body-leading-blank': [2, 'always'],
+    'footer-leading-blank': [1, 'always'],
+    'header-max-length': [2, 'always', 108],
+    'subject-empty': [2, 'never'],
+    'type-empty': [2, 'never'],
+    'type-enum': [
+      2,
+      'always',
+      [
+        'feat', // 新增功能、变更需求
+        'fix', // 修复bug
+        'perf', // 优化性能
+        'refactor', // 代码重构
+        'style', // 代码格式(不影响功能,例如空格、分号等格式修正)
+        'docs', // 文档变更
+        'test', // 测试
+        'ci', // 更改持续集成软件的配置文件和package中的scripts命令,例如scopes: Travis, Circle等
+        'chore', // 变更构建流程或辅助工具(依赖更新/脚手架配置修改/webpack、gulp、npm等)
+        'revert', // 代码回退
+        'types', // ts类型定义文件更改
+        'wip', // work in process开发中
+      ],
+    ],
+  },
+};

+ 9 - 0
wise-cost-util/lint-staged.config.js

@@ -0,0 +1,9 @@
+module.exports = {
+  '*.{js,jsx,ts,tsx}': ['eslint --fix', 'prettier --write'],
+  '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': [
+    'prettier --write--parser json',
+  ],
+  'package.json': ['prettier --write'],
+  '*.vue': ['prettier --write'],
+  '*.md': ['prettier --write'],
+};

+ 54 - 0
wise-cost-util/package.json

@@ -0,0 +1,54 @@
+{
+  "name": "@sc/wise-cost-util",
+  "version": "1.0.0",
+  "description": "wise-cost项目前后端业务通用工具包",
+  "main": "./dist/index.cjs.js",
+  "module": "./dist/index.esm.js",
+  "browser": "./dist/index.min.js",
+  "types": "./dist/index.d.ts",
+  "files": [
+    "dist",
+    "README.md"
+  ],
+  "scripts": {
+    "test": "cross-env TS_NODE_COMPILER_OPTIONS={\\\"module\\\":\\\"commonjs\\\"} mocha -r ts-node/register 'tests/**/*.ts'",
+    "build": "rollup -c"
+  },
+  "keywords": [],
+  "author": "smartcost",
+  "license": "ISC",
+  "devDependencies": {
+    "@commitlint/cli": "^11.0.0",
+    "@commitlint/config-conventional": "^11.0.0",
+    "@sc/types": "^1.0.28",
+    "@types/chai": "^4.2.14",
+    "@types/lodash": "^4.14.168",
+    "@types/mocha": "^8.0.4",
+    "@types/ms": "^0.7.31",
+    "@typescript-eslint/eslint-plugin": "^4.4.1",
+    "@typescript-eslint/parser": "^4.4.1",
+    "chai": "^4.2.0",
+    "cross-env": "^7.0.2",
+    "eslint": "^7.11.0",
+    "eslint-config-airbnb-base": "^14.2.0",
+    "eslint-config-prettier": "^6.12.0",
+    "eslint-plugin-import": "^2.22.1",
+    "eslint-plugin-prettier": "^3.1.4",
+    "husky": "^4.3.0",
+    "lint-staged": "^10.5.0",
+    "mocha": "^8.2.1",
+    "prettier": "^2.1.2",
+    "rollup": "^2.30.0",
+    "rollup-plugin-commonjs": "^10.1.0",
+    "rollup-plugin-node-resolve": "^5.2.0",
+    "rollup-plugin-terser": "^7.0.2",
+    "rollup-plugin-typescript2": "^0.27.3",
+    "ts-node": "^9.0.0",
+    "tslib": "^2.0.3",
+    "typescript": "^4.0.3"
+  },
+  "dependencies": {
+    "@sc/util": "^1.0.7",
+    "lodash": "^4.17.21"
+  }
+}

+ 7 - 0
wise-cost-util/prettier.config.js

@@ -0,0 +1,7 @@
+module.exports = {
+  singleQuote: true, // 单引号
+  trailingComma: 'es5', // 对象末尾以逗号结束
+  arrowParens: 'avoid', // 箭头函数只有一个参数的时候,不使用()
+  endOfLine: 'auto', // CRLF,LF都可以
+  printWidth: 120,
+};

+ 28 - 0
wise-cost-util/rollup.config.js

@@ -0,0 +1,28 @@
+// import resolve from 'rollup-plugin-node-resolve';
+// import commonjs from 'rollup-plugin-commonjs';
+import typescript from 'rollup-plugin-typescript2'; // 一定要是typescript2,如果使用typescript,没法自动生成.d.ts文件
+// import { terser } from 'rollup-plugin-terser';
+import pkg from './package.json';
+
+export default [
+  // UMD for browser
+  /* {
+    input: 'src/index.ts',
+    output: {
+      name: 'howLongUntilLunch',
+      file: pkg.browser,
+      format: 'umd',
+    },
+    plugins: [resolve(), commonjs(), typescript(), terser()], // 浏览器使用的代码文件进行简化
+  }, */
+  // CommonJS for Node and ES module for bundlers build
+  {
+    input: 'src/index.ts',
+    external: ['ms'],
+    plugins: [typescript()],
+    output: [
+      { file: pkg.main, format: 'cjs' },
+      // { file: pkg.module, format: 'es' },
+    ],
+  },
+];

util/src/bill.ts → wise-cost-util/src/bill.ts


util/src/glj.ts → wise-cost-util/src/glj.ts


+ 3 - 0
wise-cost-util/src/index.ts

@@ -0,0 +1,3 @@
+export * from './bill';
+export * from './rationAss';
+export * from './glj';

+ 1 - 1
util/src/rationAss.ts

@@ -1,6 +1,6 @@
 import { IRationAss, IThirdRation } from '@sc/types';
 import { ceil, floor, round, sortBy } from 'lodash';
-import { roundForObj } from './math';
+import { roundForObj } from '@sc/util';
 
 export interface IAssTime {
   times: number;

+ 18 - 0
wise-cost-util/tsconfig.json

@@ -0,0 +1,18 @@
+{
+  "compilerOptions": {
+    "target": "ESNext",
+    "module": "ESNext",
+    "declaration": true,
+    "outDir": "./",
+    "strict": true,
+    "esModuleInterop": true,
+    "moduleResolution": "node",
+  },
+  "include": [
+    "src/**/*.ts",
+  ],
+  "exclude": [
+    "node_modules",
+    "test"
+  ]
+}