Przeglądaj źródła

feat(wise-cost-util): 增加wise-cost项目前后共用的业务工具

vian 4 lat temu
rodzic
commit
7bd2fe074d

+ 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' },
+    ],
+  },
+];

+ 82 - 0
wise-cost-util/src/bill.ts

@@ -0,0 +1,82 @@
+import { IJobContent, IItemCharacter, IStdBill, IStdJobContent, IStdItemCharacter } from '@sc/types';
+
+interface IJobsAndCharacterText {
+  jobContentText: string;
+  itemCharacterText: string;
+}
+
+interface IJobContentMap {
+  [id: string]: IStdJobContent;
+}
+interface IItemCharacterMap {
+  [id: string]: IStdItemCharacter;
+}
+
+export interface IJobAndCharacter extends IJobsAndCharacterText {
+  jobContents: IJobContent[];
+  itemCharacters: IItemCharacter[];
+}
+
+export const getJobsAndCharacterText = (
+  jobContents: IJobContent[],
+  itemCharacters: IItemCharacter[]
+): IJobsAndCharacterText => {
+  const jobContentText = '';
+  let itemCharacterText = '';
+  jobContents.sort((a, b) => a.seq - b.seq);
+  itemCharacters.sort((a, b) => a.seq - b.seq);
+  const textArray: string[] = ['[项目特征]'];
+  let i = 1;
+  for (const item of itemCharacters) {
+    if (item.isChecked) textArray.push(`${i}. ${item.character || ''}: ${item.eigenvalue || ''}`);
+    i += 1;
+  }
+
+  textArray.push('[工作内容]');
+  i = 1;
+  for (const job of jobContents) {
+    if (job.isChecked) textArray.push(`${i}. ${job.content || ''}`);
+    i += 1;
+  }
+  itemCharacterText = textArray.join('\n');
+  return { jobContentText, itemCharacterText };
+};
+
+export const getJobContents = (stdBill: IStdBill, stdJobContentMap: IJobContentMap): IJobContent[] => {
+  const jobs: IJobContent[] = [];
+  let i = 1;
+  for (const j of stdBill.jobs) {
+    const job = stdJobContentMap[j.id];
+    if (job) {
+      jobs.push({ seq: i + 1, content: job.content, isChecked: true });
+      i += 1;
+    }
+  }
+
+  return jobs;
+};
+
+export const getItemCharacters = (stdBill: IStdBill, itemCharacterMap: IItemCharacterMap): IItemCharacter[] => {
+  const characters: IItemCharacter[] = [];
+  let i = 1;
+  for (const item of stdBill.items) {
+    const character = itemCharacterMap[item.id];
+    if (character) {
+      const newItem: IItemCharacter = {
+        seq: i + 1,
+        character: character.content,
+        eigenvalueList: [],
+        eigenvalue: '',
+        isChecked: false,
+      };
+      const eigenvalues = character.itemValue;
+      for (let j = 0; j < eigenvalues.length; j += 1) {
+        newItem.eigenvalueList.push(eigenvalues[j].value);
+      }
+      characters.push(newItem);
+      i += 1;
+    }
+  }
+
+  return characters;
+};

+ 27 - 0
wise-cost-util/src/glj.ts

@@ -0,0 +1,27 @@
+import { IBaseGlj, IInfoPriceItem, TaxType } from '@sc/types';
+
+export const getInfoMarketPrice = (info: IInfoPriceItem, taxType: TaxType) => {
+  // 1: 一般计税 2: 简易计税
+  const fieldArray = ['noTaxPrice']; // 一般计税 - 不含税价 || 简易计税 - 含税价
+  if (taxType === TaxType.GENERAL) {
+    fieldArray.push('taxPrice');
+  } else {
+    fieldArray.unshift('taxPrice');
+  }
+  // 一个放后面,一个放前面
+  let infoPrice = (info as any)[fieldArray[0]];
+  if (infoPrice === null || infoPrice === undefined) infoPrice = (info as any)[fieldArray[1]]; // 信息价只有一个价格(含税价/不含税价),则不分计税方式,套用仅有的价格。
+  return parseFloat(infoPrice);
+};
+
+// 返回五大项组成的索引
+export const getIndex = (obj: IBaseGlj, pops = ['code', 'name', 'specs', 'unit', 'type']): string => {
+  let index = '';
+  const arr = [];
+  for (const p of pops) {
+    const tmpK = obj[p] === undefined || obj[p] === null || obj[p] === '' ? 'null' : obj[p];
+    arr.push(tmpK);
+  }
+  index = arr.join('|-|');
+  return index;
+};

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

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

