Browse Source

feat: 编号规则设置首次提交

feat: 编号规则设置添加交互

feat: 111

feat: 优化编号规则代码
outaozhen 3 years ago
parent
commit
5bc59cc145

+ 5 - 0
config/routes.ts

@@ -132,6 +132,11 @@
         component: './Business/Inventory'
       },
       {
+        path: 'rules',
+        name: 'rules',
+        component: './Business/RulesSet'
+      },
+      {
         path: 'process',
         name: 'process',
         access: 'authRouteFilter',

+ 3 - 2
package.json

@@ -49,10 +49,11 @@
     "antd": "4.20.7",
     "array-move": "^4.0.0",
     "classnames": "^2.2.6",
-    "dayjs": "^1.10.7",
+    "dayjs": "^1.11.3",
     "lodash": "^4.17.11",
     "omit.js": "^2.0.2",
     "rc-menu": "^9.0.13",
+    "rc-tween-one": "^3.0.6",
     "rc-util": "^5.14.0",
     "react": "18.1.0",
     "react-copy-to-clipboard": "^5.1.0",
@@ -67,9 +68,9 @@
     "@unocss/cli": "^0.39.3",
     "babel-plugin-import": "^1.13.5",
     "cross-env": "^7.0.0",
+    "eslint": "^8.17.0",
     "husky": "^8.0.0",
     "lint-staged": "^10.0.0",
-    "eslint": "^8.17.0",
     "prettier": "^2.6.1",
     "stylelint": "^14.9.0",
     "typescript": "^4.7.3",

+ 94 - 59
pnpm-lock.yaml

@@ -21,7 +21,7 @@ specifiers:
   '@types/react': ^18.0.0
   '@types/react-dom': ^18.0.0
   '@umijs/max': 4.0.6
-  '@umijs/plugins': 4.0.5
+  '@umijs/plugins': 4.0.6
   '@unocss/cli': ^0.39.3
   ahooks: ^3.0.0
   antd: 4.20.7
@@ -29,7 +29,7 @@ specifiers:
   babel-plugin-import: ^1.13.5
   classnames: ^2.2.6
   cross-env: ^7.0.0
-  dayjs: ^1.10.7
+  dayjs: ^1.11.3
   eslint: ^8.17.0
   husky: ^8.0.0
   lint-staged: ^10.0.0
@@ -37,6 +37,7 @@ specifiers:
   omit.js: ^2.0.2
   prettier: ^2.6.1
   rc-menu: ^9.0.13
+  rc-tween-one: ^3.0.6
   rc-util: ^5.14.0
   react: 18.1.0
   react-copy-to-clipboard: ^5.1.0
@@ -65,7 +66,7 @@ dependencies:
   '@formily/reactive-react': 2.1.10_xo7fjoqjibrnuea75o3qm7uusm
   '@formily/shared': 2.1.10
   '@umijs/max': 4.0.6_zydoiptit3dcuzymmvs734hkw4
-  '@umijs/plugins': 4.0.5_z723i6mzf32mx7ral4p6p4azie
+  '@umijs/plugins': 4.0.6_z723i6mzf32mx7ral4p6p4azie
   ahooks: 3.5.0_react@18.1.0
   antd: 4.20.7_ef5jwxihqo6n7gxfmzogljlgcm
   array-move: 4.0.0
@@ -74,6 +75,7 @@ dependencies:
   lodash: 4.17.21
   omit.js: 2.0.2
   rc-menu: 9.6.0_ef5jwxihqo6n7gxfmzogljlgcm
+  rc-tween-one: 3.0.6_ef5jwxihqo6n7gxfmzogljlgcm
   rc-util: 5.21.5_ef5jwxihqo6n7gxfmzogljlgcm
   react: 18.1.0
   react-copy-to-clipboard: 5.1.0_react@18.1.0
@@ -2201,7 +2203,6 @@ packages:
     resolution: {integrity: sha512-OWPWTUrY/NIrjsAPkAk1wW9LZeIjSvkXRhclsFO8CZcZGCOg2G0YZy4ft+rOyYxy8B7ui5iZzi9OkDebZ7/QSA==}
     dependencies:
       '@types/react': 18.0.14
-    dev: true
 
   /@types/react-redux/7.1.24:
     resolution: {integrity: sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ==}
@@ -2469,17 +2470,6 @@ packages:
       - supports-color
     dev: false
 
-  /@umijs/bundler-utils/4.0.5:
-    resolution: {integrity: sha512-lvI3xSFe0V3/JZzGxA8XaTp3xLJugYKMnu9FeGVramZjZSLZFDI1L4CrxWCM/ZzeMOHZ8NgL71ZsZEEciXF+Zw==}
-    dependencies:
-      '@umijs/utils': 4.0.5
-      esbuild: 0.14.36
-      regenerate-unicode-properties: 10.0.1
-      spdy: 4.0.2
-    transitivePeerDependencies:
-      - supports-color
-    dev: false
-
   /@umijs/bundler-utils/4.0.6:
     resolution: {integrity: sha512-7g3akUp37Y/H03Ar7lYl9FSljFHAU0rYNsAU0QSGzGVZIcRfjAi7ip4LAnE996ZikpVEcCCH8X9jAeuYw47sBg==}
     dependencies:
@@ -2632,42 +2622,6 @@ packages:
       - supports-color
     dev: false
 
-  /@umijs/plugins/4.0.5_z723i6mzf32mx7ral4p6p4azie:
-    resolution: {integrity: sha512-LwARwSWGkvKJ1uZgg6vOMSZ5UWc3rPgss7d0C1uoFbrjwKcNNMQSJmMLzVw698t++RjvKP/9v5x4ISu3oO+j7w==}
-    dependencies:
-      '@ahooksjs/use-request': 2.8.15_react@18.1.0
-      '@ant-design/icons': 4.7.0_ef5jwxihqo6n7gxfmzogljlgcm
-      '@ant-design/pro-layout': 7.0.1-beta.20_y2ytas7iogu6k5fpudkqrkmoha
-      '@umijs/bundler-utils': 4.0.5
-      antd-dayjs-webpack-plugin: 1.0.6_dayjs@1.11.3
-      axios: 0.27.2
-      babel-plugin-import: 1.13.5
-      dayjs: 1.11.3
-      dva-core: 2.0.4_redux@4.2.0
-      dva-immer: 1.0.0
-      dva-loading: 3.0.22_dva-core@2.0.4
-      event-emitter: 0.3.5
-      fast-deep-equal: 3.1.3
-      lodash: 4.17.21
-      moment: 2.29.3
-      qiankun: 2.7.3
-      react-intl: 3.12.1_react@18.1.0
-      react-redux: 8.0.2_lzdg4usj2lye36ngaphepvfogy
-      redux: 4.2.0
-      warning: 4.0.3
-    transitivePeerDependencies:
-      - '@babel/core'
-      - '@types/react'
-      - '@types/react-dom'
-      - antd
-      - debug
-      - dva
-      - react
-      - react-dom
-      - react-native
-      - supports-color
-    dev: false
-
   /@umijs/plugins/4.0.6_z723i6mzf32mx7ral4p6p4azie:
     resolution: {integrity: sha512-4gt7B8X59MTjG5d3YdILUGyMAYc5hUqoWXqn/9aPWMVVFtqtRyq+G8cU223muP9iko/jm9RTSAL+DOOotBcsSQ==}
     dependencies:
@@ -2803,13 +2757,6 @@ packages:
       react: 18.1.0
     dev: false
 
-  /@umijs/utils/4.0.5:
-    resolution: {integrity: sha512-XLQHpf1tQwmGKPoKIwwxXPjEiX4wY9ZfCJC6G0ygr1ZVGqesYwI8p+HWVjJ28iOFr5DL5RdTfAf2M3Sq3RsK8g==}
-    dependencies:
-      chokidar: 3.5.3
-      pino: 7.11.0
-    dev: false
-
   /@umijs/utils/4.0.6:
     resolution: {integrity: sha512-dyyF6V12LSjgj+Taf+P9Js2qxIkTKetnTdh7yOA4tYsW5kuZmQ+s/90epK6cLzUjvud34y0MLAkpYosUpF/+3w==}
     dependencies:
@@ -3780,6 +3727,10 @@ packages:
       delayed-stream: 1.0.0
     dev: false
 
+  /commander/2.20.3:
+    resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
+    dev: false
+
   /commander/6.2.1:
     resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==}
     engines: {node: '>= 6'}
