服务模版
This commit is contained in:
@@ -11,9 +11,15 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.2.6",
|
||||
"@ant-design/pro-components": "^2.8.2",
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/modifiers": "^9.0.0",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@supabase/supabase-js": "^2.38.4",
|
||||
"antd": "^5.11.0",
|
||||
"dnd-kit": "^0.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
||||
511
pnpm-lock.yaml
generated
511
pnpm-lock.yaml
generated
@@ -11,6 +11,21 @@ importers:
|
||||
'@ant-design/icons':
|
||||
specifier: ^5.2.6
|
||||
version: 5.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-components':
|
||||
specifier: ^2.8.2
|
||||
version: 2.8.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@dnd-kit/core':
|
||||
specifier: ^6.3.1
|
||||
version: 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@dnd-kit/modifiers':
|
||||
specifier: ^9.0.0
|
||||
version: 9.0.0(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
'@dnd-kit/sortable':
|
||||
specifier: ^10.0.0
|
||||
version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
'@dnd-kit/utilities':
|
||||
specifier: ^3.2.2
|
||||
version: 3.2.2(react@18.3.1)
|
||||
'@monaco-editor/react':
|
||||
specifier: ^4.6.0
|
||||
version: 4.6.0(monaco-editor@0.52.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -20,6 +35,9 @@ importers:
|
||||
antd:
|
||||
specifier: ^5.11.0
|
||||
version: 5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
dnd-kit:
|
||||
specifier: ^0.0.2
|
||||
version: 0.0.2
|
||||
lodash:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
@@ -118,6 +136,82 @@ packages:
|
||||
react: '>=16.0.0'
|
||||
react-dom: '>=16.0.0'
|
||||
|
||||
'@ant-design/pro-card@2.9.2':
|
||||
resolution: {integrity: sha512-mKOmNb7jc3Pz41RrPY7EFKRWBjLdN4tp9yzmRkS2g8K7P3pW435f7Ip6rc+58FWDzbZa8lElTGPxAoFB/dq7LA==}
|
||||
peerDependencies:
|
||||
antd: ^4.24.15 || ^5.11.2
|
||||
react: '>=17.0.0'
|
||||
|
||||
'@ant-design/pro-components@2.8.2':
|
||||
resolution: {integrity: sha512-gSzt/Pw1ayZeHhxh5yaeP7pGpk0V2ZsB4PZab0s6V88O15Ql3w5ciYTObxbxGXMPc+A72AwVThoYLv2ZIl3cMA==}
|
||||
peerDependencies:
|
||||
antd: ^4.24.15 || ^5.11.2
|
||||
react: '>=17.0.0'
|
||||
react-dom: '>=17.0.0'
|
||||
|
||||
'@ant-design/pro-descriptions@2.6.2':
|
||||
resolution: {integrity: sha512-IrXf4qNMyaypEhO54oZDOFNJ9jrQgg2ovARY7hHRZCChC+I2xVGFCFWXrmtyS82kusxHb6OlLw20ahm+TLZ71w==}
|
||||
peerDependencies:
|
||||
antd: ^4.24.15 || ^5.11.2
|
||||
react: '>=17.0.0'
|
||||
|
||||
'@ant-design/pro-field@2.17.2':
|
||||
resolution: {integrity: sha512-cebfWGaE6MYwfchXpU9xA6jPETZOvk3i9+1IvebjSEKKVXecXuA+muZorpwYzORmkgGBmSPyR0KW+6Ttgtmg9Q==}
|
||||
peerDependencies:
|
||||
antd: ^4.24.15 || ^5.11.2
|
||||
react: '>=17.0.0'
|
||||
|
||||
'@ant-design/pro-form@2.31.2':
|
||||
resolution: {integrity: sha512-fzchlk+vGi8rCpmC62/SrikuwC2ZpyKnvNVAyihPCNe9oyyv+LD2TZAD0fbshfifP/1aHOOtS4fb7ptYq+LarQ==}
|
||||
peerDependencies:
|
||||
antd: ^4.24.15 || ^5.11.2
|
||||
rc-field-form: '>=1.22.0'
|
||||
react: '>=17.0.0'
|
||||
react-dom: '>=17.0.0'
|
||||
|
||||
'@ant-design/pro-layout@7.21.2':
|
||||
resolution: {integrity: sha512-dtqap5YNDrxUWxhi43QJQSv1JLHYPCV4/h4cFM10HNiX/86Cxw37DiCOMdIM/ZwWk619BiwN7CJNgL5Q8obrAQ==}
|
||||
peerDependencies:
|
||||
antd: ^4.24.15 || ^5.11.2
|
||||
react: '>=17.0.0'
|
||||
react-dom: '>=17.0.0'
|
||||
|
||||
'@ant-design/pro-list@2.6.2':
|
||||
resolution: {integrity: sha512-BEM/WFe8vj4TCdsxa1JDQwl87Xb7oj+3bxA8yLDjRWWwX+D9UuxdYyB2lZsFfSEnphau/mccDE3K/Lbtim6yJg==}
|
||||
peerDependencies:
|
||||
antd: ^4.24.15 || ^5.11.2
|
||||
react: '>=17.0.0'
|
||||
react-dom: '>=17.0.0'
|
||||
|
||||
'@ant-design/pro-provider@2.15.2':
|
||||
resolution: {integrity: sha512-7WSJcjYIuLwco1YiiSgEEJnrqvg7x/YZap8pxOChRnyNh9S3HuV1D5HTc18kfHTpWqZWTAUcS66b0kMP96uKrw==}
|
||||
peerDependencies:
|
||||
antd: ^4.24.15 || ^5.11.2
|
||||
react: '>=17.0.0'
|
||||
react-dom: '>=17.0.0'
|
||||
|
||||
'@ant-design/pro-skeleton@2.2.1':
|
||||
resolution: {integrity: sha512-3M2jNOZQZWEDR8pheY00OkHREfb0rquvFZLCa6DypGmiksiuuYuR9Y4iA82ZF+mva2FmpHekdwbje/GpbxqBeg==}
|
||||
peerDependencies:
|
||||
antd: ^4.24.15 || ^5.11.2
|
||||
react: '>=17.0.0'
|
||||
react-dom: '>=17.0.0'
|
||||
|
||||
'@ant-design/pro-table@3.18.2':
|
||||
resolution: {integrity: sha512-IIhWXvpBfdy1hqh0qYQOou6tDawrisFYwFhYdiMwuCnvy7UvaHi/JS4yikMe+KG0XVdh6xxfrF1Ad39SR8CrxQ==}
|
||||
peerDependencies:
|
||||
antd: ^4.24.15 || ^5.11.2
|
||||
rc-field-form: '>=1.22.0'
|
||||
react: '>=17.0.0'
|
||||
react-dom: '>=17.0.0'
|
||||
|
||||
'@ant-design/pro-utils@2.16.2':
|
||||
resolution: {integrity: sha512-ama73ZSzz9O6Qz6DvHd6cnyUA3vI7N+AAl5BV5plijujtnXpNC8KJMXl9jOI1K7QuUVJgJIKbZ2DVm8LnBcTAQ==}
|
||||
peerDependencies:
|
||||
antd: ^4.24.15 || ^5.11.2
|
||||
react: '>=17.0.0'
|
||||
react-dom: '>=17.0.0'
|
||||
|
||||
'@ant-design/react-slick@1.1.2':
|
||||
resolution: {integrity: sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==}
|
||||
peerDependencies:
|
||||
@@ -206,10 +300,55 @@ packages:
|
||||
resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@chenshuai2144/sketch-color@1.0.9':
|
||||
resolution: {integrity: sha512-obzSy26cb7Pm7OprWyVpgMpIlrZpZ0B7vbrU0RMbvRg0YAI890S5Xy02Aj1Nhl4+KTbi1lVYHt6HQP8Hm9s+1w==}
|
||||
peerDependencies:
|
||||
react: '>=16.12.0'
|
||||
|
||||
'@ctrl/tinycolor@3.6.1':
|
||||
resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
'@dnd-kit/accessibility@3.1.1':
|
||||
resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
|
||||
'@dnd-kit/core@6.3.1':
|
||||
resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
|
||||
'@dnd-kit/modifiers@6.0.1':
|
||||
resolution: {integrity: sha512-rbxcsg3HhzlcMHVHWDuh9LCjpOVAgqbV78wLGI8tziXY3+qcMQ61qVXIvNKQFuhj75dSfD+o+PYZQ/NUk2A23A==}
|
||||
peerDependencies:
|
||||
'@dnd-kit/core': ^6.0.6
|
||||
react: '>=16.8.0'
|
||||
|
||||
'@dnd-kit/modifiers@9.0.0':
|
||||
resolution: {integrity: sha512-ybiLc66qRGuZoC20wdSSG6pDXFikui/dCNGthxv4Ndy8ylErY0N3KVxY2bgo7AWwIbxDmXDg3ylAFmnrjcbVvw==}
|
||||
peerDependencies:
|
||||
'@dnd-kit/core': ^6.3.0
|
||||
react: '>=16.8.0'
|
||||
|
||||
'@dnd-kit/sortable@10.0.0':
|
||||
resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==}
|
||||
peerDependencies:
|
||||
'@dnd-kit/core': ^6.3.0
|
||||
react: '>=16.8.0'
|
||||
|
||||
'@dnd-kit/sortable@7.0.2':
|
||||
resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==}
|
||||
peerDependencies:
|
||||
'@dnd-kit/core': ^6.0.7
|
||||
react: '>=16.8.0'
|
||||
|
||||
'@dnd-kit/utilities@3.2.2':
|
||||
resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
|
||||
'@emotion/hash@0.8.0':
|
||||
resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==}
|
||||
|
||||
@@ -663,6 +802,14 @@ packages:
|
||||
'@types/ws@8.5.13':
|
||||
resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==}
|
||||
|
||||
'@umijs/route-utils@4.0.1':
|
||||
resolution: {integrity: sha512-+1ixf1BTOLuH+ORb4x8vYMPeIt38n9q0fJDwhv9nSxrV46mxbLF0nmELIo9CKQB2gHfuC4+hww6xejJ6VYnBHQ==}
|
||||
|
||||
'@umijs/use-params@1.0.9':
|
||||
resolution: {integrity: sha512-QlN0RJSBVQBwLRNxbxjQ5qzqYIGn+K7USppMoIOVlf7fxXHsnQZ2bEsa6Pm74bt6DVQxpUE8HqvdStn6Y9FV1w==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
|
||||
'@ungap/structured-clone@1.2.1':
|
||||
resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==}
|
||||
|
||||
@@ -682,6 +829,9 @@ packages:
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
add-dom-event-listener@1.1.0:
|
||||
resolution: {integrity: sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==}
|
||||
|
||||
ajv@6.12.6:
|
||||
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
||||
|
||||
@@ -822,6 +972,9 @@ packages:
|
||||
classnames@2.5.1:
|
||||
resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
|
||||
|
||||
client-only@0.0.1:
|
||||
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
|
||||
|
||||
clsx@2.1.1:
|
||||
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -961,6 +1114,10 @@ packages:
|
||||
dlv@1.1.3:
|
||||
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
|
||||
|
||||
dnd-kit@0.0.2:
|
||||
resolution: {integrity: sha512-d8AYd6I7D2b5u882+QNVGw0slBAt851/LWZ2j/pU+onf5/TGEKXeb47sCyhPYKEAUXp4oLfvWfNCqfkU03R1lw==}
|
||||
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
|
||||
|
||||
doctrine@2.1.0:
|
||||
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -1436,6 +1593,9 @@ packages:
|
||||
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
lodash-es@4.17.21:
|
||||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
||||
|
||||
lodash.merge@4.6.2:
|
||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||
|
||||
@@ -1538,6 +1698,9 @@ packages:
|
||||
resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
omit.js@2.0.2:
|
||||
resolution: {integrity: sha512-hJmu9D+bNB40YpL9jYebQl4lsTW6yEHRTroJzNLqQJYHm7c+NQnJGfZmIWh8S3q3KoaxV1aLhV6B3+0N0/kyJg==}
|
||||
|
||||
once@1.4.0:
|
||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||
|
||||
@@ -1579,6 +1742,10 @@ packages:
|
||||
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
|
||||
engines: {node: '>=16 || 14 >=14.18'}
|
||||
|
||||
path-to-regexp@8.0.0:
|
||||
resolution: {integrity: sha512-GAWaqWlTjYK/7SVpIUA6CTxmcg65SP30sbjdCvyYReosRkk7Z/LyHWwkK3Vu0FcIi0FNTADUs4eh1AsU5s10cg==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
picocolors@1.1.1:
|
||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||
|
||||
@@ -1788,6 +1955,12 @@ packages:
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
|
||||
rc-resize-observer@0.2.6:
|
||||
resolution: {integrity: sha512-YX6nYnd6fk7zbuvT6oSDMKiZjyngjHoy+fz+vL3Tez38d/G5iGdaDJa2yE7345G6sc4Mm1IGRUIwclvltddhmA==}
|
||||
peerDependencies:
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
|
||||
rc-resize-observer@1.4.1:
|
||||
resolution: {integrity: sha512-JbAeFDsaaZRPwaTlXnCqgeO9c6E7qoaE/hxsub08cdnnPn6767c/j9+r/TifUdfvwXtdcfHygKbZ7ecM/PXo/Q==}
|
||||
peerDependencies:
|
||||
@@ -1872,6 +2045,9 @@ packages:
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
|
||||
rc-util@4.21.1:
|
||||
resolution: {integrity: sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==}
|
||||
|
||||
rc-util@5.44.2:
|
||||
resolution: {integrity: sha512-uGSk3hpPBLa3/0QAcKhCjgl4SFnhQCJDLvvpoLdbR6KgDuXrujG+dQaUeUvBJr2ZWak1O/9n+cYbJiWmmk95EQ==}
|
||||
peerDependencies:
|
||||
@@ -1901,6 +2077,9 @@ packages:
|
||||
react-is@18.3.1:
|
||||
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
|
||||
|
||||
react-lifecycles-compat@3.0.4:
|
||||
resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==}
|
||||
|
||||
react-refresh@0.14.2:
|
||||
resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -1934,6 +2113,11 @@ packages:
|
||||
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
reactcss@1.2.3:
|
||||
resolution: {integrity: sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
|
||||
read-cache@1.0.0:
|
||||
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
|
||||
|
||||
@@ -2006,6 +2190,10 @@ packages:
|
||||
resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
safe-stable-stringify@2.5.0:
|
||||
resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
sass@1.83.0:
|
||||
resolution: {integrity: sha512-qsSxlayzoOjdvXMVLkzF84DJFc2HZEL/rFyGIKbbilYtAvlCxyuzUeff9LawTn4btVnLKg75Z8MMr1lxU1lfGw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@@ -2135,6 +2323,11 @@ packages:
|
||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
swr@2.2.5:
|
||||
resolution: {integrity: sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==}
|
||||
peerDependencies:
|
||||
react: ^16.11.0 || ^17.0.0 || ^18.0.0
|
||||
|
||||
tailwindcss@3.4.16:
|
||||
resolution: {integrity: sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@@ -2161,6 +2354,9 @@ packages:
|
||||
tiny-invariant@1.3.3:
|
||||
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
|
||||
|
||||
tinycolor2@1.6.0:
|
||||
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
|
||||
|
||||
to-regex-range@5.0.1:
|
||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||
engines: {node: '>=8.0'}
|
||||
@@ -2216,6 +2412,11 @@ packages:
|
||||
uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
||||
use-sync-external-store@1.4.0:
|
||||
resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
@@ -2250,6 +2451,9 @@ packages:
|
||||
terser:
|
||||
optional: true
|
||||
|
||||
warning@4.0.3:
|
||||
resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==}
|
||||
|
||||
webidl-conversions@3.0.1:
|
||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||
|
||||
@@ -2365,6 +2569,199 @@ snapshots:
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
'@ant-design/pro-card@2.9.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@ant-design/cssinjs': 1.22.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/icons': 5.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-provider': 2.15.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-utils': 2.16.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@babel/runtime': 7.26.0
|
||||
antd: 5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
classnames: 2.5.1
|
||||
omit.js: 2.0.2
|
||||
rc-resize-observer: 1.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
rc-util: 5.44.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
transitivePeerDependencies:
|
||||
- react-dom
|
||||
|
||||
'@ant-design/pro-components@2.8.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@ant-design/pro-card': 2.9.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-descriptions': 2.6.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-field': 2.17.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-form': 2.31.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-layout': 7.21.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-list': 2.6.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-provider': 2.15.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-skeleton': 2.2.1(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-table': 3.18.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-utils': 2.16.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@babel/runtime': 7.26.0
|
||||
antd: 5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
transitivePeerDependencies:
|
||||
- rc-field-form
|
||||
|
||||
'@ant-design/pro-descriptions@2.6.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@ant-design/pro-field': 2.17.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-form': 2.31.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-provider': 2.15.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-skeleton': 2.2.1(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-utils': 2.16.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@babel/runtime': 7.26.0
|
||||
antd: 5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
rc-resize-observer: 0.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
rc-util: 5.44.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
transitivePeerDependencies:
|
||||
- rc-field-form
|
||||
- react-dom
|
||||
|
||||
'@ant-design/pro-field@2.17.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@ant-design/icons': 5.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-provider': 2.15.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-utils': 2.16.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@babel/runtime': 7.26.0
|
||||
'@chenshuai2144/sketch-color': 1.0.9(react@18.3.1)
|
||||
antd: 5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
classnames: 2.5.1
|
||||
dayjs: 1.11.13
|
||||
lodash: 4.17.21
|
||||
lodash-es: 4.17.21
|
||||
omit.js: 2.0.2
|
||||
rc-util: 5.44.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
swr: 2.2.5(react@18.3.1)
|
||||
transitivePeerDependencies:
|
||||
- react-dom
|
||||
|
||||
'@ant-design/pro-form@2.31.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@ant-design/icons': 5.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-field': 2.17.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-provider': 2.15.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-utils': 2.16.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@babel/runtime': 7.26.0
|
||||
'@chenshuai2144/sketch-color': 1.0.9(react@18.3.1)
|
||||
'@umijs/use-params': 1.0.9(react@18.3.1)
|
||||
antd: 5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
classnames: 2.5.1
|
||||
dayjs: 1.11.13
|
||||
lodash: 4.17.21
|
||||
lodash-es: 4.17.21
|
||||
omit.js: 2.0.2
|
||||
rc-field-form: 2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
rc-resize-observer: 1.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
rc-util: 5.44.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
'@ant-design/pro-layout@7.21.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@ant-design/cssinjs': 1.22.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/icons': 5.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-provider': 2.15.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-utils': 2.16.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@babel/runtime': 7.26.0
|
||||
'@umijs/route-utils': 4.0.1
|
||||
'@umijs/use-params': 1.0.9(react@18.3.1)
|
||||
antd: 5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
classnames: 2.5.1
|
||||
lodash: 4.17.21
|
||||
lodash-es: 4.17.21
|
||||
omit.js: 2.0.2
|
||||
path-to-regexp: 8.0.0
|
||||
rc-resize-observer: 1.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
rc-util: 5.44.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
swr: 2.2.5(react@18.3.1)
|
||||
warning: 4.0.3
|
||||
|
||||
'@ant-design/pro-list@2.6.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@ant-design/cssinjs': 1.22.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/icons': 5.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-card': 2.9.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-field': 2.17.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-table': 3.18.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-utils': 2.16.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@babel/runtime': 7.26.0
|
||||
antd: 5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
classnames: 2.5.1
|
||||
dayjs: 1.11.13
|
||||
rc-resize-observer: 1.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
rc-util: 4.21.1
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
transitivePeerDependencies:
|
||||
- rc-field-form
|
||||
|
||||
'@ant-design/pro-provider@2.15.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@ant-design/cssinjs': 1.22.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@babel/runtime': 7.26.0
|
||||
'@ctrl/tinycolor': 3.6.1
|
||||
antd: 5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
dayjs: 1.11.13
|
||||
rc-util: 5.44.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
swr: 2.2.5(react@18.3.1)
|
||||
|
||||
'@ant-design/pro-skeleton@2.2.1(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.0
|
||||
antd: 5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
'@ant-design/pro-table@3.18.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@ant-design/cssinjs': 1.22.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/icons': 5.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-card': 2.9.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-field': 2.17.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-form': 2.31.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-provider': 2.15.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-utils': 2.16.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@babel/runtime': 7.26.0
|
||||
'@dnd-kit/core': 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@dnd-kit/modifiers': 6.0.1(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
'@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||
'@dnd-kit/utilities': 3.2.2(react@18.3.1)
|
||||
antd: 5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
classnames: 2.5.1
|
||||
dayjs: 1.11.13
|
||||
lodash: 4.17.21
|
||||
lodash-es: 4.17.21
|
||||
omit.js: 2.0.2
|
||||
rc-field-form: 2.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
rc-resize-observer: 1.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
rc-util: 5.44.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
'@ant-design/pro-utils@2.16.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@ant-design/icons': 5.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-provider': 2.15.2(antd@5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@babel/runtime': 7.26.0
|
||||
antd: 5.22.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
classnames: 2.5.1
|
||||
dayjs: 1.11.13
|
||||
lodash: 4.17.21
|
||||
lodash-es: 4.17.21
|
||||
rc-util: 5.44.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
safe-stable-stringify: 2.5.0
|
||||
swr: 2.2.5(react@18.3.1)
|
||||
|
||||
'@ant-design/react-slick@1.1.2(react@18.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.0
|
||||
@@ -2488,8 +2885,60 @@ snapshots:
|
||||
'@babel/helper-string-parser': 7.25.9
|
||||
'@babel/helper-validator-identifier': 7.25.9
|
||||
|
||||
'@chenshuai2144/sketch-color@1.0.9(react@18.3.1)':
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
reactcss: 1.2.3(react@18.3.1)
|
||||
tinycolor2: 1.6.0
|
||||
|
||||
'@ctrl/tinycolor@3.6.1': {}
|
||||
|
||||
'@dnd-kit/accessibility@3.1.1(react@18.3.1)':
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
tslib: 2.6.2
|
||||
|
||||
'@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@dnd-kit/accessibility': 3.1.1(react@18.3.1)
|
||||
'@dnd-kit/utilities': 3.2.2(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
tslib: 2.6.2
|
||||
|
||||
'@dnd-kit/modifiers@6.0.1(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@dnd-kit/core': 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@dnd-kit/utilities': 3.2.2(react@18.3.1)
|
||||
react: 18.3.1
|
||||
tslib: 2.6.2
|
||||
|
||||
'@dnd-kit/modifiers@9.0.0(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@dnd-kit/core': 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@dnd-kit/utilities': 3.2.2(react@18.3.1)
|
||||
react: 18.3.1
|
||||
tslib: 2.6.2
|
||||
|
||||
'@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@dnd-kit/core': 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@dnd-kit/utilities': 3.2.2(react@18.3.1)
|
||||
react: 18.3.1
|
||||
tslib: 2.6.2
|
||||
|
||||
'@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@dnd-kit/core': 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@dnd-kit/utilities': 3.2.2(react@18.3.1)
|
||||
react: 18.3.1
|
||||
tslib: 2.6.2
|
||||
|
||||
'@dnd-kit/utilities@3.2.2(react@18.3.1)':
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
tslib: 2.6.2
|
||||
|
||||
'@emotion/hash@0.8.0': {}
|
||||
|
||||
'@emotion/is-prop-valid@1.2.2':
|
||||
@@ -2898,6 +3347,12 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/node': 22.10.2
|
||||
|
||||
'@umijs/route-utils@4.0.1': {}
|
||||
|
||||
'@umijs/use-params@1.0.9(react@18.3.1)':
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
||||
'@ungap/structured-clone@1.2.1': {}
|
||||
|
||||
'@vitejs/plugin-react@4.3.4(vite@4.5.5(@types/node@22.10.2)(sass@1.83.0))':
|
||||
@@ -2917,6 +3372,10 @@ snapshots:
|
||||
|
||||
acorn@8.14.0: {}
|
||||
|
||||
add-dom-event-listener@1.1.0:
|
||||
dependencies:
|
||||
object-assign: 4.1.1
|
||||
|
||||
ajv@6.12.6:
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
@@ -3145,6 +3604,8 @@ snapshots:
|
||||
|
||||
classnames@2.5.1: {}
|
||||
|
||||
client-only@0.0.1: {}
|
||||
|
||||
clsx@2.1.1: {}
|
||||
|
||||
color-convert@2.0.1:
|
||||
@@ -3268,6 +3729,8 @@ snapshots:
|
||||
|
||||
dlv@1.1.3: {}
|
||||
|
||||
dnd-kit@0.0.2: {}
|
||||
|
||||
doctrine@2.1.0:
|
||||
dependencies:
|
||||
esutils: 2.0.3
|
||||
@@ -3865,6 +4328,8 @@ snapshots:
|
||||
dependencies:
|
||||
p-locate: 5.0.0
|
||||
|
||||
lodash-es@4.17.21: {}
|
||||
|
||||
lodash.merge@4.6.2: {}
|
||||
|
||||
lodash@4.17.21: {}
|
||||
@@ -3955,6 +4420,8 @@ snapshots:
|
||||
define-properties: 1.2.1
|
||||
es-object-atoms: 1.0.0
|
||||
|
||||
omit.js@2.0.2: {}
|
||||
|
||||
once@1.4.0:
|
||||
dependencies:
|
||||
wrappy: 1.0.2
|
||||
@@ -3995,6 +4462,8 @@ snapshots:
|
||||
lru-cache: 10.4.3
|
||||
minipass: 7.1.2
|
||||
|
||||
path-to-regexp@8.0.0: {}
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
@@ -4239,6 +4708,15 @@ snapshots:
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
rc-resize-observer@0.2.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.0
|
||||
classnames: 2.5.1
|
||||
rc-util: 5.44.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
resize-observer-polyfill: 1.5.1
|
||||
|
||||
rc-resize-observer@1.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.0
|
||||
@@ -4362,6 +4840,14 @@ snapshots:
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
rc-util@4.21.1:
|
||||
dependencies:
|
||||
add-dom-event-listener: 1.1.0
|
||||
prop-types: 15.8.1
|
||||
react-is: 16.13.1
|
||||
react-lifecycles-compat: 3.0.4
|
||||
shallowequal: 1.1.0
|
||||
|
||||
rc-util@5.44.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.26.0
|
||||
@@ -4393,6 +4879,8 @@ snapshots:
|
||||
|
||||
react-is@18.3.1: {}
|
||||
|
||||
react-lifecycles-compat@3.0.4: {}
|
||||
|
||||
react-refresh@0.14.2: {}
|
||||
|
||||
react-router-dom@6.28.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
@@ -4428,6 +4916,11 @@ snapshots:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
|
||||
reactcss@1.2.3(react@18.3.1):
|
||||
dependencies:
|
||||
lodash: 4.17.21
|
||||
react: 18.3.1
|
||||
|
||||
read-cache@1.0.0:
|
||||
dependencies:
|
||||
pify: 2.3.0
|
||||
@@ -4519,6 +5012,8 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
is-regex: 1.2.1
|
||||
|
||||
safe-stable-stringify@2.5.0: {}
|
||||
|
||||
sass@1.83.0:
|
||||
dependencies:
|
||||
chokidar: 4.0.1
|
||||
@@ -4696,6 +5191,12 @@ snapshots:
|
||||
|
||||
supports-preserve-symlinks-flag@1.0.0: {}
|
||||
|
||||
swr@2.2.5(react@18.3.1):
|
||||
dependencies:
|
||||
client-only: 0.0.1
|
||||
react: 18.3.1
|
||||
use-sync-external-store: 1.4.0(react@18.3.1)
|
||||
|
||||
tailwindcss@3.4.16:
|
||||
dependencies:
|
||||
'@alloc/quick-lru': 5.2.0
|
||||
@@ -4739,6 +5240,8 @@ snapshots:
|
||||
|
||||
tiny-invariant@1.3.3: {}
|
||||
|
||||
tinycolor2@1.6.0: {}
|
||||
|
||||
to-regex-range@5.0.1:
|
||||
dependencies:
|
||||
is-number: 7.0.0
|
||||
@@ -4809,6 +5312,10 @@ snapshots:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
use-sync-external-store@1.4.0(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
victory-vendor@36.9.2:
|
||||
@@ -4838,6 +5345,10 @@ snapshots:
|
||||
fsevents: 2.3.3
|
||||
sass: 1.83.0
|
||||
|
||||
warning@4.0.3:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
|
||||
webidl-conversions@3.0.1: {}
|
||||
|
||||
whatwg-url@5.0.0:
|
||||
|
||||
@@ -38,6 +38,26 @@ const companyRoutes = [
|
||||
name: '报价单详情',
|
||||
icon: 'file',
|
||||
},
|
||||
{
|
||||
path: 'serviceTeamplate',
|
||||
component: lazy(() => import('@/pages/company/service')),
|
||||
name: '服务管理',
|
||||
icon: 'container',
|
||||
},
|
||||
{
|
||||
path: 'serviceType',
|
||||
hidden: true,
|
||||
component: lazy(() => import('@/pages/company/service/serviceType')),
|
||||
name: '类型管理',
|
||||
icon: 'container',
|
||||
},
|
||||
{
|
||||
path: 'serviceTemplateInfo/:id?',
|
||||
hidden: true,
|
||||
component: lazy(() => import('@/pages/company/service/detail')),
|
||||
name: '服务模版详情',
|
||||
icon: 'container',
|
||||
},
|
||||
{
|
||||
path: 'quotaInfo/preview/:id?', // 添加可选的 id 参数
|
||||
hidden: true,
|
||||
|
||||
609
src/pages/company/service/detail/index.jsx
Normal file
609
src/pages/company/service/detail/index.jsx
Normal file
@@ -0,0 +1,609 @@
|
||||
import React, { useState, useEffect, useMemo } from "react";
|
||||
import {
|
||||
Card,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
Button,
|
||||
Space,
|
||||
Typography,
|
||||
message,
|
||||
Select,
|
||||
} from "antd";
|
||||
import {
|
||||
PlusOutlined,
|
||||
DeleteOutlined,
|
||||
ArrowLeftOutlined,
|
||||
EditOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { useNavigate, useParams, useLocation } from "react-router-dom";
|
||||
import { supabase } from "@/config/supabase";
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
const ServiceForm = () => {
|
||||
const [form] = Form.useForm();
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const location = useLocation();
|
||||
const isEdit = location.search.includes("edit=true");
|
||||
const [editingSectionIndex, setEditingSectionIndex] = useState(null);
|
||||
const [availableSections, setAvailableSections] = useState([]);
|
||||
const [formValues, setFormValues] = useState({});
|
||||
const [sectionNameForm] = Form.useForm();
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
fetchServiceTemplate();
|
||||
}
|
||||
fetchAvailableSections();
|
||||
}, [id]);
|
||||
|
||||
const fetchServiceTemplate = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const { data, error } = await supabase
|
||||
.from("resources")
|
||||
.select("*")
|
||||
.eq("id", id)
|
||||
.single();
|
||||
|
||||
if (error) throw error;
|
||||
form.setFieldsValue({
|
||||
templateName: data.attributes.templateName,
|
||||
description: data.attributes.description,
|
||||
sections: data.attributes.sections,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("获取服务模版失败:", error);
|
||||
message.error("获取服务模版失败");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchAvailableSections = async () => {
|
||||
try {
|
||||
const { data: sections, error } = await supabase
|
||||
.from("resources")
|
||||
.select("*")
|
||||
.eq("type", "serviceSection");
|
||||
|
||||
if (error) throw error;
|
||||
setAvailableSections(sections);
|
||||
} catch (error) {
|
||||
console.error("获取服务小节失败:", error);
|
||||
message.error("获取服务小节失败");
|
||||
}
|
||||
};
|
||||
|
||||
const onFinish = async (values) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const totalAmount = values.sections.reduce((sum, section) => {
|
||||
return (
|
||||
sum +
|
||||
(section.items || []).reduce((sectionSum, item) => {
|
||||
return sectionSum + (item.quantity * item.price || 0);
|
||||
}, 0)
|
||||
);
|
||||
}, 0);
|
||||
|
||||
const serviceData = {
|
||||
type: "serviceTemplate",
|
||||
attributes: {
|
||||
templateName: values.templateName,
|
||||
description: values.description,
|
||||
sections: values.sections,
|
||||
totalAmount,
|
||||
},
|
||||
};
|
||||
|
||||
let result;
|
||||
if (id) {
|
||||
result = await supabase
|
||||
.from("resources")
|
||||
.update(serviceData)
|
||||
.eq("id", id)
|
||||
.select();
|
||||
} else {
|
||||
result = await supabase
|
||||
.from("resources")
|
||||
.insert([serviceData])
|
||||
.select();
|
||||
}
|
||||
|
||||
if (result.error) throw result.error;
|
||||
message.success("保存成功");
|
||||
navigate("/company/serviceTeamplate");
|
||||
} catch (error) {
|
||||
console.error("保存失败:", error);
|
||||
message.error("保存失败");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleAddExistingSection = (sectionId) => {
|
||||
const section = availableSections.find((s) => s.id === sectionId);
|
||||
if (section) {
|
||||
const sections = form.getFieldValue("sections") || [];
|
||||
form.setFieldsValue({
|
||||
sections: [
|
||||
...sections,
|
||||
{
|
||||
...section.attributes,
|
||||
sectionId: section.id,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const currencyOptions = [
|
||||
{ value: "CNY", label: "人民币 (¥)" },
|
||||
{ value: "TWD", label: "台币 (NT$)" },
|
||||
{ value: "USD", label: "美元 ($)" },
|
||||
];
|
||||
|
||||
const calculateItemAmount = useMemo(
|
||||
() => (quantity, price) => {
|
||||
const safeQuantity = Number(quantity) || 0;
|
||||
const safePrice = Number(price) || 0;
|
||||
return safeQuantity * safePrice;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const calculateSectionTotal = useMemo(
|
||||
() =>
|
||||
(items = []) => {
|
||||
if (!Array.isArray(items)) return 0;
|
||||
|
||||
return items.reduce((sum, item) => {
|
||||
if (!item) return sum;
|
||||
return sum + calculateItemAmount(item.quantity, item.price);
|
||||
}, 0);
|
||||
},
|
||||
[calculateItemAmount]
|
||||
);
|
||||
|
||||
const calculateTotalAmount = useMemo(
|
||||
() =>
|
||||
(sections = []) => {
|
||||
if (!Array.isArray(sections)) return 0;
|
||||
|
||||
return sections.reduce((sum, section) => {
|
||||
if (!section) return sum;
|
||||
return sum + calculateSectionTotal(section.items);
|
||||
}, 0);
|
||||
},
|
||||
[calculateSectionTotal]
|
||||
);
|
||||
|
||||
const formatCurrency = useMemo(
|
||||
() =>
|
||||
(amount, currency = form.getFieldValue("currency")) => {
|
||||
const safeAmount = Number(amount) || 0;
|
||||
const currencySymbol =
|
||||
{
|
||||
CNY: "¥",
|
||||
TWD: "NT$",
|
||||
USD: "$",
|
||||
}[currency] || "";
|
||||
|
||||
return `${currencySymbol}${safeAmount.toLocaleString("zh-CN", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
})}`;
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const handleValuesChange = (changedValues, allValues) => {
|
||||
setFormValues(allValues);
|
||||
};
|
||||
|
||||
const [editingSectionName, setEditingSectionName] = useState('');
|
||||
|
||||
// 处理小节名称编辑
|
||||
const handleSectionNameEdit = (sectionIndex, initialValue) => {
|
||||
setEditingSectionIndex(sectionIndex);
|
||||
setEditingSectionName(initialValue || '');
|
||||
};
|
||||
|
||||
// 保存小节名称
|
||||
const handleSectionNameSave = () => {
|
||||
if (!editingSectionName.trim()) {
|
||||
message.error('请输入小节名称');
|
||||
return;
|
||||
}
|
||||
|
||||
const sections = form.getFieldValue('sections');
|
||||
const newSections = [...sections];
|
||||
newSections[editingSectionIndex] = {
|
||||
...newSections[editingSectionIndex],
|
||||
sectionName: editingSectionName.trim()
|
||||
};
|
||||
form.setFieldValue('sections', newSections);
|
||||
setEditingSectionIndex(null);
|
||||
setEditingSectionName('');
|
||||
};
|
||||
|
||||
// 取消编辑
|
||||
const handleSectionNameCancel = () => {
|
||||
setEditingSectionIndex(null);
|
||||
setEditingSectionName('');
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
title={
|
||||
<span className="text-gray-800 dark:text-gray-200">
|
||||
{id ? (isEdit ? "编辑服务模版" : "查看服务模版") : "新增服务模版"}
|
||||
</span>
|
||||
}
|
||||
className="dark:bg-gray-800"
|
||||
extra={
|
||||
<Space>
|
||||
<Button
|
||||
icon={<ArrowLeftOutlined />}
|
||||
onClick={() => navigate("/company/serviceTeamplate")}
|
||||
className="flex items-center"
|
||||
>
|
||||
返回列表
|
||||
</Button>
|
||||
{id && !isEdit && (
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() =>
|
||||
navigate(`/company/serviceTemplateInfo/${id}?edit=true`)
|
||||
}
|
||||
className="flex items-center"
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
onFinish={onFinish}
|
||||
initialValues={{
|
||||
sections: [{ items: [{}] }],
|
||||
currency: "CNY",
|
||||
}}
|
||||
disabled={id && !isEdit}
|
||||
onValuesChange={handleValuesChange}
|
||||
>
|
||||
<div className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 mb-6">
|
||||
<Title level={5} className="mb-4 dark:text-gray-200">
|
||||
基本信息
|
||||
</Title>
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<Form.Item
|
||||
label="模版名称"
|
||||
name="templateName"
|
||||
rules={[{ required: true, message: "请输入模版名称" }]}
|
||||
>
|
||||
<Input placeholder="请输入模版名称" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="货币单位"
|
||||
name="currency"
|
||||
rules={[{ required: true, message: "请选择货币单位" }]}
|
||||
initialValue="CNY"
|
||||
>
|
||||
<Select options={currencyOptions} placeholder="请选择货币单位" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="模版分类"
|
||||
name="category"
|
||||
rules={[{ required: true, message: "请选择或输入分类" }]}
|
||||
>
|
||||
<Select
|
||||
placeholder="请选择或输入分类"
|
||||
showSearch
|
||||
allowClear
|
||||
mode="tags"
|
||||
options={[
|
||||
{ value: "VI设计", label: "VI设计" },
|
||||
{ value: "平面设计", label: "平面设计" },
|
||||
{ value: "网站建设", label: "网站建设" },
|
||||
{ value: "营销推广", label: "营销推广" },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="模版描述"
|
||||
name="description"
|
||||
className="col-span-2"
|
||||
>
|
||||
<Input.TextArea rows={4} placeholder="请输入模版描述" />
|
||||
</Form.Item>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<Title level={5} className="!mb-0 dark:text-gray-200">
|
||||
报价明细
|
||||
</Title>
|
||||
{(!id || isEdit) && (
|
||||
<Select
|
||||
style={{ width: 200 }}
|
||||
placeholder="选择已有小节"
|
||||
onChange={handleAddExistingSection}
|
||||
options={availableSections.map((section) => ({
|
||||
value: section.id,
|
||||
label: section.attributes.sectionName,
|
||||
}))}
|
||||
className="w-48"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Form.List name="sections">
|
||||
{(fields, { add: addSection, remove: removeSection }) => (
|
||||
<>
|
||||
<div className="space-y-6">
|
||||
{fields.map((field, sectionIndex) => (
|
||||
<Card
|
||||
key={field.key}
|
||||
className="!border-gray-200 dark:!border-gray-700 dark:bg-gray-800 hover:shadow-md transition-shadow duration-300"
|
||||
>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-2 ">
|
||||
{editingSectionIndex === sectionIndex ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
placeholder="请输入小节名称"
|
||||
className="!w-[200px]"
|
||||
value={editingSectionName}
|
||||
onChange={e => setEditingSectionName(e.target.value)}
|
||||
onPressEnter={handleSectionNameSave}
|
||||
autoFocus
|
||||
/>
|
||||
<Space className="flex items-center gap-2">
|
||||
<Button
|
||||
type="primary"
|
||||
size="small"
|
||||
onClick={handleSectionNameSave}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={handleSectionNameCancel}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<Text
|
||||
strong
|
||||
className="text-lg dark:text-gray-200"
|
||||
>
|
||||
{form.getFieldValue([
|
||||
"sections",
|
||||
sectionIndex,
|
||||
"sectionName",
|
||||
]) || `服务类型 ${sectionIndex + 1}`}
|
||||
</Text>
|
||||
{(!id || isEdit) && (
|
||||
<Button
|
||||
type="text"
|
||||
icon={<EditOutlined />}
|
||||
onClick={() =>
|
||||
handleSectionNameEdit(
|
||||
sectionIndex,
|
||||
form.getFieldValue([
|
||||
"sections",
|
||||
sectionIndex,
|
||||
"sectionName",
|
||||
])
|
||||
)
|
||||
}
|
||||
size="small"
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<Text className="text-gray-500 dark:text-gray-400">
|
||||
合计:{" "}
|
||||
{formatCurrency(
|
||||
calculateSectionTotal(
|
||||
formValues?.sections?.[sectionIndex]?.items
|
||||
)
|
||||
)}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
{/* 表头 */}
|
||||
<div className="grid grid-cols-[3fr_4fr_1fr_1fr_2fr_1fr_40px] gap-4 mb-2 text-gray-500 dark:text-gray-400 px-2">
|
||||
<div>项目明细</div>
|
||||
<div>描述/备注</div>
|
||||
<div className="text-center">数量</div>
|
||||
<div className="text-center">单位</div>
|
||||
<div className="text-center">单价</div>
|
||||
<div className="text-right">小计</div>
|
||||
<div></div>
|
||||
</div>
|
||||
|
||||
<Form.List name={[field.name, "items"]}>
|
||||
{(itemFields, { add: addItem, remove: removeItem }) => (
|
||||
<>
|
||||
{itemFields.map((itemField, itemIndex) => (
|
||||
<div
|
||||
key={itemField.key}
|
||||
className="grid grid-cols-[3fr_4fr_1fr_1fr_2fr_1fr_40px] gap-4 mb-4 items-start"
|
||||
>
|
||||
<Form.Item
|
||||
{...itemField}
|
||||
name={[itemField.name, "name"]}
|
||||
className="!mb-0"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: "请输入服务项目名称",
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder="服务项目名称" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...itemField}
|
||||
name={[itemField.name, "description"]}
|
||||
className="!mb-0"
|
||||
>
|
||||
<Input placeholder="请输入描述/备注" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...itemField}
|
||||
name={[itemField.name, "quantity"]}
|
||||
className="!mb-0"
|
||||
>
|
||||
<InputNumber
|
||||
placeholder="数量"
|
||||
min={0}
|
||||
className="w-full"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...itemField}
|
||||
name={[itemField.name, "unit"]}
|
||||
className="!mb-0"
|
||||
>
|
||||
<Input placeholder="单位" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...itemField}
|
||||
name={[itemField.name, "price"]}
|
||||
className="!mb-0"
|
||||
>
|
||||
<InputNumber
|
||||
placeholder="单价"
|
||||
min={0}
|
||||
className="w-full"
|
||||
/>
|
||||
</Form.Item>
|
||||
<div className="text-right">
|
||||
<Text className="text-gray-500 dark:text-gray-400">
|
||||
{formatCurrency(
|
||||
calculateItemAmount(
|
||||
formValues?.sections?.[sectionIndex]
|
||||
?.items?.[itemIndex]?.quantity,
|
||||
formValues?.sections?.[sectionIndex]
|
||||
?.items?.[itemIndex]?.price
|
||||
)
|
||||
)}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
{(!id || isEdit) && itemFields.length > 1 && (
|
||||
<Button
|
||||
type="text"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={() => removeItem(itemField.name)}
|
||||
className="flex items-center justify-center"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{(!id || isEdit) && (
|
||||
<Button
|
||||
type="dashed"
|
||||
onClick={() => addItem()}
|
||||
icon={<PlusOutlined />}
|
||||
className="w-full hover:border-blue-400 hover:text-blue-500 mb-4 dark:border-gray-600 dark:text-gray-400 dark:hover:text-blue-400"
|
||||
>
|
||||
添加服务项目
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<div className="flex justify-end border-t dark:border-gray-700 pt-4">
|
||||
<Text className="text-gray-500 dark:text-gray-400">
|
||||
小计总额:
|
||||
<span className="text-blue-500 dark:text-blue-400 font-medium ml-2">
|
||||
{formatCurrency(
|
||||
calculateSectionTotal(
|
||||
formValues?.sections?.[sectionIndex]
|
||||
?.items
|
||||
)
|
||||
)}
|
||||
</span>
|
||||
</Text>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Form.List>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{(!id || isEdit) && (
|
||||
<div className="mt-6 flex gap-4 justify-center">
|
||||
<Button
|
||||
type="dashed"
|
||||
onClick={() => addSection({ items: [{}] })}
|
||||
icon={<PlusOutlined />}
|
||||
className="w-1/3 hover:border-blue-400 hover:text-blue-500 dark:border-gray-600 dark:text-gray-400 dark:hover:text-blue-400"
|
||||
>
|
||||
新建小节
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 总金额统计 */}
|
||||
<div className="mt-8 pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||
<div className="flex flex-col gap-2">
|
||||
|
||||
<div className="flex justify-between items-center mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||
<span className="text-base font-medium text-gray-700 dark:text-gray-300">
|
||||
总金额
|
||||
</span>
|
||||
<span className="text-xl font-semibold text-blue-500 dark:text-blue-400">
|
||||
{formatCurrency(
|
||||
calculateTotalAmount(formValues?.sections)
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Form.List>
|
||||
</div>
|
||||
|
||||
{(!id || isEdit) && (
|
||||
<div className="mt-6 flex justify-end gap-4">
|
||||
<Button
|
||||
onClick={() => navigate("/company/serviceTeamplate")}
|
||||
className="px-6 hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-gray-200"
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
loading={loading}
|
||||
className="px-6 hover:opacity-90"
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Form>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServiceForm;
|
||||
@@ -1,42 +1,374 @@
|
||||
import React from 'react';
|
||||
import { Card, Table, Button } from 'antd';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { Card, Table, Button, Space, Input, message, Popconfirm } from "antd";
|
||||
import { EyeOutlined } from "@ant-design/icons";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { supabase } from "@/config/supabase";
|
||||
|
||||
const ServicePage = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [data, setData] = useState([]);
|
||||
const navigate = useNavigate();
|
||||
const [editingKey, setEditingKey] = useState('');
|
||||
|
||||
// 获取服务模板列表
|
||||
const fetchServices = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const { data: services, error } = await supabase
|
||||
.from("resources")
|
||||
.select("*")
|
||||
.eq("type", "serviceTemplate")
|
||||
.order("created_at", { ascending: false });
|
||||
|
||||
if (error) throw error;
|
||||
setData(services);
|
||||
} catch (error) {
|
||||
console.error("获取服务模板失败:", error);
|
||||
message.error("获取服务模板失败");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 添加保存编辑项目的方法
|
||||
const handleSaveItem = async (record, sectionIndex, itemIndex) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const newData = [...data];
|
||||
const targetService = newData.find(item => item.id === record.serviceId);
|
||||
targetService.attributes.sections[sectionIndex].items[itemIndex] = record;
|
||||
|
||||
// 计算新的总金额
|
||||
const newTotalAmount = targetService.attributes.sections.reduce((total, section) => {
|
||||
return total + section.items.reduce((sectionTotal, item) =>
|
||||
sectionTotal + (item.price * item.quantity), 0);
|
||||
}, 0);
|
||||
|
||||
targetService.attributes.totalAmount = newTotalAmount;
|
||||
|
||||
const { error } = await supabase
|
||||
.from('resources')
|
||||
.update({ attributes: targetService.attributes })
|
||||
.eq('id', targetService.id);
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
setData(newData);
|
||||
setEditingKey('');
|
||||
message.success('更新成功');
|
||||
} catch (error) {
|
||||
console.error('保存失败:', error);
|
||||
message.error('保存失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 添加删除项目的方法
|
||||
const handleDeleteItem = async (record) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const newData = [...data];
|
||||
const targetService = newData.find(item => item.id === record.serviceId);
|
||||
|
||||
// 删除指定项目
|
||||
targetService.attributes.sections[record.sectionIndex].items.splice(record.itemIndex, 1);
|
||||
|
||||
// 重新计算总金额
|
||||
const newTotalAmount = targetService.attributes.sections.reduce((total, section) => {
|
||||
return total + section.items.reduce((sectionTotal, item) =>
|
||||
sectionTotal + (item.price * item.quantity), 0);
|
||||
}, 0);
|
||||
|
||||
targetService.attributes.totalAmount = newTotalAmount;
|
||||
|
||||
const { error } = await supabase
|
||||
.from('resources')
|
||||
.update({ attributes: targetService.attributes })
|
||||
.eq('id', targetService.id);
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
setData(newData);
|
||||
message.success('删除成功');
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error);
|
||||
message.error('删除失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 主表格列定义
|
||||
const columns = [
|
||||
{
|
||||
title: '服务名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
title: "模板名称",
|
||||
dataIndex: ["attributes", "templateName"],
|
||||
key: "templateName",
|
||||
className: "min-w-[200px]",
|
||||
},
|
||||
{
|
||||
title: '服务类型',
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
title: "描述",
|
||||
dataIndex: ["attributes", "description"],
|
||||
key: "description",
|
||||
},
|
||||
{
|
||||
title: '价格',
|
||||
dataIndex: 'price',
|
||||
key: 'price',
|
||||
title: "总金额",
|
||||
dataIndex: ["attributes", "totalAmount"],
|
||||
key: "totalAmount",
|
||||
className: "min-w-[150px] text-right",
|
||||
render: (amount) => (
|
||||
<span className="text-blue-600 font-medium">
|
||||
¥
|
||||
{amount?.toLocaleString("zh-CN", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
}) || "0.00"}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
title: "操作",
|
||||
key: "action",
|
||||
render: (_, record) => (
|
||||
<Space>
|
||||
<Button
|
||||
type="link"
|
||||
icon={<EyeOutlined />}
|
||||
onClick={() =>
|
||||
navigate(`/company/serviceTemplateInfo/${record.id}`)
|
||||
}
|
||||
>
|
||||
查看
|
||||
</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
// 子表格列定义
|
||||
const itemColumns = [
|
||||
{
|
||||
title: "项目名称",
|
||||
dataIndex: "name",
|
||||
key: "name",
|
||||
width: "40%",
|
||||
render: (text, record) => {
|
||||
const isEditing = record.key === editingKey;
|
||||
return isEditing ? (
|
||||
<Input
|
||||
value={text}
|
||||
onChange={e => {
|
||||
const newData = [...data];
|
||||
const targetService = newData.find(item => item.id === record.serviceId);
|
||||
const targetItem = targetService.attributes.sections[record.sectionIndex].items[record.itemIndex];
|
||||
targetItem.name = e.target.value;
|
||||
setData(newData);
|
||||
}}
|
||||
/>
|
||||
) : text;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "单价",
|
||||
dataIndex: "price",
|
||||
key: "price",
|
||||
width: "20%",
|
||||
render: (price, record) => {
|
||||
const isEditing = record.key === editingKey;
|
||||
return isEditing ? (
|
||||
<Input
|
||||
type="number"
|
||||
value={price}
|
||||
onChange={e => {
|
||||
const newData = [...data];
|
||||
const targetService = newData.find(item => item.id === record.serviceId);
|
||||
const targetItem = targetService.attributes.sections[record.sectionIndex].items[record.itemIndex];
|
||||
targetItem.price = Number(e.target.value);
|
||||
setData(newData);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span className="text-gray-600">
|
||||
¥{price?.toLocaleString("zh-CN", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
})}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "数量",
|
||||
dataIndex: "quantity",
|
||||
key: "quantity",
|
||||
width: "20%",
|
||||
render: (quantity, record) => {
|
||||
const isEditing = record.key === editingKey;
|
||||
return isEditing ? (
|
||||
<Input
|
||||
type="number"
|
||||
value={quantity}
|
||||
onChange={e => {
|
||||
const newData = [...data];
|
||||
const targetService = newData.find(item => item.id === record.serviceId);
|
||||
const targetItem = targetService.attributes.sections[record.sectionIndex].items[record.itemIndex];
|
||||
targetItem.quantity = Number(e.target.value);
|
||||
setData(newData);
|
||||
}}
|
||||
/>
|
||||
) : <span className="text-gray-600">{quantity}</span>;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "小计",
|
||||
key: "subtotal",
|
||||
width: "20%",
|
||||
render: (_, record) => (
|
||||
<span className="text-blue-600 font-medium">
|
||||
¥
|
||||
{((record.price || 0) * (record.quantity || 0)).toLocaleString(
|
||||
"zh-CN",
|
||||
{
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
}
|
||||
)}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: "150px",
|
||||
render: (_, record) => {
|
||||
const isEditing = record.key === editingKey;
|
||||
return isEditing ? (
|
||||
<Space>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
className="text-green-600"
|
||||
onClick={() => handleSaveItem(record, record.sectionIndex, record.itemIndex)}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
className="text-gray-600"
|
||||
onClick={() => setEditingKey('')}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
</Space>
|
||||
) : (
|
||||
<Space>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
className="text-blue-600"
|
||||
disabled={editingKey !== ''}
|
||||
onClick={() => setEditingKey(record.key)}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
<Popconfirm
|
||||
title="删除确认"
|
||||
description="确定要删除这个项目吗?"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
okButtonProps={{ danger: true }}
|
||||
onConfirm={() => handleDeleteItem(record)}
|
||||
>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
className="text-red-600"
|
||||
disabled={editingKey !== ''}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
// 修改 expandedRowRender 以支持编辑
|
||||
const expandedRowRender = (record) => (
|
||||
<div className="bg-gray-50 p-4 rounded-lg">
|
||||
{record.attributes.sections?.map((section, sectionIndex) => (
|
||||
<Card
|
||||
title="服务管理"
|
||||
key={sectionIndex}
|
||||
className="mb-4 shadow-sm"
|
||||
title={
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-lg font-medium">{section.sectionName}</span>
|
||||
<span className="text-blue-600 font-medium">
|
||||
总计: ¥
|
||||
{section.items
|
||||
.reduce(
|
||||
(total, item) => total + item.price * item.quantity,
|
||||
0
|
||||
)
|
||||
.toLocaleString("zh-CN", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Table
|
||||
columns={itemColumns}
|
||||
dataSource={section.items.map((item, itemIndex) => ({
|
||||
...item,
|
||||
key: `${sectionIndex}-${itemIndex}`,
|
||||
serviceId: record.id,
|
||||
sectionIndex: sectionIndex,
|
||||
itemIndex: itemIndex
|
||||
}))}
|
||||
pagination={false}
|
||||
className="rounded-lg overflow-hidden"
|
||||
/>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchServices();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100 ">
|
||||
<Card
|
||||
title={<span className="text-xl font-medium">服务模版管理</span>}
|
||||
className="shadow-lg rounded-lg"
|
||||
extra={
|
||||
<Button type="primary" icon={<PlusOutlined />}>
|
||||
新增服务
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => navigate("/company/serviceTemplateInfo")}
|
||||
>
|
||||
新建模版
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Table columns={columns} dataSource={[]} rowKey="id" />
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={data}
|
||||
loading={loading}
|
||||
rowKey="id"
|
||||
expandable={{
|
||||
expandedRowRender,
|
||||
}}
|
||||
className="rounded-lg overflow-hidden"
|
||||
rowClassName="hover:bg-gray-50 transition-colors"
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
169
src/pages/company/service/serviceType/index.jsx
Normal file
169
src/pages/company/service/serviceType/index.jsx
Normal file
@@ -0,0 +1,169 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Table, Button, Modal, Form, Input, Space, message } from 'antd';
|
||||
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
|
||||
const ServiceType = () => {
|
||||
const [data, setData] = useState([]);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
const [editingId, setEditingId] = useState(null);
|
||||
|
||||
// 表格列定义
|
||||
const columns = [
|
||||
{
|
||||
title: '服务类型',
|
||||
dataIndex: 'serviceType',
|
||||
key: 'serviceType',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (_, record) => (
|
||||
<Space>
|
||||
<Button type="link" onClick={() => handleEdit(record)}>
|
||||
编辑
|
||||
</Button>
|
||||
<Button type="link" danger onClick={() => handleDelete(record.id)}>
|
||||
删除
|
||||
</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
// 处理添加/编辑表单提交
|
||||
const handleSubmit = async (values) => {
|
||||
try {
|
||||
if (editingId) {
|
||||
// 编辑操作
|
||||
// await updateServiceType({ ...values, id: editingId });
|
||||
message.success('更新成功');
|
||||
} else {
|
||||
// 添加操作
|
||||
// await addServiceType(values);
|
||||
message.success('添加成功');
|
||||
}
|
||||
setVisible(false);
|
||||
form.resetFields();
|
||||
// 重新加载数据
|
||||
// loadData();
|
||||
} catch (error) {
|
||||
message.error('操作失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 编辑操作
|
||||
const handleEdit = (record) => {
|
||||
setEditingId(record.id);
|
||||
form.setFieldsValue({
|
||||
serviceType: record.serviceType,
|
||||
details: record.details || [],
|
||||
});
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
// 删除操作
|
||||
const handleDelete = async (id) => {
|
||||
try {
|
||||
// await deleteServiceType(id);
|
||||
message.success('删除成功');
|
||||
// 重新加载数据
|
||||
// loadData();
|
||||
} catch (error) {
|
||||
message.error('删除失败');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
setEditingId(null);
|
||||
form.resetFields();
|
||||
setVisible(true);
|
||||
}}
|
||||
style={{ marginBottom: 16 }}
|
||||
>
|
||||
<PlusOutlined /> 新增服务类型
|
||||
</Button>
|
||||
|
||||
<Table columns={columns} dataSource={data} rowKey="id" />
|
||||
|
||||
<Modal
|
||||
title={editingId ? '编辑服务类型' : '新增服务类型'}
|
||||
open={visible}
|
||||
onOk={() => form.submit()}
|
||||
onCancel={() => {
|
||||
setVisible(false);
|
||||
form.resetFields();
|
||||
}}
|
||||
width={800}
|
||||
>
|
||||
<Form form={form} onFinish={handleSubmit}>
|
||||
<Form.Item
|
||||
label="服务类型"
|
||||
name="serviceType"
|
||||
rules={[{ required: true, message: '请输入服务类型' }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
<Form.List name="details">
|
||||
{(fields, { add, remove }) => (
|
||||
<>
|
||||
{fields.map(({ key, name, ...restField }) => (
|
||||
<Space key={key} align="baseline">
|
||||
<Form.Item
|
||||
{...restField}
|
||||
name={[name, 'projectDetail']}
|
||||
rules={[{ required: true, message: '请输入项目明细' }]}
|
||||
>
|
||||
<Input placeholder="项目明细" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...restField}
|
||||
name={[name, 'description']}
|
||||
rules={[{ required: true, message: '请输入描述' }]}
|
||||
>
|
||||
<Input placeholder="描述" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...restField}
|
||||
name={[name, 'quantity']}
|
||||
rules={[{ required: true, message: '请输入数量' }]}
|
||||
>
|
||||
<Input placeholder="数量" type="number" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...restField}
|
||||
name={[name, 'unit']}
|
||||
rules={[{ required: true, message: '请输入单位' }]}
|
||||
>
|
||||
<Input placeholder="单位" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...restField}
|
||||
name={[name, 'price']}
|
||||
rules={[{ required: true, message: '请输入单价' }]}
|
||||
>
|
||||
<Input placeholder="单价" type="number" />
|
||||
</Form.Item>
|
||||
<DeleteOutlined onClick={() => remove(name)} />
|
||||
</Space>
|
||||
))}
|
||||
<Form.Item>
|
||||
<Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
|
||||
添加项目明细
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
</Form.List>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServiceType;
|
||||
5
tsconfig.json
Normal file
5
tsconfig.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2015"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user