+ 115 - 0
wise-cost-util/src/rationAss.ts

@@ -0,0 +1,115 @@
+import { IRationAss, IThirdRation } from '@sc/types';
+import { ceil, floor, round, sortBy } from 'lodash';
+import { roundForObj } from '@sc/util';
+
+export interface IAssTime {
+  times: number;
+  ass: IRationAss | IThirdRation;
+}
+
+export interface IStateList {
+  index: number;
+  content: string;
+  addCode?: string; // 添加工料机的编号,用来标记,如果是子目换算中的单个人材机生成的,改成 调:...
+}
+
+export const stateSeq = {
+  ass: 1,
+  replace: 2,
+  coe: 3,
+  add: 4,
+  cusQuantity: 5,
+  cusCoe: 6,
+  area: 7,
+  adjMak: 8,
+};
+// 处理多个辅助定额的情况
+export const handleMulAss = (rationAssList: IRationAss[]) => {
+  const assList = [];
+  for (const ass of rationAssList) {
+    // 处理多个辅助定额的情况
+    if (ass.groupList && ass.groupList.length > 0) {
+      const newAss = { ...ass };
+      const newList = sortBy(ass.groupList, item => parseFloat(item.param)); // 按参数排序
+      let pre = 0;
+      for (const tem of newList) {
+        if (ass.actualValue) {
+          if (ass.actualValue > pre && ass.actualValue <= parseFloat(tem.param)) {
+            // 落在中间,则用组里的这条定额
+            newAss.param = tem.param;
+            newAss.paramName = tem.paramName;
+            newAss.assistCode = tem.assistCode;
+            break;
+          }
+          pre = parseFloat(tem.param);
+        }
+      }
+      assList.push(newAss);
+    } else {
+      assList.push(ass);
+    }
+  }
+  return assList;
+};
+
+export const calcAssTime = (ass: IRationAss) => {
+  if (ass.isAdjust === false) return undefined;
+  const actualValue = ass.actualValue ? ass.actualValue : 0;
+  const stdValue = ass.stdValue ? parseInt(ass.stdValue, 10) : 0;
+  const stepValue = ass.stepValue ? parseInt(ass.stepValue, 10) : 1;
+  let times = (actualValue - stdValue) / stepValue;
+  let r = false; // 是否负数
+  if (times < 0) {
+    r = true;
+    times *= -1;
+  }
+
+  if (ass.carryBit === '四舍五入') {
+    times = round(times, ass.decimal);
+  } else if (ass.carryBit === '进一') {
+    times = ceil(times, ass.decimal);
+  } else if (ass.carryBit === '舍一') {
+    times = floor(times, ass.decimal);
+  }
+  if (r) {
+    times *= -1;
+  }
+  return roundForObj(times, 6);
+};
+
+export const calcRationAssTimes = (
+  rationAssList?: IRationAss[],
+  thirdRation?: IThirdRation,
+  stateList?: IStateList[]
+) => {
+  const timeList: IAssTime[] = [];
+  if (rationAssList) {
+    const assList = handleMulAss(rationAssList);
+    const temTimes = [];
+    const thirdRationCodes = [];
+    for (const rationAss of assList) {
+      const times = calcAssTime(rationAss);
+      if (times) {
+        const { thirdRationCode } = rationAss;
+        if (thirdRationCode) {
+          temTimes.push(times);
+          thirdRationCodes.push(thirdRationCode);
+        }
+        timeList.push({ times, ass: rationAss });
+        if (stateList)
+          stateList.push({
+            index: stateSeq.ass,
+            content: `${rationAss.name} ${rationAss.actualValue} : ${rationAss.assistCode}x${times}`,
+          });
+      }
+    }
+    if (thirdRation && temTimes.length === 2 && thirdRationCodes[0] === thirdRationCodes[1]) {
+      // 说明有第三定额
+      const timesT = temTimes[0] * temTimes[1];
+      timeList.push({ times: timesT, ass: thirdRation });
+      if (stateList) stateList.push({ index: stateSeq.ass, content: `+${thirdRationCodes[0]}x${timesT}` });
+    }
+  }
+
+  return timeList;
+};

+ 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"
+  ]
+}