@@ -4090,6 +4041,10 @@ packages:
       type: 1.2.0
     dev: false
 
+  /d3-array/1.2.4:
+    resolution: {integrity: sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==}
+    dev: false
+
   /d3-color/3.1.0:
     resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
     engines: {node: '>=12'}
@@ -4120,6 +4075,10 @@ packages:
       d3-color: 3.1.0
     dev: false
 
+  /d3-polygon/1.0.6:
+    resolution: {integrity: sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==}
+    dev: false
+
   /d3-selection/3.0.0:
     resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==}
     engines: {node: '>=12'}
@@ -4413,6 +4372,10 @@ packages:
       dva-core: 2.0.4_redux@4.2.0
     dev: false
 
+  /earcut/2.2.4:
+    resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==}
+    dev: false
+
   /electron-to-chromium/1.4.163:
     resolution: {integrity: sha512-c9q94pUVqIdc8hyr7jZDB4bNEoNF3QJ7y35lnddMD+mXtiv5GsL1bT/RmfW/KEOmvlNg5Oy1qioiy4tA7e864Q==}
     dev: false
@@ -5240,6 +5203,17 @@ packages:
     deprecated: flatten is deprecated in favor of utility frameworks such as lodash.
     dev: false
 
+  /flubber/0.4.2:
+    resolution: {integrity: sha512-79RkJe3rA4nvRCVc2uXjj7U/BAUq84TS3KHn6c0Hr9K64vhj83ZNLUziNx4pJoBumSPhOl5VjH+Z0uhi+eE8Uw==}
+    dependencies:
+      d3-array: 1.2.4
+      d3-polygon: 1.0.6
+      earcut: 2.2.4
+      svg-path-properties: 0.2.2
+      svgpath: 2.5.0
+      topojson-client: 3.1.0
+    dev: false
+
   /follow-redirects/1.15.1:
     resolution: {integrity: sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==}
     engines: {node: '>=4.0'}
@@ -7100,6 +7074,10 @@ packages:
     resolution: {integrity: sha512-NOT9AcKiDGpnV/HBhI22Str++XWcErO/bALvHCuhv33owZW/CjH8KAFLZDCmu3727sihe0wTxpDhyGc6M8qacQ==}
     dev: true
 
+  /performance-now/2.1.0:
+    resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
+    dev: false
+
   /picocolors/1.0.0:
     resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
 
@@ -7967,6 +7945,12 @@ packages:
     resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==}
     engines: {node: '>=8'}
 
+  /raf/3.4.1:
+    resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
+    dependencies:
+      performance-now: 2.1.0
+    dev: false
+
   /randombytes/2.1.0:
     resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
     dependencies:
@@ -8480,6 +8464,20 @@ packages:
       react-dom: 18.1.0_react@18.1.0
     dev: false
 
+  /rc-tween-one/3.0.6_ef5jwxihqo6n7gxfmzogljlgcm:
+    resolution: {integrity: sha512-5zTSXyyv7bahDBQ/kJw/kNxxoBqTouttoelw8FOVOyWqmTMndizJEpvaj1N+yES5Xjss6Y2iVw+9vSJQZE8Z6g==}
+    engines: {node: '>=8.x'}
+    peerDependencies:
+      react: '>=16.9.0'
+      react-dom: '>=16.9.0'
+    dependencies:
+      '@babel/runtime': 7.18.3
+      react: 18.1.0
+      react-dom: 18.1.0_react@18.1.0
+      style-utils: 0.3.8
+      tween-one: 1.1.8
+    dev: false
+
   /rc-upload/4.3.4_ef5jwxihqo6n7gxfmzogljlgcm:
     resolution: {integrity: sha512-uVbtHFGNjHG/RyAfm9fluXB6pvArAGyAx8z7XzXXyorEgVIWj6mOlriuDm0XowDHYz4ycNK0nE0oP3cbFnzxiQ==}
     peerDependencies:
@@ -9494,6 +9492,10 @@ packages:
   /style-search/0.1.0:
     resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==}
 
+  /style-utils/0.3.8:
+    resolution: {integrity: sha512-RmGftIhY4tqtD1ERwKsVEDlt/M6UyxN/rcr95UmlooWmhtL0RwVUYJkpo1kSx3ppd9/JZzbknhy742zbMAawjQ==}
+    dev: false
+
   /stylelint-config-recommended/7.0.0_stylelint@14.8.2:
     resolution: {integrity: sha512-yGn84Bf/q41J4luis1AZ95gj0EQwRX8lWmGmBwkwBNSkpGSpl66XcPTulxGa/Z91aPoNGuIGBmFkcM1MejMo9Q==}
     peerDependencies:
@@ -9648,6 +9650,14 @@ packages:
     resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==}
     dev: false
 
+  /svg-path-properties/0.2.2:
+    resolution: {integrity: sha512-GmrB+b6woz6CCdQe6w1GHs/1lt25l7SR5hmhF8jRdarpv/OgjLyuQygLu1makJapixeb1aQhP/Oa1iKi93o/aQ==}
+    dev: false
+
+  /svg-path-properties/1.0.11:
+    resolution: {integrity: sha512-Wo6SjzONZPL9UAgrnwcCkDGRYP9CbHJGkNcPFIgEVRjiOiJxSd/AtwnGk/4N4iOLGUoas57TMxY0xASDeb9YJg==}
+    dev: false
+
   /svg-tags/1.0.0:
     resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
 
@@ -9665,6 +9675,10 @@ packages:
       stable: 0.1.8
     dev: false
 
+  /svgpath/2.5.0:
+    resolution: {integrity: sha512-o/vohwqjUO9nDAh4rcjE3KaW/v//At8UJu2LJMybXidf5QLQLVA4bxH0//4YCsr+1H4Gw1Wi/Jc62ynzSBYidw==}
+    dev: false
+
   /swr/1.3.0_react@18.1.0:
     resolution: {integrity: sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==}
     peerDependencies:
@@ -9768,6 +9782,13 @@ packages:
     resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==}
     dev: false
 
+  /topojson-client/3.1.0:
+    resolution: {integrity: sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==}
+    hasBin: true
+    dependencies:
+      commander: 2.20.3
+    dev: false
+
   /totalist/3.0.0:
     resolution: {integrity: sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==}
     engines: {node: '>=6'}
@@ -9802,6 +9823,21 @@ packages:
     resolution: {integrity: sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==}
     dev: false
 
+  /tween-functions/1.2.0:
+    resolution: {integrity: sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==}
+    dev: false
+
+  /tween-one/1.1.8:
+    resolution: {integrity: sha512-b9WD0/ZauKmhpomV5skXkTw6MMOEKLmBsWXV754Vp0WuJALcDP5u7PQSvMMFqVSQ/eg8R8DAxiaNebHZtB57fg==}
+    dependencies:
+      '@babel/runtime': 7.18.3
+      flubber: 0.4.2
+      raf: 3.4.1
+      style-utils: 0.3.8
+      svg-path-properties: 1.0.11
+      tween-functions: 1.2.0
+    dev: false
+
   /type-check/0.4.0:
     resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
     engines: {node: '>= 0.8.0'}
@@ -9847,7 +9883,6 @@ packages:
     resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==}
     engines: {node: '>=4.2.0'}
     hasBin: true
-    dev: true
 
   /ufo/0.8.4:
     resolution: {integrity: sha512-/+BmBDe8GvlB2nIflWasLLAInjYG0bC9HRnfEpNi4sw77J2AJNnEVnTDReVrehoh825+Q/evF3THXTAweyam2g==}

+ 1 - 0
src/locales/zh-CN/menu.ts

@@ -27,6 +27,7 @@ export default {
   'menu.institutions.staff': '人员管理',
   'menu.institutions.restrict': '限制登录',
   'menu.business': '业务审批设置',
+  'menu.business.rules': '编号规则设置',
   'menu.business.inventory': '审核资料清单模板',
   'menu.business.process': '流程用户设置',
   'menu.institutions.company.company-list': '单位列表',

+ 310 - 0
src/pages/Business/RulesSet/index.tsx

@@ -0,0 +1,310 @@
+import { PageContainer } from '@ant-design/pro-layout'
+import { Button, Col, Form, Input, InputNumber, message, Row, Select, Tabs, Tag } from 'antd'
+import React, { useEffect, useState } from 'react'
+import { TweenOneGroup } from 'rc-tween-one'
+import { createUid, dayjsFormat } from '@/utils/util'
+import { queryRuleCodeList, updateRuleCode } from '@/services/api/business'
+import { useRequest } from '@umijs/max'
+
+const { TabPane } = Tabs
+const { Option } = Select
+const contentHeight = document.body.clientHeight - 122
+
+const connectorOption = [
+  { label: '无', value: '' },
+  { label: '-', value: '-' },
+  { label: '_', value: '_' }
+]
+
+export enum ruleOptionEunm {
+  REVIEWTYPE = '1',
+  YEAR = '2',
+  MONTH = '3',
+  NUMBER = '4',
+  TEXT = '5'
+}
+interface iTags {
+  ruleArr: ruleOption[]
+  setRuleArr: (arr: ruleOption[]) => void
+}
+
+const RenderTags: React.FC<iTags> = ({ ruleArr, setRuleArr }) => {
+  const handleClose = (removedTag: ruleOption) => {
+    const tags = ruleArr.filter(tag => tag.pid !== removedTag.pid)
+    setRuleArr(tags)
+  }
+  return (
+    <div>
+      <TweenOneGroup
+        enter={{
+          scale: 0.8,
+          opacity: 0,
+          type: 'from',
+          duration: 100
+        }}
+        leave={{ opacity: 0, width: 0, scale: 0, duration: 200 }}
+        appear={false}>
+        {ruleArr.map((tag, idx) => {
+          return (
+            <span key={idx} style={{ display: 'inline-block' }}>
+              {tag?.label ? (
+                <Tag
+                  closable
+                  onClose={(e: MouseEvent) => {
+                    e.preventDefault()
+                    handleClose(tag)
+                  }}>
+                  {tag.label}
+                </Tag>
+              ) : null}
+            </span>
+          )
+        })}
+      </TweenOneGroup>
+    </div>
+  )
+}
+
+const RulesSet = () => {
+  const [form] = Form.useForm()
+  const [state, setState] = useState({
+    ruleTypeValue: ruleOptionEunm.REVIEWTYPE,
+    tabId: 'yuS',
+    connector: '-'
+  })
+
+  const [ruleArr, setRuleArr] = useState<ruleOption[]>([])
+
+  // 处理自动位数编号 -> 联动起始编号
+  const digitHandler = (value: any) => {
+    if (value) {
+      const length = form.getFieldValue('digits')
+      const code = parseInt(form.getFieldValue('autoCode'))
+      const newCode = (Array(length).join('0') + code).slice(-length)
+      form.setFieldsValue({ autoCode: newCode })
+    }
+  }
+
+  const { run: tryRuleCode } = useRequest(() => queryRuleCodeList({ tab: state.tabId }), {
+    manual: true,
+    onSuccess: result => {
+      setRuleArr(result.rules)
+      setState({ ...state, connector: result.connector })
+    }
+  })
+
+  const { run: tryUpdateRuleCode } = useRequest(updateRuleCode, {
+    manual: true,
+    onSuccess: () => {
+      message.success('规则更改成功')
+      tryRuleCode()
+    }
+  })
+
+  useEffect(() => {
+    if (state.ruleTypeValue === ruleOptionEunm.NUMBER) {
+      form.setFieldsValue({ ruleType: ruleOptionEunm.NUMBER, digits: '5', autoCode: '00001', ruleText: '' })
+    }
+  }, [state.ruleTypeValue])
+
+  // 只需首次加载执行一次
+  useEffect(() => {
+    function fectTryRuleCode() {
+      if (state.tabId === 'yuS') {
+        tryRuleCode()
+      }
+    }
+    fectTryRuleCode()
+  }, [])
+
+  // 添加规则
+  const ruleHandel = () => {
+    switch (state.ruleTypeValue) {
+      case ruleOptionEunm.REVIEWTYPE:
+        setRuleArr([
+          ...ruleArr,
+          {
+            type: 'approvalType',
+            value: form.getFieldValue('approvalType'),
+            label: '审核类型',
+            pid: createUid()
+          }
+        ])
+        break
+      case ruleOptionEunm.YEAR:
+        setRuleArr([
+          ...ruleArr,
+          {
+            type: 'currentYear',
+            value: dayjsFormat(new Date(), 'YYYY'),
+            label: '当前年份',
+            pid: createUid()
+          }
+        ])
+        break
+      case ruleOptionEunm.MONTH:
+        setRuleArr([
+          ...ruleArr,
+          {
+            type: 'currentMonth',
+            value: dayjsFormat(new Date(), 'M'),
+            label: '当前月份',
+            pid: createUid()
+          }
+        ])
+        break
+      case ruleOptionEunm.NUMBER:
+        setRuleArr([
+          ...ruleArr,
+          {
+            type: 'autoCode',
+            value: form.getFieldValue('autoCode'),
+            label: '自动编号',
+            pid: createUid()
+          }
+        ])
+        break
+      default:
+        setRuleArr([
+          ...ruleArr,
+          {
+            type: 'fixedText',
+            value: form.getFieldValue('fixedText'),
+            label: '固定文本',
+            pid: createUid()
+          }
+        ])
+        break
+    }
+  }
+  return (
+    <PageContainer title={false}>
+      <div className="p-4 bg-white" style={{ height: `${contentHeight}px` }}>
+        <div className="flex justify-between w-full pb-2 border-b border-[bg-[#00ffcc]]">
+          <div className="text-xl">编号规则设置</div>
+          <div>
+            <Button
+              type="primary"
+              onClick={() => {
+                tryUpdateRuleCode({
+                  tab: state.tabId,
+                  rules: ruleArr.map(item => ({
+                    rule: item.type,
+                    value: item.value,
+                    label: item.label,
+                    pid: item.pid
+                  })),
+                  connector: state.connector
+                })
+              }}>
+              保存
+            </Button>
+          </div>
+        </div>
+        <Form
+          form={form}
+          initialValues={{
+            approvalType: '01',
+            Connector: state.connector,
+            ruleType: ruleOptionEunm.REVIEWTYPE
+          }}>
+          <Tabs
+            defaultActiveKey="yuS"
+            onChange={key => {
+              setState({
+                ...state,
+                tabId: key
+              })
+            }}>
+            <TabPane key="yuS" tab="预算">
+              <Form.Item labelCol={{ span: 3 }} wrapperCol={{ span: 24 }} label="编号预览">
+                {ruleArr.map(item => item?.value).join(state.connector)}
+              </Form.Item>
+              <Form.Item labelCol={{ span: 3 }} wrapperCol={{ span: 24 }} label="编号规则">
+                <div className="w-full min-h-32px border-1 border-[#d9d9d9] border-solid rounded-2px py-1 px-3">
+                  <RenderTags ruleArr={ruleArr} setRuleArr={setRuleArr} />
+                </div>
+              </Form.Item>
+              <Form.Item labelCol={{ span: 3 }} wrapperCol={{ span: 5 }} label="连接符" name="Connector">
+                <Select
+                  options={connectorOption}
+                  onSelect={value =>
+                    setState({
+                      ...state,
+                      connector: value
+                    })
+                  }
+                />
+              </Form.Item>
+              <Row>
+                <Col span={8}>
+                  <Form.Item labelCol={{ span: 9 }} wrapperCol={{ span: 24 }} label="规则" name="ruleType">
+                    <Select
+                      onSelect={value =>
+                        setState({
+                          ...state,
+                          ruleTypeValue: value
+                        })
+                      }>
+                      <Option value="0">请选择</Option>
+                      <Option value="1">审核类型</Option>
+                      <Option value="2">当前年份</Option>
+                      <Option value="3">当前月份</Option>
+                      <Option value="4">自动编号</Option>
+                      <Option value="5">固定文本</Option>
+                    </Select>
+                  </Form.Item>
+                </Col>
+                <Col span={16}>
+                  <div className="flex">
+                    <div className="px-2">
+                      <Form.Item
+                        label="类型"
+                        name="approvalType"
+                        hidden={state.ruleTypeValue === ruleOptionEunm.REVIEWTYPE ? false : true}>
+                        <Select style={{ width: 180 }}>
+                          <Option value="01">预算</Option>
+                        </Select>
+                      </Form.Item>
+                    </div>
+                    <div className="pr-2">
+                      <Form.Item
+                        label="数位"
+                        name="digits"
+                        hidden={state.ruleTypeValue === ruleOptionEunm.NUMBER ? false : true}>
+                        <InputNumber style={{ width: 180 }} min={1} onChange={value => digitHandler(value)} />
+                      </Form.Item>
+                    </div>
+                    <div className="pr-2">
+                      <Form.Item
+                        label="规则"
+                        name="fixedText"
+                        hidden={state.ruleTypeValue === ruleOptionEunm.TEXT ? false : true}>
+                        <Input style={{ width: 180 }} />
+                      </Form.Item>
+                    </div>
+                    <div className="pr-2">
+                      <Form.Item
+                        label="起始编号"
+                        name="autoCode"
+                        hidden={state.ruleTypeValue === ruleOptionEunm.NUMBER ? false : true}>
+                        <Input type="number" style={{ width: 180 }} />
+                      </Form.Item>
+                    </div>
+                    <div>
+                      <Button type="primary" ghost onClick={() => ruleHandel()}>
+                        添加
+                      </Button>
+                    </div>
+                  </div>
+                </Col>
+              </Row>
+            </TabPane>
+          </Tabs>
+        </Form>
+      </div>
+    </PageContainer>
+  )
+}
+
+export default RulesSet

+ 16 - 0
src/services/api/business.ts

@@ -54,3 +54,19 @@ export async function moveTemplate(params: { ID: string; moveID: string }) {
     data: params
   })
 }
+
+/** 编号规则生成器查询详情 */
+export async function queryRuleCodeList(params: { tab: string }) {
+  return request('/RuleCode/list', {
+    method: 'GET',
+    params
+  })
+}
+
+/** 编号规则生成器保存编号 */
+export async function updateRuleCode(params: API.RuleCodeUpdateParams) {
+  return request('/RuleCode/update', {
+    method: 'POST',
+    data: params
+  })
+}

+ 5 - 0
src/services/api/typings.d.ts

@@ -414,4 +414,9 @@ declare namespace API {
     institutionID: string
     accountID: string
   }
+
+  type RuleCodeUpdateParams = {
+    tab: string
+    rules: any[]
+  }
 }

+ 14 - 0
src/utils/util.ts

@@ -1,5 +1,7 @@
 import type { TableColumnType } from 'antd'
+import dayjs from 'dayjs'
 
+// eslint-disable-next-line no-promise-executor-return
 export const delay = (ms?: number | undefined) => new Promise(res => setTimeout(res, ms))
 
 /**
@@ -33,3 +35,15 @@ export function generateColumns(c: TableColumnType, s: any, f?: string | string[
   }
   return nC
 }
+
+/**
+ * 日期格式化
+ * @param format - 格式
+ */
+export const dayjsFormat = (date, format = 'YYYY-MM-DD HH:mm:ss') => {
+  if (date === '0001-01-01 00:00:00' || !date) return ''
+  return dayjs(date).format(format)
+}
+
+// 可控长度的随机数拼接时间戳成产唯一id
+export const createUid = () => URL.createObjectURL(new Blob()).substr(-36)