Parcourir la source

提交截止当前所有功能

code4eat il y a 1 an
Parent
commit
d3520b0eab
100 fichiers modifiés avec 11411 ajouts et 1927 suppressions
  1. BIN
      .DS_Store
  2. 62 2
      .umirc.ts
  3. 5 0
      package.json
  4. 1 2
      src/access.ts
  5. 45 13
      src/app.tsx
  6. 273 0
      src/components/KCIMLeftList/index.tsx
  7. 136 0
      src/components/KCIMLeftList/style.less
  8. 1 1
      src/components/KCIMPageContainer/index.tsx
  9. 2 1
      src/components/KCIMPageContainer/style.less
  10. 1 0
      src/components/KCIMTableSelector/index.tsx
  11. 92 0
      src/components/ProgressModal/index.tsx
  12. 34 0
      src/components/ProgressModal/service.ts
  13. BIN
      src/components/SQLEditor/images/confirm.png
  14. BIN
      src/components/SQLEditor/images/copy.png
  15. 132 0
      src/components/SQLEditor/index.tsx
  16. 55 0
      src/components/SQLEditor/style.less
  17. 20 0
      src/constant.ts
  18. 16 2
      src/global.less
  19. 16 12
      src/pages/baseSetting/accountingAccountSet/accountingSubMana/index.tsx
  20. 1 0
      src/pages/baseSetting/accountingAccountSet/accountingSubMana/service.ts
  21. 23 12
      src/pages/baseSetting/accountingAccountSet/accountingSubMap/index.tsx
  22. 6 34
      src/pages/baseSetting/accountingAccountSet/accountingSubMap/service.ts
  23. 451 0
      src/pages/baseSetting/accountingAccountSet/chargeItemMap/index.tsx
  24. 76 0
      src/pages/baseSetting/accountingAccountSet/chargeItemMap/service.ts
  25. 260 0
      src/pages/baseSetting/accountingAccountSet/chargeItemMap/style.less
  26. 201 0
      src/pages/baseSetting/accountingAccountSet/chargeItemMap/tableSelector.tsx
  27. 4 4
      src/pages/baseSetting/accountingAccountSet/costIncomeProjectMana/index.tsx
  28. 5 4
      src/pages/baseSetting/costAllocationSet/allocationLevelSet/index.tsx
  29. 2 1
      src/pages/baseSetting/costAllocationSet/allocationParamsMap/editTableModal.tsx
  30. 81 98
      src/pages/baseSetting/costAllocationSet/allocationParamsMap/index.tsx
  31. 8 6
      src/pages/baseSetting/costAllocationSet/allocationParamsMap/service.ts
  32. 498 0
      src/pages/baseSetting/costAllocationSet/costAllocationParamsDeal/index.tsx
  33. 92 0
      src/pages/baseSetting/costAllocationSet/costAllocationParamsDeal/service.ts
  34. 28 10
      src/pages/baseSetting/costAllocationSet/costAllocationParamsDeal/style.less
  35. 14 3
      src/pages/baseSetting/costAllocationSet/costAllocationParamsSet/index.tsx
  36. 4 4
      src/pages/baseSetting/costAllocationSet/costAllocationParamsSet/transform.tsx
  37. 389 0
      src/pages/baseSetting/costAllocationSet/idleCostSetting/index.tsx
  38. 96 0
      src/pages/baseSetting/costAllocationSet/idleCostSetting/service.ts
  39. 13 18
      src/pages/baseSetting/costAllocationSet/idleCostSetting/style.less
  40. 2 2
      src/pages/baseSetting/costAllocationSet/revenueImputationSet/index.tsx
  41. 433 0
      src/pages/baseSetting/otherItemSet/diySqlMana/index.tsx
  42. 109 0
      src/pages/baseSetting/otherItemSet/diySqlMana/service.ts
  43. 95 0
      src/pages/baseSetting/otherItemSet/diySqlMana/style.less
  44. 563 264
      src/pages/baseSetting/otherItemSet/reportItemSet/index.tsx
  45. 0 69
      src/pages/baseSetting/otherItemSet/reportItemSet/service.js
  46. 103 0
      src/pages/baseSetting/otherItemSet/reportItemSet/service.ts
  47. 10 51
      src/pages/baseSetting/otherItemSet/reportItemSet/style.less
  48. 301 0
      src/pages/baseSetting/otherItemSet/reportItemSet/transform.tsx
  49. 4 3
      src/pages/baseSetting/otherItemSet/visitsAndBedDayCostSetting/index.tsx
  50. 5 2
      src/pages/baseSetting/otherItemSet/wholeHospCostAndIncomeSet/index.tsx
  51. 38 19
      src/pages/baseSetting/responsibilityCenterSet/responsibilityCenter/index.tsx
  52. 16 11
      src/pages/baseSetting/responsibilityCenterSet/responsibilityCenterConnect/index.tsx
  53. 2 2
      src/pages/baseSetting/responsibilityCenterSet/responsibilityCenterConnect/service.ts
  54. 13 5
      src/pages/baseSetting/responsibilityCenterSet/responsibilityCenterConnect/transform.tsx
  55. 493 2
      src/pages/costAccounting/calcPageTemplate/columns.tsx
  56. 205 1
      src/pages/costAccounting/calcPageTemplate/config.ts
  57. 562 41
      src/pages/costAccounting/calcPageTemplate/index.tsx
  58. 236 4
      src/pages/costAccounting/calcPageTemplate/service.ts
  59. 2 1
      src/pages/costAccounting/calcPageTemplate/style.less
  60. 0 227
      src/pages/costAccounting/chargeItemCostCalc/index.tsx
  61. 0 41
      src/pages/costAccounting/chargeItemCostCalc/service.js
  62. 0 263
      src/pages/costAccounting/patientCostCalc/index.tsx
  63. 0 41
      src/pages/costAccounting/patientCostCalc/service.js
  64. 0 204
      src/pages/costAccounting/unitPersonnelCostCalc/index.tsx
  65. 0 41
      src/pages/costAccounting/unitPersonnelCostCalc/service.js
  66. 8 2
      src/pages/costLibraryManagement/basicCostManagement/drugCostManagement/index.tsx
  67. 3 2
      src/pages/costLibraryManagement/basicCostManagement/equipmentCostManagement/index.tsx
  68. 8 2
      src/pages/costLibraryManagement/basicCostManagement/materialCostManagement/index.tsx
  69. 99 14
      src/pages/costLibraryManagement/basicCostManagement/personnelClassificationMana/index.tsx
  70. 17 1
      src/pages/costLibraryManagement/basicCostManagement/personnelClassificationMana/service.ts
  71. 3 0
      src/pages/costLibraryManagement/basicCostManagement/personnelClassificationMana/style.less
  72. 3 9
      src/pages/costLibraryManagement/diseaseCostManagement/diseaseDiagnosisComparison/index.tsx
  73. 0 1
      src/pages/costLibraryManagement/diseaseCostManagement/diseaseDiagnosisComparison/service.ts
  74. 2 2
      src/pages/costLibraryManagement/diseaseCostManagement/diseaseMana/index.tsx
  75. 6 3
      src/pages/costLibraryManagement/medicalOrderProject/medicalOrderProjectMana/index.tsx
  76. 526 0
      src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/match.tsx
  77. 593 0
      src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/setting.tsx
  78. 522 0
      src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/style.less
  79. 196 0
      src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/tableSelector.tsx
  80. 341 116
      src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/index.tsx
  81. 181 2
      src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/service.ts
  82. 125 2
      src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/style.less
  83. 176 0
      src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/editTableModal.tsx
  84. 375 0
      src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/index.tsx
  85. 134 0
      src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/service.ts
  86. 90 0
      src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/style.less
  87. 186 0
      src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/tableSelector.tsx
  88. 307 0
      src/pages/costLibraryManagement/projectCostManagement/projectShareParamsSet/index.tsx
  89. 95 0
      src/pages/costLibraryManagement/projectCostManagement/projectShareParamsSet/service.ts
  90. 15 7
      src/pages/costLibraryManagement/projectCostManagement/projectShareParamsSet/style.less
  91. 60 23
      src/pages/costLibraryManagement/projectCostManagement/standardProjectMana/index.tsx
  92. 3 2
      src/pages/costLibraryManagement/projectCostManagement/standardProjectMana/service.ts
  93. 382 0
      src/pages/costLibraryManagement/reportMana/reportColumnMana/UpDateActBtn.tsx
  94. 19 204
      src/pages/costLibraryManagement/reportMana/reportColumnMana/index.tsx
  95. 5 0
      src/pages/costLibraryManagement/reportMana/reportColumnMana/style.less
  96. 24 11
      src/pages/costLibraryManagement/reportMana/reportListMana/index.tsx
  97. 3 1
      src/pages/costLibraryManagement/reportMana/reportListMana/style.less
  98. 2 2
      src/pages/costLibraryManagement/reportMana/reportNavSet/index.tsx
  99. 387 0
      src/pages/monthlyInfoCollection/components/leftAndRighrStructure.tsx
  100. 180 0
      src/pages/monthlyInfoCollection/components/style.less

BIN
.DS_Store


+ 62 - 2
.umirc.ts

@@ -2,14 +2,18 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2022-12-14 14:14:32
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-21 10:50:25
+ * @LastEditTime: 2024-04-07 13:30:11
  * @FilePath: /BudgetManaSystem/.umirc.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
 import { defineConfig } from '@umijs/max';
 
+import MonacoWebpackPlugin from 'monaco-editor-webpack-plugin';
+
 
 const { REACT_APP_ENV } = process.env;
+const path = require('path');
+
 
 
 export default defineConfig({
@@ -18,6 +22,9 @@ export default defineConfig({
       prefixCls: 'cost-ant',
     },
   },
+  // alias:{
+  //   'ace-builds': path.resolve(__dirname, './node_modules/ace-builds/src-noconflict'),
+  // },
   qiankun: {
     slave: {},
   },
@@ -31,7 +38,14 @@ export default defineConfig({
     javascriptEnabled: true,
   }, //对应修改生成的 antd 样式类名
 
-
+  chainWebpack(config, { webpack }) {
+    config.plugin('monaco-editor').use(MonacoWebpackPlugin, [
+        {
+            // 指定需要加载的语言和特性
+            languages: ['sql', 'javascript', 'typescript']
+        }
+    ]);
+  },
 
   access: {},
   model: {},
@@ -106,10 +120,16 @@ export default defineConfig({
               name: '会计科目对应',
               component: './baseSetting/accountingAccountSet/accountingSubMap/index',
             },
+            {
+              path: '/baseSetting/accountingAccountSet/chargeItemMap',
+              name: '收费项目对应',
+              component: './baseSetting/accountingAccountSet/chargeItemMap/index',
+            },
           ],
         },
         {
           path: '/baseSetting/costAllocationSet',
+          
           name: '成本分摊设置',
           routes: [
             {
@@ -117,11 +137,21 @@ export default defineConfig({
               name: '分摊层级设置',
               component: './baseSetting/costAllocationSet/allocationLevelSet/index',
             },
+            {
+              path: '/baseSetting/costAllocationSet/idleCostSetting',
+              name: '闲置成本设置',
+              component: './baseSetting/costAllocationSet/idleCostSetting/index',
+            },
             {
               path: '/baseSetting/costAllocationSet/costAllocationParamsSet',
               name: '成本分摊参数设置',
               component: './baseSetting/costAllocationSet/costAllocationParamsSet/index',
             },
+            {
+              path: '/baseSetting/costAllocationSet/costAllocationParamsDeal',
+              name: '成本分摊参数处理',
+              component: './baseSetting/costAllocationSet/costAllocationParamsDeal/index',
+            },
             {
               path: '/baseSetting/costAllocationSet/allocationParamsMap',
               name: '分摊参数对应',
@@ -139,6 +169,11 @@ export default defineConfig({
           name: '其它设置',
           icon: 'tool',
           routes: [
+            {
+              path: '/baseSetting/otherItemSet/diySqlMana',
+              name: '自定义SQl管理',
+              component: './baseSetting/otherItemSet/diySqlMana/index',
+            },
             {
               path: '/baseSetting/otherItemSet/reportItemSet',
               name: '报表项目设置',
@@ -158,10 +193,20 @@ export default defineConfig({
         },
       ],
     },
+    {
+      path:'/monthlyInfoCollection',
+      name: '月度信息采集2',
+      component:'./monthlyInfoCollection/index'
+    },
     {
       path: '/monthlyInfoSearch',
       name: '月度信息采集',
       routes: [
+        {
+          path: '/monthlyInfoSearch/wholeHospIncomeAndCost',
+          name: '全院其他收支',
+          component: './monthlyInfoSearch/wholeHospIncomeAndCost/index',
+        },
         {
           path: '/monthlyInfoSearch/empCostDataImport',
           name: '人事成本数据导入',
@@ -177,6 +222,11 @@ export default defineConfig({
           name: '患者信息导入',
           component: './monthlyInfoSearch/patientInfoImport/index',
         },
+        {
+          path: '/monthlyInfoSearch/incomeCostDataImport',
+          name: '收入成本数据导入',
+          component: './monthlyInfoSearch/incomeCostDataImport/index',
+        },
       ],
     },
     {
@@ -261,6 +311,16 @@ export default defineConfig({
               name: '标准项目管理',
               component: './costLibraryManagement/projectCostManagement/standardProjectMana/index',
             },
+            {
+              path: '/costLibraryManagement/projectCostManagement/projectShareParamsSet',
+              name: '项目分摊参数设置',
+              component: './costLibraryManagement/projectCostManagement/projectShareParamsSet/index',
+            },
+            {
+              path: '/costLibraryManagement/projectCostManagement/projectCostShareSet',
+              name: '项目成本分摊设置',
+              component: './costLibraryManagement/projectCostManagement/projectCostShareSet/index',
+            },
           ],
         },
         {

+ 5 - 0
package.json

@@ -16,11 +16,16 @@
     "@ant-design/icons": "^4.7.0",
     "@ant-design/pro-components": "^2.0.1",
     "@umijs/max": "^4.0.51",
+    "ace-builds": "^1.32.3",
     "axios": "^1.3.3",
     "file-saver": "^2.0.5",
     "json-bigint": "^1.0.0",
     "lodash": "^4.17.21",
     "mathjs": "^11.6.0",
+    "monaco-editor": "^0.45.0",
+    "monaco-editor-webpack-plugin": "^7.1.0",
+    "react-ace": "^10.1.0",
+    "react-monaco-editor": "^0.55.0",
     "react-sortable-hoc": "^2.0.0",
     "umi-request": "^1.4.0",
     "xlsx": "^0.18.5"

+ 1 - 2
src/access.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2022-12-14 14:14:32
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-08-10 13:56:50
+ * @LastEditTime: 2024-01-19 11:26:51
  * @FilePath: /BudgetManaSystem/src/access.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -50,7 +50,6 @@ export default (initialState: { name: string;memuData:any[] }) => {
        
         if(memuData){
           const thisPageData = findMenuItem(memuData,pagePath);
-          // console.log({pagePath,thisPageData});
           if(thisPageData){
             return thisPageData.function?thisPageData.function:[];
           }

+ 45 - 13
src/app.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2022-12-14 14:14:32
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-09 20:53:19
+ * @LastEditTime: 2024-03-28 18:02:27
  * @FilePath: /BudgetManaSystem/src/app.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -28,11 +28,12 @@ import DevicePixelRatio from './utils/devicePixelRatio.js';
 
 import Icon, { createFromIconfontCN, FolderOutlined } from '@ant-design/icons';
 import { getPlatformMenu } from '@/services/auth';
-import { Key, useState } from 'react';
+import { Key, useEffect, useState } from 'react';
 
 
 import './utils/zhongtaiC'
 import { RuntimeAntdConfig } from '@umijs/max';
+import { useLocation } from '@umijs/max';
 
 
 const IconFont = createFromIconfontCN({
@@ -132,15 +133,9 @@ export const request: RequestConfig = {
 
         if (status == 200) {
           // 网络请求成功
-
           if (errorMessage && errorMessage.indexOf('Token') != -1) {
-            Modal.error({
-              title: '登陆已过期,请重新登录!',
-              okText: '确定',
-              onOk(...args) {
-                localStorage.removeItem('userData');
-              },
-            });
+            console.log({response,errorMessage});
+            localStorage.removeItem('tokenExpired');
 
             return false;
           }
@@ -253,7 +248,7 @@ const reportCheck = () => {
 
 
 export function patchClientRoutes({ routes }: { routes: any }) {
-  console.log({routes});
+
   const treeLoop = (treeData: any) => {
 
     if (treeData.routes) {
@@ -303,12 +298,47 @@ export const layout = ({ initialState, setInitialState }: { initialState: any, s
   const { isCollapsed } = initialState;
   const [openKeys, set_openKeys] = useState<string[]>([]);
   const [selectedKeys, set_selectedKeys] = useState<string[]>([]);
+  const location = useLocation();
+  const currentPath = location.pathname;
+  const [menuData,set_menuData] = useState<any[]>([]);
 
   const onCollapse = (isCollapsed: boolean): void => {
     setInitialState({ ...initialState, isCollapsed }).then();
   };
 
 
+  useEffect(()=>{
+    
+        function findMenuItemByPath(menu:any, path:string) {
+          let result:any = null;
+        
+          // 递归搜索函数
+          function search(items:any) {
+            for (let item of items) {
+              if (item.path === path) {
+                result = item;
+                return; // 找到匹配项,提前终止搜索
+              }
+              if (item.children && item.children.length > 0) {
+                search(item.children); // 递归搜索子菜单
+                if (result) return; // 如果在子菜单中找到匹配项,提前终止搜索
+              }
+            }
+          }
+        
+          search(menu); // 从顶层菜单开始搜索
+          return result;
+        }
+
+        const matchedItem = findMenuItemByPath(menuData, currentPath);
+        if (matchedItem) {
+          
+          set_selectedKeys([matchedItem.key]);
+        }
+
+  },[currentPath])
+
+
   return {
     menuHeaderRender: false,
     token: {
@@ -328,6 +358,7 @@ export const layout = ({ initialState, setInitialState }: { initialState: any, s
       }
 
     },
+    
     siderWidth: 200,
     menuProps: {
       openKeys: [...openKeys],
@@ -351,9 +382,10 @@ export const layout = ({ initialState, setInitialState }: { initialState: any, s
           const systemId = menuId;
           const data: any[] = await getPlatformMenu(systemId);
           if (data) {
-
+ 
             const selectedKeys = localStorage.getItem('selectedKeys');
             const openKeys = localStorage.getItem('openKeys');
+            set_menuData(data);
             if (selectedKeys && openKeys) {
               const _selectedKeys = JSON.parse(selectedKeys);
               const _openKeys = JSON.parse(openKeys);
@@ -423,7 +455,7 @@ export const layout = ({ initialState, setInitialState }: { initialState: any, s
             function addIconToPath(node: any, paths: string[]) {
               if (paths.includes(node.path)) {
                 if (node.path == '/home') {
-                  node.icon = <Icon component={imgNode} />;
+                  node.icon = <Icon component={imgNode}  />;
                 }
                 if (node.path == '/baseSetting') {
                   

+ 273 - 0
src/components/KCIMLeftList/index.tsx

@@ -0,0 +1,273 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-03-19 10:27:43
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-03-29 14:46:08
+ * @FilePath: /CostAccountingSys/src/components/KCIMLeftList/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+import { createFromIconfontCN } from '@ant-design/icons';
+import Dropdown from '@ant-design/pro-table/es/components/Dropdown';
+import {Input,Tooltip,TreeProps,Empty} from 'antd'
+import { Key, useEffect, useState } from 'react';
+import DirectoryTree from 'antd/es/tree/DirectoryTree';
+import { DataNode } from 'antd/es/tree';
+
+import './style.less';
+
+
+import expandedIcon from '../../../static/treenode_open.png';
+import closeIcon from '../../../static/treenode_collapse.png';
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+interface ListItem {
+     name:string,
+     subText:string,
+     [key:string]:any
+}
+
+interface TreeNodeItem {
+    [key:string]:any
+}
+
+export interface KCIMLeftListProps {
+    dataSource?:any[],
+    searchKey:string,
+    placeholder?:string,
+    listType?:'list'|'tree',
+    icon?:string,
+    contentH?:number,
+    rowKey?:string,
+    fieldNames?:{title?:string,key?:string,children?:string},
+    onChange?:(selectedItem:ListItem)=>void
+}
+
+
+function searchTreeAndKeepHierarchy(tree:any[], keyword:string) {
+    function search(node:any) {
+      // 深度复制节点,避免修改原始树
+      let newNode = { ...node };
+      if (node.responsibilityName.includes(keyword)) {
+        // 如果节点名称包含关键字,返回整个节点及其子节点
+        return newNode;
+      } else if (node.child && node.child.length > 0) {
+        // 如果当前节点不匹配但有子节点,递归搜索子节点
+        let filteredChildren = node.child.map(search).filter((child:any) => child !== null); // 递归并过滤掉null
+        if (filteredChildren.length > 0) {
+          // 如果有子节点匹配,只返回匹配的子节点
+          newNode.child = filteredChildren;
+          return newNode;
+        }
+      }
+      // 如果节点和其子节点都不匹配,返回null
+      return null;
+    }
+  
+    // 对树的每个根节点进行搜索,并过滤掉不匹配的节点
+    return tree.map(search).filter(node => node !== null);
+  }
+
+
+
+function findFirstLeafNodeInForest(forest:any,children:string) {
+    // 遍历森林中的每棵树
+    for (let i = 0; i < forest.length; i++) {
+      // 使用之前定义的函数来寻找当前树的第一个叶子节点
+      const leaf = findFirstLeafNode(forest[i],'children');
+      if (leaf) {
+        return leaf;
+      }
+    }
+    // 如果森林为空或没有叶子节点,返回null
+    return null;
+  }
+  
+  const findFirstLeafNode:any = (node:any,children:string)=> {
+    // 检查当前节点是否为叶子节点
+    if (!node[`${children}`] || node[`${children}`].length === 0) {
+      return node;
+    }
+    // 否则,递归查找第一个子节点的第一个叶子节点
+    return findFirstLeafNode(node[`${children}`][0]);
+  }
+
+
+export const KCIMLeftList = (props:KCIMLeftListProps)=>{
+
+    const {searchKey,placeholder = '请输入',onChange,listType = 'list',dataSource:data = [],icon,contentH = 500,rowKey = 'id',fieldNames={title:'title',key:'key',children:'children'}} = props;
+
+    const [dataSource,set_dataSource] = useState<ListItem[]|TreeNodeItem[]>([]);
+    const [showList,set_showList] = useState<ListItem[]|TreeNodeItem[]>([]);
+    const [currentSelected,set_currentSelected] = useState<undefined|any>(undefined);
+    const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
+    const [searchValue, setSearchValue] = useState('');
+    const [autoExpandParent, setAutoExpandParent] = useState(true);
+    const [defaultSelectedKeys,set_defaultSelectedKeys] = useState<Key[]>([]);
+
+
+
+
+    const onSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
+        // console.log('selected', selectedKeys, info);
+        const { node } = info;
+        set_currentSelected(node);
+    };
+
+    const onExpand = (newExpandedKeys: React.Key[]) => {
+        setExpandedKeys(newExpandedKeys);
+        setAutoExpandParent(false);
+    };
+    
+
+    useEffect(()=>{
+        onChange&&onChange(currentSelected);
+    },[currentSelected])
+
+    useEffect(()=>{
+        if(showList.length>0){
+              if(listType =='list'){
+                set_currentSelected(showList[0]);
+              }
+              if(listType =='tree'){
+                const first = findFirstLeafNodeInForest(showList,fieldNames.children?fieldNames.children:'children');
+                console.log({first});
+                set_currentSelected(first);
+                set_defaultSelectedKeys([first[`${fieldNames.key}`]]);
+              }
+        
+        }else{
+              set_currentSelected(undefined);
+        }
+    },[showList]);
+
+
+    useEffect(()=>{
+        set_dataSource([...data]);
+        set_showList([...data]);
+    },[data]);
+     
+
+    return (
+        <div className="KCIMLeftList">
+              <div className='toolbar'>
+                    <Input placeholder={placeholder} allowClear
+                        suffix={
+                            <IconFont style={{color:'#99A6BF'}} type="iconsousuo" />
+                        }
+                        // style={{ width: 156 }}
+                        onChange={(e) => {
+                            if(listType == 'list'){
+                                const result = dataSource.filter(item => item[`${searchKey}`].indexOf(e.target.value) != -1);
+                                set_showList(result);
+                            }
+                            if(listType == 'tree'){
+                                const result = searchTreeAndKeepHierarchy(dataSource,e.target.value);
+                                set_showList(result);
+                                console.log({result});
+                            }
+                            
+                        }}
+
+                    />
+                    {/* <UpDataActBtn key={'act'} record={undefined} type='ADD_LEFTDATA' /> */}
+
+            </div>
+            <div className='wrap' style={{height:contentH,overflowY:'scroll'}}>
+                    {
+                        listType == 'list'&& showList.map((item, index) => {
+                            return (
+                                <div className={currentSelected ? currentSelected[`${rowKey}`] == item[`${rowKey}`] ? 'list on' : 'list' : 'list'}
+                                    key={index}
+                                    onClick={() => {
+                                        set_currentSelected(item);
+                                        
+                                        // _currentSelectedType = item;
+                                    }}
+                                >
+                                    <img className='icon' src={icon?icon:require('../../../static/departmentIcon.png')} alt="" />
+                                    <div className='content'>
+                                        <Tooltip title={item.subText} >
+                                            <div className='name'>{item.name}</div>
+                                            <div className='sub'>{item.subText}</div>
+                                        </Tooltip>
+                                    </div>
+
+                                    {/* <Dropdown menu={{ items: moreItems }} placement="bottom" onOpenChange={(bool) => { bool && set_currentEditLeftData(item) }}>
+                                        <div className='more'>
+                                            <img src={require('../../../../../static/more_point_gray.png')} alt="" />
+                                        </div>
+                                    </Dropdown> */}
+                                </div>
+                            )
+                        })
+                    }
+
+                    {
+                        (!showList||showList.length == 0)&&(
+                            <div><Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /></div>
+                        )
+                    }
+        
+                    {
+                     listType == 'tree'&&dataSource.length > 0 && currentSelected && defaultSelectedKeys.length>0&& (
+                        <DirectoryTree
+                            className='KC-DirectoryTree'
+                            fieldNames={fieldNames}
+                            rootStyle={{ height: '100%', paddingBottom: 50, overflowY: 'scroll', overflowX: 'hidden' }}
+                            onSelect={onSelect}
+                            onExpand={onExpand}
+                            expandedKeys={expandedKeys}
+                            autoExpandParent={autoExpandParent}
+                            selectedKeys={[currentSelected[`${fieldNames.key}`]]}
+                            blockNode={true}
+                            icon={() => null}
+                            // titleRender={
+                            //     (nodeData: any) => {
+                            //         const strTitle = nodeData.name as string;
+                            //         const index = strTitle.indexOf(searchValue);
+                            //         const beforeStr = strTitle.substring(0, index);
+                            //         const afterStr = strTitle.slice(index + searchValue.length);
+                            //         const title =
+                            //             index > -1 ? (
+                            //                 <span>
+                            //                     {beforeStr}
+                            //                     <span className="site-tree-search-value" style={{ color: 'red', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{searchValue}</span>
+                            //                     {afterStr}
+                            //                 </span>
+                            //             ) : (
+                            //                 <span className='strTitle'>{strTitle}</span>
+                            //             );
+                            //         return <div style={{
+                            //             display: 'flex', flexDirection: 'row',
+                            //             width: '100%',
+                            //             justifyContent: 'flex-start', alignItems: 'center', height: 32,
+                            //             borderRadius: '4px',
+                            //             overflow: 'hidden',
+                            //             color: '#17181A',
+                            //             textOverflow: 'ellipsis',
+                            //             whiteSpace: 'nowrap'
+
+                            //         }}>{title}</div>
+                            //     }
+                            // }
+                            // defaultSelectedKeys={['B0100']}
+                            treeData={showList as unknown as DataNode[]}
+                            // treeData={treeDataNew}
+                            switcherIcon={(props: any) => {
+                                const { expanded } = props;
+                                return !expanded ? <img style={{ width: 20, height: 20, position: 'relative', top: 5 }} src={expandedIcon} /> : <img style={{ width: 20, height: 20, position: 'relative', top: 5 }} src={closeIcon} />
+                            }}
+                        />
+                    )
+                }
+                </div>
+
+        </div>
+    )
+}

+ 136 - 0
src/components/KCIMLeftList/style.less

@@ -0,0 +1,136 @@
+
+
+
+.KCIMLeftList {
+    border-radius: 4px;
+    padding:8px 8px;
+    width: 100%;
+    // padding-top: 16px;
+    // border: 1px solid #DAE2F2;
+    .toolbar {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        padding: 0 8px;
+  
+        .add {
+          cursor: pointer;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          width: 24px;
+          height: 24px;
+          background: #FAFCFF;
+          border-radius: 4px;
+          border: 1px solid #DAE2F2;
+  
+          &>img {
+            width: 16px;
+            height: 16px;
+          }
+        }
+      }
+  
+      .wrap {
+        margin-top: 12px;
+        padding-right: 0;
+        .cost-ant-tree.cost-ant-tree-directory .cost-ant-tree-treenode-selected:hover::before,
+        .cost-ant-tree.cost-ant-tree-directory .cost-ant-tree-treenode-selected::before {
+            border-radius: 4px;
+            background: rgb(240 242 245 / 100%);
+        }
+
+        .bms-ant-tree.bms-ant-tree-directory .bms-ant-tree-treenode .bms-ant-tree-node-content-wrapper.bms-ant-tree-node-selected {
+            font-weight: bold;
+        }
+
+        .DirectoryTree {
+          // .cost-ant-tree-treenode-selected {
+          //      .cost-ant-tree-title {
+          //         color:#17181A !important;
+          //         font-weight: 500 !important;
+          //      }
+          // }
+
+          
+        }
+
+        .cost-ant-tree.cost-ant-tree-directory .cost-ant-tree-treenode .cost-ant-tree-node-content-wrapper.cost-ant-tree-node-selected {
+          color:#17181A !important;
+          font-weight: 500 !important;
+        }
+  
+        .list {
+          cursor: pointer;
+          height: 48px;
+          border-radius: 4px;
+          background: #FFFFFF;
+          display: flex;
+          padding-left: 8px;
+          padding-right: 8px;
+          flex-direction: row;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 4px;
+  
+          .icon {
+            width: 25px;
+            height: 25px;
+          }
+  
+          .content {
+            width: 87%;
+            padding-left: 7px;
+  
+            .name {
+              height: 15px;
+              font-size: 14px;
+              font-family: SourceHanSansCN-Medium, SourceHanSansCN;
+              font-weight: 500;
+              color: #17181A;
+              line-height: 15px;
+              margin-bottom: 4px;
+              overflow: hidden;
+              white-space: nowrap;
+              text-overflow: ellipsis;
+            }
+  
+            .sub {
+              height: 13px;
+              font-size: 12px;
+              font-family: SourceHanSansCN-Normal, SourceHanSansCN;
+              font-weight: 400;
+              color: #7A8599;
+              line-height: 13px;
+            }
+          }
+  
+          .more {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            cursor: pointer;
+            width: 16px;
+            height: 16px;
+            border-radius: 4px;
+            background: #FFFFFF;
+  
+            &>img {
+              width: 100%;
+              height: 100%;
+            }
+          }
+  
+          &.on {
+            font-weight: 500;
+            color: #17181A;
+            background: #F0F2F5;
+          }
+  
+          &:last-child {
+            margin-bottom: 0;
+          }
+        }
+      }
+}

+ 1 - 1
src/components/KCIMPageContainer/index.tsx

@@ -45,7 +45,7 @@ function findMenuItem(menu: MenuItem[], path: string): MenuItem | undefined {
 const KCIMPagecontainer = (props: KCIMPagecontainerPropType) => {
 
   const { children, header, ...rest } = props;
-
+  
   const { initialState } = useModel('@@initialState');
 
   const [open,set_open] = useState(false);

+ 2 - 1
src/components/KCIMPageContainer/style.less

@@ -1,6 +1,7 @@
 
 .cost-ant-pro-page-container {
-    border: 16px solid #F7F9FC !important;
+    
+    border: 16px solid #F7F9FC;
 }
 .cost-ant-pro-page-container .cost-ant-pro-page-container-warp-page-header~.cost-ant-pro-grid-content .cost-ant-pro-page-container-children-content {
     padding-block: 0 !important;

+ 1 - 0
src/components/KCIMTableSelector/index.tsx

@@ -78,6 +78,7 @@ const TableSelecter = (
             let selectedCodes: string[] = [];
             let selectedRows: any[] = [];
             if (resp) {
+                console.log({defaultSelectedKeys});
                 const data = resp.map((a: any) => {
                     if (defaultSelectedKeys.includes(a[`${rowKey}`])) {
                         selectedCodes.push(a[`${rowKey}`]);

+ 92 - 0
src/components/ProgressModal/index.tsx

@@ -0,0 +1,92 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-12-28 20:32:45
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-03-08 15:10:59
+ * @FilePath: /CostAccountingSys/src/components/ProgressModal/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import React, { useEffect, useState } from 'react';
+import { Modal, Progress } from 'antd';
+import { getPercentData, stopGetPercentData } from './service';
+
+interface ProgressModalProps {
+  type: string;
+  onComplete: () => void;
+  visible: boolean;
+  title: string
+}
+
+const ProgressModal: React.FC<ProgressModalProps> = ({ type, onComplete, visible, title }) => {
+  const [progressPercent, setProgressPercent] = useState(0);
+  const [processStr, set_processStr] = useState('');
+
+  const fetchProgressData = async () => {
+    try {
+      const response = await getPercentData(type); // 替换为你的API端点
+      if (response) {
+        if (type == 'ITEM_BATCH_MATCH') {
+          const [cur, total] = response.split('/');
+          setProgressPercent(Math.floor((cur / total) * 100));
+          set_processStr(response);
+        } else {
+          setProgressPercent(response);
+        }
+
+        if (response >= 100) {
+          onComplete(); // 当进度达到100%时,触发完成回调
+        }
+      }
+
+    } catch (error) {
+      console.error('Error fetching progress data:', error);
+    }
+  };
+
+  const stopHandle = async () => {
+    const resp = await stopGetPercentData(type);
+    if (resp) {
+      onComplete();
+    }
+  }
+
+  useEffect(() => {
+    let pollingInterval: NodeJS.Timeout | null = null;
+    if (visible) {
+      setProgressPercent(0); // 重置进度
+      pollingInterval = setInterval(fetchProgressData, 1000); // 开始轮询
+    } else {
+      progressPercent > 0 && stopHandle();
+    }
+
+    return () => {
+      if (pollingInterval) {
+        clearInterval(pollingInterval); // 清理轮询
+      }
+    };
+  }, [visible, type]); // 依赖项包括 visible 和 type
+
+  return (
+    <Modal
+      title={title}
+      open={visible}
+      footer={null}
+      closable={false} // 如果不需要模态框的关闭按钮,可以设置为 false
+    >
+      <Progress percent={progressPercent} />
+      {
+        type == 'ITEM_BATCH_MATCH' && (
+          <>
+            <div style={{ fontSize: 14, color: '#525866', marginTop: 3, marginBottom: 24 }}>已完成{processStr}</div>
+            <div onClick={() => stopHandle()} style={{
+              width: 56, height: 24, textAlign: 'center', fontSize: 14, marginLeft: 430,
+              color: '#17181A', cursor: 'pointer', background: '#FAFCFF', borderRadius: 4, border: '1px solid #DAE2F2'
+            }}>取消</div>
+          </>
+        )
+      }
+    </Modal>
+  );
+};
+
+export default ProgressModal;

+ 34 - 0
src/components/ProgressModal/service.ts

@@ -0,0 +1,34 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-12-28 20:33:26
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2023-12-29 15:56:44
+ * @FilePath: /CostAccountingSys/src/components/ProgressModal/service.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+
+
+import { request } from '@@/plugin-request'
+
+
+
+export const getPercentData = (type:string)=>{
+    return request('/costAccount/public/getPercent', {
+         method:'GET',
+         params:{
+            type 
+        }
+    })
+}
+
+export const stopGetPercentData = (type:string)=>{
+    return request('/costAccount/public/endProgress', {
+         method:'POST',
+         params:{
+            type 
+        }
+    })
+}

BIN
src/components/SQLEditor/images/confirm.png


BIN
src/components/SQLEditor/images/copy.png


+ 132 - 0
src/components/SQLEditor/index.tsx

@@ -0,0 +1,132 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-01-04 13:46:15
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-01-08 19:58:03
+ * @FilePath: /CostAccountingSys/src/components/SQLEditor/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import React, { useEffect, useState } from 'react';
+import MonacoEditor from 'react-monaco-editor';
+import { Form, message, Modal, Input } from 'antd';
+import './style.less';
+import { copyToClipboard } from '@/utils/tooljs';
+
+interface SQLEditorProps {
+    name: string;
+    label: string;
+    rules: { required: boolean; message: string }[];
+    form: any; // 你可以根据你的表单库提供更具体的类型
+    width?: string; // 可选的宽度属性
+    height?: string;
+    value?: string;
+}
+
+function extractSqlParameters(sqlQuery:string) {
+    // 正则表达式匹配冒号开头的参数名,如 :param
+    const paramRegex = /#(\w+)/g;
+    const params = [];
+  
+    let match;
+    while (match = paramRegex.exec(sqlQuery)) {
+      params.push(match[1]); // 将匹配的参数名添加到数组中
+    }
+  
+    return params;
+  }
+
+const SQLEditor: React.FC<SQLEditorProps> = ({ name, label, rules, form, width = '100%', value = '', height = '100%' }) => {
+    const [editorValue, setEditorValue] = useState(value);
+    const [modalForm] = Form.useForm();
+    const handleSQLEditorChange = (newValue: string) => {
+        setEditorValue(newValue); 
+        form.current.setFieldValue(name, newValue);
+    };
+
+    const copyHandle = ()=>{
+        copyToClipboard(editorValue as string);
+        message.success('复制成功!');
+    }
+
+    const verifyHandle = ()=>{
+        const params = extractSqlParameters(editorValue as string);
+        
+
+        Modal.confirm({
+            title:'验证参数',
+            icon:null,
+            content:(
+                <Form form={modalForm} layout="vertical">
+                    {[...new Set(params)].map(param => (
+                        <Form.Item
+                            key={param}
+                            label={`${param}`}
+                            name={param}
+                            rules={[{ required: true, message: `请输入${param}` }]}
+                        >
+                            <Input />
+                        </Form.Item>
+                    ))}
+                </Form>
+            ),
+            onOk: () => {
+                return new Promise((resolve, reject) => {
+                    modalForm.validateFields()
+                        .then(values => {
+                            let finalSql = editorValue as string;
+                            params.forEach(param => {
+                                finalSql = finalSql.replace(new RegExp(`#${param}`, 'g'), values[param]);
+                            });
+                            copyToClipboard(finalSql);
+                            message.success('替换参数值并复制成功!');
+                            resolve(true);
+                        }).catch(errorInfo => {
+                            reject(errorInfo);
+                        });
+                });
+            }
+        })
+    }
+
+    const editorDidMount = (editor:any, monaco:any) => {
+        editor.focus();
+    };
+
+
+    useEffect(() => {
+        setEditorValue(form.current.getFieldValue(name));
+    }, [form, name]);
+
+    return (
+        <Form.Item
+            name={name}
+            label={label}
+            rules={rules}
+            getValueProps={() => ({ value: editorValue })}
+        >
+            <div className='sql_editor' style={{ border: '1px solid #CFD7E6', borderRadius: 4 }}>
+                <MonacoEditor
+                    language="sql"
+                    theme="vs-light"
+                    value={editorValue}
+                    options={{
+                        selectOnLineNumbers: true,
+                        // autoIndent: true,
+                        automaticLayout: true,
+                        fontSize: 14,
+                    }}
+                    width={width}
+                    height={height}
+                    onChange={handleSQLEditorChange}
+                    editorDidMount={editorDidMount}
+                />
+                <div className='editerFooter'>
+                       <div className='a' onClick={()=>copyHandle()}>原文复制</div>
+                       <div className='b' onClick={()=>verifyHandle()}>替换参数值并复制</div>
+                </div>
+            </div>
+        </Form.Item>
+    );
+};
+
+export default SQLEditor;

+ 55 - 0
src/components/SQLEditor/style.less

@@ -0,0 +1,55 @@
+.sql_editor {    
+    // .ace_editor_custom {
+    //     font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace !important;
+    // } 
+    // @media screen and (-webkit-min-device-pixel-ratio:0) {
+    //     .ace_editor_custom {
+    //         font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace !important;
+    //     }
+       
+    // }
+    .editerFooter {
+        display: flex;
+        flex-direction: row;
+        justify-content:flex-start;
+        align-items:center;
+        height: 32px;
+        padding: 0 10px;
+        border-top: 1px solid #DAE2F2;
+        background-color: #EEF3FA;
+
+        .a,.b {
+            cursor: pointer;
+            font-size: 12px;
+            font-weight: 400;
+            color: #17181A;
+        }
+        .a {
+             margin-right: 16px;
+              &::before {
+                  position: relative;
+                  top:3px;
+                  display: inline-block;
+                  content: '';
+                  margin-right: 5px;
+                  width: 16px;
+                  height: 16px;
+                  background: url('./images/copy.png');
+                  background-size: cover;
+              }
+        }
+        .b {
+            &::before {
+                position: relative;
+                top:3px;
+                display: inline-block;
+                content: '';
+                margin-right: 5px;
+                width: 16px;
+                height: 16px;
+                background: url('./images/confirm.png');
+                background-size: cover;
+            }
+      }
+    }
+}

+ 20 - 0
src/constant.ts

@@ -0,0 +1,20 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-01-12 13:34:17
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-01-18 20:24:20
+ * @FilePath: /CostAccountingSys/src/constant.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+export const KcimCenterSysId = '1547394914533380096';
+
+export const CostAccountingSysId = '1714195886747291648';
+
+export const  tableColumnsWidObj = {
+       departmentName:'10%',
+       responsibilityCenter:'10%',
+       responsibilityCenterCode:'10%',
+       year:'5%',
+       month:'5%',
+       shareLevel:'5%'
+}

+ 16 - 2
src/global.less

@@ -8,11 +8,11 @@
   * {
     margin: 0;
     padding: 0;
-    font-family:system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif !important;
+    font-family:system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
   }
   #password {
     &::placeholder {
-      font-family:system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif !important;
+      font-family:system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
     }
   }
 }
@@ -389,8 +389,11 @@ textarea {
 .cost-ant-pro .cost-ant-pro-layout .cost-ant-pro-sider-menu {
     height: calc(100vh - 200px) !important;
     overflow-y: scroll !important;
+    overflow-x: hidden;
 }
 
+
+
 .cost-ant-menu .cost-ant-menu-root .cost-ant-menu-inline .cost-ant-menu-light .cost-ant-pro-sider-menu  .cost-ant-pro-base-menu{
      height: calc(100vh - 90px) !important;
 }
@@ -403,12 +406,14 @@ textarea {
 
 .cost-ant-menu-item-selected {
     background-color:#F2F6FF !important;
+    // margin:8px !important;
     &:hover {
          color: #3376FE !important; 
     }
 }
 .cost-ant-menu-light:not(.cost-ant-menu-horizontal) .cost-ant-menu-item:not(.cost-ant-menu-item-selected):hover {
     background-color: #f0f2f5 !important;
+    // margin:8px !important;
 }
 
 .cost-ant-menu-light:not(.cost-ant-menu-horizontal) .cost-ant-menu-submenu-title:hover {
@@ -669,6 +674,15 @@ textarea {
     }
 }
 
+.cost-ant-pro .cost-ant-pro-layout .cost-ant-pro-sider .cost-ant-layout-sider-children {
+    padding-inline: 0 !important;
+    &>div {
+       &>ul {
+          padding-inline: 8px !important;
+       }
+    }
+}
+
 
 .cost-ant-pro-form>div:not(.cost-ant-pro-form-light-filter) .pro-field-lg {
     width: 100% !important;

+ 16 - 12
src/pages/baseSetting/accountingAccountSet/accountingSubMana/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-13 17:31:15
+ * @LastEditTime: 2024-04-07 14:24:36
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -29,12 +29,16 @@ import locale from 'antd/es/date-picker/locale/zh_CN';
 import { addData, delData, editData, getAccountingSubjectList } from './service';
 
 import './style.less';
+import { renameChildListToChildren } from '@/utils/tooljs';
 
 
 const IconFont = createFromIconfontCN({
     scriptUrl: '',
 });
 
+let currentRow:any = undefined;
+
+
 
 
 export default function AccountingSubMana() {
@@ -43,7 +47,6 @@ export default function AccountingSubMana() {
     const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
     const tableRef = useRef<ActionType>();
     const formRef = useRef<ProFormInstance>();
-    const [currentRow, setCurrentRow] = useState<any | undefined>(undefined);
     const [selectableLevelList, setSelectableLevelList] = useState([]);//可选的分摊层级列表
     const [tabs, set_tabs] = useState<any[]>([]);
     const [accountType, set_accountType] = useState<Key>(1);
@@ -64,7 +67,7 @@ export default function AccountingSubMana() {
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [
-                    <UpDataActBtn record type='ADDCHILD' />,
+                    <UpDataActBtn record={record} type='ADDCHILD' />,
                     <UpDataActBtn key={'act'} record={record} type='EDIT' />,
                     <Popconfirm
                         title="是否确认删除?"
@@ -84,7 +87,7 @@ export default function AccountingSubMana() {
         const resp = await getAccountingSubjectList({ ...params,accountType });
         if (resp) {
             return {
-                data: resp.list,
+                data: renameChildListToChildren(resp.list,'child'),
                 success: true,
                 total: resp.totalCount,
                 pageSize: resp.pageSize,
@@ -108,21 +111,22 @@ export default function AccountingSubMana() {
         if (type == 'ADD' || type == 'ADDCHILD') {
 
             let id = 0;
-            (currentRow && type == 'ADDCHILD') && (id = currentRow.id);
-    
-            const result = { ...formVal,accountingType:accountType, id: id};
+            (type == 'ADDCHILD') && (id = formVal.id);
+
+            const result = accountType == 1?{ ...formVal,accountingType:accountType, id: id}:{...formVal,accountingType:accountType, id: id,};
 
             const resp = await addData(result);
             if (resp) {
+                currentRow = undefined;
                 tableRef.current?.reload();
                 message.success('操作成功!');
+                
             }
 
         }
         if (type == 'EDIT') {
-            console.log({formVal});
             try {
-                const resp = await editData({ ...formVal,isBaseCost:formVal.isBaseCost,isIncomeGroutSetSelect:false,isShareParamSelect:false,accountType });
+                const resp = await editData({ ...formVal,isIncomeGroutSetSelect:false,isShareParamSelect:false,accountType });
                 if (resp) {
                     tableRef.current?.reload();
                     message.success('操作成功!');
@@ -138,20 +142,20 @@ export default function AccountingSubMana() {
 
 
     const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD' | 'ADDCHILD' }) => {
-        setCurrentRow(record);
+
         return (
             <ModalForm
                 title={`${type == 'EDIT' ? '编辑' : '新增'}会计科目`}
                 width={350}
                 formRef={formRef}
                 initialValues={type == 'EDIT' ? {
-                    ...record,
+                    ...record
                 } : {}}
                 trigger={
                     type == 'EDIT' ? <a key="edit" >编辑</a> :type == 'ADDCHILD'?<a className='add'>添加</a>: <span className='add'>新增</span>
                 }
                 onFinish={(val) => {
-                    return updateTable(type == 'EDIT' ? { ...record, ...val } : { ...val }, type);
+                    return updateTable(type == 'EDIT' ? { ...record, ...val } :type == 'ADDCHILD'?{...val,id:record.id}:{ ...val }, type);
                 }}
                 modalProps={{ destroyOnClose: true }}
                 colProps={{ span: 24 }}

+ 1 - 0
src/pages/baseSetting/accountingAccountSet/accountingSubMana/service.ts

@@ -30,6 +30,7 @@ export type AddTableDataType = {
 
 export const addData = (data:AddTableDataType) => {
   return request('/costAccount/accounting/save', {
+    
     method: 'POST',
     data:{...data}
   });

+ 23 - 12
src/pages/baseSetting/accountingAccountSet/accountingSubMap/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-14 11:31:58
+ * @LastEditTime: 2024-01-05 13:36:31
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -26,10 +26,11 @@ import locale from 'antd/es/date-picker/locale/zh_CN';
 
 
 
-import { addData, delData, editData, getAccountProductConnectableList, getAccountProductConnectList } from './service';
+import { getAccountProductConnectableList, getAccountProductConnectList, saveAccountProductConnected } from './service';
 
 import './style.less';
 import TableSelecter from '@/components/KCIMTableSelector';
+import { renameChildListToChildren } from '@/utils/tooljs';
 
 
 const IconFont = createFromIconfontCN({
@@ -40,6 +41,7 @@ const IconFont = createFromIconfontCN({
 const tableSelectorColumns = [
     {
         title: 'Id',
+        width:60,
         dataIndex: 'id',
     },
     {
@@ -49,6 +51,7 @@ const tableSelectorColumns = [
 ]
 
 
+let currentRow:any = undefined;
 
 export default function AccountingSubMap() {
 
@@ -56,7 +59,6 @@ export default function AccountingSubMap() {
     const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
     const tableRef = useRef<ActionType>();
     const formRef = useRef<ProFormInstance>();
-    const [currentRow, setCurrentRow] = useState<any | undefined>(undefined);
     const [tabs, set_tabs] = useState<any[]>([]);
     const [accountType, set_accountType] = useState<Key>(1);
     const [tableSelecterVisible,set_tableSelecterVisible] = useState(false);
@@ -64,10 +66,12 @@ export default function AccountingSubMap() {
 
         {
             title: '会计科目名称',
+            width:200,
             dataIndex: 'accountingName',
         },
         {
             title: '会计科目编码',
+            width:120,
             dataIndex: 'accountingCode',
         },
         {
@@ -84,7 +88,7 @@ export default function AccountingSubMap() {
         {
             title: '操作',
             key: 'option',
-            width: 120,
+            width: 80,
             valueType: 'option',
             render: (_: any, record: any) => {
                 const { isParent } = record;
@@ -92,7 +96,7 @@ export default function AccountingSubMap() {
                   <a
                     key="config"
                     onClick={() => {
-                      setCurrentRow(record);
+                      currentRow = record;
                       set_tableSelecterVisible(true);
                     }}
                   >
@@ -109,7 +113,7 @@ export default function AccountingSubMap() {
         const resp = await getAccountProductConnectList({ ...params, accountType });
         if (resp) {
             return {
-                data: resp.list,
+                data: renameChildListToChildren(resp.list,'child'),
                 success: true,
                 total: resp.totalCount,
                 pageSize: resp.pageSize,
@@ -126,17 +130,24 @@ export default function AccountingSubMap() {
         set_accountType(key);
         tableRef.current?.reload();
     }
-
+//productCode,productName
     const getTableSelectorData = async () => {
-        const {responsibilityId} = currentRow;
+        const {responsibilityId,productVOs = []} = currentRow;
+        const defaultRows = productVOs?productVOs.map((a:any)=>({id:a.id,name:a.productName})):[];
         const resp = await getAccountProductConnectableList({responsibilityId,pageSize:500,current:1});
-        return resp
-        
+        if(resp){
+            return [...resp,...defaultRows]
+        }        
     }
 
 
     const tableSelecterCommit = async (keys:Key[],rows:any[]) => {
-        
+        const {id} = currentRow;
+        const resp = await saveAccountProductConnected({id,products:keys});
+        if(resp){
+             set_tableSelecterVisible(false)
+             tableRef.current?.reload();
+        }
     }
 
     useEffect(() => {
@@ -160,7 +171,7 @@ export default function AccountingSubMap() {
                 title='关联成本收入项目'
                 rowKey={'id'}
                 request={getTableSelectorData}
-                defaultSelectedKeys={[]}
+                defaultSelectedKeys={(currentRow&&currentRow.productVOs)?[...(currentRow.productVOs).map((a:any)=>a.id)]:[]}
                 record={currentRow}
                 open={tableSelecterVisible}
                 onFinish={(keys, rows) => tableSelecterCommit(keys, rows)}

+ 6 - 34
src/pages/baseSetting/accountingAccountSet/accountingSubMap/service.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 16:31:27
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-14 11:13:37
+ * @LastEditTime: 2023-12-07 15:01:32
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -29,43 +29,15 @@ export const getAccountProductConnectableList = (params:any) => {
 }
 
 
-
-//新增
-export type AddTableDataType = {
-  code:string,
-  name:string,
-  description:string
-}
-
-export const addData = (data:AddTableDataType) => {
-  return request('/costAccount/accounting/save', {
+//保存绑定信息
+export const saveAccountProductConnected = (body:any) => {
+  return request('/costAccount/accountProduct/save', {
     method: 'POST',
-    data:{...data}
+    data:{...body},
   });
-};
-
-
-
-//编辑表格数据
-
-export type TableRowEditType = {
-  id:number;
-}&AddTableDataType
+}
 
-export const editData = (data:any) => {
-  return request('/costAccount/accounting/edit', {
-    method: 'POST',
-    data
-  });
-};
 
-//删除表格操作
-export const delData = (id:string) => {
-  return request('/costAccount/accounting/delete', {
-    method: 'POST',
-    params:{id}
-  });
-};
 
 
 

+ 451 - 0
src/pages/baseSetting/accountingAccountSet/chargeItemMap/index.tsx

@@ -0,0 +1,451 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 11:30:33
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2023-12-01 14:56:59
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+import { createFromIconfontCN } from '@ant-design/icons';
+import { ActionType } from '@ant-design/pro-components';
+import { ModalForm, ProFormSelect, ProFormText, ProFormTextArea } from '@ant-design/pro-form';
+import { ProColumns } from '@ant-design/pro-table';
+import { Dropdown, Input, MenuProps, message, Tooltip, Popconfirm, TreeProps } from 'antd';
+
+import { Key } from 'react';
+import { useEffect, useRef, useState } from 'react';
+import DirectoryTree from 'antd/es/tree/DirectoryTree';
+import { DataNode } from 'antd/es/tree';
+
+import { getAccountingItemMap, addTableData, delData, getAccountingList, batchDelTableData } from './service';
+
+
+import './style.less';
+
+import expandedIcon from '../../../../../static/treenode_open.png';
+import closeIcon from '../../../../../static/treenode_collapse.png';
+
+
+import '../../../../utils/zhongtaiB'
+import KCIMPagecontainer from '@/components/KCIMPageContainer';
+import { KCIMTable } from '@/components/KCIMTable';
+import { getTargetDic } from '@/services/auth';
+import TableSelecter from './tableSelector';
+import { getDeepestTreeData } from '@/utils/tooljs';
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+let _currentSelectedType: any = undefined;
+
+const ChargeItemMap = () => {
+
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
+
+    const [currentSelectedType, set_currentSelectedType] = useState<any | undefined>(undefined);
+    const [treeData, set_treeData] = useState<any[]>([]);
+    const [currentSelectedTreeNode, set_currentSelectedTreeNode] = useState<null | any>(null);
+    const [expandedKeys, set_expandedKeys] = useState<Key[]>([]);
+    const [autoExpandParent, set_autoExpandParent] = useState(true);
+    const [searchValue, set_searchValue] = useState('');
+    const [currentTreeDataFilter, set_currentTreeDataFilter] = useState({ name: '全部', code: 0 });
+    const [treeFilterVisible, set_treeFilterVisible] = useState(false);
+    const [selectedRowKeys,set_selectedRowKeys] = useState<Key[]>([]);
+
+    const [tableSelecterVisible, set_tableSelecterVisible] = useState(false);
+
+    const [treeDataDefault, set_treeDataDefault] = useState<any[]>([]);
+
+    const [leftDataSearchKeyVal, set_leftDataSearchKeyVal] = useState<undefined | string>(undefined);
+
+    const tableRef = useRef<ActionType>();
+
+    const column: ProColumns[] = [
+
+        {
+            title: '收费项目代码',
+            ellipsis: true,
+            width: 120,
+            dataIndex: 'itemCode',
+
+        },
+        {
+            title: '收费项目名称',
+            dataIndex: 'itemName',
+
+        },
+        {
+            title: '收费项目类别',
+            width: 100,
+            dataIndex: 'typeName',
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 60,
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                return [
+                    <Popconfirm
+                        title="是否确认删除?"
+                        key="del"
+                        onConfirm={() => delTableData(record.id)}
+                    >
+                        <a>删除</a>
+                    </Popconfirm>
+                ]
+            },
+        },
+    ]
+
+
+    const getTableData = async (params: any) => {
+
+        const resp = await getAccountingItemMap({ ...params });
+        if (resp) {
+            return {
+                data: resp.list,
+                success: true,
+                total: resp.totalCount,
+                pageSize: resp.pageSize,
+                totalPage: resp.totalPage,
+            }
+        } else {
+            return []
+        }
+    }
+
+
+    //获取左侧列表
+    const getPageLeftData = async () => {
+        const resp = await getAccountingList('', currentTreeDataFilter.code);
+        if(resp){
+            set_treeData(resp);
+            set_treeDataDefault(resp);
+            set_currentSelectedTreeNode(null);
+        } 
+    }
+
+    const delTableData = async (id: number) => {
+        const resp = await delData(id);
+        if (resp) {
+            message.success('操作成功!');
+            tableRef.current?.reload();
+        }
+    }
+
+
+    const tableSelecterCommit = async (keys: Key[], rows: any[]) => {
+
+        const arr = rows.map((a, index) => ({
+            itemCode: a.itemCode,
+            itemName: a.itemName,
+            type: a.itemType,
+        }));
+        const result = {
+            accountingCode: currentSelectedTreeNode.accountingCode,
+            accountingName: currentSelectedTreeNode.accountingName,
+            itemMaps: arr
+        }
+        const resp = await addTableData(result);
+        if (resp) {
+            message.success('操作成功');
+            set_tableSelecterVisible(false);
+            tableRef.current?.reload();
+        }
+    }
+
+
+
+    const tableDataSearchHandle = (paramName: string) => {
+
+        set_tableDataFilterParams({
+            ...tableDataFilterParams,
+            [`${paramName}`]: tableDataSearchKeywords
+        })
+
+    }
+
+    const batchDelHandle = async () => {
+        const resp = await batchDelTableData(selectedRowKeys);
+        if (resp) {
+            message.success('操作成功!');
+            set_selectedRowKeys([]);
+            tableRef.current?.reload();
+        }
+    }
+
+
+    const onSelect: TreeProps['onSelect'] = (selectedKeys, info: any) => {
+        const { node } = info;
+        if (!node.children || node.children.length == 0) {
+            set_currentSelectedTreeNode(node);
+        }
+    };
+
+    const onExpand = (newExpandedKeys: React.Key[]) => {
+        // setExpandedKeys(newExpandedKeys);
+        // setAutoExpandParent(false);
+        set_expandedKeys(newExpandedKeys);
+        set_autoExpandParent(false);
+    };
+
+
+    const dataList: any[] = [];
+
+    const getParentKey = (key: React.Key, tree: any[]): React.Key => {
+        let parentKey: React.Key;
+        for (let i = 0; i < tree.length; i++) {
+            const node = tree[i];
+            if (node.children) {
+                if (node.children.some((item: { accountingCode: React.Key; }) => item.accountingCode === key)) {
+                    parentKey = node.accountingCode;
+                } else if (getParentKey(key, node.children)) {
+                    parentKey = getParentKey(key, node.children);
+                }
+            }
+        }
+        return parentKey!;
+    };
+
+    const generateList = (data: any[]) => {
+        for (let i = 0; i < data.length; i++) {
+            const node = data[i];
+            dataList.push(node);
+            if (node.children) {
+                generateList(node.children);
+            }
+        }
+    };
+
+    generateList(treeData as any);
+
+
+    const onTreeSearchKeyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+
+        const { value } = e.target;
+
+        const newExpandedKeys = dataList
+            .map((item) => {
+                if (item.accountingName.indexOf(value) > -1) {
+                    return getParentKey(item.accountingCode, treeData);
+                }
+                return null;
+            });
+
+        set_expandedKeys(newExpandedKeys as React.Key[]);
+        set_searchValue(value);
+        set_autoExpandParent(true);
+    }
+
+    //左侧树结构筛选
+    const changeTreeDataFilter = (obj: any) => {
+
+        set_currentTreeDataFilter(obj);
+        set_treeFilterVisible(false);
+    }
+
+
+
+    useEffect(() => {
+
+        if (currentSelectedTreeNode) {
+            set_tableDataFilterParams({ ...tableDataFilterParams, accountingCode: currentSelectedTreeNode.accountingCode });
+        }
+    }, [currentSelectedTreeNode])
+
+    useEffect(() => {
+        //初始化左侧树结构数据后
+        
+        if (treeData?.length > 0) {
+            if (!currentSelectedTreeNode) {
+                if (treeData[0].children && treeData[0].children.length > 0) {
+                    const [node, nodeParent] = getDeepestTreeData(treeData[0], 'children');
+                    set_currentSelectedTreeNode(node);
+                    set_expandedKeys([nodeParent.accountingCode]);
+                } else {
+                    set_currentSelectedTreeNode(treeData[0]);
+                    set_expandedKeys([treeData[0].accountingCode]);
+                }
+
+            }
+        }
+    }, [treeData]);
+
+    useEffect(() => {
+        getPageLeftData();
+    }, [currentTreeDataFilter])
+
+    useEffect(() => {
+        getPageLeftData();
+    }, [])
+
+
+
+    return (
+        <KCIMPagecontainer title={false} className='ChargeItemMap'>
+            <TableSelecter
+                onVisibleChange={(bool) => set_tableSelecterVisible(bool)}
+                title='添加'
+                rowKey={'itemCode'}
+                defaultSelectedKeys={[]}
+                record={_currentSelectedType}
+                open={tableSelecterVisible}
+                onFinish={(keys, rows) => tableSelecterCommit(keys, rows)}
+            />
+
+            {selectedRowKeys.length > 0 && (
+                <div className='bottomBar'>
+                    <span>已选择<a>{selectedRowKeys.length}</a>项</span>
+                    <a onClick={() => batchDelHandle()}>批量删除</a>
+                </div>
+            )}
+
+            {
+                treeFilterVisible && (
+                    <div className='selecterList'>
+                        <div onClick={() => changeTreeDataFilter({ name: '全部', code: 0 })} className={currentTreeDataFilter.code == 0 ? 'list on' : 'list'}>全部</div>
+                        <div onClick={() => changeTreeDataFilter({ name: '已对照', code: 1 })} className={currentTreeDataFilter.code == 1 ? 'list on' : 'list'}>{'已对照'}</div>
+                        <div onClick={() => changeTreeDataFilter({ name: '未对照', code: 3 })} className={currentTreeDataFilter.code == 3 ? 'list on' : 'list'}>{'未对照'}</div>
+                    </div>
+                )
+            }
+
+            <div className='left'>
+                <div className='toolbar'>
+                    <Input placeholder={'会计科目名称'} allowClear
+                        suffix={
+                            <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} />
+                        }
+                        value={leftDataSearchKeyVal}
+                        style={{ width: 156 }}
+                        onChange={onTreeSearchKeyChange}
+                    />
+                    <Tooltip placement="top" title={currentTreeDataFilter.name}>
+                        <div className={currentTreeDataFilter.code == 0 ? 'filter' : currentTreeDataFilter.code == 1 ? 'filter blue' : 'filter orange'} onClick={() => set_treeFilterVisible(true)}></div>
+                    </Tooltip>
+
+
+                </div>
+
+                <div className='wrap'>
+                    {
+                        treeData && treeData.length > 0 && currentSelectedTreeNode && (
+                            <DirectoryTree
+                                fieldNames={{ title: 'accountingName', key: 'accountingCode' }}
+                                rootStyle={{ height: '100%', paddingBottom: 50, padding: '0 16px' }}
+                                onSelect={onSelect}
+                                onExpand={onExpand}
+                                expandedKeys={expandedKeys}
+                                autoExpandParent={autoExpandParent}
+                                selectedKeys={[currentSelectedTreeNode.accountingCode]}
+                                blockNode={true}
+
+                                icon={() => null}
+
+                                titleRender={
+                                    (nodeData: any) => {
+                                        const strTitle = nodeData.accountingName as string;
+                                        const index = strTitle.indexOf(searchValue);
+                                        const beforeStr = strTitle.substring(0, index);
+                                        const afterStr = strTitle.slice(index + searchValue.length);
+                                        const title =
+                                            index > -1 ? (
+                                                <span>
+                                                    {beforeStr}
+                                                    <span className="site-tree-search-value" style={{ color: '#3377ff', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{searchValue}</span>
+                                                    {afterStr}
+                                                </span>
+                                            ) : (
+                                                <span className='strTitle'>{strTitle}</span>
+                                            );
+                                        return <div style={{
+                                            display: 'flex', flexDirection: 'row',
+                                            width: '100%',
+                                            justifyContent: 'space-between', alignItems: 'center', height: 32,
+                                            borderRadius: '4px',
+                                            overflow: 'hidden',
+                                            color: '#17181A',
+                                            textOverflow: 'ellipsis',
+                                            whiteSpace: 'nowrap'
+
+                                        }}>
+                                            {title}
+                                            {!nodeData.map && <span className={nodeData.unitType ? 'point lastChild' : 'point'}></span>}
+                                        </div>
+                                    }
+                                }
+                                defaultSelectedKeys={[currentSelectedTreeNode.accountingCode]}
+                                treeData={treeData as unknown as DataNode[]}
+                                // treeData={treeDataNew}
+                                switcherIcon={(props: any) => {
+                                    const { expanded } = props;
+                                    return !expanded ? <img style={{ width: 20, height: 20, position: 'relative', top: 5 }} src={expandedIcon} /> : <img style={{ width: 20, height: 20, position: 'relative', top: 5 }} src={closeIcon} />
+                                }}
+                            />
+                        )
+                    }
+                </div>
+            </div>
+            <div className='right'>
+                <div className='toolBar'>
+                    <div className='filter'>
+                        <div className='filterItem'>
+                            <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
+                            <Input placeholder={'收费项目名称'} allowClear
+                                suffix={
+                                    <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('itemName')} />
+                                }
+                                onChange={(e) => {
+                                    set_tableDataSearchKeywords(e.target.value);
+                                    if (e.target.value.length == 0) {
+                                        set_tableDataFilterParams({
+                                            ...tableDataFilterParams,
+                                            itemName: ''
+                                        });
+                                    }
+                                }}
+                                onPressEnter={(e) => {
+
+                                    set_tableDataFilterParams({
+                                        ...tableDataFilterParams,
+                                        itemName: (e.target as HTMLInputElement).value
+                                    });
+                                }}
+
+                            />
+                        </div>
+                    </div>
+                    <div className='btnGroup'>
+                        <span className='add' onClick={() => set_tableSelecterVisible(true)}>添加</span>
+                    </div>
+                </div>
+                <div style={{ marginTop: 16 }}>
+                    {currentSelectedTreeNode && <KCIMTable actionRef={tableRef} columns={column}
+                        scroll={{ y: 500 }}
+                        rowKey='id'
+                        params={tableDataFilterParams}
+                        request={(params) => getTableData(params)}
+                        tableAlertRender={false}
+                        rowSelection={{
+                            onChange(selectedRowKeys, selectedRows, info) {
+                                set_selectedRowKeys(selectedRowKeys);
+                            },
+                        }}
+                    />}
+                </div>
+            </div>
+        </KCIMPagecontainer>
+    )
+}
+
+
+export default ChargeItemMap;
+function getParentKey(code: any, treeData: any[]) {
+    throw new Error('Function not implemented.');
+}
+

+ 76 - 0
src/pages/baseSetting/accountingAccountSet/chargeItemMap/service.ts

@@ -0,0 +1,76 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-07 11:12:10
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2023-11-30 10:34:32
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicMana/service.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import { string } from 'mathjs';
+import { Key } from 'react';
+import { request } from 'umi';
+
+
+//获取左侧数据
+export const getAccountingList = (accountingName:string,type:number) => {
+  return request('/costAccount/setting/getAccountingList', {
+    method: 'GET',
+    params:{accountingName,type}
+  });
+};
+
+//获取右侧表格数据
+
+export const getAccountingItemMap = (params:{accountingCode:string,itemName?:string,pageSize:number,current:number}) => {
+    return request('/costAccount/setting/getAccountingItemMap', {
+      method: 'GET',
+      params:{...params}
+    });
+};
+
+//获取可添加列表
+export const getAddableTableData = (type:number,name?:string) => {
+  return request('/costAccount/setting/getAccountingItemDictList', {
+    method: 'GET',
+    params:{type,name}
+  });
+};
+
+
+
+//新增表格数据
+
+export const addTableData = (data:any) => {
+  return request('/costAccount/setting/addAccountingItemMap', {
+    method: 'POST',
+    data
+  });
+};
+
+
+
+
+//删除表格操作
+export const delData = (id:number) => {
+    return request('/costAccount/setting/deleteAccountingItemMap', {
+      method: 'POST',
+      params:{id}
+    });
+};
+
+
+//批量删除表格数据
+export const batchDelTableData = (ids:Key[]) => {
+  return request('/costAccount/setting/batchDeleteAccountingItemMap', {
+    method: 'POST',
+    data:[...ids]
+  });
+};
+
+
+
+
+

+ 260 - 0
src/pages/baseSetting/accountingAccountSet/chargeItemMap/style.less

@@ -0,0 +1,260 @@
+.row-dragging {
+
+  .cost-ant-table-cell {
+    width: 130px;
+  }
+}
+
+.TableSelecter {
+
+  .pfm-ant-modal-footer {
+    display: none !important;
+  }
+
+  .footer {
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-end;
+    margin-top: 15px;
+
+    span {
+      display: inline-block;
+      width: 56px;
+      height: 24px;
+      font-size: 14px;
+      line-height: 23px;
+      text-align: center;
+      border-radius: 4px;
+      cursor: pointer;
+
+      &.ok {
+        color: #FFFFFF;
+        background: #3377FF;
+        margin-left: 8px;
+      }
+
+      &.cancel {
+        border: 1px solid #DAE2F2;
+      }
+    }
+
+  }
+}
+
+.ChargeItemMap {
+  width: 100%;
+  height: calc(100vh - 48px);
+  position: relative;
+
+  .bottomBar {
+    position: absolute;
+    bottom: -16px;
+    left: -16px;
+    width: 102.5%;
+    height: 48px;
+    display: flex;
+    padding: 0 16px;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    background: #FFFFFF;
+    box-shadow: 0px -8px 16px 0px rgba(64, 85, 128, 0.1);
+
+    &>span {
+      font-size: 14px;
+      font-weight: 400;
+      color: #17181A;
+    }
+
+    &>a {
+      width: 80px;
+      height: 24px;
+      line-height: 24px;
+      font-size: 14px;
+      font-weight: 400;
+      color: #FFFFFF;
+      text-align: center;
+      background: #3377FF;
+      border-radius: 4px;
+    }
+  }
+
+  .selecterList {
+    position: absolute;
+    z-index: 99;
+    top: 44px;
+    left: 180px;
+    width: 120px;
+    height: 104px;
+    background: #FFFFFF;
+    box-shadow: 0px 8px 16px 0px rgba(64, 85, 128, 0.1);
+    border-radius: 4px;
+    padding: 4px;
+
+    .list {
+      position: relative;
+      height: 32px;
+      line-height: 16px;
+      border-radius: 2px;
+      font-size: 14px;
+      cursor: pointer;
+      padding: 8px;
+      font-family: SourceHanSansCN-Normal, SourceHanSansCN;
+      font-weight: 400;
+      color: #17181A;
+
+      &.on {
+        font-weight: 500;
+        background: rgba(51, 119, 255, 0.08);
+
+        &::after {
+          position: absolute;
+          right: 8px;
+          display: inline-block;
+          content: '';
+          width: 16px;
+          height: 16px;
+          background: url('../../../../../static/gou_blue.png');
+          background-size: contain;
+        }
+      }
+    }
+  }
+
+  .left {
+    float: left;
+    border-radius: 4px;
+    width: 220px;
+    height: calc(100vh - 80px);
+    overflow: hidden;
+    margin-right: 16px;
+    padding: 16px 0px;
+    background: #FFFFFF;
+
+
+    .toolbar {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+      padding: 0 16px;
+
+      .filter {
+        position: relative;
+        width: 24px;
+        height: 24px;
+        background: #FAFCFF;
+        border-radius: 4px;
+        border: 1px solid #DAE2F2;
+        margin-left: 8px;
+        cursor: pointer;
+        background: url('../../../../../static/filter.png');
+        background-size: 16px 16px;
+        background-position: center;
+        background-repeat: no-repeat;
+
+        &.orange {
+          &::after {
+            position: absolute;
+            z-index: 9;
+            top: 1px;
+            right: 1px;
+            display: inline-block;
+            content: '';
+            width: 4px;
+            height: 4px;
+            border-radius: 50%;
+            background: #FF9832;
+          }
+        }
+
+        &.blue {
+          &::after {
+            position: absolute;
+            z-index: 9;
+            top: 1px;
+            right: 1px;
+            display: inline-block;
+            content: '';
+            width: 4px;
+            height: 4px;
+            border-radius: 50%;
+            background: #3377FF;
+          }
+        }
+      }
+    }
+
+    .wrap {
+      margin-top: 16px;
+      height: calc((100vh - 80px) - 75px);
+      overflow: hidden;
+      overflow-y: scroll;
+      // border: 1px solid red;
+
+      .cos-ant-tree.cos-ant-tree-directory .cos-ant-tree-treenode-selected:hover::before,
+      .cos-ant-tree.cos-ant-tree-directory .cos-ant-tree-treenode-selected::before {
+        border-radius: 4px;
+        background: rgb(240 242 245 / 100%);
+      }
+
+      .cos-ant-tree.cos-ant-tree-directory .cos-ant-tree-treenode .cos-ant-tree-node-content-wrapper.cos-ant-tree-node-selected {
+        font-weight: bold;
+
+      }
+
+      .cost-ant-tree.cost-ant-tree-directory .cost-ant-tree-treenode-selected::before {
+        border-radius: 4px;
+        background: rgb(240 242 245 / 100%);
+      }
+
+    }
+  }
+
+  .right {
+    float: left;
+    width: calc(100% - 236px);
+    padding: 16px;
+    border-radius: 4px;
+    background: #FFFFFF;
+
+    .toolBar {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+
+      .filter {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+
+        .filterItem {
+          display: flex;
+          flex-direction: row;
+          justify-content: center;
+          align-items: center;
+        }
+      }
+
+      .btnGroup {
+        .add {
+          cursor: pointer;
+          display: inline-block;
+          font-size: 14px;
+          font-family: SourceHanSansCN-Normal, SourceHanSansCN;
+          font-weight: 400;
+          color: #FFFFFF;
+          line-height: 24px;
+          padding: 0 14px;
+          background: #3377FF;
+          border-radius: 4px;
+          margin-left: 8px;
+        }
+      }
+
+
+    }
+  }
+}

+ 201 - 0
src/pages/baseSetting/accountingAccountSet/chargeItemMap/tableSelector.tsx

@@ -0,0 +1,201 @@
+import React, { Key, useEffect, useState } from "react";
+import { Input, Select } from 'antd'
+import { KCIMTable } from "@/components/KCIMTable";
+import { createFromIconfontCN } from "@ant-design/icons";
+
+
+import { ModalForm, ProColumns, ProFormSelect, ProFormText } from "@ant-design/pro-components";
+
+import { set } from "lodash";
+import { getAddableTableData } from "./service";
+
+
+// import './style.less';
+
+
+interface TableSelecterProps {
+    record: any
+}
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+
+
+const TableSelecter = ({ record, open, title, onVisibleChange, rowKey = 'id', request, onFinish, defaultSelectedKeys }: {
+    record: any, open: boolean, title: string, onVisibleChange: (bool: boolean) => void, defaultSelectedKeys: Key[],
+    rowKey?: string, request?: (params: any) => Promise<any>, onFinish?: (selectedKeys: React.Key[], selectedRows: any[]) => void
+}) => {
+
+
+    const Table = React.forwardRef(({ }: TableSelecterProps, ref) => {
+
+        const [datasource, set_datasource] = useState<any[]>([]);
+        const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);
+        const [selectedRows, set_selectedRows] = useState<any[]>([]);
+        const [showList, set_showList] = useState<any[]>([]);
+        const [type, set_type] = useState<number>(3);
+        const [keyword, set_keyword] = useState<string | undefined>(undefined);
+
+
+        const columns: ProColumns[] = [
+            {
+                title: '收费项目代码',
+                ellipsis:true,
+                dataIndex: 'itemCode',
+            },
+            {
+                title: '收费项目名称',
+                ellipsis:true,
+                dataIndex: 'itemName',
+            }
+        ];
+
+
+        const onSelectChange = (newSelectedRowKeys: React.Key[], selectedRows: any) => {
+            setSelectedKeys([...newSelectedRowKeys]);
+            set_selectedRows([...selectedRows]);
+
+        };
+
+        const saveHandle = async () => {
+            const selectedRowCodes = selectedRows.map((a) => a[`${rowKey}`]);
+            const rows = datasource.filter((a) => selectedRowCodes.includes(a[`${rowKey}`]));
+            onFinish && onFinish(selectedKeys, rows);
+        }
+
+        const getTableData = async () => {
+            const resp = await getAddableTableData(type);
+
+            let selectedCodes: string[] = [];
+            let selectedRows: any[] = [];
+            if (resp) {
+                const data = resp.map((a: any) => {
+                    if (defaultSelectedKeys.includes(a[`${rowKey}`])) {
+                        selectedCodes.push(a[`${rowKey}`]);
+                        selectedRows.push(a);
+                        const needItem = record.departList.filter((b: any) => a[`${rowKey}`] == b[`${rowKey}`]);
+
+                        return {
+                            ...a,
+                            flag: needItem[0].isManager ? true : false
+                        }
+                    } else {
+                        return a
+                    }
+                });
+
+                set_showList(data);
+                set_selectedRows([...selectedRows]);
+                setSelectedKeys([...selectedCodes]);
+                set_datasource([...datasource, ...data]);
+            }
+
+
+            return Promise.resolve([]);
+        }
+
+        useEffect(() => {
+            // console.log({code, keyword});
+            const result = datasource.filter((a) => {
+                return a.itemName.indexOf(keyword) != -1 
+            });
+
+            set_showList([...result]);
+        }, [keyword]);
+
+        useEffect(()=>{
+            getTableData()
+        },[type]);
+
+
+        return (
+            <div >
+                <div className="filter" style={{marginBottom:8,display:'flex',flexDirection:'row',alignItems:'center'}}>
+                    <ProFormSelect
+                         noStyle
+                         style={{marginRight:8}}
+                         options={[
+                            {label:'药品',value:1},
+                            {label:'材料',value:2},
+                            {label:'项目',value:3}
+                         ]}
+                         fieldProps={{
+                             defaultValue:3,
+                             onChange(value, option) {
+                                set_type(value);
+                                set_keyword('');
+                             },
+                         }}
+                    />
+                    <ProFormText noStyle placeholder={'项目名称'}
+                        fieldProps={{
+                            value:keyword,
+                            suffix: <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" />,
+                            onChange: (e) => {
+                                if (e.target.value.length != 0) {
+                                    set_keyword(e.target.value);
+                                } else {
+                                    set_keyword('');
+                                }
+                            }
+                        }}
+                    />
+                </div>
+
+                <KCIMTable columns={columns}
+                    options={{
+                        density: true,
+                        setting: {
+                            listsHeight: 100,
+                        },
+                    }}
+                    rowKey={rowKey}
+                    scroll={{ y: 400 }}
+                    tableAlertRender={false}
+                    rowSelection={{
+                        // 自定义选择项参考: https://ant.design/components/table-cn/#components-table-demo-row-selection-custom
+                        // 注释该行则默认不显示下拉选项
+                        // selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT],
+                        selectedRowKeys: selectedKeys,
+                        onChange: onSelectChange,
+                    }}
+                    pagination={{ showTitle: false, showSizeChanger: true,simple:true }}
+                    dataSource={showList}
+
+                />
+                <div className='footer'>
+                    <span className='cancel' onClick={() => close()}>取消</span>
+                    <span className='ok' onClick={() => saveHandle()}>{`确认(${selectedKeys.length > 0 && selectedKeys.length})`}</span>
+                </div>
+            </div>
+
+        )
+    });
+
+    const close = () => {
+        onVisibleChange && onVisibleChange(false);
+    }
+
+
+    return (
+        <ModalForm className="TableSelecter" title={title} width={400} submitter={{
+            render: false
+        }} open={open} modalProps={{
+            closable: false,
+        }}>
+            <Table
+                // ref={tableSelecterRef}
+                record={undefined}
+            ></Table>
+        </ModalForm>
+    )
+
+}
+
+
+
+
+export default TableSelecter

+ 4 - 4
src/pages/baseSetting/accountingAccountSet/costIncomeProjectMana/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-13 16:12:56
+ * @LastEditTime: 2023-12-07 14:52:40
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -56,7 +56,7 @@ export default function CostIncomeProjectMana() {
             dataIndex: 'productCode',
         },
         {
-            title: '成本项目名',
+            title: '成本项目名',
             dataIndex: 'productName',
         },
         {
@@ -255,8 +255,8 @@ export default function CostIncomeProjectMana() {
             <div className='toolBar'>
                 <div className='filter'>
                     <div className='filterItem' style={{ marginLeft: 16, width: 205 }}>
-                        <span className='label' style={{ whiteSpace: 'nowrap' }}> 成本项目名:</span>
-                        <Input placeholder={'请输入'} allowClear
+                        <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
+                        <Input placeholder={'成本项目名称'} allowClear
                             suffix={
                                 <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('filter')} />
                             }

+ 5 - 4
src/pages/baseSetting/costAllocationSet/allocationLevelSet/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-16 17:39:01
+ * @LastEditTime: 2024-01-05 13:45:36
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -70,7 +70,7 @@ export default function AllocationLevelSet() {
         {
             title: '操作',
             key: 'option',
-            width: 120,
+            width: 90,
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [
@@ -125,6 +125,7 @@ export default function AllocationLevelSet() {
     }
 
     const updateTable = async (formVal: any, type: 'EDIT' | "ADD") => {
+        console.log({formVal});
 
         if (type == 'ADD') {
   
@@ -141,7 +142,7 @@ export default function AllocationLevelSet() {
         if (type == 'EDIT') {
             try {
                 const {targetLevel} = formVal;
-                const resp = await editData({ ...formVal,targetLevel:(targetLevel.map((a:any) => a.value)).join(',') });
+                const resp = await editData({ ...formVal,targetLevel:(targetLevel.map((a:any) => a.value?a.value:a)).join(',') });
                 if (resp) {
                     tableRef.current?.reload();
                     message.success('操作成功!');
@@ -243,7 +244,7 @@ export default function AllocationLevelSet() {
                                             mode="multiple"
                                             labelInValue={true}
                                             placeholder='请选择'
-                                            
+                                            maxTagCount={2}
                                         >
                                             {filteredArr.map((item, index) => (
                                                 <Select.Option key={index} value={item.value}>

+ 2 - 1
src/pages/baseSetting/costAllocationSet/allocationParamsMap/editTableModal.tsx

@@ -74,7 +74,7 @@ const EditTableModal = ({ record, open, title, onVisibleChange, rowKey = 'id', o
                   <a
                     key="delete"
                     onClick={() => {
-                    //   setDataSource(dataSource.filter((item) => item.id !== record.id));
+                        set_datasource(datasource.filter((item) => item.id !== record.id));
                     }}
                   >
                     删除
@@ -87,6 +87,7 @@ const EditTableModal = ({ record, open, title, onVisibleChange, rowKey = 'id', o
 
         const saveHandle = async () => {
             onFinish && onFinish(datasource);
+        
         }
 
         const getTableData = async () => {

+ 81 - 98
src/pages/baseSetting/costAllocationSet/allocationParamsMap/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-20 15:29:57
+ * @LastEditTime: 2024-01-05 13:43:06
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -56,55 +56,61 @@ export default function AllocationParamsMap() {
     const [selectedResponsibility, setSelectedResponsibility] = useState(null);
 
     const [editTableVisible, set_editTableVisible] = useState(false);
-    const [tableSelecterVisible,set_tableSelecterVisible] = useState(false);
+    const [tableSelecterVisible, set_tableSelecterVisible] = useState(false);
 
 
     const columns: ProColumns[] = [
 
         {
             title: '分摊级别',
-            ellipsis:true,
+            width:80,
+            ellipsis: true,
             dataIndex: 'shareLevel',
         },
         {
             title: '责任中心编码',
-            ellipsis:true,
+            ellipsis: true,
+            width:120,
             dataIndex: 'responsibilityCode',
         },
         {
             title: '责任中心名',
-            ellipsis:true,
+            ellipsis: true,
+            width:120,
             dataIndex: 'responsibilityName',
         },
         {
             title: '会计科目名称',
-            ellipsis:true,
+            ellipsis: true,
             dataIndex: 'accountingNames',
         },
         {
             title: '会计科目编码',
-            ellipsis:true,
+            ellipsis: true,
             dataIndex: 'accountingCodes',
         },
         {
             title: '别名',
-            ellipsis:true,
+            ellipsis: true,
+            width:100,
             dataIndex: 'alias',
         },
         {
             title: '备注',
-            ellipsis:true,
+            ellipsis: true,
+            width:200,
             dataIndex: 'costNode',
         },
         {
             title: '操作',
             key: 'option',
-            width:200,
+            width: 200,
+            fixed:'right',
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [
-                    
-                    <a key='copy' onClick={()=>{set_tableSelecterVisible(true);setCurrentRow(record);}}>复制</a>,
+
+                    <a key='copy' onClick={() => { set_tableSelecterVisible(true); setCurrentRow(record); }}>复制</a>,
                     <UpDataActBtn key={'act'} record={record} type='EDIT' />,
                     <Popconfirm
                         title="是否确认删除?"
@@ -113,7 +119,7 @@ export default function AllocationParamsMap() {
                     >
                         <a>删除</a>
                     </Popconfirm>,
-                    <a key='share' onClick={()=>{set_editTableVisible(true);setCurrentRow(record)}}>分摊参数</a>
+                    <a key='share' onClick={() => { set_editTableVisible(true); setCurrentRow(record) }}>分摊参数</a>
 
                 ]
             },
@@ -147,7 +153,7 @@ export default function AllocationParamsMap() {
     }
 
     const delTableData = async (record: any) => {
-        const resp = await delData(record.id);
+        const resp = await delData([record.id]);
         if (resp) {
             message.success('操作成功!');
             tableRef.current?.reload();
@@ -156,39 +162,43 @@ export default function AllocationParamsMap() {
     }
 
     const updateTable = async (formVal: any, type: 'EDIT' | "ADD") => {
+        console.log({formVal});
+        try {
+            const result = {
+                responsibilityId: formVal.responsibilityId,
+                accountingIds: formVal.accountingIds.join(','),
+                isShareCost: formVal.isShareCost,
+                alias: formVal.alias,
+                costNode: formVal.costNode,
+                responsibilityName: formVal.responsibility?formVal.responsibility.responsibilityName:formVal.responsibilityName,
+                shareLevel: formVal.responsibility?formVal.responsibility.shareLevel:formVal.shareLevel,
+                responsibilityCode: formVal.responsibility?formVal.responsibility.responsibilityCode:formVal.responsibilityCode
+            };
+
+            if (type == 'ADD') {
+                const resp = await addData(result);
+                if (resp) {
+                    tableRef.current?.reload();
+                    message.success('操作成功!');
+                }
 
-        const result = {
-            responsibilityId: formVal.responsibilityId,
-            accountingIds: formVal.accountingIds.join(','),
-            isShareCost: formVal.isShareCost,
-            alias: formVal.alias,
-            costNode: formVal.costNode,
-            responsibilityName: formVal.responsibility.responsibilityName,
-            shareLevel: formVal.responsibility.shareLevel,
-            responsibilityCode: formVal.responsibility.responsibilityCode
-        };
-
-        if (type == 'ADD') {
-            const resp = await addData(result);
-            if (resp) {
-                tableRef.current?.reload();
-                message.success('操作成功!');
             }
+            if (type == 'EDIT') {
 
-        }
-        if (type == 'EDIT') {
 
-            try {
-                const resp = await editData({ ...formVal, isBaseCost: formVal.isBaseCost, isIncomeGroutSetSelect: false, isShareParamSelect: false, accountType });
+                const resp = await editData({...result,id:formVal.id});
                 if (resp) {
                     tableRef.current?.reload();
                     message.success('操作成功!');
                 }
-            } catch (error) {
-                console.log({ error });
+
+
             }
 
+        } catch (error) {
+            console.log({ error });
         }
+
         return true;
 
     }
@@ -198,7 +208,7 @@ export default function AllocationParamsMap() {
 
         const [ifDisable, setIfDisable] = useState(false);
         let needDisableIds: any[] = [];
-        let accountingIds:Key[] = [];
+        let accountingIds: Key[] = record.accountingIdList?record.accountingIdList.map((a:string)=>Number(a)):[];
 
         return (
             <ModalForm
@@ -207,17 +217,19 @@ export default function AllocationParamsMap() {
                 formRef={formRef}
                 initialValues={type == 'EDIT' ? {
                     ...record,
+                    accountings:record.accountingIdList?record.accountingIdList.map((a:string)=>Number(a)):[],
                 } : {}}
                 trigger={
                     type == 'EDIT' ? <a key="edit" >编辑</a> : <span className='add'>新增</span>
                 }
                 onFinish={(val) => {
-                    return updateTable(type == 'EDIT' ? { ...record, ...val,accountingIds } : { ...val,accountingIds }, type);
+                    return updateTable(type == 'EDIT' ? { ...record, ...val, accountingIds } : { ...val, accountingIds }, type);
                 }}
                 modalProps={{ destroyOnClose: true }}
                 colProps={{ span: 24 }}
                 grid
             >
+                <ProFormText name="responsibility" hidden />
                 <ProFormText name="responsibility" hidden />
                 <ProFormSelect
                     rules={[
@@ -230,18 +242,7 @@ export default function AllocationParamsMap() {
                         onChange: async (val, option: any) => {
                             const { } = option;
                             const resp = await getResponsibilityCenterSelecterList();
-                            // const resp = [
-                            //     {
-                            //         calcType: 1,
-                            //         id: 401,
-                            //         responsibilityCode: "B0100",
-                            //         responsibilityId: 401,
-                            //         responsibilityName: "公共费用",
-                            //         shareId: 59,
-                            //         shareLevel: 1,
-                            //         shareName: "公共费用",
-                            //     }
-                            // ]
+                
                             if (resp) {
                                 const selected = resp.filter((item: any) => item.id == val);
                                 if (selected[0]) {
@@ -297,30 +298,8 @@ export default function AllocationParamsMap() {
                         },
                     ]}
                     request={async () => {
-                        const resp = await getAccountingSubjectList({ accountType, pageSize: 500, current: 1 });
-
-                        // const resp = {
-                        //     list: [
-                        //         {
-                        //             accountingCode: "C0160",
-                        //             accountingName: "其他支出",
-                        //             id: 259,
-                        //             isBaseCost: 0,
-                        //             isIncomeGroutSetSelect: false,
-                        //             isShareParamSelect: false,
-                        //             children: [
-                        //                 {
-                        //                     accountingCode: "C0164",
-                        //                     accountingName: "社会服务辅助",
-                        //                     id: 263,
-                        //                     isBaseCost: 0,
-                        //                     isIncomeGroutSetSelect: false,
-                        //                     isShareParamSelect: false,
-                        //                 }
-                        //             ]
-                        //         }
-                        //     ]
-                        // };
+                        const resp = await getAccountingSubjectList({ accountType:2, pageSize: 500, current: 1 });
+
                         if (resp) {
                             return resp.list
                         }
@@ -329,24 +308,28 @@ export default function AllocationParamsMap() {
                     fieldProps={{
                         showSearch: true,
                         multiple: true,
-                        treeCheckable:true,
+                        maxTagCount:3,
+                        maxTagPlaceholder:'...',
+                        treeCheckable: true,
                         treeNodeFilterProp: 'accountingName',
-                        showCheckedStrategy:'SHOW_CHILD',
+                        showCheckedStrategy: 'SHOW_CHILD',
                         fieldNames: {
                             label: 'accountingName',
                             value: 'id'
                         },
-                        onSelect: (value, opt) => {
-                            // console.log({ value, opt });
-                            // console.log(getChilds(opt,'children'));
-                            if(opt.children&&opt.children.length>0){
-                                  const childs = getChilds(opt,'children');
-                                  const ids = childs.map((a)=>a.id);
-                                  accountingIds = accountingIds.concat(ids);
-                            }else{
-                                accountingIds.push(value);
-                            }
-                        }
+                        onChange(value, labelList, extra) {
+                            // console.log({value,labelList,extra});
+                            accountingIds = value;
+                        },
+                        // onSelect: (value, opt) => {
+                        //     console.log({ value, opt });
+                        //     // console.log(getChilds(opt,'children'));
+                        //     if (opt.children && opt.children.length > 0) {
+                        //         const childs = getChilds(opt, 'children');
+                        //         const ids = childs.map((a) => a.id);
+                        //         accountingIds = ids;
+                        //     }
+                        // }
                     }}
                     name="accountings"
                     label="选择会计科目"
@@ -379,19 +362,19 @@ export default function AllocationParamsMap() {
         )
     }
 
-    const shareParamsSetCommit = async (rows:any[])=>{
-          const resp = await saveParamsList({id:currentRow.id,shareParamProportionVOList:rows});
-          if(resp){
-               set_editTableVisible(false);
-               message.success('操作成功!');
-               tableRef.current?.reload();
-          }
+    const shareParamsSetCommit = async (rows: any[]) => {
+        const resp = await saveParamsList({ id: currentRow.id, shareParamProportionVOList: rows });
+        if (resp) {
+            set_editTableVisible(false);
+            message.success('操作成功!');
+            tableRef.current?.reload();
+        }
     }
 
-    const tableSelecterCommit = async (keys:Key[],rows:any) => {
+    const tableSelecterCommit = async (keys: Key[], rows: any) => {
         const { id } = currentRow;
         const resp = await copyParamsList({ id, responsibilityIds: keys });
-        if(resp){
+        if (resp) {
             set_tableSelecterVisible(false);
             message.success('操作成功!');
             tableRef.current?.reload();
@@ -423,7 +406,7 @@ export default function AllocationParamsMap() {
                         <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
                         <Input placeholder={'责任中心名称'} allowClear
                             suffix={
-                                <IconFont type="iconsousuo" style={{color:'#99A6BF'}} onClick={() => tableDataSearchHandle('name')} />
+                                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('name')} />
                             }
                             onChange={(e) => {
                                 set_tableDataSearchKeywords(e.target.value);
@@ -451,7 +434,7 @@ export default function AllocationParamsMap() {
             </div>
 
             <div>
-                <KCIMTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+                <KCIMTable scroll={{x:2000}} columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
             </div>
         </KCIMPagecontainer>
     )

+ 8 - 6
src/pages/baseSetting/costAllocationSet/allocationParamsMap/service.ts

@@ -2,13 +2,14 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 16:31:27
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-20 15:28:55
+ * @LastEditTime: 2023-12-07 20:53:36
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
 
 
 
+import { Key } from 'react';
 import { request } from 'umi';
 
 //获取table列表数据
@@ -59,7 +60,7 @@ export async function getParamsSelectableList(params:any) {
 export type AddTableDataType = any
 
 export const addData = (data:AddTableDataType) => {
-  return request('/costAccount/accounting/save', {
+  return request('/costAccount/costaccountshare/save', {
     method: 'POST',
     data:{...data}
   });
@@ -74,7 +75,7 @@ export type TableRowEditType = {
 }&AddTableDataType
 
 export const editData = (data:any) => {
-  return request('/costAccount/accounting/edit', {
+  return request('/costAccount/costaccountshare/update', {
     method: 'POST',
     data
   });
@@ -92,10 +93,11 @@ export const saveParamsList = (data:any) => {
 
 
 //删除表格操作
-export const delData = (id:string) => {
-  return request('/costAccount/accounting/delete', {
+export const delData = (ids:Key[]) => {
+  console.log({ids});
+  return request('/costAccount/costaccountshare/delete', {
     method: 'POST',
-    params:{id}
+    data:ids
   });
 };
 

+ 498 - 0
src/pages/baseSetting/costAllocationSet/costAllocationParamsDeal/index.tsx

@@ -0,0 +1,498 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 11:30:33
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-03-29 14:41:03
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import KCIMPagecontainer from '@/components/KCIMPageContainer';
+import { KCIMTable } from '@/components/KCIMTable';
+
+import { createFromIconfontCN } from '@ant-design/icons';
+
+
+import { ActionType, ProFormInstance, ProFormText, ProFormSelect, ProFormCascader, ProFormDigit, ProFormDatePicker } from '@ant-design/pro-components';
+import { ModalForm } from '@ant-design/pro-form'
+import { ProColumns } from '@ant-design/pro-table';
+import { Input, message, Popconfirm, Dropdown } from 'antd';
+import type { MenuProps } from 'antd';
+import { Key, useEffect, useRef, useState } from 'react';
+
+import 'moment/locale/zh-cn';
+import locale from 'antd/es/date-picker/locale/zh_CN';
+
+
+
+import { addData, calculateMonthCostShareData, copyMonthCostShareData, delData, editData, getMonthCostShareDataList } from './service';
+
+import './style.less';
+import moment from 'moment';
+import { getCostshareparamList } from '../costAllocationParamsSet/service';
+import { getResponsibilityCenterList } from '../../responsibilityCenterSet/responsibilityCenter/service';
+import { renameChildListToChildren } from '@/utils/tooljs';
+import { tableColumnsWidObj } from '@/constant';
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+const currentData = `${new Date().getFullYear()}-${(new Date().getMonth() + 1).toString().padStart(2, '0')}`;
+
+
+
+export default function CostAllocationParamsDeal(
+    { date, ifShowGetBtn, ifShowCancelBtn,responsibilityCode,
+        cancelHandle,getHandle
+     }: { date: string, ifShowGetBtn: boolean, ifShowCancelBtn: boolean,responsibilityCode:string,
+        cancelHandle: () => Promise<boolean>,
+        getHandle:() => Promise<boolean>,
+
+    }
+) {
+
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>({ computeDate: currentData });
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
+    const tableRef = useRef<ActionType>();
+    const formRef = useRef<ProFormInstance>();
+    const [computeDate, set_computeDate] = useState(currentData);
+    const [currentEditRow, set_currentEditRow] = useState<undefined | any>(undefined);
+
+
+    const columns: ProColumns[] = [
+        {
+            title: '分摊参数',
+            dataIndex: 'shareParamName',
+            renderText(text, record, index, action) {
+                const {shareParamCode,shareParamName} = record;
+                return `[${shareParamCode}]${shareParamName}`
+            },
+        },
+        {
+            title: '数值',
+            dataIndex: 'valueNum',
+            renderText(num, record, index, action) {
+                return (
+                    <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
+                        {
+                            (currentEditRow && currentEditRow.id == record.id) && (
+                                <>
+                                    <ProFormDigit
+                                        width={80}
+                                        noStyle
+                                        fieldProps={{
+                                            value: num,
+                                            onChange(value) {
+                                                set_currentEditRow({ ...record, valueNum: value ? value : 0 });
+                                            },
+                                        }}
+                                    />
+                                    <img onClick={() => updateTable({ ...record, ...currentEditRow }, 'EDIT')} style={{ width: 16, height: 16, display: 'inline-block', marginLeft: 8, cursor: 'pointer' }} src={require('../../../../../static/confirmIcon.png')} />
+                                </>
+                            )
+                        }
+
+                        {
+                            (!currentEditRow || (currentEditRow && currentEditRow.id != record.id)) && (
+                                <>
+                                    <div>{num}</div>
+                                    <img onClick={() => set_currentEditRow(record)} style={{ width: 16, height: 16, display: 'inline-block', marginLeft: 8, cursor: 'pointer' }} src={require('../../../../../static/editIcon.png')} />
+                                </>
+                            )
+                        }
+                    </div>
+                )
+            },
+        },
+        {
+            title: '责任中心',
+            dataIndex: 'responsibilityName',
+            renderText(text, record, index, action) {
+                const {responsibilityCode,responsibilityName} = record;
+                return `[${responsibilityCode}]${responsibilityName}`
+            },
+        },
+        
+        {
+            title: '操作',
+            key: 'option',
+            width: 90,
+            fixed: 'right',
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                return [
+                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
+                    <Popconfirm
+                        title="是否确认删除?"
+                        key="del"
+                        onConfirm={() => delTableData(record)}
+                    >
+                        <a>删除</a>
+                    </Popconfirm>
+                ]
+            },
+        },
+
+    ]
+
+    const items: MenuProps['items'] = [
+        {
+            key: '1',
+            label: (
+                <a onClick={()=>cancelHandle().then((isok)=>{
+                       if(isok)tableRef.current?.reload();
+                })} style={{ display: ifShowCancelBtn ? 'inline-block' : 'none' }}>
+                    撤销
+                </a>
+            ),
+        },
+        {
+            key: '2',
+            label: (
+                <a onClick={()=>getHandle().then((isok)=>{
+                    if(isok)tableRef.current?.reload();
+                })} style={{ display: ifShowGetBtn ? 'inline-block' : 'none' }}>
+                    获取
+                </a>
+            ),
+        },
+
+    ];
+
+
+    const getTableData = async (params: any) => {
+        const {computeDate,responsibilityCode} = params;
+        if(computeDate&&responsibilityCode){
+            const resp = await getMonthCostShareDataList({ ...params });
+            if (resp) {
+                return {
+                    data: resp.list,
+                    success: true,
+                    total: resp.totalCount,
+                    pageSize: resp.pageSize,
+                    totalPage: resp.totalPage,
+                }
+            }
+        }
+        return []
+    }
+
+
+    const delTableData = async (record: any) => {
+        const resp = await delData([record.id]);
+        if (resp) {
+            message.success('操作成功!');
+            tableRef.current?.reload();
+            // message.success('操作成功!');
+        }
+    }
+
+    const tableDataSearchHandle = (paramName: string) => {
+
+        set_tableDataFilterParams({
+            ...tableDataFilterParams,
+            [`${paramName}`]: tableDataSearchKeywords
+        })
+
+    }
+
+    const updateTable = async (formVal: any, type: 'EDIT' | "ADD" | "COPY") => {
+
+        const result = {
+            date: computeDate.replace('-', ''),
+            shareParamCode: formVal.shareParamCode,
+            valueNum: formVal.valueNum,
+        };
+
+        if (type == 'ADD') {
+            const resp = await addData({ ...result, responsibilityCode: formVal.responsibilityCode[formVal.responsibilityCode.length - 1] });
+            if (resp) {
+                tableRef.current?.reload();
+                message.success('操作成功!');
+            }
+
+        }
+        if (type == 'EDIT') {
+            try {
+                const resp = await editData({ ...result, id: formVal.id, responsibilityCode: typeof formVal.responsibilityCode == 'string' ? formVal.responsibilityCode : formVal.responsibilityCode[formVal.responsibilityCode.length - 1] });
+                if (resp) {
+                    tableRef.current?.reload();
+                    message.success('操作成功!');
+                }
+            } catch (error) {
+                console.log({ error });
+            }
+
+        }
+
+        if (type == 'COPY') {
+            const { dataSourceType, toDate, date: fromDate } = formVal;
+            const resp = await copyMonthCostShareData({ dataSourceType, toDate: moment(toDate).format('yyyyMM'), fromDate: moment(fromDate).format('yyyyMM') });
+            if (resp) {
+                tableRef.current?.reload();
+                message.success('操作成功!');
+            }
+        }
+        return true;
+
+    }
+
+    const calculateHandle = async () => {
+        const resp = await calculateMonthCostShareData({ date: computeDate.replace('-', '') });
+        if (resp) {
+            message.success('计算成功!');
+            tableRef?.current?.reload();
+        }
+    };
+
+    useEffect(() => {
+        console.log({date,responsibilityCode});
+        if (date&&responsibilityCode) {
+            set_computeDate(date);
+            set_tableDataFilterParams({
+                ...tableDataFilterParams,
+                computeDate: date,
+                responsibilityCode:responsibilityCode
+            });
+        }
+    }, [date,responsibilityCode])
+
+
+    const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD' | 'COPY' }) => {
+        return (
+            <ModalForm
+                title={`${type == 'EDIT' ? '编辑' : '新增'}成本分摊参数处理`}
+                width={350}
+                formRef={formRef}
+                initialValues={type == 'EDIT' ? {
+                    ...record,
+                } : {}}
+                trigger={
+                    type == 'EDIT' ? <a key="edit" >编辑</a> : type == 'COPY' ? <span>复制</span> : <span>新增</span>
+                }
+                onFinish={(val) => {
+                    return updateTable(type == 'EDIT' ? { ...record, ...val } : { ...val }, type);
+                }}
+                modalProps={{ destroyOnClose: true }}
+                colProps={{ span: 24 }}
+                grid
+            >
+
+                {
+                    type == 'COPY' && (
+                        <>
+                            <ProFormDatePicker
+                                name="date"
+                                width={318}
+                                rules={[
+                                    {
+                                        required: true,
+                                        message: '复制时间是必填项!',
+                                    },
+                                ]}
+                                label="复制数据年月"
+                                fieldProps={{ picker: 'month', locale: locale, format: 'YYYY-MM' }}
+                            />
+                            <ProFormDatePicker
+                                name="toDate"
+                                width={318}
+                                label="目标年月"
+                                rules={[
+                                    {
+                                        required: true,
+                                        message: '目标时间是必填项!',
+                                    },
+                                ]}
+                                fieldProps={{ picker: 'month', locale: locale, format: 'YYYY-MM' }}
+                            />
+                            <ProFormSelect
+                                options={[
+                                    {
+                                        value: 1,
+                                        label: '手动输入',
+                                    },
+                                    {
+                                        value: 2,
+                                        label: '文件导入',
+                                    },
+                                    {
+                                        value: 3,
+                                        label: '全部',
+                                    },
+                                ]}
+                                rules={[
+                                    {
+                                        required: true,
+                                        message: '数据类型是必填项!',
+                                    },
+                                ]}
+                                name="dataSourceType"
+                                label="数据类型"
+                            />
+                        </>
+                    )
+                }
+                {
+                    type != 'COPY' && (
+                        <>
+                            <ProFormSelect
+                                name="shareParamCode"
+                                label="选择分摊参数"
+                                request={async (params) => {
+                                    const resp = await getCostshareparamList({ ...params, pageSize: 500 });
+                                    if (resp) {
+                                        return resp.list.map((item: any) => ({ label: item.shareParamName, value: item.shareParamCode }))
+                                    }
+                                }}
+                                placeholder="请选择"
+                                rules={[{ required: true, message: '分摊参数是必选项!' }]}
+                            />
+                            <ProFormCascader
+                                label='责任中心'
+                                name='responsibilityCode'
+                                allowClear
+                                placeholder="请选择"
+                                request={async () => {
+                                    const resp = await getResponsibilityCenterList({ pageSize: 500 });
+                                    if (resp) {
+                                        return resp.list
+                                    }
+                                    return [];
+                                }}
+                                fieldProps={{
+                                    fieldNames: { label: 'responsibilityName', value: 'responsibilityCode', children: 'child', },
+                                }}
+                            />
+                            <ProFormDigit
+                                label="数值"
+                                name="valueNum"
+                                rules={[
+                                    {
+                                        required: true,
+                                        message: '必选项!',
+                                    },
+                                ]}
+                            />
+                        </>
+                    )
+                }
+
+            </ModalForm>
+        )
+    }
+
+    return (
+        <KCIMPagecontainer className='CostAllocationParamsDeal' title={false}>
+            <div className='toolBar'>
+                <div className='filter'>
+                    <div className='filterItem'>
+                        <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
+                        <Input placeholder={'分摊参数代码/名称'} allowClear
+                            suffix={
+                                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('shareParamCode')} />
+                            }
+                            onChange={(e) => {
+                                set_tableDataSearchKeywords(e.target.value);
+                                if (e.target.value.length == 0) {
+                                    set_tableDataFilterParams({
+                                        ...tableDataFilterParams,
+                                        shareParamCode: ''
+                                    });
+                                }
+                            }}
+                            onPressEnter={(e) => {
+
+                                set_tableDataFilterParams({
+                                    ...tableDataFilterParams,
+                                    shareParamCode: (e.target as HTMLInputElement).value
+                                });
+                            }}
+
+                        />
+                    </div>
+                    {/* <div className="filterItem">
+                        {
+                            <div className="search">
+                                <span>核算年月:</span>
+                                <DatePicker
+                                    onChange={(data, dateString) => {
+                                        set_computeDate(dateString);
+                                        set_tableDataFilterParams({
+                                            ...tableDataFilterParams,
+                                            computeDate: dateString,
+                                        });
+                                    }}
+                                    picker="month"
+                                    locale={locale}
+                                    defaultValue={moment(`${new Date().getFullYear()}-${(new Date().getMonth() + 1).toString().padStart(2, '0')}`, 'YYYY-MM')}
+                                    format="YYYY-MM"
+                                    placeholder="选择年月"
+                                />
+                            </div>
+                        }
+                    </div>
+                    <div className='filterItem' style={{ marginLeft: 16 }}>
+                        <span className='label'>分摊参数:</span>
+                        <ProFormSelect
+                            noStyle
+                            allowClear
+                            placeholder="请选择"
+                            style={{ width: 160, marginRight: 16 }}
+                            request={async (params) => {
+                                const resp = await getCostshareparamList({ ...params, pageSize: 500 });
+                                if (resp) return resp.list.map((item: any) => ({ label: item.shareParamName, value: item.shareParamCode }))
+                                return [];
+                            }}
+                            fieldProps={{
+                                onChange(value, option) {
+                                    set_tableDataFilterParams({ ...tableDataFilterParams, shareParamCode: value })
+                                },
+                            }}
+                        />
+                    </div>
+                    <div className='filterItem' style={{ marginLeft: 16 }}>
+                        <span className='label'>责任中心:</span>
+                        <ProFormCascader
+                            noStyle
+                            allowClear
+                            placeholder="请选择"
+                            request={async () => {
+                                const resp = await getResponsibilityCenterList({ pageSize: 500 });
+                                if (resp) {
+                                    return resp.list
+                                }
+                                return [];
+                            }}
+                            fieldProps={{
+                                fieldNames: { label: 'responsibilityName', value: 'responsibilityCode', children: 'child', },
+                                onChange(value: any, option: any) {
+                                    set_tableDataFilterParams({ ...tableDataFilterParams, responsibilityCode: value ? value[value.length - 1] : '' })
+                                },
+                            }}
+                        />
+                    </div> */}
+                </div>
+                <div className='btnGroup'>
+                    <UpDataActBtn record type='COPY' />
+                    <span onClick={() => calculateHandle()}>计算</span>
+                    <UpDataActBtn record type='ADD' />
+                    {
+                        (ifShowCancelBtn && ifShowGetBtn) && (
+                            <Dropdown menu={{ items }} placement="bottomRight">
+                                <IconFont type="icongengduochuizhi" />
+                            </Dropdown>
+                        )
+                    }
+                </div>
+            </div>
+
+            <div>
+                <KCIMTable  columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+            </div>
+        </KCIMPagecontainer>
+    )
+}

+ 92 - 0
src/pages/baseSetting/costAllocationSet/costAllocationParamsDeal/service.ts

@@ -0,0 +1,92 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 16:31:27
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2023-12-05 15:03:16
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import { Key } from 'react';
+import { request } from 'umi';
+
+//获月成本分摊参数值处理列表
+export const getMonthCostShareDataList = (params:any) => {
+  return request('/costAccount/shareParamValue/list', {
+    method: 'GET',
+    params: {...params,date:params.computeDate.replace('-',''),computeDate:null},
+  });
+}
+
+
+
+//新增
+export type AddTableDataType = {
+  date:string,
+  shareParamCode:string,
+  responsibilityCode:string,
+  valueNum:number
+}
+
+export const addData = (data:AddTableDataType) => {
+  return request('/costAccount/shareParamValue/addData', {
+    method: 'POST',
+    data:{...data}
+  });
+};
+
+
+
+//编辑表格数据
+
+export type TableRowEditType = {
+  id:number;
+}&AddTableDataType
+
+export const editData = (data:any) => {
+  return request('/costAccount/shareParamValue/edit', {
+    method: 'POST',
+    data
+  });
+};
+
+//删除表格操作
+export const delData = (ids:Key[]) => {
+  return request('/costAccount/shareParamValue/delete', {
+    method: 'POST',
+    data:ids
+  });
+};
+
+//计算数据
+export const calculateMonthCostShareData = (params:any) => {
+  return request('/costAccount/shareParamValue/calcData', {
+    method: 'POST',
+    params: {...params},
+  });
+}
+
+//复制数据
+export const copyMonthCostShareData = (body:any) => {
+  return request('/costAccount/shareParamValue/copyData', {
+    method: 'POST',
+    data: {...body},
+  });
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 28 - 10
src/pages/costAccounting/unitPersonnelCostCalc/style.less → src/pages/baseSetting/costAllocationSet/costAllocationParamsDeal/style.less

@@ -1,8 +1,5 @@
-
-
-.unitPersonnelCostCalc {
-  position: relative;
-  padding: 16px;
+.CostAllocationParamsDeal {
+  // padding: 16px;
   background: #FFFFFF;
   border-radius: 4px;
 
@@ -12,6 +9,7 @@
     flex-direction: row;
     justify-content: space-between;
     align-items: center;
+    margin-bottom: 16px;
 
     .filter {
       display: flex;
@@ -28,12 +26,10 @@
     }
 
     .btnGroup {
-      
-      .calc {
+      .add {
         cursor: pointer;
         display: inline-block;
         font-size: 14px;
-        font-family: SourceHanSansCN-Normal, SourceHanSansCN;
         font-weight: 400;
         color: #FFFFFF;
         line-height: 24px;
@@ -41,7 +37,29 @@
         background: #3377FF;
         border-radius: 4px;
       }
-    }
 
+      &>span {
+        cursor: pointer;
+        display: inline-block;
+        font-size: 14px;
+        font-weight: 400;
+        color: #17181A;
+        line-height: 24px;
+        padding: 0 14px;
+        background: #FAFCFF;
+        border-radius: 4px;
+        margin-right: 8px;
+        border-radius: 4px;
+        border: 1px solid #DAE2F2;
+
+        &:last-child {
+          position: relative;
+          top:-2px;
+          padding: 0 4px;
+          margin-right: 0;
+          
+        }
+      }
+    }
   }
-}
+}

+ 14 - 3
src/pages/baseSetting/costAllocationSet/costAllocationParamsSet/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-16 17:39:17
+ * @LastEditTime: 2024-01-05 13:46:21
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -72,15 +72,17 @@ export default function CostAllocationParamsSet() {
             title: '计算方式',
             dataIndex: 'calcType',
             renderText(text, record) {
-                return text.calcType == 1 ? '手动填写' : '按对应会计科目计算'
+                return text == 1 ? '手动填写' : '按对应会计科目计算'
             },
         },
         {
             title: '操作',
             key: 'option',
+            width:160,
             valueType: 'option',
             render: (_: any, record: any) => {
-                return [
+                const {calcType} = record;
+                return calcType != 1?[
                     <UpDataActBtn key={'act'} record={record} type='EDIT' />,
                     <Popconfirm
                         title="是否确认删除?"
@@ -90,6 +92,15 @@ export default function CostAllocationParamsSet() {
                         <a>删除</a>
                     </Popconfirm>,
                     <a key={'bind'} onClick={() => {oprnTableTransform(record)}}>会计科目</a>
+                ]:[
+                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
+                    <Popconfirm
+                        title="是否确认删除?"
+                        key="del"
+                        onConfirm={() => delTableData(record)}
+                    >
+                        <a>删除</a>
+                    </Popconfirm>
                 ]
             },
         },

+ 4 - 4
src/pages/baseSetting/costAllocationSet/costAllocationParamsSet/transform.tsx

@@ -24,9 +24,9 @@ interface TableTransferProps extends TransferProps<TransferItem> {
 const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, keyName, record, onSave, ...restProps }: TableTransferProps, ref) => {
     
     const [_data, _set_data] = useState<any>();
-    const [targetKeys, setTargetKeys] = useState<string[]>([]);
+    const [targetKeys, setTargetKeys] = useState<string[]>(record.accountingIds?[...((record.accountingIds).map((a:string)=>Number(a)))]:[]);
     const [datasource, set_datasource] = useState<any[]>([]);
-    const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
+    const [selectedKeys, setSelectedKeys] = useState<string[]>(record.accountingIds?[...((record.accountingIds).map((a:string)=>Number(a)))]:[]);
     const [accountType, set_accountType] = useState(1);
     const [tabs, set_tabs] = useState<any[]>([]);
 
@@ -40,7 +40,6 @@ const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, keyName, re
 
             set_datasource(resp.list);
             _set_data(resp.list);
-            // setTargetKeys(accountingIds);
         }
 
     }
@@ -108,7 +107,7 @@ const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, keyName, re
                 targetKeys={targetKeys}
                 selectedKeys={selectedKeys}
                 filterOption={(inputValue, item) => {
-                    return item.name!.indexOf(inputValue) !== -1
+                    return item.accountingName!.indexOf(inputValue) !== -1
 
                 }}
             >
@@ -147,6 +146,7 @@ const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, keyName, re
                             size="small"
                             bordered={false}
                             rowKey={keyName}
+                            scroll={{y:280}}
                             pagination={{ showTitle: false, pageSize: 9, showLessItems: false, simple: true, showTotal: () => false }}
                             tableAlertRender={false}
                             style={{ pointerEvents: listDisabled ? 'none' : undefined }}

+ 389 - 0
src/pages/baseSetting/costAllocationSet/idleCostSetting/index.tsx

@@ -0,0 +1,389 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 11:30:33
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-04-09 13:36:13
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import KCIMPagecontainer from '@/components/KCIMPageContainer';
+import { KCIMTable } from '@/components/KCIMTable';
+
+import { createFromIconfontCN } from '@ant-design/icons';
+
+
+import { ActionType, ProFormDependency, ProFormInstance, ProFormText, ProFormSelect, ProFormDigit } from '@ant-design/pro-components';
+import { ModalForm, ProFormCascader } from '@ant-design/pro-form'
+import { ProColumns } from '@ant-design/pro-table';
+import { Input, message, Popconfirm, Form, Select } from 'antd';
+import { Key, useEffect, useRef, useState } from 'react';
+
+import 'moment/locale/zh-cn';
+import locale from 'antd/es/date-picker/locale/zh_CN';
+
+
+
+import { addData, delData, editData, getAccountList, getIdleCostTableList, getShareParamList } from './service';
+
+import './style.less';
+import { getAccountingSubjectList } from '../../accountingAccountSet/accountingSubMana/service';
+import { getCostshareparamList } from '../costAllocationParamsSet/service';
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+function filterTree(trees: any[]) {
+    // 递归筛选函数
+    function filterNode(node: any) {
+        // 如果是叶子节点,直接根据条件返回节点或null
+        if (!node.children || node.children.length === 0) {
+            return node.isBaseCost === 1 ? { ...node } : null;
+        }
+
+        // 对于非叶子节点,先递归筛选子节点
+        const filteredChildren = node.children.map(filterNode).filter((child: any) => child !== null);
+
+        // 如果子节点中有被保留的,或者当前节点自身满足条件,保留当前节点
+        // 注意这里的改变:我们不再检查非叶子节点是否直接满足条件,而是基于其子节点是否被保留
+        if (filteredChildren.length > 0) {
+            return { ...node, children: filteredChildren };
+        } else {
+            // 如果没有子节点被保留,且当前节点不满足条件,返回null
+            return null;
+        }
+    }
+
+    // 遍历树结构集合并应用筛选函数
+    return trees.map(filterNode).filter(root => root !== null);
+}
+
+
+
+
+
+export default function IdleCostSetting() {
+
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>({ accountType: 1 });
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
+    const tableRef = useRef<ActionType>();
+    const formRef = useRef<ProFormInstance>();
+    const [currentRow, setCurrentRow] = useState<any | undefined>(undefined);
+    const [selectableLevelList, setSelectableLevelList] = useState<any[]>([]);//可选的分摊层级列表
+
+    const columns: ProColumns[] = [
+
+        {
+            title: '闲置成本项目',
+            dataIndex: 'freeAccountName',
+        },
+        {
+            title: '设备成本项目',
+            dataIndex: 'accountName',
+        },
+        {
+            title: '可检查时间参数',
+            dataIndex: 'canParamName',
+        },
+        {
+            title: '实际检查时间参数',
+            dataIndex: 'actualParamName',
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 90,
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                return [
+                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
+                    <Popconfirm
+                        title="是否确认删除?"
+                        key="del"
+                        onConfirm={() => delTableData(record)}
+                    >
+                        <a>删除</a>
+                    </Popconfirm>,
+                ]
+            },
+        },
+
+    ]
+
+
+    const getTableData = async (params: any) => {
+        const resp = await getIdleCostTableList({ ...params });
+        if (resp) {
+            return {
+                data: resp,
+                success: true,
+                // total: resp.totalCount,
+                // pageSize: resp.pageSize,
+                // totalPage: resp.totalPage,
+            }
+        }
+        return []
+    }
+
+
+    const tableDataSearchHandle = (paramName: string) => {
+
+        set_tableDataFilterParams({
+            ...tableDataFilterParams,
+            [`${paramName}`]: tableDataSearchKeywords
+        })
+
+    }
+
+    const delTableData = async (record: any) => {
+        const resp = await delData(record.id);
+        if (resp) {
+            message.success('操作成功!');
+            tableRef.current?.reload();
+            // message.success('操作成功!');
+        }
+    }
+
+    const updateTable = async (formVal: any, type: 'EDIT' | "ADD") => {
+    
+        const { freeAccount = [], account, canParam, actualParam } = formVal;
+            const result = {
+                freeAccountCode: freeAccount.accountingCode,
+                freeAccountName: freeAccount.accountingName,
+                accountCode: account.accountingCode,
+                accountName: account.accountingName,
+                canParamCode: canParam.shareParamCode,
+                canParamName: canParam.shareParamName,
+                actualParamCode: actualParam.shareParamCode,
+                actualParamName: actualParam.shareParamName,
+            };
+
+        if (type == 'ADD') {
+            const resp = await addData(result);
+            if (resp) {
+                tableRef.current?.reload();
+                message.success('操作成功!');
+            }
+
+        }
+        if (type == 'EDIT') {
+            try {
+                const { id } = formVal;
+                const resp = await editData({ ...result,id});
+                if (resp) {
+                    tableRef.current?.reload();
+                    message.success('操作成功!');
+                }
+            } catch (error) {
+                console.log({ error });
+            }
+
+        }
+        return true;
+
+    }
+
+
+    const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD' }) => {
+        setCurrentRow(record);
+        return (
+            <ModalForm
+                title={`${type == 'EDIT' ? '编辑' : '新增'}闲置成本对应`}
+                width={350}
+                formRef={formRef}
+                initialValues={type == 'EDIT' ? {
+                    ...record,
+                    freeAccount:record.freeAccountCode,
+                    account:record.accountCode,
+                    canParam: record.canParamCode,
+                    actualParam: record.actualParamCode
+                } : {}}
+                trigger={
+                    type == 'EDIT' ? <a key="edit" >编辑</a> : <span className='add'>新增</span>
+                }
+                onFinish={(val) => {
+                    return updateTable(type == 'EDIT' ? { ...record, ...val } : { ...val }, type);
+                }}
+                modalProps={{ destroyOnClose: true }}
+                colProps={{ span: 24 }}
+                grid
+            >
+                {/* <ProFormText name='freeAccount' hidden />
+                <ProFormText name='account' hidden /> */}
+                {/* <ProFormCascader
+                    rules={[
+                        {
+                            required: true,
+                            message: '请选择闲置成本项目',
+                        },
+                    ]}
+                    request={async ()=>{
+                         const resp = await getAccountList({accountType: 2,pageSize:500,current:1});
+                         return filterTree(resp.list)
+                    }}
+
+                    fieldProps={{
+                        // searchValue:'accountingName',
+                        showSearch:true,
+                        fieldNames:{label:'accountingName',value:'accountingCode',children:'children'},
+                        onChange:(value:any, selectedOptions:any)=>{
+                            formRef.current?.setFieldValue('freeAccount',selectedOptions)
+                        }
+                    }}
+                    name='freeCostItem'
+                    label="闲置成本项目"
+                />
+                <ProFormCascader
+                    rules={[
+                        {
+                            required: true,
+                            message: '请选择设备成本项目',
+                        },
+                    ]}
+                    request={async ()=>{
+                         const resp = await getAccountingSubjectList({accountType: 2,pageSize:500,current:1});
+                         return filterTree(resp.list)
+                    }}
+                
+                    fieldProps={{
+                        showSearch:true,
+                        fieldNames:{label:'accountingName',value:'accountingCode',children:'children'},
+                        onChange:(value:any, selectedOptions:any)=>{
+                            formRef.current?.setFieldValue('account',selectedOptions)
+                        }
+                    }}
+                    name='equipmentCostItem'
+                    label="设备成本项目"
+                /> */}
+                <ProFormSelect
+                    rules={[
+                        {
+                            required: true,
+                            message: '请选择闲置成本项目',
+                        },
+                    ]}
+                    request={async () => {
+                        const resp = await getAccountList({ pageSize: 500, current: 1 });
+                        return resp
+                    }}
+
+                    fieldProps={{
+                        labelInValue: true,
+                        showSearch: true,
+                        fieldNames: { label: 'accountingName', value: 'accountingCode' },
+                    }}
+                    name="freeAccount"
+                    label="闲置成本项目"
+                />
+                <ProFormSelect
+                    rules={[
+                        {
+                            required: true,
+                            message: '请选择设备成本项目',
+                        },
+                    ]}
+                    request={async () => {
+                        const resp = await getAccountList({ pageSize: 500, current: 1 });
+                        return resp
+                    }}
+
+                    fieldProps={{
+                        labelInValue: true,
+                        showSearch: true,
+                        fieldNames: { label: 'accountingName', value: 'accountingCode' },
+                    }}
+                    name="account"
+                    label="设备成本项目"
+                />
+                <ProFormSelect
+                    rules={[
+                        {
+                            required: true,
+                            message: '请选择可检查时间参数',
+                        },
+                    ]}
+                    request={async () => {
+                        const resp = await getShareParamList({ pageSize: 500, current: 1 });
+                        return resp
+                    }}
+
+                    fieldProps={{
+                        labelInValue: true,
+                        showSearch: true,
+                        fieldNames: { label: 'shareParamName', value: 'shareParamCode' },
+                    }}
+                    name="canParam"
+                    label="可检查时间参数"
+                />
+                <ProFormSelect
+                    rules={[
+                        {
+                            required: true,
+                            message: '请选择实际检查时间参数',
+                        },
+                    ]}
+                    request={async () => {
+                        const resp = await getShareParamList({ pageSize: 500, current: 1 });
+                        return resp
+                    }}
+
+                    fieldProps={{
+                        labelInValue: true,
+                        showSearch: true,
+                        fieldNames: { label: 'shareParamName', value: 'shareParamCode' },
+                    }}
+                    name="actualParam"
+                    label="实际检查时间参数"
+                />
+
+            </ModalForm>
+        )
+    }
+
+
+    return (
+        <KCIMPagecontainer className='IdleCostSetting' title={false}>
+            <div className='toolBar'>
+                <div className='filter'>
+                    <div className='filterItem'>
+                        <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
+                        <Input placeholder={'闲置成本项目编码/名称'} allowClear
+                            suffix={
+                                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('filter')} />
+                            }
+                            onChange={(e) => {
+                                set_tableDataSearchKeywords(e.target.value);
+                                if (e.target.value.length == 0) {
+                                    set_tableDataFilterParams({
+                                        ...tableDataFilterParams,
+                                        filter: ''
+                                    });
+                                }
+                            }}
+                            onPressEnter={(e) => {
+
+                                set_tableDataFilterParams({
+                                    ...tableDataFilterParams,
+                                    filter: (e.target as HTMLInputElement).value
+                                });
+                            }}
+
+                        />
+                    </div>
+                </div>
+                <div className='btnGroup'>
+                    <UpDataActBtn record type='ADD' />
+                </div>
+            </div>
+
+            <div>
+                <KCIMTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+            </div>
+        </KCIMPagecontainer>
+    )
+}

+ 96 - 0
src/pages/baseSetting/costAllocationSet/idleCostSetting/service.ts

@@ -0,0 +1,96 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 16:31:27
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-04-07 15:31:38
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import { Key } from 'react';
+import { request } from 'umi';
+
+//获取table列表数据
+export const getIdleCostTableList = (params:any) => {
+  return request('/costAccount/freeCost/getList', {
+    method: 'GET',
+    params:{...params},
+  });
+}
+
+
+//获取会计科目
+export const getAccountList = (params:any) => {
+  return request('/costAccount/freeCost/getAccountList', {
+    method: 'GET',
+    params:{...params},
+  });
+}
+
+//获取分摊参数
+export const getShareParamList = (params:any) => {
+  return request('/costAccount/freeCost/getShareParamList', {
+    method: 'GET',
+    params:{...params},
+  });
+}
+
+
+
+//新增
+export type AddTableDataType = {
+  "freeAccountCode":string, //闲置成本代码
+  "freeAccountName":string, //闲置成本名称
+  "accountCode":string, //成本代码
+  "accountName": string, //成本名称
+  "canParamCode": string, //可检查时间参数代码
+  "canParamName":string, //可检查时间参数名称
+  "actualParamCode": string, //实际检查时间参数代码
+  "actualParamName": string //实际检查时间参数名称
+}
+
+export const addData = (data:AddTableDataType) => {
+  return request('/costAccount/freeCost/addFreeCost', {
+    method: 'POST',
+    data:{...data}
+  });
+};
+
+
+
+//编辑表格数据
+
+export type TableRowEditType = {
+  id:number;
+}&AddTableDataType
+
+export const editData = (data:any) => {
+  return request('/costAccount/freeCost/editFreeCost', {
+    method: 'POST',
+    data
+  });
+};
+
+//删除表格操作
+export const delData = (id:number) => {
+  return request('/costAccount/freeCost/deleteFreeCost', {
+    method: 'POST',
+    params:{id}
+  });
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 13 - 18
src/pages/costAccounting/chargeItemCostCalc/style.less → src/pages/baseSetting/costAllocationSet/idleCostSetting/style.less

@@ -1,7 +1,4 @@
-
-
-.chargeItemCostCalc {
-  position: relative;
+.IdleCostSetting {
   padding: 16px;
   background: #FFFFFF;
   border-radius: 4px;
@@ -12,6 +9,7 @@
     flex-direction: row;
     justify-content: space-between;
     align-items: center;
+    margin-bottom: 16px;
 
     .filter {
       display: flex;
@@ -28,20 +26,17 @@
     }
 
     .btnGroup {
-      
-      .calc {
-        cursor: pointer;
-        display: inline-block;
-        font-size: 14px;
-        font-family: SourceHanSansCN-Normal, SourceHanSansCN;
-        font-weight: 400;
-        color: #FFFFFF;
-        line-height: 24px;
-        padding: 0 14px;
-        background: #3377FF;
-        border-radius: 4px;
-      }
+        .add {
+          cursor: pointer;
+          display: inline-block;
+          font-size: 14px;
+          font-weight: 400;
+          color: #FFFFFF;
+          line-height: 24px;
+          padding: 0 14px;
+          background: #3377FF;
+          border-radius: 4px;
+        }
     }
-
   }
 }

+ 2 - 2
src/pages/baseSetting/costAllocationSet/revenueImputationSet/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-20 17:35:21
+ * @LastEditTime: 2023-12-21 17:11:20
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -220,7 +220,7 @@ export default function AccountingSubMana() {
 
         return (
             <ModalForm
-                title={`${type == 'EDIT' ? '编辑' : '新增'}会计科目`}
+                title={`${type == 'EDIT' ? '编辑' : '新增'}收入归集设置`}
                 width={350}
                 formRef={formRef}
                 initialValues={type == 'EDIT' ? {

+ 433 - 0
src/pages/baseSetting/otherItemSet/diySqlMana/index.tsx

@@ -0,0 +1,433 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 11:30:33
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-03-22 11:34:26
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+
+
+
+import KCIMPagecontainer from '@/components/KCIMPageContainer';
+import { KCIMTable } from '@/components/KCIMTable';
+import SQLEditor from '@/components/SQLEditor';
+import { createFromIconfontCN } from '@ant-design/icons';
+
+import { ActionType, arrayMoveImmutable, ProFormText, ProFormTextArea, useRefFunction } from '@ant-design/pro-components';
+import { ModalForm, ProFormDependency, ProFormDigit, ProFormSelect } from '@ant-design/pro-form'
+import { ProColumns } from '@ant-design/pro-table';
+import { Input, message, Popconfirm,Switch } from 'antd';
+import { useEffect, useRef, useState } from 'react';
+import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
+
+
+import { addData, delData, editData, getSqlListTableData, getSqlTypeList, updateTableSort } from './service';
+
+import './style.less';
+
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+export default function DiySqlMana() {
+
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
+    const [dataSource, set_dataSource] = useState<any[]>([]);
+    const [showList,set_showList] = useState<any[]>([]);
+
+    const SortableItem = SortableElement((props: any) => <tr {...props} />);
+    const SortContainer = SortableContainer((props: any) => <tbody {...props} />);
+
+    const [typeList, set_typeList] = useState<any[]>([]);
+    const [showTypeListArr, set_showTypeListArr] = useState<any[]>([]);
+    const [currentSelectedType, set_currentSelectedType] = useState<any | undefined>(undefined);
+
+    const DragHandle = SortableHandle(() => <img width={16} style={{ cursor: 'pointer' }} src={require('../../../../../static/tuozhuai_icon.png')} alt="" />);
+
+    const tableRef = useRef<ActionType>();
+
+    const columns: ProColumns[] = [
+        {
+            dataIndex: 'sort',
+            width: 50,
+            className: 'drag-visible',
+            render: () => <DragHandle />
+        },
+        {
+            title: 'SQL代码',
+            width:150,
+            ellipsis: true,
+            dataIndex: 'sqlCode',
+        },
+        {
+            title: 'SQL语句',
+            ellipsis: true,
+            dataIndex: 'sql',
+        },
+        {
+            title: 'SQL说明',
+            ellipsis: true,
+            dataIndex: 'sqlDefinition',
+            // render:(_:any)=>_ == 1?'指标':'自定义SQL'
+        },
+        {
+            title: '启用',
+            width:80,
+            dataIndex: 'status',
+            renderText: (_: any, record: any) => {
+
+                return <Switch size='small' checked={_?true:false} onChange={(bool) => switchChangeHandle(bool, record, 'status')} />
+            }
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 120,
+            fixed:'right',
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                return [
+                    <UpDataActBtn key={'act'} record={record} type='ADD_NEXT' />,
+                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
+                    <Popconfirm
+                        title="是否确认删除?"
+                        key="del"
+                        onConfirm={() => delTableData(record)}
+                    >
+                        <a>删除</a>
+                    </Popconfirm>
+                ]
+            },
+        },
+
+    ]
+
+
+    const getTableData = async (params: any) => {
+        const resp = await getSqlListTableData(params);
+        if (resp) {
+            set_dataSource(resp);
+            set_showList(resp);
+        }
+    }
+
+    const delTableData = async (record: any) => {
+        const resp = await delData(record.id);
+        if (resp) {
+            message.success('操作成功!');
+            getTableData({sqlType:currentSelectedType.code});
+            // message.success('操作成功!');
+        }
+    }
+
+    const switchChangeHandle = (checked: boolean, record: any, key: string) => {
+
+        const newData = dataSource.map((a: any) => {
+            if (a.id == record.id) {
+                return { ...a, [`${key}`]: checked ? 1 : 0 }
+            }
+            return a
+        });
+
+        set_dataSource([...newData]);
+        updateTable({...record, [`${key}`]: checked ? 1 : 0 }, 'EDIT')
+    }
+
+    const updateTable = async (formVal: any, type: 'EDIT' |'ADD'|'ADD_NEXT') => {
+
+        if (type == 'ADD') {
+            const resp = await addData({
+                sqlCode: formVal.sqlCode,
+                sql: formVal.sql,
+                sqlDefinition: formVal.sqlDefinition,
+                sqlType:currentSelectedType.code,
+                sort:dataSource.length + 1,
+                status:1
+            });
+            if (resp) {
+                
+                getTableData({sqlType:currentSelectedType.code});
+                message.success('操作成功!');
+            }
+
+        }
+        if (type == 'ADD_NEXT') {
+            const {sort} = formVal;
+
+            const temp = [...dataSource];
+
+            const index = temp.findIndex(a=>a.sort == sort);
+
+            const objectToInsert =  {
+                sqlCode: formVal.sqlCode,
+                sql: formVal.sql,
+                sqlDefinition: formVal.sqlDefinition,
+                sqlType:currentSelectedType.code,
+                status:1
+            }
+        
+            temp.splice(index+1,0, objectToInsert);
+            const arr = temp.map((a,index)=>({...a,sort:index+1}));
+  
+            updateTableSortHandle(arr);
+
+
+        }
+        if (type == 'EDIT') {
+
+            const resp = await editData({
+                id: formVal.id,
+                sql: formVal.sql,
+                sqlDefinition: formVal.sqlDefinition,
+                sqlType: formVal.sqlType,
+                sort: formVal.sort,
+                status:formVal.status
+            });
+            if (resp) {
+                getTableData({sqlType:currentSelectedType.code});
+                message.success('操作成功!');
+            }
+        }
+        return true;
+
+    }
+
+    const formRef = useRef();
+
+    const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD'|'ADD_NEXT' }) => {
+
+        return (
+            <ModalForm
+                title={`${type == 'EDIT' ? '编辑' : type == 'ADD_NEXT'?'插入':'新增'}自定义SQL`}
+                width={880}
+                formRef={formRef}
+                initialValues={type == 'EDIT' ? { ...record } : {}}
+                trigger={
+                    type == 'EDIT' ? <a key="edit" >编辑</a> :type == 'ADD_NEXT'?<a>插入</a>: <span className='add'>新增</span>
+                }
+                onFinish={(val) => {
+                    return updateTable(type == 'EDIT' ? { ...record, ...val } : type =='ADD_NEXT'?{...record, ...val}: { ...val }, type);
+                }}
+                modalProps={{ destroyOnClose: true }}
+                colProps={{ span: 24 }}
+                grid
+            >
+                <div className='formContent' style={{ display: 'flex', flexDirection: 'row', alignContent: 'flex-start' }}>
+                    <div className='left' style={{ width: 240, marginRight: 16 }}>
+                        {
+                            type != 'EDIT' && (
+                                <ProFormText
+                                    name="sqlCode"
+                                    label="SQL代码:"
+                                    placeholder="请输入"
+                                    rules={[{ required: true, message: 'SQL代码不能为空!' }]}
+                                />
+                            )
+                        }
+                        <ProFormTextArea placeholder="请输入" name={'sqlDefinition'} label='SQL说明:' rules={[{ required: true, message: '说明不能为空!' }]} />
+                    </div>
+                    <div className='right' style={{ width: 'calc(880px - 288px)' }}>
+                        {/* <ProFormTextArea placeholder="请输入" name={'sql'} label='SQL语句:' rules={[{ required: true, message: 'SQL不能为空!' }]} /> */}
+                        <SQLEditor
+                            name="sql"
+                            label="SQL语句:"
+                            rules={[{ required: true, message: 'SQL不能为空!' }]}
+                            form={formRef}
+                            height={'230px'}
+                        />
+                    </div>
+                </div>
+            </ModalForm>
+        )
+    }
+
+    const tableDataSearchHandle = (key:string) => {
+        const result = dataSource.filter((a)=>a.sqlDefinition.indexOf(tableDataSearchKeywords) != -1);
+        set_showList(result);
+    }
+
+    const getSqlTypeRequest = async () => {
+        const resp = await getSqlTypeList();
+        if (resp) {
+            set_typeList(resp);
+            set_showTypeListArr(resp);
+        }
+    }
+
+    const updateTableSortHandle = async (data:any[]) => {
+          const resp = await updateTableSort(data);
+          if(resp){
+            getTableData({sqlType:currentSelectedType.code});
+          }
+    }
+
+    const onSortEnd = useRefFunction(
+        ({ oldIndex, newIndex }: { oldIndex: number; newIndex: number }) => {
+            if (oldIndex !== newIndex) {
+                const newData = arrayMoveImmutable({
+                    array: [...dataSource],
+                    fromIndex: oldIndex,
+                    toIndex: newIndex,
+                }).filter((el) => !!el);
+
+                const updatedSortArr = newData.map((item: any, index: number) => ({ ...item, sort: index+1 }))
+                set_dataSource([...updatedSortArr]);
+                updateTableSortHandle(updatedSortArr);
+            }
+        },
+    );
+
+    const DraggableContainer = (props: any) => (
+        <SortContainer
+            useDragHandle
+            disableAutoscroll
+            helperClass="row-dragging"
+            onSortEnd={onSortEnd}
+            {...props}
+        />
+    );
+
+    const DraggableBodyRow = (props: any) => {
+        const { className, style, ...restProps } = props;
+
+        // function findIndex base on Table rowKey props and should always be a right array index
+        const index = dataSource.findIndex((x) => x.id === restProps['data-row-key']);
+
+        return <SortableItem index={index} {...restProps} />;
+    };
+
+    
+    useEffect(()=>{
+         if(showTypeListArr.length>0){
+              set_currentSelectedType(showTypeListArr[0]);
+         }
+    },[showTypeListArr]);
+
+    useEffect(()=>{
+           if(currentSelectedType){
+               getTableData({sqlType:currentSelectedType.code});
+           }
+    },[currentSelectedType]);
+
+
+    useEffect(() => {
+        getSqlTypeRequest();
+    }, [])
+
+    return (
+        <KCIMPagecontainer className='DiySqlMana' title={false}>
+            {/* <div className='toolBar'>
+                <div className='filter'>
+                    <div className='filterItem'>
+                        <span className='label'>检索:</span>
+                        <ProFormSelect
+                            noStyle
+                            allowClear
+                            placeholder="请选择类型"
+                            style={{ width: 160, marginRight: 16 }}
+                            request={async () => {
+                                const resp = await getSqlTypeList();
+
+                                if (resp) {
+                                    return resp.list.map((a: any) => ({ label: a.name, value: a.code }))
+                                }
+
+                            }}
+                            fieldProps={{
+                                onChange(value, option) {
+                                    set_tableDataFilterParams({ ...tableDataFilterParams, sqlType: value })
+                                },
+                            }}
+                        />
+                    </div>
+                </div>
+                <div className='btnGroup'>
+                    <UpDataActBtn record type='ADD' />
+                </div>
+            </div>
+
+            <div style={{ marginTop: 16 }}>
+                <BMSTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+            </div> */}
+
+            <div className='left'>
+                <Input placeholder={'请输入类目名称'} allowClear
+                    suffix={
+                        <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" />
+                    }
+                    onChange={(e) => {
+                        const result = typeList.filter(item => item.name.indexOf(e.target.value) != -1);
+                        set_showTypeListArr(result);
+                    }}
+
+                />
+                <div className='wrap'>
+                    {
+                        showTypeListArr.map((item, index) => {
+                            return (
+                                <div className={currentSelectedType ? currentSelectedType.code == item.code ? 'type on' : 'type' : 'type'}
+                                    key={index}
+                                    onClick={() => set_currentSelectedType(item)}
+                                >{item.name}</div>
+                            )
+                        })
+                    }
+                </div>
+            </div>
+            <div className='right'>
+                <div className='toolBar'>
+                    <div className='filter'>
+                        <div className='filterItem'>
+                            <span className='label'>检索:</span>
+                            <Input placeholder={'sql说明'} style={{ width: 160 }} allowClear
+
+                                suffix={
+                                    <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" onClick={() => tableDataSearchHandle('sqlDefinition')} />
+                                }
+                                onChange={(e) => {
+                                    set_tableDataSearchKeywords(e.target.value);
+                                    if (e.target.value.length == 0) {
+                                        set_tableDataSearchKeywords('');
+                                        getTableData({sqlType:currentSelectedType.code});
+                                    }
+                                }}
+
+                                onPressEnter={(e) => {
+                                    tableDataSearchHandle('sqlDefinition')
+                                }}
+
+                            />
+                        </div>
+                    </div>
+                    <div className='btnGroup'>
+                        <UpDataActBtn record type='ADD' />
+                    </div>
+                </div>
+                <div style={{ marginTop: 16 }}>
+                    {currentSelectedType && <KCIMTable scroll={{ y: `calc(100vh - 230px)` }}
+                        actionRef={tableRef} columns={columns as ProColumns[]} rowKey='id'
+                        // params={tableDataFilterParams} 
+                        // request={(params) => getTableData(params)} 
+                        dataSource={showList}
+                        tableAlertRender={false}
+
+                        components={{
+                            body: {
+                                wrapper: DraggableContainer,
+                                row: DraggableBodyRow,
+                            },
+                        }}
+                    />}
+                </div>
+            </div>
+        </KCIMPagecontainer>
+    )
+}

+ 109 - 0
src/pages/baseSetting/otherItemSet/diySqlMana/service.ts

@@ -0,0 +1,109 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 16:31:27
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-03-21 10:23:18
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import { request } from 'umi';
+
+//获取table列表数据
+
+export type SQLTableDataType = {
+  id:number,
+  hospId:number,
+  code:number,
+  sqlCode:string,
+  sql:string,
+  sqlDefinition:string,
+  sqlType:string,
+  sqlTypeName:string,
+  sort:number
+}
+
+
+export const getSqlListTableData = (params?:any) => {
+  return request<any[]>('/costAccount/report/getSql', {
+    method: 'GET',
+    params:{...params}
+  });
+};
+
+
+//新增报表
+export type AddSqlTableDataType = {
+  sqlCode:string,
+  sql:string,
+  sqlDefinition:string,
+  sqlType:string,
+  sort:number,
+  status:number
+}
+
+export const addData = (data:AddSqlTableDataType) => {
+  return request('/costAccount/report/addSql', {
+    method: 'POST',
+    data
+  });
+};
+
+
+
+
+
+
+//编辑表格数据
+
+export type EditSqlTableDataType = {
+  id:number,
+  sql:string,
+  sqlDefinition:string,
+  sqlType:string,
+  sort:number,
+  status:number,
+  [key:string]:any
+}
+
+export const editData = (data:EditSqlTableDataType) => {
+  return request('/costAccount/report/editSql', {
+    method: 'POST',
+    data
+  });
+};
+
+export const updateTableSort = (data:EditSqlTableDataType[]) => {
+  return request('/costAccount/report/sortSql', {
+    method: 'POST',
+    data
+  });
+};
+
+//删除表格操作
+export const delData = (id:string) => {
+  return request('/costAccount/report/deleteSql', {
+    method: 'POST',
+    params:{id}
+  });
+};
+
+//获取sql类型
+export const getSqlTypeList = (params?:any) => {
+  return request('/costAccount/report/getSqlType?current=1&pageSize=1000&typeCode=10', {
+    method: 'GET',
+  });
+};
+
+
+
+
+
+
+
+
+
+
+

+ 95 - 0
src/pages/baseSetting/otherItemSet/diySqlMana/style.less

@@ -0,0 +1,95 @@
+.row-dragging {
+
+  .cost-ant-table-cell {
+    width: 130px;
+  }
+}
+
+.DiySqlMana {
+  // padding: 16px;
+  border-radius: 4px;
+
+  .left {
+    float: left;
+    border-radius: 4px;
+    width: 220px;
+    height:calc(100vh - 80px);
+    overflow: scroll;
+    margin-right: 16px;
+    padding: 16px;
+    background: #FFFFFF;
+    
+    .wrap {
+      margin-top: 16px;
+
+      .type {
+        cursor: pointer;
+        height: 32px;
+        line-height: 32px;
+        padding-left: 8px;
+        background: #FFFFFF;
+        border-radius: 4px;
+        font-size: 14px;
+        font-family: SourceHanSansCN-Normal, SourceHanSansCN;
+        font-weight: 400;
+        color: #17181A;
+        margin-bottom: 4px;
+
+        &.on {
+          font-weight: 500;
+          color: #17181A;
+          background: #F0F2F5;
+        }
+
+        &:last-child {
+            margin-bottom: 0;
+        }
+      }
+    }
+  }
+
+  .right {
+    float: left;
+    width: calc(100% - 236px);
+    padding: 16px;
+    border-radius: 4px;
+    background: #FFFFFF;
+
+    .toolBar {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+
+      .filter {
+        display: flex;
+        flex-direction: row;
+        justify-content: flex-start;
+        align-items: center;
+
+        .filterItem {
+          display: flex;
+          flex-direction: row;
+          justify-content: center;
+          align-items: center;
+        }
+      }
+
+      .btnGroup {
+        .add {
+          cursor: pointer;
+          display: inline-block;
+          font-size: 14px;
+          font-family: SourceHanSansCN-Normal, SourceHanSansCN;
+          font-weight: 400;
+          color: #FFFFFF;
+          line-height: 24px;
+          padding: 0 14px;
+          background: #3377FF;
+          border-radius: 4px;
+        }
+      }
+
+    }
+  }
+}

+ 563 - 264
src/pages/baseSetting/otherItemSet/reportItemSet/index.tsx

@@ -2,315 +2,614 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-10-30 14:04:24
+ * @LastEditTime: 2024-02-23 14:56:00
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
 
 
 
-import { ModalForm, ProFormText } from '@ant-design/pro-form';
+import KCIMPagecontainer from '@/components/KCIMPageContainer';
+import { KCIMTable } from '@/components/KCIMTable';
 
-import { Tabs, Popconfirm } from 'antd';
-import { useEffect, useRef, useState } from 'react';
+import { createFromIconfontCN } from '@ant-design/icons';
 
-import { addData, delData, editData, getData, getTabs } from './service';
 
-import './style.less';
+import { ActionType, ProFormDependency, ProFormInstance, ProFormText, ProFormSelect, ProFormDigit } from '@ant-design/pro-components';
+import { ModalForm } from '@ant-design/pro-form'
+import { ProColumns } from '@ant-design/pro-table';
+import { Modal, message, Popconfirm, Form, Tabs, Switch } from 'antd';
+import { Key, useEffect, useRef, useState } from 'react';
 
-import KCIMPagecontainer from '@/components/KCIMPageContainer';
-import { KCIMTable } from '@/components/KCIMTable';
+import 'moment/locale/zh-cn';
+import locale from 'antd/es/date-picker/locale/zh_CN';
 
-import { ProFormDependency, ProFormDigit, ProFormInstance, ProFormRadio, ProFormSelect } from '@ant-design/pro-components';
-import { getTargetDic } from '@/services/auth';
 
 
-export default function reportItemSet() {
+import { addData, copyDataToSelectedType, delData, editData, getReportProjectSettingList, saveReportRelation } from './service';
 
-  const tableRef = useRef();
-  const [tabs, set_tabs] = useState<any[]>([]);
+import './style.less';
+import TableTransfer from './transform';
+import React from 'react';
+import { cleanTree } from '@/utils/tooljs';
 
-  const [currentEdit, set_currentEdit] = useState<any|undefined>(undefined);
-  const [tableData, set_tableData] = useState<any[]>([]);
-  const [currentTab, set_currentTab] = useState<any|undefined>(undefined);
 
-  const columns = [
-    {
-      title: '报表项目名称',
-      dataIndex: 'columnName',
-    },
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+let currentRow: any = undefined;
+
+const accountingSubjectColumn = [
     {
-      title: '报表项目代码',
-      dataIndex: 'columnCode',
+        title: '会计科目编码',
+        dataIndex: 'accountingCode',
+        ellipsis: true,
     },
     {
-      title: '计算方式',
-      dataIndex: 'computeTypeName',
+        title: '会计科目名',
+        dataIndex: 'accountingName',
+        ellipsis: true,
     },
+];
+
+const shareParamsColumn = [
     {
-      title: '计算来源',
-      dataIndex: 'computeSourceName',
+        title: '分摊层级Id',
+        dataIndex: 'id',
+        ellipsis: true,
     },
     {
-      title: '序号',
-      dataIndex: 'sort',
+        title: '分摊层级名',
+        dataIndex: 'shareName',
+        ellipsis: true,
     },
+];
+
+const responsibilityColumn = [
     {
-      title: '下钻界面',
-      dataIndex: 'redirectName',
+        title: '责任中心编码',
+        dataIndex: 'responsibilityCode',
+        ellipsis: true,
     },
     {
-      title: '操作',
-      dataIndex: 'option',
-      valueType: 'option',
-      width: '15%',
-      render: (_: any, record: { parentColumnCode: any,id:any }) => {
-        const { parentColumnCode } = record;
-        const delBtn = () => (
-          <Popconfirm
-            key={3}
-            title="是否确定删除?"
-            onConfirm={() => delTableData(record.id)}
-            okText="确定"
-            cancelText="取消"
-          >
-            <a key={3}>删除</a>
-          </Popconfirm>
-        );
-        return parentColumnCode == '0'
-          ? [
-              <UpDataActBtn key={1} record={record} type={'ADD'} />,
-              <UpDataActBtn key={2} record={record} type={'EDIT'} />,
-              delBtn()
-            ]
-          : [<a key={1}>编辑</a>, delBtn()];
-      },
+        title: '责任中心名',
+        dataIndex: 'responsibilityName',
+        ellipsis: true,
     },
-  ];
+];
 
-  const getTableData = async (key: any) => {
-    const resp = await getData(key);
-    if (resp) {
-      set_tableData(resp.map((a:any) => ({ ...a, children: a.childColumns })));
-      //const columns = convertToColumnsFunc(title, true);
-    }
-  };
+const openRule = () => {
+    Modal.info({
+        title: '报表项目填写注意事项!',
+        width: 800,
+        content: (
+            <div>
+                <h4>计算类型说明 </h4>
+                <span>不设置:</span>
+                一般用于第一层。 对应成本科目:对应的是成本科目,如工资,收入类等
+                <div></div>
+                <span>对应责任中心:</span>
+                对应的是分摊的责任中心,放射科,功能科等
+                <div></div>
+                <span>对应分摊层级:</span>
+                对应的是分摊的层级,如“护理”分摊层级,“医技”分摊层级。
+                <div></div>
+                <span>小计:</span>
+                是对第一层下的所有项目的合计计算。
+                <div></div>
+                <span>计算公式:</span>
+                是按编号对报表项目的项目进行计算结果,支持加/减法。
+                <div style={{ marginBottom: 20 }}></div>
+                <h4>报表项目顺序注意事项</h4>
+                计算类型是小计报表项目需要维护在对应层级的其他项目之后
+                <div></div>
+                计算类型是计算公式的报表项目需要维护在公式里包含的其他项目之后
+            </div>
+        ),
+    });
+};
+
+export default function ReportItemSet() {
+
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>({ reportType: 0 });
+    const tableRef = useRef<ActionType>();
+    const formRef = useRef<ProFormInstance>();
+    const [tabs, set_tabs] = useState<any[]>([]);
+    const [reportType, set_reportType] = useState<Key>(0);
+    const columns: ProColumns[] = [
+
+        {
+            title: '报表项目名',
+            dataIndex: 'reportName',
+            width: 200
+        },
+        {
+            title: 'Id',
+            dataIndex: 'id',
+            width: 80
+        },
+        {
+            title: '编号',
+            dataIndex: 'num',
+            width: 80
+        },
+        {
+            title: '计算方式',
+            dataIndex: 'calcType',
+            renderText(num, record) {
+                switch (num) {
+                    case 0:
+                        return <>不设置</>;
+                    case 1:
+                        return <>对应会计科目</>;
+                    case 2:
+                        return <>对应分摊层级</>;
+                    case 3:
+                        return <>小计</>;
+                    case 4:
+                        return <>计算公式</>;
+                    case 5:
+                        return <>按责任中心</>;
+                }
+            },
+
+        },
+        {
+            title: '报表类型',
+            dataIndex: 'reportType',
+            renderText(num) {
+                switch (num) {
+                    case 0:
+                        return <>损益表</>;
+                    case 1:
+                        return <>完全成本法表</>;
+                    case 2:
+                        return <>变动成本表</>;
+                    case 3:
+                        return <>全院损益表</>;
+                    case 4:
+                        return <>全成本报表</>;
+                }
+            },
+        },
+        {
+            title: '计算公式',
+            width:300,
+            dataIndex: 'calcFormula',
+        },
+        {
+            title: '项目类型',
+            dataIndex: 'costType',
+            renderText(num) {
+                switch (num) {
+                    case 1:
+                        return <>收入</>;
+                    case 2:
+                        return <>成本</>;
+                }
+            },
+            
+        },
+        {
+            title: '占比计算类型',
+            dataIndex: 'fraction',
+            renderText(num) {
+                switch (num) {
+                    case 1:
+                        return <>分子</>;
+                    case 2:
+                        return <>分母</>;
+                    case 3:
+                        return <>不计算</>;
+                }
+            },
+            
+        },
+        {
+            title: '排序',
+            dataIndex: 'sort',
+            width: 80
+        },
+        {
+            title: '比率基数',
+            width: 80,
+            dataIndex: 'ratioBase',
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 160,
+            fixed:'right',
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                const { showAddRelation, parentId, calcType } = record;
+
+                const btnGroup = calcType == 0 ? [
+                    <UpDataActBtn key={'addChild'} record={record} type='ADDCHILD' />,
+                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
+                    <Popconfirm
+                        title="是否确认删除?"
+                        key="del"
+                        onConfirm={() => delTableData(record)}
+                    >
+                        <a>删除</a>
+                    </Popconfirm>,
+                ] : [
+                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
+                    <Popconfirm
+                        title="是否确认删除?"
+                        key="del"
+                        onConfirm={() => delTableData(record)}
+                    >
+                        <a>删除</a>
+                    </Popconfirm>,
+                ]
+
+                return showAddRelation ? [
+                    ...btnGroup,
+                    <a key="config3" onClick={() => {
+                        currentRow = record;
+                        if (showAddRelation == 1) oprnTableTransform(record, accountingSubjectColumn, 1);
+                        if (showAddRelation == 2) oprnTableTransform(record, shareParamsColumn, 2);
+                        if (showAddRelation == 3) oprnTableTransform(record, responsibilityColumn, 3);
+
+                    }}>
+                        {showAddRelation == 1
+                            ? '会计科目'
+                            : showAddRelation == 2
+                                ? '分摊层级'
+                                : showAddRelation == 3 && '责任中心'}
+                    </a>
+                ] : btnGroup
+            },
+        },
 
-  const delTableData = async (id: any) => {
-    const resp = await delData(id);
-    const { status } = resp;
-    if (status == 200) {
-      getTableData(currentTab.key);
+    ]
+
+
+    const getTableData = async (params: any) => {
+        const resp = await getReportProjectSettingList({ ...params, reportType });
+        if (resp) {
+            return {
+                data: cleanTree(resp.list),
+                success: true,
+                total: resp.totalCount,
+                pageSize: resp.pageSize,
+                totalPage: resp.totalPage,
+            }
+        }
+        return []
     }
-  };
-
-  const updateTable = async (formVal: { columnName: any; computeType: number; computeSource: any; parentColumnCode: any; sort: any; dataType: any; redirect: any; redirectParameter: any[]; id: any; }, type: string) => {
-  
-    try {
-      const result = {
-        reportCode: currentTab.key,
-        columnName: formVal.columnName,
-        computeType: formVal.computeType,
-        computeSource: formVal.computeType != 3 ? formVal.computeSource : 3,
-        parentColumnCode: formVal.computeType == 1 ? formVal.parentColumnCode : '',
-        sort: formVal.sort,
-        dataType: formVal.dataType,
-        redirect: formVal.redirect,
-        redirectParameter: formVal.redirectParameter?(formVal.redirectParameter instanceof Array)?formVal.redirectParameter.join(','):formVal.redirectParameter:'',
-      };
-
-      if (type == 'ADD') {
-        const resp = await addData({ ...result });
+
+    const delTableData = async (record: any) => {
+        const resp = await delData([record.id]);
         if (resp) {
-          getTableData(currentTab.key);
+            message.success('操作成功!');
+            tableRef.current?.reload();
+            // message.success('操作成功!');
+        }
+    }
+
+    const onSaveHandle = async (keys: Key[], rows: any[], record: any, settingType: number) => {
+
+        let selectedRowKeysToStr: string[] = [];
+        if (settingType == 2) {
+            keys
+                ? keys.map((item: any) => selectedRowKeysToStr.push(`${item}`))
+                : [];
         }
-      }
-      if (type == 'EDIT') {
-        const resp = await editData({ ...result, id: formVal.id });
+
+        let selectedRowKeys: Key[] = [];
+        if (settingType == 1) {
+            selectedRowKeys = rows.map((a: any) => a.accountingCode)
+        }
+        if (settingType == 2) {
+            selectedRowKeys = keys.map((a: any) => `${a}`)
+        }
+        if (settingType == 3) {
+            selectedRowKeys = rows.map((a: any) => a.responsibilityCode)
+        }
+        const { id: reportId } = record;
+        const resp = await saveReportRelation({
+            reportId,
+            reportType,
+            relation: settingType,
+            relationCodes: selectedRowKeys,
+        });
         if (resp) {
-          getTableData(currentTab.key);
+            message.success('对照成功!');
+            tableRef.current?.reload();
         }
-      }
-    } catch (e) {
-      console.log({ e });
     }
 
-    return true;
-  };
+    const oprnTableTransform = (record: any, transferTableColumn: ProColumns[], settingType: number) => {
 
-  const UpDataActBtn = ({ record, type}:{record:any, type:'ADD'|'EDIT'}) => {
-    const formRef = useRef<ProFormInstance<any>>();
-    return (
-      <ModalForm
-        title={`${type == 'EDIT' ? '编辑' :record?'添加':'新增'}报表`}
-        width={400}
-        initialValues={type == 'EDIT' ? { ...record,redirectParameter:record.redirectParameter?record.redirectParameter.split(','):[]} : {computeType:1,dataType:1 }}
-        trigger={type == 'EDIT' ? <a key="edit">编辑</a> : <a className="add" >{record?'添加':'新增'}</a>}
-        onFinish={(val) => {
-          set_currentEdit(undefined);
-          return updateTable(type == 'EDIT' ? { ...record, ...val,id:record.id } : { ...val,parentColumnCode:record?record.columnCode:'0' }, type);
-        }}
-        formRef={formRef}
-        modalProps={{ destroyOnClose: true }}
-      >
-        <ProFormText
-          name="columnName"
-          label="报表项目名称:"
-          placeholder="请输入"
-          rules={[{ required: true, message: '名称不能为空!' }]}
-        />
-        <ProFormSelect
-          name="computeType"
-          label="计算方式:"
-          options={[
-            { label: '对应成本项', value: 1 },
-            { label: '计算公式', value: 2 },
-            { label: '合计', value: 3 },
-          ]}
-          rules={[{ required: true, message: '计算方式不能为空!' }]}
-        />
-        <ProFormDependency name={['computeType']}>
-          {({ computeType }) => {
-            if (computeType == 1) {
-              return (
-                <ProFormSelect
-                  name="computeSource"
-                  label="报表项目类别:"
-                  request={async () => {
-                    const resp = await getTargetDic('REPORT_ITEM_TYPE');
-                    if (resp) {
-                      const { dataVoList } = resp;
-                      return dataVoList.map((a:any) => {
-                        if(a.defaultValue&&type == 'ADD'){
-                            formRef.current?.setFieldValue('computeSource',a.code);
-                          }
-                          return { label: a.name, value: a.code }
-                      });
-                    }
-                    return [];
-                  }}
-                  rules={[{ required: true, message: '报表项目类别不能为空!' }]}
-                />
-              );
+        const ref = React.createRef<{ save: any; }>();
+
+        Modal.confirm({
+            title: settingType == 1 ? `选择会计科目` : settingType == 2 ? '选择分摊层级' : '选择责任中心',
+            icon: <></>,
+            width: 750,
+            centered: true,
+            okText: '确定',
+            cancelText: '取消',
+            content: <TableTransfer
+                ref={ref}
+                keyName="id"
+                record={record}
+                settingType={settingType}                                                                                                                                                                                                             
+                onSave={(keys, rows, settingType) => onSaveHandle(keys, rows, record, settingType)}
+                leftColumns={transferTableColumn}
+                rightColumns={transferTableColumn}
+            ></TableTransfer>,
+            onOk: () => {
+                return ref.current && ref.current.save();
             }
-            if (computeType == 2) {
-              return (
-                <ProFormText
-                  name="computeSource"
-                  label="计算公式:"
-                  placeholder="请输入"
-                  rules={[{ required: true, message: '名称不能为空!' }]}
-                />
-              );
+        })
+    }
+
+
+    const updateTable = async (formVal: any, type: 'EDIT' | "ADD" | "ADDCHILD" | 'COPY') => {
+
+        if (type == 'ADD' || type == 'ADDCHILD') {
+
+            let parentId = 0;
+            const { calcType = 0, calcFormula = '' } = formVal;
+
+            (type == 'ADDCHILD') && (parentId = formVal.id);
+
+            console.log({formVal});
+
+            const result = {
+                ...formVal,
+                calcType,
+                calcFormula,
+                isLoss: formVal.isLoss ? 1 : 0,
+                reportType: Number(reportType),
+                parentId
+            }
+
+            const resp = await addData(result);
+            if (resp) {
+                currentRow = undefined;
+                tableRef.current?.reload();
+                message.success('操作成功!');
+
             }
-          }}
-        </ProFormDependency>
-
-        <ProFormDigit
-          name="sort"
-          label="序号:"
-          placeholder="请输入"
-          rules={[{ required: true, message: '序号不能为空!' }]}
-        />
-        <ProFormRadio.Group
-          name="dataType"
-          label="数据格式:"
-          options={[
-            { label: '数值', value: 1 },
-            { label: '百分比', value: 2 },
-          ]}
-          rules={[{ required: true }]}
-        />
-        <ProFormSelect
-          name="redirect"
-          label="下钻界面:"
-          request={async () => {
-            const resp = await getTargetDic('REPORT_REDIRECT_PATH');
+
+        }
+        if (type == 'EDIT') {
+            try {
+                const { reportName, sort, calcType = 0, calcFormula = '', isLoss, parentId, id,fraction,costType } = formVal;
+                const result = {
+                    id,
+                    parentId,
+                    reportName,
+                    sort,
+                    reportType,
+                    calcType,
+                    calcFormula,
+                    fraction,
+                    costType,
+                    isLoss: isLoss ? 1 : 0,
+                };
+                const resp = await editData(result);
+                if (resp) {
+                    tableRef.current?.reload();
+                    message.success('操作成功!');
+                }
+            } catch (error) {
+                console.log({ error });
+            }
+
+        }
+        if (type == 'COPY') {
+            //复制数据
+            const { toReportType } = formVal;
+            const resp = await copyDataToSelectedType({
+                fromReportType: Number(reportType),
+                toReportType,
+            });
             if (resp) {
-              const { dataVoList } = resp;
-              return dataVoList.map((a:any) => {
-                  if(a.defaultValue&&type == 'ADD'){
-                    formRef.current?.setFieldValue('redirect',a.code);
-                  }
-                  return { label: a.name, value: a.code }
-              });
+                message.success('复制成功!');
+                tableRef.current?.reload();
             }
-            return [];
-          }}
-          rules={[{ required: true, message: '下钻界面不能为空!' }]}
-        />
-        <ProFormDependency name={['redirect']}>
-              {
-                ({redirect})=>{
-                      return redirect != '0'?(
+        }
+        return true;
+
+    }
+
+
+    const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD' | 'ADDCHILD' | 'COPY' }) => {
+        const reportType = type == 'EDIT' || type == 'ADDCHILD' ? record.reportType : undefined
+        return (
+            <ModalForm
+                title={type == 'COPY' ? '复制' : `${type == 'EDIT' ? '编辑' : '新增'}报表`}
+                width={350}
+                formRef={formRef}
+                initialValues={type == 'EDIT' ? {
+                    ...record
+                } : {}}
+                trigger={
+                    type == 'EDIT' ? <a key="edit" >编辑</a> : type == 'ADDCHILD' ? <a className='add'>添加</a> : type == 'COPY' ? <span className='copy' style={{ marginRight: 8 }}>复制</span> : <span className='add'>新增</span>
+                }
+                onFinish={(val) => {
+                    return updateTable(type == 'EDIT' ? { ...record, ...val } : type == 'ADDCHILD' ? { ...val, id: record.id } : { ...val }, type);
+                }}
+                modalProps={{ destroyOnClose: true }}
+                colProps={{ span: 24 }}
+                grid
+            >
+                {
+                    type != 'COPY' && (
+                        <>
+                            <ProFormText
+                                label="报表名"
+                                rules={[
+                                    {
+                                        required: true,
+                                        message: '报表名是必填项!',
+                                    },
+                                ]}
+                                name="reportName"
+                            />
+                            <ProFormDigit
+                                label="排序"
+                                rules={[
+                                    {
+                                        required: true,
+                                        message: '排序必填项!',
+                                    },
+                                ]}
+                                name="sort"
+                            />
+                            {(
+                                //新增顶级不展示
+                                <>
+                                    <ProFormSelect
+                                        name="calcType"
+                                        label="计算类型"
+                                        options={[
+                                            { label: '不设置', value: 0 },
+                                            { label: '对应会计科目', value: 1 },
+                                            { label: '对应分摊层级', value: 2 },
+                                            { label: '小计', value: 3 },
+                                            { label: '计算公式', value: 4 },
+                                            { label: '按责任中心', value: 5 },
+                                        ]}
+                                        placeholder="请选择状态"
+                                        rules={[{ required: true, message: '请选择计算类型!' }]}
+                                    />
+
+                                    <ProFormDependency name={['calcType']}>
+                                        {({ calcType }) => {
+                                            // const resp = await getResponsibilityCenterList({pageSize:100,current:1});
+                                            return calcType == 4 ? (
+                                                <ProFormText
+                                                    label="计算公式"
+                                                    rules={[
+                                                        {
+                                                            required: true,
+                                                            message: '计算公式是必填项!',
+                                                        },
+                                                    ]}
+                                                    placeholder="例如:[1] + [2]"
+                                                    name="calcFormula"
+                                                />
+                                            ) : (
+                                                <></>
+                                            );
+                                        }}
+                                    </ProFormDependency>
+                                    <ProFormDependency name={['calcType']}>
+                                        {({ calcType }) => {
+                                            // const resp = await getResponsibilityCenterList({pageSize:100,current:1});
+                                            return calcType == 4 && reportType == 3 ? (
+                                                <Form.Item
+                                                    name="isLoss"
+                                                    label="损益标志"
+                                                    valuePropName="checked"
+                                                >
+                                                    <Switch />
+                                                </Form.Item>
+                                            ) : (
+                                                <></>
+                                            );
+                                        }}
+                                    </ProFormDependency>
+                                </>
+                            )}
+                            <ProFormSelect
+                                name="costType"
+                                label="报表项目类型"
+                                options={[
+                                    { label: '收入', value: 1 },
+                                    { label: '成本', value: 2 },
+                                ]}
+                                placeholder="请选择"
+                                rules={[{ required: true, message: '请选择报表项目类型!' }]}
+                            />
+                            <ProFormSelect
+                                name="fraction"
+                                label="占比计算类型"
+                                options={[
+                                    { label: '分子', value: 1 },
+                                    { label: '分母', value: 2 },
+                                    { label: '不计算', value: 3 },
+                                ]}
+                                placeholder="请选择"
+                                rules={[{ required: true, message: '请选择占比计算类型!' }]}
+                            />
+                        </>
+                    )
+                }
+                {
+                    type == 'COPY' && (
                         <ProFormSelect
-                        name="redirectParameter"
-                        label="下钻参数:"
-                        fieldProps={{mode:'multiple'}}
-                        request={async () => {
-                            const resp = await getTargetDic('REPORT_REDIRECT_PARAM');
-                            if (resp) {
-                            const { dataVoList } = resp;
-                            return dataVoList.map((a:any) => {
-                                if(a.defaultValue&&type == 'ADD'){
-                                    formRef.current?.setFieldValue('redirectParameter',a.value?a.value.split(','):[]);
+                            name="toReportType"
+                            label="复制到"
+                            width="sm"
+                            options={[
+                                {
+                                    label: '损益表',
+                                    value: 0,
+                                },
+                                {
+                                    label: '全院损益表',
+                                    value: 3,
                                 }
-                                return { label: a.name, value: a.value }
-                            });
-                            }
-                            return [];
-                        }}
-                        rules={[{ required: true, message: '下钻参数不能为空!' }]}
+                            ]}
+                            placeholder="请选择"
+                            rules={[{ required: true, message: '请选择复制到目标!' }]}
                         />
-                      ):null
+                    )
                 }
-              }
-        </ProFormDependency>
-        
-      </ModalForm>
-    );
-  };
-
-
-  const getTabsReq = async () => {
-    const resp = await getTabs();
-    if (resp) {
-      set_tabs(resp.map((a: { code: any; name: any; }) => ({ key: a.code, label: a.name })));
-      set_currentTab({key:resp[0].code,label:resp[0].name});
-      getTableData(resp[0].code);
+            </ModalForm>
+        )
+    }
+
+    const onTabChanged = (key: Key) => {
+        set_reportType(key);
+        tableRef.current?.reload();
     }
-  };
-
-  const onTabChanged = (key: any) => {
-    const needitem = tabs.filter((a: { key: any; }) => a.key == key);
-    set_currentTab(needitem[0]);
-    getTableData(key);
-  };
-
-
-
-  useEffect(() => {
-    getTabsReq();
-  }, []);
-
-  return (
-    <KCIMPagecontainer className="reportItemSet" title={false}>
-      <Tabs
-        defaultActiveKey={tabs.length > 0 ? tabs[0].key : undefined}
-        items={tabs}
-        key={'key'}
-        onChange={(key) => onTabChanged(key)}
-      />
-      <div className="toolBar">
-        <div className="filter"></div>
-        <div className="btnGroup">
-          {/* <a className='copy'>复制</a> */}
-          <UpDataActBtn record={undefined} type="ADD" />
-        </div>
-      </div>
-      <div>
-        <KCIMTable columns={columns} actionRef={tableRef} rowKey="id" dataSource={tableData} />
-      </div>
-    </KCIMPagecontainer>
-  );
+
+
+
+
+    useEffect(() => {
+        set_tabs([
+            {
+                label: '损益表',
+                key: 0,
+            },
+            {
+                label: '全院损益表',
+                key: 3,
+            }
+        ])
+    }, [])
+
+    return (
+        <KCIMPagecontainer className='ReportItemSet' title={false}>
+            <div className='toolBar' style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
+                <Tabs
+                    defaultActiveKey={tabs.length > 0 ? tabs[0].key : undefined}
+                    items={tabs}
+                    key={'key'}
+                    onChange={(key) => onTabChanged(key)}
+                />
+                <div className='btnGroup'>
+                    <span style={{ marginRight: 8, cursor: 'pointer' }} onClick={() => openRule()}><img style={{ width: 16, marginRight: 4, marginTop: -1 }} src={require('../../../../../static/tip.png')} />说明</span>
+                    <UpDataActBtn record={undefined} type='COPY' />
+                    <UpDataActBtn record={undefined} type='ADD' />
+                </div>
+            </div>
+
+            <div>
+                <KCIMTable pagination={false} scroll={{x:1500, y: `calc(100vh - 230px)` }} columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+            </div>
+        </KCIMPagecontainer>
+    )
 }

+ 0 - 69
src/pages/baseSetting/otherItemSet/reportItemSet/service.js

@@ -1,69 +0,0 @@
-/*
- * @Author: code4eat awesomedema@gmail.com
- * @Date: 2023-03-03 16:31:27
- * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-10-19 16:43:53
- * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- */
-
-
-
-import { request } from 'umi';
-
-//获取table列表数据
-
-
-
-export const getData = (key) => {
-  return request('/costAccount/setting/getReportColumn', {
-    method: 'GET',
-    params:{reportCode:key}
-  });
-};
-
-
-//获取Tabs
-export const getTabs = () => {
-  return request('/costAccount/setting/getReport', {
-    method: 'GET',
-  });
-};
-
-
-//新增表格数据 
-
-export const addData = (data) => {
-  return request('/costAccount/setting/addReportColumn', {
-    method: 'POST',
-    data
-  });
-};
-
-
-//编辑权
-export const editData = (data) => {
-  return request('/costAccount/setting/editReportColumn', {
-    method: 'POST',
-    data
-  });
-};
-
-
-
-//删除表格操作
-
-export const delData = (id) => {
-  return request('/costAccount/setting/deleteReportColumn', {
-    method: 'POST',
-    params:{id}
-  });
-};
-
-
-
-
-
-
-
-

+ 103 - 0
src/pages/baseSetting/otherItemSet/reportItemSet/service.ts

@@ -0,0 +1,103 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 16:31:27
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2023-12-14 16:27:30
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import { Key } from 'react';
+import { request } from 'umi';
+
+//获取table列表数据
+export const getReportProjectSettingList = (params:any) => {
+  return request('/costAccount/reportForm/list', {
+    method: 'GET',
+    params:{...params},
+  });
+}
+
+
+
+//新增
+export type AddTableDataType = {
+  calcFormula?:string,
+  calcType?:number,
+  isLoss?:number,
+  parentId?:number,
+  reportName?:string,
+  reportType?:number,
+  sort?:number
+}
+
+export const addData = (data:AddTableDataType) => {
+  return request('/costAccount/reportForm/save', {
+    method: 'POST',
+    data:{...data}
+  });
+};
+
+
+
+//编辑表格数据
+
+export type TableRowEditType = {
+  id:number;
+}&AddTableDataType
+
+export const editData = (data:any) => {
+  return request('/costAccount/reportForm/edit', {
+    method: 'POST',
+    data
+  });
+};
+
+//删除表格操作
+export const delData = (ids:Key[]) => {
+  return request('/costAccount/reportForm/delete', {
+    method: 'POST',
+    data:ids
+  });
+};
+
+
+//根据关系类型,获取已绑定的关系数据
+export const getHasSetReportRelation = (params:any) => {
+  return request('/costAccount/reportForm/getRelationList', {
+    method: 'GET',
+    params: {...params},
+  });
+}
+
+//保存对应设置
+export const saveReportRelation = (body:any) => {
+  return request('/costAccount/reportForm/saveReportRelation', {
+    method: 'POST',
+    data: {...body},
+  });
+}
+
+//复制数据
+export const copyDataToSelectedType = (body:any) => {
+  return request('/costAccount/reportForm/copyReport', {
+    method: 'POST',
+    data: {...body},
+  });
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 10 - 51
src/pages/baseSetting/otherItemSet/reportItemSet/style.less

@@ -1,42 +1,4 @@
-
-
-
-.TableSelecter {
-
-  .pfm-ant-modal-footer {
-    display: none !important;
-  }
-  
-  .footer {
-       display: flex;
-       flex-direction:row;
-       justify-content: flex-end;
-       margin-top: 15px;
-       span {
-           display: inline-block;
-           width: 56px;
-           height: 24px;  
-           font-size: 14px;
-           line-height: 23px;
-           text-align: center;
-           border-radius: 4px;
-           cursor: pointer;
-
-           &.ok {
-               color: #FFFFFF;
-               background:#3377FF;
-               margin-left: 8px;
-           }
-           &.cancel {
-               border: 1px solid #DAE2F2;
-           }
-       }
-
-  }
-}
-
-.reportItemSet {
-  position: relative;
+.ReportItemSet {
   padding: 16px;
   padding-top: 0;
   background: #FFFFFF;
@@ -44,9 +6,6 @@
 
 
   .toolBar {
-    position:absolute;
-    right:16px;
-    top:16px;
     display: flex;
     flex-direction: row;
     justify-content: space-between;
@@ -67,12 +26,12 @@
     }
 
     .btnGroup {
-      
-      .add ,.copy{
+
+      .add,
+      .copy {
         cursor: pointer;
         display: inline-block;
         font-size: 14px;
-        font-family: SourceHanSansCN-Normal, SourceHanSansCN;
         font-weight: 400;
         color: #FFFFFF;
         line-height: 24px;
@@ -80,13 +39,13 @@
         background: #3377FF;
         border-radius: 4px;
       }
+
       .copy {
-          color: #17181A;
-          border: 1px solid #DAE2F2;
-          background: #FAFCFF;
-          margin-right: 8px;
+        color: #17181A;
+        background: #FAFCFF;
+        border-radius: 4px;
+        border: 1px solid #DAE2F2;
       }
     }
-
   }
-}
+}

+ 301 - 0
src/pages/baseSetting/otherItemSet/reportItemSet/transform.tsx

@@ -0,0 +1,301 @@
+import React, { Key, useEffect, useImperativeHandle, useState } from "react";
+import { Transfer } from 'antd'
+import { TransferItem, TransferProps } from 'antd/es/transfer';
+import { ColumnsType } from 'antd/es/table';
+import { difference } from "lodash";
+import { TableRowSelection } from 'antd/es/table/interface';
+import { KCIMTable } from "@/components/KCIMTable";
+import { ProColumns } from "@ant-design/pro-components";
+import { Tabs,Tree } from 'antd';
+
+import { log } from "mathjs";
+import { getAccountingSubjectList } from "../../accountingAccountSet/accountingSubMana/service";
+import { getApportionmentLevelList } from "../../costAllocationSet/allocationLevelSet/service";
+import { getResponsibilityCenterList } from "../../responsibilityCenterSet/responsibilityCenter/service";
+import { findAllParents, renameChildListToChildren, searchLeaves } from "@/utils/tooljs";
+import { getHasSetReportRelation } from "./service";
+
+
+
+interface TableTransferProps extends TransferProps<TransferItem> {
+    leftColumns: ProColumns[];
+    rightColumns: ProColumns[];
+    record: any,
+    settingType: number,
+    keyName: string,
+    onSave: (selectedKeys: Key[], selectedRowKeys: any[], settingType: number) => void;
+}
+
+const flattenTreeData = (treeData:any[], childKey = 'children', parentKey = 'parentId') => {
+    let result:any[] = [];
+
+    function flatten(node:any, parentId = null) {
+        // 创建一个新对象,包含原始节点的所有属性,除了 children,并添加 parentId
+        const { [childKey]: _, ...flatNode } = node;
+        result.push({ ...flatNode, [parentKey]: parentId });
+
+        // 如果节点有子节点,递归扁平化这些子节点
+        if (node[childKey] && node[childKey].length > 0) {
+            node[childKey].forEach((childNode:any) => flatten(childNode, node.id));
+        }
+    }
+
+    // 遍历每个根级节点
+    treeData.forEach(node => flatten(node));
+
+    return result;
+}
+
+
+function buildTree(flatData:any[], rootParentId = null, idKey = 'id', parentKey = 'parentId', childrenKey = 'children') {
+    const nodeMap = new Map();
+
+    // 首先,将所有节点存储到一个 Map 中,以便快速访问
+    flatData.forEach(node => nodeMap.set(node[idKey], { ...node }));
+
+    const tree:any[] = [];
+
+    flatData.forEach(node => {
+        const parentNode = nodeMap.get(node[parentKey]);
+
+        if (parentNode) {
+            // 检查父节点是否已经有了 children 属性
+            if (!parentNode[childrenKey]) {
+                parentNode[childrenKey] = [];
+            }
+            // 将当前节点添加到父节点的 children 数组中
+            parentNode[childrenKey].push(nodeMap.get(node[idKey]));
+        } else if (node[parentKey] === rootParentId) {
+            // 如果没有父节点且 parentId 与根 parentId 匹配,则为根节点
+            tree.push(nodeMap.get(node[idKey]));
+        }else{
+            tree.push(nodeMap.get(node[idKey]));
+        }
+    });
+
+    // 清除那些 children 长度为 0 的节点的 children 属性
+    function clearEmptyChildren(node:any) {
+        if (node[childrenKey] && node[childrenKey].length === 0) {
+            delete node[childrenKey];
+        } else if (node[childrenKey]) {
+            node[childrenKey].forEach(clearEmptyChildren);
+        }
+    }
+
+    tree.forEach(clearEmptyChildren);
+
+    return tree;
+}
+
+
+const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, keyName, record, settingType, onSave, ...restProps }: TableTransferProps, ref) => {
+
+    const [_data, _set_data] = useState<any>();
+    const [targetKeys, setTargetKeys] = useState<string[]>(record.accountingIds ? [...((record.accountingIds).map((a: string) => Number(a)))] : []);
+    const [datasource, set_datasource] = useState<any[]>([]);
+    const [selectedKeys, setSelectedKeys] = useState<string[]>(record.accountingIds ? [...((record.accountingIds).map((a: string) => Number(a)))] : []);
+    const [accountType, set_accountType] = useState(1);
+    const [tabs, set_tabs] = useState<any[]>([]);
+
+
+    //获取列表
+    const getFuncList = async () => {
+
+        if (settingType == 1) {
+            const resp = await getAccountingSubjectList({ pageSize: 500, current: 1, accountType });
+            if (resp) {
+                const initData = await getHasSetReportRelation({ reportId: record.id, relation: settingType });
+                if (initData) {
+                    const hasSelectedKeys = initData.map((a: any) => a.code);
+                    console.log(flattenTreeData(resp.list));
+                    const hasSelectedRows = flattenTreeData(resp.list).filter((a: any) => hasSelectedKeys.includes(a.accountingCode));
+                    const selectedKeys = hasSelectedRows.map((a: any) => a.id)
+                    // setSelectedKeys(selectedKeys);
+                    setTargetKeys(selectedKeys);
+                }
+                set_datasource(resp.list);
+                _set_data(resp.list);
+            }
+
+        }
+        if (settingType == 2) {
+            const resp = await getApportionmentLevelList({ pageSize: 500, current: 1 });
+            if (resp) {
+                const initData = await getHasSetReportRelation({ reportId: record.id, relation: settingType });
+                if (initData) {
+                    const hasSelectedKeys = initData.map((a: any) => Number(a.id));
+                    const hasSelectedRows = resp.list.filter((a: any) => hasSelectedKeys.includes(a.id));
+                    const selectedKeys = hasSelectedRows.map((a: any) => a.id)
+                    // setSelectedKeys(selectedKeys);
+                    setTargetKeys(selectedKeys);
+                }
+                set_datasource(resp.list);
+                _set_data(resp.list);
+            }
+
+
+        }
+        if (settingType == 3) {
+            const resp = await getResponsibilityCenterList({ pageSize: 500, current: 1 });
+            //const opendedArr = renameChildListToChildren(resp.list, 'child');
+            if (resp) {
+                const initData = await getHasSetReportRelation({ reportId: record.id, relation: settingType });
+                if (initData) {
+                    const hasSelectedKeys = initData.map((a: any) => a.code);
+                    const hasSelectedRows = resp.list.filter((a: any) => hasSelectedKeys.includes(a.responsibilityCode));
+                    const selectedKeys = hasSelectedRows.map((a: any) => a.id)
+                    // setSelectedKeys(selectedKeys);
+                    setTargetKeys(selectedKeys);
+                }
+                set_datasource(renameChildListToChildren(resp.list, 'child'));
+                _set_data(renameChildListToChildren(resp.list, 'child'));
+            }
+
+        }
+
+    }
+
+    const onChange = (nextTargetKeys: string[]) => {
+        // console.log({ nextTargetKeys });
+        setTargetKeys(nextTargetKeys);
+    };
+
+    const onSelectChange = (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => {
+        // console.log('sourceSelectedKeys:', sourceSelectedKeys, 'targetSelectedKeys:', targetSelectedKeys);
+        setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]);
+    };
+
+    useImperativeHandle(ref, () => ({
+        save: async () => {
+            if(settingType == 1||settingType == 3){
+                const items = flattenTreeData(datasource).filter(a => targetKeys.includes(a[`${keyName}`]));
+                onSave(targetKeys, items, settingType);
+            }else{
+                const items = datasource.filter(a => targetKeys.includes(a[`${keyName}`]));
+                onSave(targetKeys, items, settingType);
+            }
+            
+        }
+    }));
+
+
+    const onTabChanged = (key: string) => {
+        set_accountType(Number(key));
+    }
+
+    useEffect(() => {
+        getFuncList();
+    }, [accountType]);
+
+
+
+    useEffect(() => {
+        set_tabs([
+            {
+                label: '收入',
+                key: 1,
+            },
+            {
+                label: '支出',
+                key: 2,
+            },
+        ])
+    }, []);
+
+
+    return (
+        <div>
+            {settingType == 1 && (
+                <Tabs
+                    defaultActiveKey={tabs.length > 0 ? tabs[0].key : undefined}
+                    items={tabs}
+                    key={'key'}
+                    onChange={(key) => onTabChanged(key)}
+                />
+            )}
+            <Transfer className='TableTransfer' showSearch
+                titles={['待选项', '已选项']}
+                locale={{
+                    itemUnit: '项',
+                    itemsUnit: '项',
+                    searchPlaceholder: '请输入',
+                }}
+                oneWay={false}
+                onChange={onChange}
+                onSelectChange={onSelectChange}
+                dataSource={settingType == 2?datasource:flattenTreeData(datasource)}
+                rowKey={record => record[`${keyName}`]}
+                targetKeys={targetKeys}
+                selectedKeys={selectedKeys}
+                filterOption={(inputValue, item) => {
+
+                    if(settingType == 1){
+                        return item['accountingName']!.indexOf(inputValue) !== -1
+                    }
+                    if(settingType == 2){
+                        return item['shareName']!.indexOf(inputValue) !== -1
+                    }
+                    if(settingType == 3){
+                        return item['responsibilityName']!.indexOf(inputValue) !== -1
+                    }
+                    return false
+
+                }}
+            
+            >
+                {({
+                    direction,
+                    filteredItems,
+                    onItemSelectAll,
+                    onItemSelect,
+                    selectedKeys: listSelectedKeys,
+                    disabled: listDisabled,
+                }) => {
+
+                    const columns = direction === 'left' ? leftColumns : rightColumns;
+
+                    const rowSelection: TableRowSelection<TransferItem> = {
+                        getCheckboxProps: (item) => ({ disabled: listDisabled || item.disabled }),
+                        onSelectAll(selected, selectedRows) {
+                            const treeSelectedKeys = selectedRows.map((a) => a[`${keyName}`]);
+                            const diffKeys = selected
+                                ? difference(treeSelectedKeys, listSelectedKeys)
+                                : difference(listSelectedKeys, treeSelectedKeys);
+                            onItemSelectAll(diffKeys as string[], selected);
+                        },
+                        onSelect(item, selected) {
+                            onItemSelect(item[`${keyName}`], selected);
+                        },
+                        selectedRowKeys: listSelectedKeys,
+                    };
+
+                    return  (
+                        <KCIMTable
+                            rowSelection={rowSelection}
+                            columns={columns as TransferItem[]}
+                            dataSource={settingType == 2?filteredItems:direction == 'left'?buildTree(filteredItems):filteredItems}
+                            size="small"
+                            bordered={false}
+                            rowKey={keyName}
+                            scroll={{ y: 280 }}
+                            pagination={{ showTitle: false, pageSize: 9, showLessItems: false, simple: true, showTotal: () => false }}
+                            tableAlertRender={false}
+                            style={{ pointerEvents: listDisabled ? 'none' : undefined }}
+                            onRow={(row) => ({
+                                onClick: () => {
+                                    if (row.itemDisabled || listDisabled) return;
+                                    onItemSelect(row[`${keyName}`], !listSelectedKeys.includes(row[`${keyName}`]));
+                                },
+                            })}
+                        />
+                    )
+                }}
+            </Transfer>
+        </div>
+
+    )
+});
+
+export default TableTransfer
+
+

+ 4 - 3
src/pages/baseSetting/otherItemSet/visitsAndBedDayCostSetting/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-21 19:36:50
+ * @LastEditTime: 2024-01-05 13:49:28
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -77,7 +77,7 @@ export default function VisitsAndBedDayCostSetting() {
         {
             title: '操作',
             key: 'option',
-            width: 120,
+            width: 90,
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [
@@ -255,7 +255,8 @@ export default function VisitsAndBedDayCostSetting() {
             </ModalForm>
         )
     }
-
+    
+    
 
     return (
         <KCIMPagecontainer className='VisitsAndBedDayCostSetting' title={false}>

+ 5 - 2
src/pages/baseSetting/otherItemSet/wholeHospCostAndIncomeSet/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-21 11:10:04
+ * @LastEditTime: 2024-01-05 13:48:46
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -51,6 +51,9 @@ export default function WholeHospCostAndIncomeSet() {
         {
             title: '收支类型',
             dataIndex: 'paymentsType',
+            renderText(num) {
+                 return num == 1?'收入':'支出'
+            },
         },
         {
             title: '收支名称',
@@ -59,7 +62,7 @@ export default function WholeHospCostAndIncomeSet() {
         {
             title: '操作',
             key: 'option',
-            width: 120,
+            width: 90,
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [

+ 38 - 19
src/pages/baseSetting/responsibilityCenterSet/responsibilityCenter/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-09 19:17:52
+ * @LastEditTime: 2024-03-08 11:06:30
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -30,14 +30,15 @@ import { addData, delData, editData, getApportionmentLevelListNoPage, getRespons
 
 import './style.less';
 import KCIMUpload from '@/components/KCIMUpload';
-import { downloadTemplateReq } from '@/utils/tooljs';
+import { downloadTemplateReq, renameChildListToChildren } from '@/utils/tooljs';
 
 
 const IconFont = createFromIconfontCN({
     scriptUrl: '',
 });
 
-
+let selectableLevelList:any[] = [];
+let currentRow:any = undefined;
 
 export default function ResponsibilityCenter() {
 
@@ -45,8 +46,6 @@ export default function ResponsibilityCenter() {
     const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
     const tableRef = useRef<ActionType>();
     const formRef = useRef<ProFormInstance>();
-    const [currentRow, setCurrentRow] = useState<any | undefined>(undefined);
-    const [selectableLevelList, setSelectableLevelList] = useState([]);//可选的分摊层级列表
     const columns: ProColumns[] = [
 
         {
@@ -74,6 +73,9 @@ export default function ResponsibilityCenter() {
             title: '责任类型',
             ellipsis: true,
             dataIndex: 'responsibilityType',
+            renderText(num, record) {
+                  return num == 1?'收益中心':num == 2?'成本(费用)中心':'半收益中心'
+            },
         },
         {
             title: '分摊级别',
@@ -91,7 +93,18 @@ export default function ResponsibilityCenter() {
             width: 120,
             valueType: 'option',
             render: (_: any, record: any) => {
-                return [
+                const {isGatherCenter} = record;
+                return isGatherCenter == 1?[
+                    <UpDataActBtn key={'act'} record={record} type='ADDCHILD' />,
+                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
+                    <Popconfirm
+                        title="是否确认删除?"
+                        key="del"
+                        onConfirm={() => delTableData(record)}
+                    >
+                        <a>删除</a>
+                    </Popconfirm>,
+                ]:[
                     <UpDataActBtn key={'act'} record={record} type='EDIT' />,
                     <Popconfirm
                         title="是否确认删除?"
@@ -111,7 +124,7 @@ export default function ResponsibilityCenter() {
         const resp = await getResponsibilityCenterList({ ...params });
         if (resp) {
             return {
-                data: resp.list,
+                data: renameChildListToChildren(resp.list,'child'),
                 success: true,
                 total: resp.totalCount,
                 pageSize: resp.pageSize,
@@ -135,10 +148,11 @@ export default function ResponsibilityCenter() {
         if (type == 'ADD' || type == 'ADDCHILD') {
 
             let id = 0;
-            (currentRow && type == 'ADDCHILD') && (id = currentRow.id);
+            type == 'ADDCHILD' && (id = formVal.id);
+
             const { isDefault = 0, selectedSharelevel } = formVal;
 
-            const result = { ...formVal, shareName: selectedSharelevel ? selectedSharelevel.shareName : '', shareId: selectedSharelevel ? selectedSharelevel.id : 0, shareLevel: selectedSharelevel ? selectedSharelevel.leverSort : 0, isDefault, id };
+            const result = { ...formVal, shareName: selectedSharelevel ? selectedSharelevel.shareName : '', shareId: selectedSharelevel ? selectedSharelevel.id : 0, shareLevel: selectedSharelevel ? selectedSharelevel.leverSort : 0, isDefault, id,selectedSharelevel:null };
 
             const resp = await addData(result);
             if (resp) {
@@ -149,9 +163,9 @@ export default function ResponsibilityCenter() {
         }
         if (type == 'EDIT') {
             try {
-                const { responsibilityLevel = 0, selectedSharelevel = [], shareId } = formVal;
+                const { responsibilityLevel = 0, selectedSharelevel, shareId } = formVal;
                 let body = {};
-                if (selectedSharelevel.length == 0) {
+                if (!selectedSharelevel) {
                     //没有修改分摊层级
                     body = { ...formVal }
                 }
@@ -159,7 +173,7 @@ export default function ResponsibilityCenter() {
                 if (Object.prototype.toString.call(selectedSharelevel) == '[object Object]') {
                     //修改了分摊层级
                     //  console.log('修改了分摊层级');
-                    body = { ...formVal, shareId: selectedSharelevel.id, shareName: selectedSharelevel.shareName, shareLevel: selectedSharelevel.leverSort }
+                    body = { ...formVal, shareId: selectedSharelevel.id, shareName: selectedSharelevel.shareName, shareLevel: selectedSharelevel.leverSort,selectedSharelevel:null }
                 }
 
                 const resp = await editData({ ...body });
@@ -188,16 +202,18 @@ export default function ResponsibilityCenter() {
                     ...record,
                 } : { selectedSharelevel: 0 }}
                 trigger={
-                    type == 'EDIT' ? <a key="edit" >编辑</a> : <span className='add'>新增</span>
+                    type == 'EDIT' ? <a key="edit" >编辑</a> : type == 'ADDCHILD'?<a className='add'>添加</a>:<span className='add'>新增</span>
                 }
                 onFinish={(val) => {
-                    return updateTable(type == 'EDIT' ? { ...record, ...val } : { ...val }, type);
+                    return updateTable(type == 'EDIT' ? { ...record, ...val } :type == 'ADDCHILD'?{...val,id:record.id}:{ ...val }, type);
                 }}
                 modalProps={{ destroyOnClose: true }}
                 colProps={{ span: 24 }}
                 grid
             >
+                <ProFormText name='selectedSharelevel' hidden />
                 <ProFormSelect
+                    disabled={type == 'EDIT'}
                     rules={[
                         {
                             required: true,
@@ -223,7 +239,7 @@ export default function ResponsibilityCenter() {
                     rules={[
                         {
                             required: true,
-                            message: '医院名是必填项',
+                            message: '责任中心名是必填项',
                         },
                     ]}
                     name="responsibilityName"
@@ -286,6 +302,10 @@ export default function ResponsibilityCenter() {
                             value: 2,
                             label: '成本(费用)中心',
                         },
+                        {
+                            value: 3,
+                            label: '半收益中心',
+                        },
                     ]}
                     name="responsibilityType"
                     label="选择责任类型"
@@ -312,10 +332,9 @@ export default function ResponsibilityCenter() {
                                     }}
                                     request={async () => {
                                         const resp = await getApportionmentLevelListNoPage();
-                                        const { status, data: { list = [] } } = resp;
-                                        if (status == 200) {
-                                            setSelectableLevelList(list);
-                                            return list.map((item: any) => ({ label: `级别${item.leverSort}-${item.shareName}`, value: item.id }))
+                                        if (resp) {
+                                            selectableLevelList = resp.list;
+                                            return resp.list.map((item: any) => ({ label: `级别${item.leverSort}-${item.shareName}`, value: item.id }))
                                         } else {
                                             return []
                                         }

+ 16 - 11
src/pages/baseSetting/responsibilityCenterSet/responsibilityCenterConnect/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-13 15:06:47
+ * @LastEditTime: 2024-01-05 13:33:39
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -30,7 +30,7 @@ import { getResponsibilityCenterConnectList, saveResponsibilityCenterConnected }
 
 import './style.less';
 import KCIMUpload from '@/components/KCIMUpload';
-import { downloadTemplateReq } from '@/utils/tooljs';
+import { downloadTemplateReq, renameChildListToChildren } from '@/utils/tooljs';
 import React from 'react';
 import TableTransfer from './transform';
 
@@ -44,8 +44,8 @@ const IconFont = createFromIconfontCN({
 const transferTableColumn:ProColumns[] = [
     {
         title: 'Id',
-        ellipsis: true,
-        dataIndex: 'departmentId',
+        width:60,
+        dataIndex: 'id',
     },
     {
         title: '科室名称',
@@ -58,19 +58,21 @@ const transferTableColumn:ProColumns[] = [
 ]
 
 
+let currentRow:any = undefined;
+
 export default function ResponsibilityCenterConnect() {
 
     const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
     const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
     const tableRef = useRef<ActionType>();
     const formRef = useRef<ProFormInstance>();
-    const [currentRow, setCurrentRow] = useState<any|undefined>(undefined);
     const columns: ProColumns[] = [
 
         {
             title: '责任中心名称',
             dataIndex: 'responsibilityName',
             ellipsis: true,
+            width:120,
             renderText(_,record) {
                 const { isDefault, responsibilityName } = record;
                 return isDefault == 1 ? <Tag>{`${responsibilityName}(是)`}</Tag> : responsibilityName
@@ -79,11 +81,13 @@ export default function ResponsibilityCenterConnect() {
         {
             title: '责任中心Id',
             ellipsis: true,
+            width:120,
             dataIndex: 'responsibilityId',
         },
         {
             title: '部门列表',
             ellipsis: true,
+          
             dataIndex: 'departments',
             renderText(_,record) {
                 if (Array.isArray(_)) {
@@ -96,7 +100,7 @@ export default function ResponsibilityCenterConnect() {
         {
             title: '操作',
             key: 'option',
-            width: 120,
+            width: 100,
             valueType: 'option',
             render: (_: any, record: any) => {
                 const {isGatherCenter } = record;
@@ -104,8 +108,8 @@ export default function ResponsibilityCenterConnect() {
                     <a
                     key="1"
                     onClick={() => {
-                      addConnectDepartments(record)
-                      setCurrentRow(record);
+                      addConnectDepartments(record);
+                      currentRow = record;
                     }}
                   >
                     绑定科室
@@ -121,7 +125,7 @@ export default function ResponsibilityCenterConnect() {
         const resp = await getResponsibilityCenterConnectList({...params});
         if (resp) {
             return {
-                data: resp.list,
+                data:renameChildListToChildren(resp.list,'child'),
                 success: true,
                 total: resp.totalCount,
                 pageSize: resp.pageSize,
@@ -136,6 +140,7 @@ export default function ResponsibilityCenterConnect() {
         const {responsibilityId} = currentRow;
         const resp = await saveResponsibilityCenterConnected({responsibilityId,departmentIds:keys});
         if(resp){
+            currentRow = undefined;
             tableRef.current?.reload();
         }
     }
@@ -145,7 +150,7 @@ export default function ResponsibilityCenterConnect() {
         const ref = React.createRef<{ save: any; }>();
 
         Modal.confirm({
-            title: `选择报表列`,
+            title: `选择科室`,
             icon: <></>,
             width: 750,
             centered: true,
@@ -180,7 +185,7 @@ export default function ResponsibilityCenterConnect() {
             </div>
 
             <div style={{ }}>
-                <KCIMTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+                <KCIMTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='responsibilityId' params={tableDataFilterParams} request={(params) => getTableData(params)} />
             </div>
         </KCIMPagecontainer>
     )

+ 2 - 2
src/pages/baseSetting/responsibilityCenterSet/responsibilityCenterConnect/service.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 16:31:27
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-13 15:05:43
+ * @LastEditTime: 2023-12-07 14:50:05
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -32,7 +32,7 @@ export const  getResponsibilityCenterConnectableList = (params:any) => {
 
 //保存绑定信息
 export const saveResponsibilityCenterConnected = (body:any) => {
-  return request('/api/costAccount/centerDepartment/save', {
+  return request('/costAccount/centerDepartment/save', {
     method: 'POST',
     data:{...body},
   });

+ 13 - 5
src/pages/baseSetting/responsibilityCenterSet/responsibilityCenterConnect/transform.tsx

@@ -30,10 +30,18 @@ const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, record, onS
         let resp = await getResponsibilityCenterConnectableList({responsibilityId:record.responsibilityId});
         if (resp) {
            
-            //const allData = resp.allEmployees.concat(resp.checkEmployees);
-            resp = resp.map((a:any)=>({...a,code:a.departmentId}))
-            set_datasource(resp);
-            _set_data(resp);
+            const defaultDepartments = record.departments?(
+                record.departments.map((a:any)=>({
+                    id:a.departmentId,
+                    code:a.departmentId,
+                    departmentCode:'',
+                    departmentName:a.departmentName,
+                    departmentStatus:0
+                }))
+            ):[];
+            resp = resp.map((a:any)=>({...a,code:a.id}))
+            set_datasource([...resp,...defaultDepartments]);
+            _set_data([...resp,...(record.departments?(record.departments):[])]);
             const defaultSelctedkeys = record.departments?record.departments.map((a:any)=>a.departmentId):[]
             setTargetKeys(defaultSelctedkeys);
         }
@@ -76,7 +84,7 @@ const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, record, onS
             targetKeys={targetKeys}
             selectedKeys={selectedKeys}
             filterOption={(inputValue, item) => {
-                return item.name!.indexOf(inputValue) !== -1
+                return item.departmentName!.indexOf(inputValue) !== -1
 
             }}
         >

+ 493 - 2
src/pages/costAccounting/calcPageTemplate/columns.tsx

@@ -1,3 +1,4 @@
+import { tableColumnsWidObj } from "@/constant";
 import { formatMoneyNumber } from "@/utils/format";
 import { ProColumns } from "@ant-design/pro-components";
 
@@ -53,6 +54,7 @@ export const chargeItemCostCalc: ProColumns[] = [
     {
         title: '收费项目名称',
         dataIndex: 'name',
+        width:'20%'
     },
     {
         title: '项目类别',
@@ -168,7 +170,7 @@ export const patientCostCalc: ProColumns[] = [
     },
     {
         title: '项目成本',
-        dataIndex: 'itemIncome',
+        dataIndex: 'itemCost',
         renderText(num, record, index, action) {
             return formatMoneyNumber(num);
         },
@@ -301,6 +303,7 @@ export const DRG_DIPCostCalc: ProColumns[] = [
     },
     {
         title: '分组名称',
+        width:'18%',
         dataIndex: 'name',
     },
     {
@@ -382,6 +385,7 @@ export const clinicalPathway: ProColumns[] = [
     },
     {
         title: '路径名称',
+        width:'20%',
         dataIndex: 'name',
     },
     {
@@ -465,6 +469,7 @@ export const medicalOrderItem: ProColumns[] = [
     {
         title: '医嘱项目名称',
         dataIndex: 'name',
+        width:'18%'
     },
     {
         title: '科室代码',
@@ -474,7 +479,7 @@ export const medicalOrderItem: ProColumns[] = [
         title: '科室名称',
         dataIndex: 'departmentName',
     },
-    
+
     {
         title: '项目成本',
         dataIndex: 'itemCost',
@@ -538,4 +543,490 @@ export const medicalOrderItem: ProColumns[] = [
             return formatMoneyNumber(num);
         },
     },
+];
+
+export const medicalMaterialCostCalc: ProColumns[] = [
+    {
+        title: '责任中心代码',
+        dataIndex: 'responsibilityCode',
+    },
+    {
+        title: '责任中心名称',
+        dataIndex: 'responsibilityName',
+        width:'10%'
+    },
+    {
+        title: '收费项目编码',
+        dataIndex: 'code',
+    },
+    {
+        title: '收费项目名称',
+        dataIndex: 'name',
+        width:'30%'
+    },
+
+    {
+        title: '项目类别',
+        dataIndex: 'itemType',
+    },
+    {
+        title: '药品收入',
+        dataIndex: 'drugIncome',
+        renderText(num, record, index, action) {
+            return formatMoneyNumber(num);
+        },
+    },
+    {
+        title: '材料收入',
+        dataIndex: 'materialIncome',
+        renderText(num, record, index, action) {
+            return formatMoneyNumber(num);
+        },
+    },
+    {
+        title: '药品成本',
+        dataIndex: 'drugCost',
+        renderText(num, record, index, action) {
+            return formatMoneyNumber(num);
+        },
+    },
+    {
+        title: '材料成本',
+        dataIndex: 'materialCost',
+        renderText(num, record, index, action) {
+            return formatMoneyNumber(num);
+        },
+    },
+    
+];
+export const beforeCollectionSearch: ProColumns[] = [
+    {
+        title: '收入项目',
+        dataIndex: 'productCodeName',
+    },
+    {
+        title: '会计科目',
+        dataIndex: 'accountCodeName',
+    },
+    {
+        title: '金额(元)',
+        dataIndex: 'amount',
+        width:130,
+        renderText(num, record, index, action) {
+            return formatMoneyNumber(num);
+        },
+    },
+    {
+        title: '开单科室',
+        dataIndex: 'openDepartmentCodeName',
+        
+    },
+    {
+        title: '开单责任中心',
+        dataIndex: 'openResponsibilityCodeName',
+    },
+
+    {
+        title: '执行科室',
+        dataIndex: 'startDepartmentCodeName',
+    },
+    {
+        title: '执行责任中心',
+        dataIndex: 'startResponsibilityCodeName',
+    },
+];
+
+export const incomeCollection: ProColumns[] = [
+    {
+        title: '年份',
+        dataIndex: 'year',
+    },
+    {
+        title: '月份',
+        dataIndex: 'month',
+    },
+    {
+        title: '金额',
+        dataIndex: 'amount',
+        renderText(num, record, index, action) {
+            return formatMoneyNumber(num);
+        },
+    },
+
+];
+export const afterCollectionSearch: ProColumns[] = [
+    {
+        title: '年份',
+        dataIndex: 'year',
+        width: tableColumnsWidObj.year
+    },
+    {
+        title: '月份',
+        dataIndex: 'month',
+        width: tableColumnsWidObj.month
+    },
+    {
+        title: '科室编码',
+        dataIndex: 'departmentCode',
+    },
+    {
+        title: '科室名称',
+        width: tableColumnsWidObj.departmentName,
+        dataIndex: 'departmentName',
+    },
+    {
+        title: '责任中心编码',
+        width: tableColumnsWidObj.responsibilityCenterCode,
+        dataIndex: 'responsibilityCode',
+    },
+    {
+        title: '责任中心名称',
+        width: tableColumnsWidObj.responsibilityCenter,
+        dataIndex: 'responsibilityName',
+    },
+    {
+        title: '会计科目编码',
+        dataIndex: 'accountingCode',
+    },
+    {
+        title: '会计科目名',
+        dataIndex: 'accountingName',
+    },
+    {
+        title: '成本项目编码',
+        dataIndex: 'productCode',
+    },
+    {
+        title: '成本项目名',
+        dataIndex: 'productName',
+    },
+    {
+        title: '金额',
+        dataIndex: 'amount',
+        renderText(num, record, index, action) {
+            return formatMoneyNumber(num);
+        },
+    },
+
+];
+
+export const beforeCostShareSearch: ProColumns[] = [
+    {
+        title: '成本项目',
+        width:'20%',
+        dataIndex: 'productName',
+        renderText(num, record, index, action) {
+            const {productCode,productName} = record;
+            return `[${productCode}]${productName}`
+        },
+    },
+    {
+        title: '会计科目',
+        width:'20%',
+        dataIndex: 'accountName',
+        renderText(num, record, index, action) {
+            const {accountCode,accountName} = record;
+            return `[${accountCode}]${accountName}`
+        },
+    },
+    {
+        title: '金额(元)',
+        width:'20%',
+        dataIndex: 'amount',
+        renderText(num, record, index, action) {
+            return formatMoneyNumber(num);
+        },
+    },
+    {
+        title: '科室名称',
+        width:'20%',
+        dataIndex: 'departName',
+        renderText(num, record, index, action) {
+            const {departCode,departName} = record;
+            return `[${departCode}]${departName}`
+        },
+    },
+    {
+        title: '责任中心名',
+        dataIndex: 'responsibilityName',
+        width:'20%',
+        renderText(num, record, index, action) {
+            const {responsibilityCode,responsibilityName} = record;
+            return `[${responsibilityCode}]${responsibilityName}`
+        },
+    },
+];
+
+export const costShare: ProColumns[] = [
+    {
+        title: '年份',
+        dataIndex: 'year',
+    },
+    {
+        title: '月份',
+        dataIndex: 'month',
+    },
+    {
+        title: '金额',
+        dataIndex: 'amount',
+        renderText(num, record, index, action) {
+            return formatMoneyNumber(num);
+        },
+    },
+    {
+        title: '是否分摊',
+        dataIndex: 'isAllocation',
+        render: bool => bool ? '已分摊' : '未分摊'
+    },
+
+];
+
+export const afterCostShareSearch: ProColumns[] = [
+    {
+        title: '年份',
+        dataIndex: 'dateYear',
+        width: tableColumnsWidObj.year
+    },
+    {
+        title: '月份',
+        dataIndex: 'dateMonth',
+        width: tableColumnsWidObj.month
+    },
+    {
+        title: '分摊层级',
+        width: tableColumnsWidObj.shareLevel,
+        dataIndex: 'levelSort',
+    },
+    {
+        title: '分摊层级名',
+        dataIndex: 'levelName',
+    },
+    {
+        title: '责任中心编码',
+        width: tableColumnsWidObj.responsibilityCenterCode,
+        dataIndex: 'responsibilityCode',
+    },
+    {
+        title: '责任中心名',
+        width: tableColumnsWidObj.responsibilityCenter,
+        dataIndex: 'responsibilityName',
+    },
+    {
+        title: '会计科目编码',
+        dataIndex: 'accountingCode',
+        width: 300
+    },
+    {
+        title: '会计科目名',
+        dataIndex: 'accountingName',
+    },
+    {
+        title: '金额',
+        dataIndex: 'amount',
+        renderText(num, record, index, action) {
+            return formatMoneyNumber(num);
+        },
+    },
+
+];
+
+export const departmentCostCalculate: ProColumns[] = [
+    {
+        title: '责任中心',
+        dataIndex: 'responsibilityCode',
+
+    },
+    {
+        title: '年份',
+        dataIndex: 'year',
+
+    },
+    {
+        title: '月份',
+        dataIndex: 'month',
+
+    },
+    {
+        title: '报表项目编码',
+        width: '10%',
+        dataIndex: 'reportNum',
+    },
+    {
+        title: '报表项目名',
+        dataIndex: 'reportName',
+    },
+    {
+        title: '责任中心名',
+        dataIndex: 'responsibilityName',
+    },
+    {
+        title: '责任中心编码',
+        dataIndex: 'responsibilityCode',
+
+    },
+    {
+        title: '金额',
+        width: '10%',
+        dataIndex: 'amount',
+        renderText(num, record, index, action) {
+            return formatMoneyNumber(num);
+        },
+    },
+    {
+        title: '占比',
+        dataIndex: 'percentName',
+    },
+
+];
+export const wholeHospCostCalculate: ProColumns[] = [
+    {
+
+        title: '年份',
+        dataIndex: 'dateYear',
+    },
+    {
+        title: '月份',
+        dataIndex: 'dateMonth',
+    },
+    {
+        title: '报表项目编码',
+        dataIndex: 'reportNum',
+    },
+    {
+        title: '报表项目名',
+        dataIndex: 'reportName',
+    },
+    {
+        title: '责任中心名',
+        dataIndex: 'responsibilityName',
+    },
+    {
+        title: '金额',
+        dataIndex: 'amount',
+        renderText(num, record, index, action) {
+            return formatMoneyNumber(num);
+        },
+    },
+
+];
+
+export const costShareReportTable: ProColumns[] = [
+    {
+        title: '年份',
+        dataIndex: 'year',
+    },
+    {
+        title: '月份',
+        dataIndex: 'month',
+    },
+    {
+        title: '分摊报表名称',
+        dataIndex: 'shareReportName',
+    },
+    {
+        title: '分摊层级',
+        dataIndex: 'shareLevel',
+    },
+    {
+        title: '分摊时间',
+        dataIndex: 'shareTime',
+    },
+];
+
+export const departmentOperatingReport: ProColumns[] = [
+    {
+        title: '年份',
+        width: 100,
+        dataIndex: 'dateYear',
+    },
+    {
+        title: '月份',
+        width: 100,
+        dataIndex: 'dateMonth',
+    },
+    {
+        title: '报表类型',
+        width: 100,
+        dataIndex: 'fileType',
+    },
+    {
+        title: '报表名称',
+        dataIndex: 'fileName',
+    },
+    {
+        title: '更新时间',
+        width: 180,
+        dataIndex: 'updateTime',
+    },
+];
+export const wholeHospOperatingReport: ProColumns[] = [
+    {
+        title: '年份',
+        width: 100,
+        dataIndex: 'dateYear',
+    },
+    {
+        title: '月份',
+        width: 100,
+        dataIndex: 'dateMonth',
+    },
+    {
+        title: '报表类型',
+        width: 120,
+        dataIndex: 'fileType',
+    },
+    {
+        title: '报表名称',
+        dataIndex: 'fileName',
+    }
+];
+
+export const projectShareParamsCalc: ProColumns[] = [];
+export const projectCostCalc: ProColumns[] = [
+    {
+        title: '责任中心编码',
+        dataIndex: 'responsibilityCode',
+        width:tableColumnsWidObj.responsibilityCenterCode
+    },
+    {
+        title: '责任中心名称',
+        dataIndex: 'responsibilityName',
+        width:tableColumnsWidObj.responsibilityCenter
+    },
+    {
+        title: '收费项目编码',
+        dataIndex: 'code',
+    },
+    {
+        title: '收费项目名称',
+        dataIndex: 'name',
+    },
+    {
+        title: '项目分类',
+        dataIndex: 'itemTypeName',
+    },
+    {
+        title: '项目成本',
+        dataIndex: 'itemCost',
+    },
+    {
+        title: '人事成本',
+        dataIndex: 'empCost',
+    },
+    {
+        title: '设备成本',
+        dataIndex: 'equipmentCost',
+    },
+    {
+        title: '空间成本',
+        dataIndex: 'spaceCost',
+    },
+    {
+        title: '公共费用分摊',
+        dataIndex: 'publicShareCost',
+    },
+    {
+        title: '管理费用分摊',
+        dataIndex: 'managerShareCost',
+    }
 ];

+ 205 - 1
src/pages/costAccounting/calcPageTemplate/config.ts

@@ -2,12 +2,17 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-11-01 11:13:38
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-23 19:25:46
+ * @LastEditTime: 2024-01-17 15:11:17
  * @FilePath: /CostAccountingSys/src/pages/costAccounting/calcPageTemplate/config.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
 
+import { KcimCenterSysId } from "@/constant";
+import { getAccountingSubjectList } from "@/pages/baseSetting/accountingAccountSet/accountingSubMana/service";
+import { getResponsibilityCenterList } from "@/pages/baseSetting/responsibilityCenterSet/responsibilityCenter/service";
 import { getTargetDic } from "@/services/auth";
+import { getDicDataBySysId } from "@/services/getDic";
+import { getCostProjecttList } from "./service";
 
 
 
@@ -106,3 +111,202 @@ export const medicalOrderItemFilterConf = [
     }
 ]
 
+export const beforeCollectionSearchFilterConf = [
+    {
+        type:'cascader',
+        label:'执行责任中心:',
+        placeholder:'请选择',
+        key:'responsibilityCode',
+        request:async ()=>{
+            const resp = await await getResponsibilityCenterList({pageSize:500});
+            if (resp) {
+              return resp.list
+            }
+        }
+    },
+    {
+        type:'select',
+        label:'成本项目:',
+        placeholder:'请选择',
+        key:'productCode',
+        request:async ()=>{
+            const resp = await getCostProjecttList({pageSize:500});
+            if (resp) {
+              return resp.list.map((a:any) => ({ label: a.productName, value: a.productCode }));
+            }
+        }
+    },
+]
+
+export const afterCollectionSearchFilterConf = [
+    {
+        type:'cascader',
+        label:'责任中心:',
+        placeholder:'请选择',
+        key:'responsibilityCode',
+        request:async ()=>{
+            const resp = await await getResponsibilityCenterList({pageSize:500});
+            if (resp) {
+              return resp.list
+            }
+        }
+    },
+    {
+        type:'select',
+        label:'成本项目:',
+        placeholder:'请选择',
+        key:'productCode',
+        request:async ()=>{
+            const resp = await getCostProjecttList({pageSize:500});
+            if (resp) {
+              return resp.list.map((a:any) => ({ label: a.productName, value: a.productCode }));
+            }
+        }
+    },
+]
+
+export const beforeCostShareSearchFilterConf = [
+    {
+        type:'cascader',
+        label:'责任中心:',
+        placeholder:'请选择',
+        key:'responsibilityCode',
+        request:async ()=>{
+            const resp = await await getResponsibilityCenterList({pageSize:500});
+            if (resp) {
+              return resp.list
+            }
+        }
+    },
+    {
+        type:'select',
+        label:'会计科目(支出):',
+        placeholder:'请选择',
+        key:'accountCode',
+        request:async ()=>{
+            const resp =  await getAccountingSubjectList({pageSize:500,current:1,accountType:2});
+            if (resp) {
+              return resp.list.map((a:any) => ({ label: a.accountingName, value: a.accountingCode }));
+            }
+        }
+    },
+]
+
+export const afterCostShareSearchFilterConf = [
+    {
+        type:'cascader',
+        label:'责任中心:',
+        placeholder:'请选择',
+        key:'responsibilityCode',
+        request:async ()=>{
+            const resp = await await getResponsibilityCenterList({pageSize:500});
+            if (resp) {
+              return resp.list
+            }
+        }
+    }
+]
+
+export const departmentCostCalculateFilterConf = [
+    {
+        type:'cascader',
+        label:'执行责任中心:',
+        placeholder:'请选择',
+        key:'responsibilityCode',
+        request:async ()=>{
+            const resp = await await getResponsibilityCenterList({pageSize:500});
+            if (resp) {
+              return resp.list
+            }
+        }
+    }
+]
+
+export const medicalMaterialCostCalcFilterConf = [
+    {
+        type:'cascader',
+        label:'责任中心:',
+        placeholder:'请选择',
+        key:'responsibilityCode',
+        request:async ()=>{
+            const resp = await await getResponsibilityCenterList({pageSize:500});
+            if (resp) {
+              return resp.list
+            }
+        }
+    },
+    {
+        type:'input',
+        label:'检索:',
+        placeholder:'项目代码/名称',
+        key:'filter'
+    }
+];
+
+export const projectShareParamsCalcFilterConf = [
+    {
+        type:'select',
+        label:'项目分类:',
+        placeholder:'请选择',
+        key:'itemType',
+        request:async ()=>{
+            const resp = await getDicDataBySysId(KcimCenterSysId,'MED_SERVICE_ITEM_TYPE');
+            if (resp) {
+              return resp.dataVoList.map((a:any) => ({ label: a.name, value: a.code }));
+            }
+        }
+    },
+    {
+        type:'cascader',
+        label:'责任中心:',
+        placeholder:'请选择',
+        key:'responsibility',
+        request:async ()=>{
+            const resp = await await getResponsibilityCenterList({pageSize:500});
+            if (resp) {
+              return resp.list
+            }
+        }
+    },
+    {
+        type:'input',
+        label:'检索:',
+        placeholder:'项目代码/名称',
+        key:'itemFilter'
+    }
+]
+export const projectCostCalcFilterConf = [
+    {
+        type:'select',
+        label:'项目分类:',
+        placeholder:'请选择',
+        key:'itemType',
+        request:async ()=>{
+            const resp = await getDicDataBySysId(KcimCenterSysId,'MED_SERVICE_ITEM_TYPE');
+            if (resp) {
+              return resp.dataVoList.map((a:any) => ({ label: a.name, value: a.code }));
+            }
+        }
+    },
+    {
+        type:'cascader',
+        label:'责任中心:',
+        placeholder:'请选择',
+        key:'responsibility',
+        request:async ()=>{
+            const resp = await await getResponsibilityCenterList({pageSize:500});
+            if (resp) {
+              return resp.list
+            }
+        }
+    },
+    {
+        type:'input',
+        label:'检索:',
+        placeholder:'项目代码/名称',
+        key:'itemFilter'
+    }
+]
+
+
+

+ 562 - 41
src/pages/costAccounting/calcPageTemplate/index.tsx

@@ -2,17 +2,17 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-23 19:21:35
+ * @LastEditTime: 2024-03-19 14:26:21
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
 
 import { createFromIconfontCN } from '@ant-design/icons';
 
-import { DatePicker, Input, Modal, message } from 'antd';
+import { DatePicker, Input, Modal, message, Table, Button } from 'antd';
 import { useEffect, useRef, useState } from 'react';
 
-import { calculateReq, getData } from './service';
+import { calculateReq, cancelAllocation, cancelIncomeCollection, downloadTemplateReq, generateReportHandle, getAfterCostShareSearchTableData, getAfterIncomeCollectionTableData, getCalcPageTableData, startAllocation, startIncomeCollection } from './service';
 
 import './style.less';
 import moment from 'moment';
@@ -21,19 +21,29 @@ import locale from 'antd/es/date-picker/locale/zh_CN';
 import KCIMPagecontainer from '@/components/KCIMPageContainer';
 import { KCIMTable } from '@/components/KCIMTable';
 
-import { ActionType, ProColumns, ProFormSelect } from '@ant-design/pro-components';
+import { ActionType, ProColumns, ProFormCascader, ProFormSelect } from '@ant-design/pro-components';
 import { formatMoneyNumber } from '@/utils/format';
 import { getTargetDic } from '@/services/auth';
 import { useParams } from '@umijs/max';
-import { chargeItemCostCalc, diseaseCostCalculation, DRG_DIPCostCalc, medicalOrderItem, patientCostCalc, unitPersonnelCostCalc } from './columns';
-import { chargeItemCostCalcFilterConf, clinicalPathwayFilterConf, diseaseCostCalculationFilterConf, DRG_DIPCostCalcFilterConf, medicalOrderItemFilterConf, patientCostCalcFilterConf, unitPersonnelCostCalcFilterConf } from './config';
+import { afterCollectionSearch, afterCostShareSearch, beforeCollectionSearch, beforeCostShareSearch, chargeItemCostCalc, clinicalPathway, costShare, costShareReportTable, departmentCostCalculate, departmentOperatingReport, diseaseCostCalculation, DRG_DIPCostCalc, incomeCollection, medicalMaterialCostCalc, medicalOrderItem, patientCostCalc, projectCostCalc, projectShareParamsCalc, unitPersonnelCostCalc, wholeHospCostCalculate, wholeHospOperatingReport } from './columns';
+import { afterCollectionSearchFilterConf, afterCostShareSearchFilterConf, beforeCollectionSearchFilterConf, beforeCostShareSearchFilterConf, chargeItemCostCalcFilterConf, clinicalPathwayFilterConf, departmentCostCalculateFilterConf, diseaseCostCalculationFilterConf, DRG_DIPCostCalcFilterConf, medicalMaterialCostCalcFilterConf, medicalOrderItemFilterConf, patientCostCalcFilterConf, projectCostCalcFilterConf, projectShareParamsCalcFilterConf, unitPersonnelCostCalcFilterConf } from './config';
+import { getStringWidth, renameChildListToChildren } from '@/utils/tooljs';
+import ProgressModal from '@/components/ProgressModal';
+import { useAccess } from '@umijs/max';
+import ExportProgressModal from '@/pages/reportExport/report/ExportProgressModal';
+import exportTableToExcel from '@/utils/tableToExcel';
 
 
 const IconFont = createFromIconfontCN({
   scriptUrl: '',
 });
 
-const currentData = `${new Date().getFullYear()}-${(new Date().getMonth() + 1).toString().padStart(2, '0')}`
+const currentData = `${new Date().getFullYear()}-${(new Date().getMonth() + 1).toString().padStart(2, '0')}`;
+
+const calTypeStr = `ITEM_COST_CALCULATE${(new Date()).getTime()}`;
+
+let currentPage = 0;
+let totalTableData:any[] = [];
 
 export default function calcPageTemplate() {
   const [computeDate, set_computeDate] = useState(currentData);
@@ -44,24 +54,92 @@ export default function calcPageTemplate() {
   const params = useParams();
   const [columns, set_columns] = useState<ProColumns[]>([]);
   const [filterConf, set_filterConf] = useState<any[]>([]);
-  const [scrollX,set_scrollX] = useState(1000);
+  const [scrollX, set_scrollX] = useState(500);
+  const [ifShowCalcBtn, set_ifShowCalcBtn] = useState(true);
+  const [totalCount, set_totalCount] = useState<undefined | number>(undefined);
+  const [inputValues, setInputValues] = useState<{ [key: string]: any }>({});
+  const [btnAccessStr,set_btnAccessStr] = useState<undefined|string>(undefined);
+
+  const access = useAccess();
+
+  const [isModalVisible, setIsModalVisible] = useState(false);
+  const [openProcessModal,set_openProcessModal] = useState(false);
+
 
   const getTableData = async (params: any) => {
-    const resp = await getData({ ...params, ...tableDataFilterParams });
+    const resp = await getCalcPageTableData({ ...params, ...tableDataFilterParams });
     if (resp) {
-      let data = resp.list?resp.list:resp
-      if(params.calcPageKey == 'unitPersonnelCostCalc'){
-        data = data.map((a:any) => ({ ...a, children: a.childList }))
-      }
-      return {
-        data:data,
-        success: true,
-        total: resp.totalCount,
-        pageSize: resp.pageSize,
-        totalPage: resp.totalPage,
-        
-      };
+      try {
+        if(params.calcPageKey == 'projectShareParamsCalc'){
+            const {pageData:{list=[],pageSize,totalCount,totalPage},title} = resp;
+            const columns: ProColumns[] = title.map((item: any, index: number) => {
+              return {
+                title: item.name,
+                dataIndex: `${item.code}`,
+                key: `${item.code}`,
+                // width: getStringWidth(item.name, '14px'),
+                ellipsis: true,
+                fixed: item.freeze ? true : false,
+                hideInTable: item.hide,
+                sorter: item.sortStatus ? (a: any, b: any) => {
+                  if (item.dataType == 3) {
+                    //数值
+                    return b[`${item.code}`] - (a[`${item.code}`]);
+                  } else {
+                    return b[`${item.code}`]?.localeCompare(a[`${item.code}`]);
+                  }
+                } : undefined,      
+              }
+            });
+            set_columns([...columns]);
+
+            const data = list.map((item: any) => {
+
+              let rowData: { [key: string]: any } = {};
+      
+              item.forEach((b: any) => {
+                const needTitle = title.filter((a: any) => a.code == b.code);
+                if (needTitle.length > 0) {
+                  rowData[`${needTitle[0].code}`] = b.value
+                }
+              });
+      
+      
+              return { ...item, ...rowData, id: Math.random(), columns }
+            });
+
+            return {
+              data: data,
+              success: true,
+              total: totalCount,
+              pageSize: pageSize,
+              totalPage: totalPage,
+            }
+
+        }
+        let data = (resp.list && resp.list != null) ? resp.list : (Array.isArray(resp) ? resp : []);
+        if (params.calcPageKey == 'unitPersonnelCostCalc') {
+          data = data ? data.map((a: any) => ({ ...a, children: a.childList })) : []
+        }
+        if (params.calcPageKey == 'beforeCollectionSearch' || params.calcPageKey == 'beforeCostShareSearch' || params.calcPageKey == 'afterCostShareSearch' || params.calcPageKey == 'afterCollectionSearch') {
+          const { totalAmount = 0 } = resp;
+          set_totalCount(totalAmount);
+        } else {
+          set_totalCount(undefined);
+        }
 
+        return {
+          data,
+          success: true,
+          total: resp.totalCount,
+          pageSize: resp.pageSize,
+          totalPage: resp.totalPage,
+
+        };
+
+      } catch (err) {
+        console.log({ err })
+      }
     }
     return [];
   };
@@ -70,7 +148,7 @@ export default function calcPageTemplate() {
 
     set_tableDataFilterParams({
       ...tableDataFilterParams,
-      [`${paramName}`]: tableDataSearchKeywords
+      [`${paramName}`]: inputValues[`${paramName}`]
     })
 
   }
@@ -80,26 +158,47 @@ export default function calcPageTemplate() {
     Modal.confirm({
       title: '注意',
       content: '计算操作会覆盖当月已计算的数据,是否继续操作?',
-      okText:'确定',
-      cancelText:'取消',
+      okText: '确定',
+      cancelText: '取消',
       onOk: async (...args) => {
-        set_loading(true);
-        const resp = await calculateReq(computeDate, params.calcPageKey);
-        if (resp) {
 
-          set_loading(false);
-          message.success('操作成功!');
-          tableRef.current?.reload();
-        } else {
-          set_loading(false);
+        if (params.calcPageKey != 'chargeItemCostCalc') {
+          set_loading(true);
+          const resp = await calculateReq(computeDate, params.calcPageKey);
+          if (resp) {
+            set_loading(false);
+            message.success('操作成功!');
+            tableRef.current?.reload();
+          } else {
+            set_loading(false);
+          }
         }
+
+
+        if (params.calcPageKey == 'chargeItemCostCalc') {
+          a();
+          return false;
+        }
+
       },
     })
   }
 
+  const a = async () => {
+    setIsModalVisible(true);
+    const resp = await calculateReq(computeDate, params.calcPageKey,calTypeStr);
+
+    if(resp){
+      setIsModalVisible(false);
+    }else{
+      setIsModalVisible(false);
+    }
+    tableRef.current?.reload();
+  }
+
   const generateFilterItems = (configs: any[]) => {
     const nodes = configs.map((item: any) => {
-      const { type, key, label, placeholder,request } = item;
+      const { type, key, label, placeholder, request } = item;
       if (type == 'input') {
         return (
           <div className='filterItem' style={{ marginLeft: 16, width: 205 }}>
@@ -108,9 +207,12 @@ export default function calcPageTemplate() {
               suffix={
                 <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle(`${key}`)} />
               }
-            
+              value={inputValues[`${key}`] || ''}
               onChange={(e) => {
-                set_tableDataSearchKeywords(e.target.value);
+                setInputValues(prevValues => ({
+                  ...prevValues,
+                  [key]: e.target.value
+                }));
                 if (e.target.value.length == 0) {
                   set_tableDataFilterParams({
                     ...tableDataFilterParams,
@@ -118,6 +220,7 @@ export default function calcPageTemplate() {
                   });
                 }
               }}
+
               onPressEnter={(e) => {
                 set_tableDataFilterParams({
                   ...tableDataFilterParams,
@@ -130,7 +233,7 @@ export default function calcPageTemplate() {
         )
       }
       if (type == 'select') {
-       
+
         return (
           <div className='filterItem' style={{ marginLeft: 16 }}>
             <span className='label'>{label}</span>
@@ -140,8 +243,8 @@ export default function calcPageTemplate() {
               placeholder="请选择"
               style={{ width: 160, marginRight: 16 }}
               request={async () => {
-                const arr =  await request();
-                if(arr)return arr
+                const arr = await request();
+                if (arr) return arr
                 return [];
               }}
               fieldProps={{
@@ -153,6 +256,32 @@ export default function calcPageTemplate() {
           </div>
         )
       }
+      if (type == 'cascader') {
+
+        return (
+          <div className='filterItem' style={{ marginLeft: 16 }}>
+            <span className='label'>{label}</span>
+            <ProFormCascader
+              noStyle
+              allowClear
+              placeholder="请选择"
+              request={async () => {
+                const resp = await request();
+                if (resp) {
+                  return resp
+                }
+                return [];
+              }}
+              fieldProps={{
+                fieldNames: { label: 'responsibilityName', value: 'responsibilityCode', children: 'child' },
+                onChange(value: any, option: any) {
+                  set_tableDataFilterParams({ ...tableDataFilterParams, [`${key}`]: value ? value[value.length - 1] : null })
+                },
+              }}
+            />
+          </div>
+        )
+      }
       return <></>
     });
 
@@ -160,50 +289,436 @@ export default function calcPageTemplate() {
   }
 
 
+  const optionBtnGroupshandle = async (isCollection: boolean, record: any) => {
+
+    if (params.calcPageKey == 'incomeCollection') {
+      const { year, month } = record;
+      if (isCollection) {
+        const resp = await cancelIncomeCollection({ year, month });
+        if (resp) {
+          message.success('操作成功!');
+          tableRef.current?.reload();
+        }
+      } else {
+        Modal.confirm({
+          title: '注意',
+          content: '收入归集操作会覆盖已有的归集后数据,确定要继续操作?',
+          okText: '确定',
+          cancelText: '取消',
+          onOk: async (...args) => {
+            set_loading(true);
+            const resp = await startIncomeCollection({ year, month });
+            if (resp) {
+
+              set_loading(false);
+              message.success('操作成功!');
+              tableRef?.current?.reload();
+            } else {
+              set_loading(false);
+            }
+          },
+        })
+      }
+    }
+    if (params.calcPageKey == 'costShare') {
+      const { year, month } = record;
+      if (!isCollection) {
+        //开始分摊
+        Modal.confirm({
+          title: '注意',
+          content: '成本分摊操作会覆盖已有的分摊后数据,确定要继续操作?',
+          okText: '确定',
+          cancelText: '取消',
+          onOk: async (...args) => {
+            set_loading(true);
+            const resp = await startAllocation({ year, month});
+            if (resp) {
+
+              set_loading(false);
+              message.success('操作成功!');
+              tableRef?.current?.reload();
+            } else {
+              set_loading(false);
+            }
+          },
+        })
+
+      }
+      if (isCollection) {
+        //撤销分摊
+        const resp = await cancelAllocation({ year, month });
+        if (resp) message.success('操作成功!');
+        tableRef?.current?.reload();
+      }
+
+
+    }
+
+  }
+
+
+  const openDataTable = async () => {
+    set_loading(true);
+    try {
+      const { responsibilityCode = null } = tableDataFilterParams;
+      let resp: any = undefined;
+      if (params.calcPageKey == 'afterCostShareSearch') {
+        resp = await getAfterCostShareSearchTableData(
+          { year: `${computeDate}-01`, responsibilityCode }
+        );
+      }
+      if (params.calcPageKey == 'afterCollectionSearch') {
+        resp = await getAfterIncomeCollectionTableData(
+          { ...params, date: `${computeDate.replace(/-/g, '')}` }
+        );
+      }
+
+      if (resp) {
+        const { titleMap = {}, realData = [], totalMap = {} } = resp;
+        const titleMapToArr = Object.entries(titleMap);
+        const totalMapToArr = Object.entries(totalMap);
+        const columns = [...titleMapToArr].map((item, index) => {
+          if (index == 0 || index == [...titleMapToArr].length - 1) {
+            return {
+              title: item[1],
+              key: item[0],
+              dataIndex: item[0],
+              fixed: index == 0 ? 'left' : 'right',
+              width: 150,
+            }
+          }
+          return {
+            title: item[1],
+            dataIndex: item[0],
+            key: item[0],
+            width: 150,
+          }
+        });
+        set_loading(false);
+        Modal.info({
+          title: '报表数据',
+          icon: '',
+          okText: '确定',
+          width: 800,
+          content: (
+            <KCIMTable
+              rowKey='id'
+              scroll={{ x: (columns.length) * 150, y: 450 }}
+              columns={columns as ProColumns[]}
+              dataSource={[...realData]}
+              pagination={false}
+              summary={() => (
+                <Table.Summary fixed >
+                  <Table.Summary.Row className="rowCell">
+                    {/* <Table.Summary.Cell className="firstCell" index={0}>合计</Table.Summary.Cell> */}
+                    {
+                      totalMapToArr.map((item, index) => {
+                        return (
+                          <Table.Summary.Cell key={index} className={index == totalMapToArr.length - 1 ? 'ant-table-cell ant-table-cell-fix-right ant-table-cell-fix-right-last' : 'cell'} index={index}>{item[1] as any}</Table.Summary.Cell>
+                        )
+                      })
+                    }
+                  </Table.Summary.Row>
+                </Table.Summary>
+              )}
+            />
+          )
+        })
+
+      }
+    } catch (err) {
+      console.log({ err });
+    }
+
+
+  }
+
+  const generateReport = async () => {
+    // {date:computeDate,reportType:0}
+    let today = new Date();
+    let day = today.getDate();
+    if (params.calcPageKey == 'departmentOperatingReport') {
+      const resp = await generateReportHandle({ date: `${computeDate}-${day < 10 ? '0' + day : day}`, reportType: 0 }, '/costAccount/costdepartmentprofit/getDepartProfitReport');
+      if (resp) {
+        tableRef.current?.reload();
+      }
+    }
+    if (params.calcPageKey == 'wholeHospOperatingReport') {
+      const resp = await generateReportHandle({ date: `${computeDate}-${day < 10 ? '0' + day : day}`, reportType: 0 }, '/costAccount/hospProfitAndLoss/report');
+      if (resp) {
+        tableRef.current?.reload();
+      }
+    }
+    if (params.calcPageKey == 'costShareReportTable') {
+      const resp = await generateReportHandle({ date: `${computeDate}-${day < 10 ? '0' + day : day}`, reportType: 0 }, '/costAccount/hospProfitAndLoss/report');
+      if (resp) {
+        tableRef.current?.reload();
+      }
+    }
+
+  }
+
+  const handleCompletion = () => {
+    setIsModalVisible(false);
+  };
+
+  const handleExportCompletion = ()=>{
+    currentPage = 0;
+    set_openProcessModal(false);
+    exportHandle();
+  }
+
+  const exportHandle = () => {
+
+    let headers: { [key: string]: any } = {};
+    let data: any[] = [];
+    
+    columns.forEach(a => {
+      headers[`${a.dataIndex}`] = a.title;
+    });
+
+    totalTableData.forEach(b => {
+      let _temp: { [key: string]: any } = {};
+      Object.keys(headers).forEach(key => {
+        _temp[`${key}`] = b[`${key}`]
+      });
+      data.push(_temp);
+    });
+
+    exportTableToExcel(data, columns as any[],'项目成本计算');
+    currentPage = 0;
+    totalTableData = [];
+    // tableRef.current?.reload();
+  }
+
+  const fetchExportData = async () => {
+    
+    currentPage  = currentPage + 1 ;
+
+    const resp:any = await getTableData({...tableDataFilterParams,current:currentPage,pageSize:100});
+   
+    if(resp){
+      const { total=0,data} = resp;
+      totalTableData = [...totalTableData,...data];
+      return {
+        currentCount:totalTableData.length,
+        totalCount:total,
+      }
+
+    }else{
+      return { currentCount:0, totalCount:0};
+    }
+  };
+
 
   useEffect(() => {
+    setInputValues({});
     const { calcPageKey } = params;
     if (calcPageKey == "chargeItemCostCalc") {
       set_columns(chargeItemCostCalc);
       set_filterConf(chargeItemCostCalcFilterConf);
+      set_ifShowCalcBtn(true);
+      set_scrollX(1500);
     }
     if (calcPageKey == "patientCostCalc") {
       set_columns(patientCostCalc);
       set_scrollX(1500);
       set_filterConf(patientCostCalcFilterConf);
+      set_ifShowCalcBtn(true);
     }
     if (calcPageKey == "unitPersonnelCostCalc") {
       set_columns(unitPersonnelCostCalc);
       set_scrollX(1000);
       set_filterConf(unitPersonnelCostCalcFilterConf);
+      set_ifShowCalcBtn(true);
     }
     if (calcPageKey == "diseaseCostCalculation") {
       set_columns(diseaseCostCalculation);
       set_scrollX(1500);
       set_filterConf(diseaseCostCalculationFilterConf);
+      set_ifShowCalcBtn(true);
     }
     if (calcPageKey == "DRG_DIPCostCalc") {
       set_columns(DRG_DIPCostCalc);
       set_scrollX(1500);
       set_filterConf(DRG_DIPCostCalcFilterConf);
+      set_ifShowCalcBtn(true);
     }
     if (calcPageKey == "clinicalPathway") {
-      set_columns(DRG_DIPCostCalc);
+      set_columns(clinicalPathway);
       set_scrollX(1500);
       set_filterConf(clinicalPathwayFilterConf);
+      set_ifShowCalcBtn(true);
     }
     if (calcPageKey == "medicalOrderItem") {
       set_columns(medicalOrderItem);
       set_scrollX(1500);
       set_filterConf(medicalOrderItemFilterConf);
+      set_ifShowCalcBtn(true);
+    }
+    if (calcPageKey == "beforeCollectionSearch") {
+      set_columns(beforeCollectionSearch);
+      set_scrollX(1500);
+      set_filterConf(beforeCollectionSearchFilterConf);
+      set_ifShowCalcBtn(false);
+    }
+    if (calcPageKey == "incomeCollection") {
+      set_columns([...incomeCollection, {
+        title: '操作',
+        dataIndex: 'option',
+        width:90,
+        renderText(text, record) {
+          const { isCollection } = record;
+          return <a style={{ fontSize: 14 }} onClick={() => {
+            optionBtnGroupshandle(isCollection, record);
+          }}>{isCollection ? '撤销归集' : '开始归集'}</a>
+        },
+      }]);
+      set_filterConf([]);
+      set_ifShowCalcBtn(false);
+      set_scrollX(600);
+    }
+    if (calcPageKey == "afterCollectionSearch") {
+      set_columns([...afterCollectionSearch]);
+      set_filterConf(afterCollectionSearchFilterConf);
+      set_ifShowCalcBtn(false);
+      set_scrollX(1300);
+    }
+    if (calcPageKey == "beforeCostShareSearch") {
+      set_columns([...beforeCostShareSearch]);
+      set_filterConf(beforeCostShareSearchFilterConf);
+      set_ifShowCalcBtn(false);
+      set_scrollX(1300);
+
+    }
+
+    if (calcPageKey == "costShare") {
+      set_columns([...costShare, {
+        title: '操作',
+        dataIndex: 'option',
+        width: '15%',
+        render: (_, record) => {
+          const { isAllocation: isCollection } = record;
+          return [
+            <a style={{ fontSize: 14 }} onClick={() => optionBtnGroupshandle(isCollection, record)}>{isCollection ? '撤销分摊' : '开始分摊'}</a>
+          ]
+        },
+      }]);
+      set_filterConf([]);
+      set_ifShowCalcBtn(false);
+      set_scrollX(600);
+    }
+    if (calcPageKey == "afterCostShareSearch") {
+      set_columns([...afterCostShareSearch]);
+      set_filterConf(afterCostShareSearchFilterConf);
+      set_ifShowCalcBtn(false);
+      set_scrollX(1200);
+    }
+
+    if (calcPageKey == "medicalMaterialCostCalc") {
+      set_columns([...medicalMaterialCostCalc]);
+      set_filterConf(medicalMaterialCostCalcFilterConf);
+      set_ifShowCalcBtn(true);
+      set_scrollX(1200);
+    }
+
+    if (calcPageKey == "departmentCostCalculate") {
+      set_columns([...departmentCostCalculate]);
+      set_filterConf(departmentCostCalculateFilterConf);
+      set_ifShowCalcBtn(true);
+    }
+    if (calcPageKey == "wholeHospCostCalculate") {
+      set_columns([...wholeHospCostCalculate]);
+      set_filterConf([]);
+      set_ifShowCalcBtn(true);
+    }
+    if (calcPageKey == "costShareReportTable") {
+      set_columns([...costShareReportTable, {
+        title: '操作',
+        dataIndex: 'option',
+        width: '15%',
+        render: (_, record) => {
+          const { year, month, shareLevel, shareLevelId } = record;
+          return [
+            <a style={{ fontSize: 14 }} onClick={async () => {
+              downloadTemplateReq('/costAccount/excel/getShareReportTemplate', { year, month, levelSort: shareLevel, shareLevelId });
+              //const resp = await downloadReportHandle({ year, month, levelSort:shareLevel, shareLevelId });
+            }}>下载</a>
+          ]
+        },
+      }]);
+      set_filterConf([]);
+      set_ifShowCalcBtn(false);
+    }
+    if (calcPageKey == "departmentOperatingReport") {
+      set_columns([...departmentOperatingReport, {
+        title: '操作',
+        dataIndex: 'option',
+        width: 100,
+        render: (_, record) => {
+          const { fileUrl = '' } = record;
+          return [
+            <a style={{ fontSize: 14 }} onClick={async () => window.open(fileUrl)}>下载</a>
+          ]
+        },
+      }]);
+      set_filterConf([]);
+      set_ifShowCalcBtn(false);
+    }
+    if (calcPageKey == "wholeHospOperatingReport") {
+      set_columns([...wholeHospOperatingReport, {
+        title: '操作',
+        dataIndex: 'option',
+        width: 100,
+        render: (_, record) => {
+          const { fileUrl } = record;
+          return [
+            <a style={{ fontSize: 14 }} onClick={async () => {
+              window.open(fileUrl);
+            }}>下载</a>
+          ]
+        },
+      }]);
+      set_filterConf([]);
+      set_ifShowCalcBtn(false);
+    }
+    if (calcPageKey == "projectShareParamsCalc") {
+      set_filterConf([...projectShareParamsCalcFilterConf]);
+      set_ifShowCalcBtn(true);
+      set_scrollX(1600);
+      set_totalCount(undefined);
+    }
+    if (calcPageKey == "projectCostCalc") {
+      set_columns([...projectCostCalc]);
+      set_filterConf([...projectCostCalcFilterConf]);
+
+      const tabs = access.whatCanIDoInThisPage(location.pathname.replace('/CostAccountingSys', ''));
+      const a = tabs.reduce((prev:any,cur:any)=>`${prev},${cur.code}`,'');
+      set_btnAccessStr(a);
+      set_ifShowCalcBtn(a.indexOf('calculate') != -1);
+      set_scrollX(1200);
     }
 
 
     set_tableDataFilterParams({ computeDate, calcPageKey });
   }, [params]);
 
+
+
   return (
     <KCIMPagecontainer className="calcPageTemplate" title={false}>
+      <ProgressModal
+        title='计算进度'
+        type={calTypeStr}
+        onComplete={handleCompletion}
+        visible={isModalVisible}
+      />
+      <ExportProgressModal
+        visible={openProcessModal}
+        onCancel={() => set_openProcessModal(false)}
+        fetchData={fetchExportData}
+        onCompletion={handleExportCompletion}
+      />
       <div className="toolBar">
         <div className="filter">
           <div className="filterItem">
@@ -230,7 +745,10 @@ export default function calcPageTemplate() {
           {generateFilterItems(filterConf)}
         </div>
         <div className="btnGroup">
-          <a className='calc' onClick={() => calcFunc()}>计算</a>
+          {(params.calcPageKey == 'projectCostCalc'&&btnAccessStr?.indexOf('export') != -1) && <a className='export' onClick={() => set_openProcessModal(true)}>导出</a>}
+          {ifShowCalcBtn && <a className='calc' onClick={() => calcFunc()}>计算</a>}
+          {(params.calcPageKey == 'afterCostShareSearch' || params.calcPageKey == 'afterCollectionSearch') && (<Button loading={loading} size='small' className='reportDataBtn' onClick={() => openDataTable()}>报表数据</Button>)}
+          {(params.calcPageKey == 'departmentOperatingReport' || params.calcPageKey == 'wholeHospOperatingReport' || params.calcPageKey == 'costShareReportTable') && (<span className='reportDataBtn' onClick={() => generateReport()}>生成报表</span>)}
         </div>
       </div>
       <div style={{ marginTop: 16 }}>
@@ -238,10 +756,13 @@ export default function calcPageTemplate() {
           columns={columns}
           actionRef={tableRef}
           rowKey="id"
-          scroll={{x:scrollX}}
+          scroll={{ x: scrollX }}
           params={tableDataFilterParams}
           request={(params) => getTableData(params)}
         />
+        {
+          totalCount != undefined && <a style={{ marginTop: 16, display: 'inline-block' }}>{`合计:${formatMoneyNumber(totalCount)}`}</a>
+        }
       </div>
     </KCIMPagecontainer>
   );

+ 236 - 4
src/pages/costAccounting/calcPageTemplate/service.ts

@@ -2,18 +2,19 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 16:31:27
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-23 19:22:06
+ * @LastEditTime: 2024-03-19 14:25:42
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
 
 
 
+import axios from 'axios';
 import { request } from 'umi';
 
 //获取table列表数据
 
-export const getData = (params: any) => {
+export const getCalcPageTableData = (params: any) => {
 
   const {calcPageKey,...next} = params;
   
@@ -59,10 +60,94 @@ export const getData = (params: any) => {
       params:{...next}
     });
   }
+  if(calcPageKey == 'beforeCollectionSearch'){
+    return request('/costAccount/costincomegroup/list', {
+      method: 'GET',
+      params:{...next,dateTime:next.computeDate,computeDate:null}
+    });
+  }
+  if(calcPageKey == 'incomeCollection'){
+    return request('/costAccount/incomeCollection/getCollections', {
+      method: 'GET',
+      params:{...next,date:(next.computeDate).replace('-', ''),computeDate:null}
+    });
+  }
+  if(calcPageKey == 'afterCollectionSearch'){
+    return request('/costAccount/incomeCollection/collectList', {
+      method: 'GET',
+      params:{...next,date:(next.computeDate).replace('-', ''),computeDate:null}
+    });
+  }
+  if(calcPageKey == 'beforeCostShareSearch'){
+    return request('/costAccount/costcostinggroup/queryStartAllocation', {
+      method: 'GET',
+      params:{...next,date:next.computeDate,computeDate:null}
+    });
+  }
+  if(calcPageKey == 'costShare'){
+    return request('/costAccount/costcostinggroup/allocationList', {
+      method: 'GET',
+      params:{...next,date:`${next.computeDate}-01`,computeDate:null}
+    });
+  }
+  if(calcPageKey == 'afterCostShareSearch'){
+    return request('/costAccount/costcostinggroup/queryAfterAllocation', {
+      method: 'GET',
+      params:{...next,year:`${next.computeDate}-01`,computeDate:null}
+    });
+  }
+  if(calcPageKey == 'departmentCostCalculate'){
+    return request('/costAccount/costdepartmentprofit/list', {
+      method: 'GET',
+      params:{...next,date:`${next.computeDate}-01`,computeDate:null}
+    });
+  }
+  if(calcPageKey == 'wholeHospCostCalculate'){
+    return request('/costAccount/hospProfitAndLoss/getHospProfits', {
+      method: 'GET',
+      params:{...next,date:`${next.computeDate}-01`,computeDate:null}
+    });
+  }
+  if(calcPageKey == 'costShareReportTable'){
+    return request('/costAccount/costcostinggroup/afterAllocationFormList', {
+      method: 'GET',
+      params:{...next,date:`${next.computeDate}-01`,computeDate:null}
+    });
+  }
+  if(calcPageKey == 'wholeHospOperatingReport'){
+    return request('/costAccount/hospProfitAndLoss/hospReports', {
+      method: 'GET',
+      params:{...next,date:`${next.computeDate}-01`,computeDate:null}
+    });
+  }
+  if(calcPageKey == 'departmentOperatingReport'){
+    return request('/costAccount/departmentprofitfile/list', {
+      method: 'GET',
+      params:{...next,date:`${next.computeDate}-01`,computeDate:null}
+    });
+  }
+  if(calcPageKey == 'medicalMaterialCostCalc'){
+    return request('/costAccount/calculate/drugMaterialCostCalculateList', {
+      method: 'GET',
+      params:{...next}
+    });
+  }
+  if(calcPageKey == 'projectShareParamsCalc'){
+    return request('/costAccount/calculate/getShareParamCostList', {
+      method: 'GET',
+      params:{...next}
+    });
+  }
+  if(calcPageKey == 'projectCostCalc'){
+    return request('/costAccount/calculate/getItemCostList', {
+      method: 'GET',
+      params:{...next}
+    });
+  }
 };
 
 //计算
-export const calculateReq = (computeDate: string,calcPageKey: string | undefined) => {
+export const calculateReq = (computeDate: string,calcPageKey: string | undefined,type?:string) => {
   if(calcPageKey == 'unitPersonnelCostCalc'){
     return request('/costAccount/calculate/empCostCalculate', {
       method: 'POST',
@@ -78,7 +163,7 @@ export const calculateReq = (computeDate: string,calcPageKey: string | undefined
   if(calcPageKey == 'chargeItemCostCalc'){
     return request('/costAccount/calculate/itemCostCalculate', {
       method: 'POST',
-      params:{computeDate}
+      params:{computeDate,type}
     });
   }
   if(calcPageKey == 'diseaseCostCalculation'){
@@ -105,11 +190,158 @@ export const calculateReq = (computeDate: string,calcPageKey: string | undefined
       params:{computeDate}
     });
   }
+  if(calcPageKey == 'departmentCostCalculate'){
+    return request('/costAccount/costdepartmentprofit/setDepartmentProfit', {
+      method: 'POST',
+      params:{date:`${computeDate}-01`}
+    });
+  }
+  if(calcPageKey == 'wholeHospCostCalculate'){
+    return request('/costAccount/hospProfitAndLoss/calc', {
+      method: 'POST',
+      params:{date:`${computeDate}-01`}
+    });
+  }
+  if(calcPageKey == 'medicalMaterialCostCalc'){
+    return request('/costAccount/calculate/drugMaterialCostCalculate', {
+      method: 'POST',
+      params:{computeDate}
+    });
+  }
+  if(calcPageKey == 'projectShareParamsCalc'){
+    return request('/costAccount/calculate/computeShareParamCost', {
+      method: 'POST',
+      params:{computeDate}
+    });
+  }
+  if(calcPageKey == 'projectCostCalc'){
+    return request('/costAccount/calculate/computeItemCost', {
+      method: 'POST',
+      params:{computeDate}
+    });
+  }
   
 };
 
+//获取科室列表
+export const getCostProjecttList = (params:any) => {
+  const {productName,current,pageSize} = params;
+  return request('/costAccount/product/list', {
+    method: 'GET',
+    params:{
+        name:productName,
+        current,
+        pageSize
+    },
+  });
+}
+
+
+//开始归集
+export const startIncomeCollection = (params:any) => {
+  const {year,month} = params;
+  return request('/costAccount/incomeCollection/collect', {
+    method: 'POST',
+    params:{year,month},
+  });
+}
+
+//撤销归集
+export const cancelIncomeCollection = (body:any) => {
+  const {year,month} = body;
+  return request('/costAccount/incomeCollection/cancelCollect', {
+    method: 'POST',
+    params:{year,month}
+  });
+}
+
+
+//开始分摊
+export const startAllocation = (body:any) => {
+  return request('/costAccount/costcostinggroup/startAllocation', {
+    method: 'POST',
+    data:body,
+  });
+}
+
+//撤销分摊
+export const cancelAllocation = (body:any) => {
+  return request('/costAccount/costcostinggroup/cancelAllocation', {
+    method: 'POST',
+    params:body,
+  });
+}
+
+//获取报表数据列表
+export const getAfterCostShareSearchTableData = (params:any) => {
+  return request('/costAccount/costcostinggroup/queryAfterAllocationForm', {
+    method: 'GET',
+    params:{...params},
+  });
+}
+
+//获取收入归集后报表数据列表
+export const getAfterIncomeCollectionTableData = (params:any)=> {
+  return request('/costAccount/incomeCollection/collectDataForm', {
+    method: 'GET',
+    params:{...params},
+  });
+}
+
+//下载报表
+export const downloadReportHandle = (params:any) => {
+  return request('/costAccount/excel/getShareReportTemplate', {
+    method: 'GET',
+    params:{...params},
+  });
+}
+
+//生成报表数据
+export const generateReportHandle = (params:any,path:string) => {
+  return request(path, {
+    method: 'POST',
+    params:{...params},
+  });
+}
+
+
+//下载excel
+export const downloadTemplateReq = (pathStr: string,data:any) => {
+
+
+  let path = `/gateway${pathStr}`;
+
+  const userData = localStorage.getItem('userData');
+  const { token = '' } = JSON.parse(userData as string);
+
+  axios({
+    method: 'get',
+    url: path,
+    responseType: 'blob',
+    headers: { token },
+    params:data
+  })
+    .then(function (response) {
+      //console.log({ 'chunk': response });
+      const filename = decodeURI(response.headers["content-disposition"]);
+      const objectUrl = URL.createObjectURL(
+        new Blob([response.data], {
+          type: 'application/vnd.ms-excel',
+        })
+      )
+      const link = document.createElement('a')
+      // 设置导出的文件名称
+      link.download = `${filename}` + '.xls'
+      link.style.display = 'none'
+      link.href = objectUrl
+      link.click()
+      document.body.appendChild(link)
+
+    });
+
 
 
+}
 
 
 

+ 2 - 1
src/pages/costAccounting/calcPageTemplate/style.less

@@ -29,7 +29,7 @@
 
     .btnGroup {
       
-      .calc {
+      .calc,.reportDataBtn,.export {
         cursor: pointer;
         display: inline-block;
         font-size: 14px;
@@ -39,6 +39,7 @@
         line-height: 24px;
         padding: 0 14px;
         background: #3377FF;
+        margin-left: 8px;
         border-radius: 4px;
       }
     }

+ 0 - 227
src/pages/costAccounting/chargeItemCostCalc/index.tsx

@@ -1,227 +0,0 @@
-/*
- * @Author: code4eat awesomedema@gmail.com
- * @Date: 2023-03-03 11:30:33
- * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-01 09:52:42
- * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- */
-
-import { createFromIconfontCN } from '@ant-design/icons';
-
-import { DatePicker, Input, Modal, message } from 'antd';
-import { useEffect, useRef, useState } from 'react';
-
-import { calculateReq, getData } from './service';
-
-import './style.less';
-import moment from 'moment';
-import 'moment/locale/zh-cn';
-import locale from 'antd/es/date-picker/locale/zh_CN';
-import KCIMPagecontainer from '@/components/KCIMPageContainer';
-import { KCIMTable } from '@/components/KCIMTable';
-
-import { ActionType, ProColumns, ProFormSelect } from '@ant-design/pro-components';
-import { formatMoneyNumber } from '@/utils/format';
-import { getTargetDic } from '@/services/auth';
-
-
-const IconFont = createFromIconfontCN({
-  scriptUrl: '',
-});
-
-const currentData = `${new Date().getFullYear()}-${(new Date().getMonth() + 1).toString().padStart(2, '0')}`
-
-export default function chargeItemCostCalc() {
-  const [computeDate, set_computeDate] = useState(currentData);
-  const [tableDataFilterParams, set_tableDataFilterParams] = useState<any>({ computeDate: currentData });
-  const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState('');
-  const tableRef = useRef<ActionType>();
-  const [loading, set_loading] = useState(false);
-
-  const columns: ProColumns[] = [
-    {
-      title: '人事分类名称',
-      dataIndex: 'name',
-    },
-    {
-      title: '实际编制人数',
-      dataIndex: 'empNum',
-    },
-    {
-      title: '实际总工时',
-      dataIndex: 'actualHour',
-    },
-    {
-      title: '预计总工时',
-      dataIndex: 'expectHour',
-    },
-    {
-      title: '总成本',
-      dataIndex: 'totalCost',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-    {
-      title: '人均成本',
-      dataIndex: 'avgCost',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-    {
-      title: '每分钟成本',
-      dataIndex: 'minuteCost',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-  ];
-
-  const getTableData = async (params: any) => {
-    const resp = await getData({ ...params, ...tableDataFilterParams });
-    if (resp) {
-      // function renameChildListToChildren(node: any) {
-      //   if (node.childList) {
-      //     node.children = node.childList;
-      //   }
-
-      //   if (node.children && node.children.length > 0) {
-      //     node.children.forEach((child: any) => renameChildListToChildren(child));
-      //   }
-      // }
-
-      // resp.forEach((tree: any) => renameChildListToChildren(tree));
-
-      return {
-        data: resp.list,
-        success: true
-      };
-    }
-    return [];
-  };
-
-  const tableDataSearchHandle = (paramName: string) => {
-
-
-    set_tableDataFilterParams({
-      ...tableDataFilterParams,
-      [`${paramName}`]: tableDataSearchKeywords
-    })
-  }
-
-  const calcFunc = () => {
-
-    Modal.confirm({
-      title: '注意',
-      content: '计算操作会覆盖当月已计算的数据,是否继续操作?',
-
-      onOk: async (...args) => {
-        set_loading(true);
-        const resp = await calculateReq(computeDate);
-        if (resp) {
-
-          set_loading(false);
-          message.success('操作成功!');
-          tableRef.current?.reload();
-        } else {
-          set_loading(false);
-        }
-      },
-    })
-  }
-
-
-
-  useEffect(() => { }, []);
-
-  return (
-    <KCIMPagecontainer className="chargeItemCostCalc" title={false}>
-      <div className="toolBar">
-        <div className="filter">
-          <div className="filterItem">
-            {
-              <div className="search">
-                <span>核算年月:</span>
-                <DatePicker
-                  onChange={(data, dateString) => {
-                    set_computeDate(dateString);
-                    set_tableDataFilterParams({
-                      ...tableDataFilterParams,
-                      computeDate: dateString,
-                    });
-                  }}
-                  picker="month"
-                  locale={locale}
-                  defaultValue={moment(`${new Date().getFullYear()}-${(new Date().getMonth() + 1).toString().padStart(2, '0')}`, 'YYYY-MM')}
-                  format="YYYY-MM"
-                  placeholder="选择年月"
-                />
-              </div>
-            }
-          </div>
-          <div className='filterItem' style={{ marginLeft: 16 }}>
-              <span className='label'>项目类别:</span>
-              <ProFormSelect
-                  noStyle
-                  allowClear
-                  placeholder="请选择"
-                  style={{ width: 160, marginRight: 16 }}
-                  request={async () => {
-                    const resp = await getTargetDic('CHARGE_ITEM_TYPE');
-                    if (resp) {
-                      const { dataVoList } = resp;
-                      return dataVoList.map((a:any) => ({ label: a.name, value: a.code }));
-                    }
-                    return [];
-                  }}
-                  fieldProps={{
-                      onChange(value, option) {
-                          set_tableDataFilterParams({ ...tableDataFilterParams,itemType: value })
-                      },
-                  }}
-              />
-          </div>
-          <div className='filterItem' style={{ marginLeft: 16, width: 205 }}>
-            <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
-            <Input placeholder={'收费项目'} allowClear
-              suffix={
-                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('itemName')} />
-              }
-              onChange={(e) => {
-                set_tableDataSearchKeywords(e.target.value);
-                if (e.target.value.length == 0) {
-                  set_tableDataFilterParams({
-                    ...tableDataFilterParams,
-                    itemName: ''
-                  });
-                }
-              }}
-              onPressEnter={(e) => {
-                set_tableDataFilterParams({
-                  ...tableDataFilterParams,
-                  itemName: ((e.target) as HTMLInputElement).value
-                });
-              }}
-
-            />
-          </div>
-        </div>
-        <div className="btnGroup">
-          <a className='calc' onClick={() => calcFunc()}>计算</a>
-        </div>
-      </div>
-      <div style={{ marginTop: 16 }}>
-        <KCIMTable
-          columns={columns}
-          actionRef={tableRef}
-          rowKey="id"
-
-          params={tableDataFilterParams}
-          request={(params) => getTableData(params)}
-        />
-      </div>
-    </KCIMPagecontainer>
-  );
-}

+ 0 - 41
src/pages/costAccounting/chargeItemCostCalc/service.js

@@ -1,41 +0,0 @@
-/*
- * @Author: code4eat awesomedema@gmail.com
- * @Date: 2023-03-03 16:31:27
- * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-10-31 10:01:55
- * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- */
-
-
-
-import { request } from 'umi';
-
-//获取table列表数据
-
-export const getData = (params) => {
-  return request('/costAccount/calculate/itemCostCalculateList', {
-    method: 'GET',
-    params:{...params}
-  });
-};
-
-//计算
-export const calculateReq = (computeDate) => {
-  return request('/costAccount/calculate/itemCostCalculate', {
-    method: 'POST',
-    params:{computeDate}
-  });
-};
-
-
-
-
-
-
-
-
-
-
-
-

+ 0 - 263
src/pages/costAccounting/patientCostCalc/index.tsx

@@ -1,263 +0,0 @@
-/*
- * @Author: code4eat awesomedema@gmail.com
- * @Date: 2023-03-03 11:30:33
- * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-01 10:04:17
- * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- */
-
-import { createFromIconfontCN } from '@ant-design/icons';
-
-import { DatePicker, Input, Modal, message } from 'antd';
-import { useEffect, useRef, useState } from 'react';
-
-import { calculateReq, getData } from './service';
-
-import './style.less';
-import moment from 'moment';
-import 'moment/locale/zh-cn';
-import locale from 'antd/es/date-picker/locale/zh_CN';
-import KCIMPagecontainer from '@/components/KCIMPageContainer';
-import { KCIMTable } from '@/components/KCIMTable';
-
-import { ActionType, ProColumns } from '@ant-design/pro-components';
-import { formatMoneyNumber } from '@/utils/format';
-
-
-const IconFont = createFromIconfontCN({
-  scriptUrl: '',
-});
-
-const currentData = `${new Date().getFullYear()}-${(new Date().getMonth() + 1).toString().padStart(2, '0')}`
-
-export default function patientCostCalc() {
-  const [computeDate, set_computeDate] = useState(currentData);
-  const [tableDataFilterParams, set_tableDataFilterParams] = useState<any>({ computeDate: currentData });
-  const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState('');
-  const tableRef = useRef<ActionType>();
-  const [loading, set_loading] = useState(false);
-
-  const columns: ProColumns[] = [
-    {
-      title: '住院号/门诊号',
-      dataIndex: 'visitNo',
-    },
-    {
-      title: '病人ID',
-      dataIndex: 'patientNo',
-    },
-    {
-      title: '患者姓名',
-      dataIndex: 'name',
-    },
-    {
-      title: '科室代码',
-      dataIndex: 'departmentCode',
-    },
-    {
-      title: '科室名称',
-      dataIndex: 'departmentName',
-    },
-    {
-      title: '人力成本',
-      dataIndex: 'empCost',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-    {
-      title: '设备成本',
-      dataIndex: 'equipmentCost',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-    {
-      title: '空间成本',
-      dataIndex: 'spaceCost',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-    {
-      title: '项目成本',
-      dataIndex: 'itemIncome',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-    {
-      title: '药品成本',
-      dataIndex: 'drugCost',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-    {
-      title: '材料成本',
-      dataIndex: 'materialCost',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-    {
-      title: '项目收入',
-      dataIndex: 'itemIncome',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-    {
-      title: '药品收入',
-      dataIndex: 'drugIncome',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-    {
-      title: '材料收入',
-      dataIndex: 'materialIncome',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-
-    },
-  ];
-
-  const getTableData = async (params: any) => {
-    const resp = await getData({ ...params, ...tableDataFilterParams });
-    if (resp) {
-      return {
-        data: resp.list,
-        success: true
-      };
-    }
-    return [];
-  };
-
-  const tableDataSearchHandle = (paramName: string) => {
-
-
-    set_tableDataFilterParams({
-      ...tableDataFilterParams,
-      [`${paramName}`]: tableDataSearchKeywords
-    })
-  }
-
-  const calcFunc = () => {
-
-    Modal.confirm({
-      title: '注意',
-      content: '计算操作会覆盖当月已计算的数据,是否继续操作?',
-
-      onOk: async (...args) => {
-        set_loading(true);
-        const resp = await calculateReq(computeDate);
-        if (resp) {
-
-          set_loading(false);
-          message.success('操作成功!');
-          tableRef.current?.reload();
-        } else {
-          set_loading(false);
-        }
-      },
-    })
-  }
-
-
-
-  useEffect(() => { }, []);
-
-  return (
-    <KCIMPagecontainer className="patientCostCalc" title={false}>
-      <div className="toolBar">
-        <div className="filter">
-          <div className="filterItem">
-            {
-              <div className="search">
-                <span>核算年月:</span>
-                <DatePicker
-                  onChange={(data, dateString) => {
-                    set_computeDate(dateString);
-                    set_tableDataFilterParams({
-                      ...tableDataFilterParams,
-                      computeDate: dateString,
-                    });
-                  }}
-                  picker="month"
-                  locale={locale}
-                  defaultValue={moment(`${new Date().getFullYear()}-${(new Date().getMonth() + 1).toString().padStart(2, '0')}`, 'YYYY-MM')}
-                  format="YYYY-MM"
-                  placeholder="选择年月"
-                />
-              </div>
-            }
-          </div>
-          <div className='filterItem' style={{ marginLeft: 16, width: 205 }}>
-            <span className='label' style={{ whiteSpace: 'nowrap' }}> 科室名称:</span>
-            <Input placeholder={'人事分类'} allowClear
-              suffix={
-                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('departmentName')} />
-              }
-              onChange={(e) => {
-                set_tableDataSearchKeywords(e.target.value);
-                if (e.target.value.length == 0) {
-                  set_tableDataFilterParams({
-                    ...tableDataFilterParams,
-                    departmentName: ''
-                  });
-                }
-              }}
-              onPressEnter={(e) => {
-                set_tableDataFilterParams({
-                  ...tableDataFilterParams,
-                  departmentName: ((e.target) as HTMLInputElement).value
-                });
-              }}
-
-            />
-          </div>
-          <div className='filterItem' style={{ marginLeft: 16, width: 205 }}>
-            <span className='label' style={{ whiteSpace: 'nowrap' }}> 患者姓名:</span>
-            <Input placeholder={'人事分类'} allowClear
-              suffix={
-                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('patientName')} />
-              }
-              onChange={(e) => {
-                set_tableDataSearchKeywords(e.target.value);
-                if (e.target.value.length == 0) {
-                  set_tableDataFilterParams({
-                    ...tableDataFilterParams,
-                    patientName: ''
-                  });
-                }
-              }}
-              onPressEnter={(e) => {
-                set_tableDataFilterParams({
-                  ...tableDataFilterParams,
-                  patientName: ((e.target) as HTMLInputElement).value
-                });
-              }}
-
-            />
-          </div>
-        </div>
-        <div className="btnGroup">
-          <a className='calc' onClick={() => calcFunc()}>计算</a>
-        </div>
-      </div>
-      <div style={{ marginTop: 16 }}>
-        <KCIMTable
-          columns={columns}
-          actionRef={tableRef}
-          rowKey="id"
-
-          params={tableDataFilterParams}
-          request={(params) => getTableData(params)}
-        />
-      </div>
-    </KCIMPagecontainer>
-  );
-}

+ 0 - 41
src/pages/costAccounting/patientCostCalc/service.js

@@ -1,41 +0,0 @@
-/*
- * @Author: code4eat awesomedema@gmail.com
- * @Date: 2023-03-03 16:31:27
- * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-01 09:55:02
- * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- */
-
-
-
-import { request } from 'umi';
-
-//获取table列表数据
-
-export const getData = (params) => {
-  return request('/costAccount/calculate/patientCostCalculateList', {
-    method: 'GET',
-    params:{...params}
-  });
-};
-
-//计算
-export const calculateReq = (computeDate) => {
-  return request('/costAccount/calculate/patientCostCalculate', {
-    method: 'POST',
-    params:{computeDate}
-  });
-};
-
-
-
-
-
-
-
-
-
-
-
-

+ 0 - 204
src/pages/costAccounting/unitPersonnelCostCalc/index.tsx

@@ -1,204 +0,0 @@
-/*
- * @Author: code4eat awesomedema@gmail.com
- * @Date: 2023-03-03 11:30:33
- * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-10-30 11:12:12
- * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- */
-
-import { createFromIconfontCN } from '@ant-design/icons';
-
-import { DatePicker, Input, Modal, message } from 'antd';
-import { useEffect, useRef, useState } from 'react';
-
-import { calculateReq, getData } from './service';
-
-import './style.less';
-import moment from 'moment';
-import 'moment/locale/zh-cn';
-import locale from 'antd/es/date-picker/locale/zh_CN';
-import KCIMPagecontainer from '@/components/KCIMPageContainer';
-import { KCIMTable } from '@/components/KCIMTable';
-
-import { ActionType, ProColumns } from '@ant-design/pro-components';
-import { formatMoneyNumber } from '@/utils/format';
-
-
-const IconFont = createFromIconfontCN({
-  scriptUrl: '',
-});
-
-const currentData = `${new Date().getFullYear()}-${(new Date().getMonth() + 1).toString().padStart(2, '0')}`
-
-export default function unitPersonnelCostCalc() {
-  const [computeDate, set_computeDate] = useState(currentData);
-  const [tableDataFilterParams, set_tableDataFilterParams] = useState<any>({ computeDate: currentData });
-  const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState('');
-  const tableRef = useRef<ActionType>();
-  const [loading, set_loading] = useState(false);
-
-  const columns: ProColumns[] = [
-    {
-      title: '人事分类名称',
-      dataIndex: 'name',
-    },
-    {
-      title: '实际编制人数',
-      dataIndex: 'empNum',
-    },
-    {
-      title: '实际总工时',
-      dataIndex: 'actualHour',
-    },
-    {
-      title: '预计总工时',
-      dataIndex: 'expectHour',
-    },
-    {
-      title: '总成本',
-      dataIndex: 'totalCost',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-    {
-      title: '人均成本',
-      dataIndex: 'avgCost',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-    {
-      title: '每分钟成本',
-      dataIndex: 'minuteCost',
-      renderText(num, record, index, action) {
-        return formatMoneyNumber(num);
-      },
-    },
-  ];
-
-  const getTableData = async (params: any) => {
-    const resp = await getData({ ...params, ...tableDataFilterParams });
-    if (resp) {
-      function renameChildListToChildren(node: any) {
-        if (node.childList) {
-          node.children = node.childList;
-        }
-
-        if (node.children && node.children.length > 0) {
-          node.children.forEach((child: any) => renameChildListToChildren(child));
-        }
-      }
-
-      resp.forEach((tree: any) => renameChildListToChildren(tree));
-
-      return {
-        data: resp,
-        success: true
-      };
-    }
-    return [];
-  };
-
-  const tableDataSearchHandle = (paramName: string) => {
-
-
-    set_tableDataFilterParams({
-      ...tableDataFilterParams,
-      [`${paramName}`]: tableDataSearchKeywords
-    })
-  }
-
-  const calcFunc = () => {
-
-    Modal.confirm({
-      title: '注意',
-      content: '计算操作会覆盖当月已计算的数据,是否继续操作?',
-
-      onOk: async (...args) => {
-        set_loading(true);
-        const resp = await calculateReq(computeDate);
-        if (resp) {
-
-          set_loading(false);
-          message.success('操作成功!');
-          tableRef.current?.reload();
-        } else {
-          set_loading(false);
-        }
-      },
-    })
-  }
-
-
-
-  useEffect(() => { }, []);
-
-  return (
-    <KCIMPagecontainer className="unitPersonnelCostCalc" title={false}>
-      <div className="toolBar">
-        <div className="filter">
-          <div className="filterItem">
-            {
-              <div className="search">
-                <span>核算年月:</span>
-                <DatePicker
-                  onChange={(data, dateString) => {
-                    set_computeDate(dateString);
-                    set_tableDataFilterParams({
-                      ...tableDataFilterParams,
-                      computeDate: dateString,
-                    });
-                  }}
-                  picker="month"
-                  locale={locale}
-                  defaultValue={moment(`${new Date().getFullYear()}-${(new Date().getMonth() + 1).toString().padStart(2, '0')}`, 'YYYY-MM')}
-                  format="YYYY-MM"
-                  placeholder="选择年月"
-                />
-              </div>
-            }
-          </div>
-          <div className='filterItem' style={{ marginLeft: 16, width: 205 }}>
-            <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
-            <Input placeholder={'人事分类'} allowClear
-              suffix={
-                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('filter')} />
-              }
-              onChange={(e) => {
-                set_tableDataSearchKeywords(e.target.value);
-                if (e.target.value.length == 0) {
-                  set_tableDataFilterParams({
-                    ...tableDataFilterParams,
-                    filter: ''
-                  });
-                }
-              }}
-              onPressEnter={(e) => {
-                set_tableDataFilterParams({
-                  ...tableDataFilterParams,
-                  filter: ((e.target) as HTMLInputElement).value
-                });
-              }}
-
-            />
-          </div>
-        </div>
-        <div className="btnGroup">
-          <a className='calc' onClick={() => calcFunc()}>计算</a>
-        </div>
-      </div>
-      <div style={{ marginTop: 16 }}>
-        <KCIMTable
-          columns={columns}
-          actionRef={tableRef}
-          rowKey="id"
-
-          params={tableDataFilterParams}
-          request={(params) => getTableData(params)}
-        />
-      </div>
-    </KCIMPagecontainer>
-  );
-}

+ 0 - 41
src/pages/costAccounting/unitPersonnelCostCalc/service.js

@@ -1,41 +0,0 @@
-/*
- * @Author: code4eat awesomedema@gmail.com
- * @Date: 2023-03-03 16:31:27
- * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-10-26 16:30:43
- * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- */
-
-
-
-import { request } from 'umi';
-
-//获取table列表数据
-
-export const getData = (params) => {
-  return request('/costAccount/calculate/empCostCalculateList', {
-    method: 'GET',
-    params:{...params}
-  });
-};
-
-//计算
-export const calculateReq = (computeDate) => {
-  return request('/costAccount/calculate/empCostCalculate', {
-    method: 'POST',
-    params:{computeDate}
-  });
-};
-
-
-
-
-
-
-
-
-
-
-
-

+ 8 - 2
src/pages/costLibraryManagement/basicCostManagement/drugCostManagement/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-09 13:49:35
+ * @LastEditTime: 2024-01-05 14:36:59
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -51,18 +51,22 @@ export default function DrugCostManagement() {
         {
             title: '项目代码',
             dataIndex: 'code',
+            width:100
         },
         {
             title: '项目名称',
             dataIndex: 'name',
+            width:350,
         },
         {
             title: '项目类型',
             dataIndex: 'typeName',
+            width:90
         },
         {
             title: '单价',
             dataIndex: 'price',
+            width:90,
             renderText(num) {
                 return formatMoneyNumber(num)
             },
@@ -70,6 +74,7 @@ export default function DrugCostManagement() {
         {
             title: '成本',
             dataIndex: 'cost',
+            width:90,
             renderText(num) {
                 return formatMoneyNumber(num)
             },
@@ -77,6 +82,7 @@ export default function DrugCostManagement() {
         {
             title: '停用',
             dataIndex: 'status',
+            width:90,
             renderText(stat) {
                 return stat ? '是' : '否'
             },
@@ -84,7 +90,7 @@ export default function DrugCostManagement() {
         {
             title: '操作',
             key: 'option',
-            width: 120,
+            width: 60,
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [

+ 3 - 2
src/pages/costLibraryManagement/basicCostManagement/equipmentCostManagement/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-09 13:44:18
+ * @LastEditTime: 2024-01-05 14:39:16
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -51,6 +51,7 @@ export default function EquipmentCostManagement() {
         {
             title: '设备编码',
             dataIndex: 'code',
+            width:90
         },
         {
             title: '项目名称',
@@ -92,7 +93,7 @@ export default function EquipmentCostManagement() {
         {
             title: '操作',
             key: 'option',
-            width: 120,
+            width: 90,
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [

+ 8 - 2
src/pages/costLibraryManagement/basicCostManagement/materialCostManagement/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-16 17:39:52
+ * @LastEditTime: 2024-01-05 14:38:28
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -53,14 +53,17 @@ export default function MaterialCostManagement() {
         {
             title: '项目代码',
             dataIndex: 'code',
+            width:90
         },
         {
             title: '项目名称',
             dataIndex: 'name',
+            width:360
         },
         {
             title: '项目类型',
             dataIndex: 'type',
+            width:90,
             renderText(num) {
                 return num == 1?'不计价材料':'高值材料'
             },
@@ -68,12 +71,14 @@ export default function MaterialCostManagement() {
         {
             title: '单价',
             dataIndex: 'price',
+            width:90,
             renderText(num) {
                 return formatMoneyNumber(num)
             },
         },
         {
             title: '成本',
+            width:90,
             dataIndex: 'cost',
             renderText(num) {
                 return formatMoneyNumber(num)
@@ -81,6 +86,7 @@ export default function MaterialCostManagement() {
         },
         {
             title: '停用',
+            width:90,
             dataIndex: 'status',
             renderText(stat) {
                 return stat ? '是' : '否'
@@ -89,7 +95,7 @@ export default function MaterialCostManagement() {
         {
             title: '操作',
             key: 'option',
-            width: 120,
+            width: 60,
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [

+ 99 - 14
src/pages/costLibraryManagement/basicCostManagement/personnelClassificationMana/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-20 10:02:48
+ * @LastEditTime: 2024-03-25 16:35:11
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -19,8 +19,8 @@ import { Key } from 'react';
 import { useEffect, useRef, useState } from 'react';
 
 
-import { getLeftList, getClolumnTableData, addLeftList, editLeftList, editReportTbaleData, delLeftReportData, batchDelTableData, addReportTbaleData, delData, getEmpCostTypeDict, updateEmpInfo } from './service';
-
+import { getLeftList, getClolumnTableData, addLeftList, editLeftList, editReportTbaleData, delLeftReportData, batchDelTableData, addReportTbaleData, delData, getEmpCostTypeDict, updateEmpInfo, importDataPost, generateTableData } from './service';
+import FormItem from 'antd/es/form/FormItem';
 
 import './style.less';
 
@@ -32,6 +32,8 @@ import KCIMPagecontainer from '@/components/KCIMPageContainer';
 import { KCIMTable } from '@/components/KCIMTable';
 
 import TableSelecter from './tableSelector';
+import KCIMUpload from '@/components/KCIMUpload';
+import { downloadTemplateReq } from '@/utils/tooljs';
 const IconFont = createFromIconfontCN({
     scriptUrl: '',
 });
@@ -76,6 +78,10 @@ const PersonnelClassificationMana = () => {
             title: '科室代码',
             dataIndex: 'departmentCode',
         },
+        {
+            title: '科室名称',
+            dataIndex: 'departmentName',
+        },
         {
             title: '岗位',
             dataIndex: 'positionName',
@@ -159,10 +165,10 @@ const PersonnelClassificationMana = () => {
             userId: a.id,
             account: a.account,
             name: a.name,
-            departmentCode:a.departmentCode,
-            departmentName:a.departmentName,
-            position:a.position,
-            positionName:a.positionName
+            departmentCode: a.departmentCode,
+            departmentName: a.departmentName,
+            position: a.position,
+            positionName: a.positionName
         }))
         const resp = await addReportTbaleData(result);
         if (resp) {
@@ -221,6 +227,52 @@ const PersonnelClassificationMana = () => {
 
     }
 
+    const downloadTemplate = async () => {
+        await downloadTemplateReq('/costAccount/setting/exportEmpType');
+    };
+
+    const importData = () => {
+        return (
+            <ModalForm
+                width={360}
+                title={`导入数据`}
+                trigger={
+                    <a className="import" key="3">
+                        导入
+                    </a>
+                }
+                submitter={{
+                    render: (props, defaultDoms) => {
+                        const needBtn = defaultDoms.filter((b) => {
+                            return b.key != 'rest';
+                        });
+                        return [
+                            ...needBtn,
+                        ];
+                    },
+                }}
+                onFinish={async (values) => {
+                    const {
+                        importFile: { fileList },
+                    } = values;
+
+                    let formData = new FormData();
+                    formData.append('file', fileList[0].originFileObj);
+                    const resp = await importDataPost(formData);
+
+                    if (resp) {
+                        getPageLeftReports();
+                        return true;
+                    }
+                }}
+            >
+                <FormItem name={'importFile'}>
+                    <KCIMUpload downloadTemplateFile={() => downloadTemplate()} />
+                </FormItem>
+            </ModalForm>
+        );
+    };
+
     const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD' | 'ADD_LEFTDATA' | 'EDIT_LEFTDATA' }) => {
         const formRef = useRef<ProFormInstance>();
         const getTrriger = () => {
@@ -232,9 +284,7 @@ const PersonnelClassificationMana = () => {
             }
             if (type == 'ADD_LEFTDATA') {
                 return (
-                    <div className='add'>
-                        <img src={require('../../../../../static/addIcon_black.png')} alt="" />
-                    </div>
+                    <span className='add' >新增</span>
                 )
             }
             if (type == 'EDIT_LEFTDATA') {
@@ -347,13 +397,42 @@ const PersonnelClassificationMana = () => {
     }
 
     const updateEmpInfoHandle = async () => {
-          const resp = await updateEmpInfo();
-          if(resp){
+        const resp = await updateEmpInfo();
+        if (resp) {
             message.success('更新成功!');
             tableRef.current?.reload();
-          }
+        }
     }
 
+    const generateEmpHandle = ()=>{
+        Modal.confirm({
+            title:'注意',
+            content:'生成操作会覆盖现有的人事分类及对应人员信息,确定要继续操作?',
+            onOk:async (...args) => {
+                const resp = await generateTableData(); 
+                if(resp){
+                    getPageLeftReports();
+                    tableRef.current?.reload();
+                    message.success('操作成功!');
+                }
+            },
+        })
+    }
+
+
+    const items: MenuProps['items'] = [
+        {
+            key: '1',
+            label: (
+                <UpDataActBtn key={'act'} record={undefined} type='ADD_LEFTDATA' />
+            ),
+        },
+        {
+            key: '2',
+            label: importData()
+        },
+    ];
+
 
 
     useEffect(() => {
@@ -415,7 +494,12 @@ const PersonnelClassificationMana = () => {
                         }}
 
                     />
-                    <UpDataActBtn key={'act'} record={undefined} type='ADD_LEFTDATA' />
+                    <Dropdown menu={{ items }} placement="bottomLeft">
+                        <div className='add'>
+                            <img src={require('../../../../../static/addIcon_black.png')} alt="" />
+                        </div>
+                    </Dropdown>
+
 
                 </div>
 
@@ -478,6 +562,7 @@ const PersonnelClassificationMana = () => {
                         </div>
                     </div>
                     <div className='btnGroup'>
+                        <span className='update' onClick={() => generateEmpHandle()}>按人员类别生成</span>
                         <span className='update' onClick={() => updateEmpInfoHandle()}>更新人员信息</span>
                         <span className='add' onClick={() => set_tableSelecterVisible(true)}>添加</span>
                     </div>

+ 17 - 1
src/pages/costLibraryManagement/basicCostManagement/personnelClassificationMana/service.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-07 11:12:10
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-08 16:06:26
+ * @LastEditTime: 2024-03-21 11:16:06
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicMana/service.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -128,5 +128,21 @@ export const batchDelTableData = (ids:Key[]) => {
 };
 
 
+//导入数据
+export const importDataPost = (data:any) => {
+  return request('/costAccount//setting/importEmpType', {
+    method: 'POST',
+    data
+  });
+};
+
+//按人员分类生成数据
+export const generateTableData = () => {
+  return request('/costAccount//setting/generateEmpType', {
+    method: 'POST',
+  });
+};
+
+
 
 

+ 3 - 0
src/pages/costLibraryManagement/basicCostManagement/personnelClassificationMana/style.less

@@ -240,6 +240,9 @@ box-shadow: 0px -8px 16px 0px rgba(64,85,128,0.1);
           background: #FAFCFF;
           border-radius: 4px;
           border: 1px solid #DAE2F2;
+          &:first-child {
+            margin-right: 8px;
+          }
         }
       }
 

+ 3 - 9
src/pages/costLibraryManagement/diseaseCostManagement/diseaseDiagnosisComparison/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-24 14:52:46
+ * @LastEditTime: 2024-01-05 14:24:47
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -72,7 +72,7 @@ export default function DiseaseDiagnosisComparison() {
         {
             title: '操作',
             key: 'option',
-            width: 120,
+            width: 90,
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [
@@ -250,7 +250,7 @@ export default function DiseaseDiagnosisComparison() {
                 title={`导入数据`}
                 trigger={
                     <a className="import" key="3">
-                        导入
+                        导入  
                     </a>
                 }
                 submitter={{
@@ -259,12 +259,6 @@ export default function DiseaseDiagnosisComparison() {
                             return b.key != 'rest';
                         });
                         return [
-                            // <Button
-                            //     key="ok"
-                            //     onClick={auditType == '0' ? () => downloadTemplate(index) : () => { }}
-                            // >
-                            //     下载模板
-                            // </Button>,
                             ...needBtn,
                         ];
                     },

+ 0 - 1
src/pages/costLibraryManagement/diseaseCostManagement/diseaseDiagnosisComparison/service.ts

@@ -67,7 +67,6 @@ export const importDataPost = (data:any) => {
 };
 
 
-
 //编辑表格数据
 
 export type TableRowEditType = {

+ 2 - 2
src/pages/costLibraryManagement/diseaseCostManagement/diseaseMana/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-24 14:52:11
+ * @LastEditTime: 2024-01-05 14:24:06
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -63,7 +63,7 @@ export default function DiseaseMana() {
         {
             title: '操作',
             key: 'option',
-            width: 120,
+            width: 90,
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [

+ 6 - 3
src/pages/costLibraryManagement/medicalOrderProject/medicalOrderProjectMana/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-24 14:47:26
+ * @LastEditTime: 2023-11-28 11:00:07
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -66,6 +66,7 @@ const MedicalOrderProjectMana = () => {
         {
             title: '收费项目代码',
             ellipsis: true,
+            width:120,
             dataIndex: 'itemCode',
 
         },
@@ -76,12 +77,13 @@ const MedicalOrderProjectMana = () => {
         },
         {
             title: '收费项目类别',
+            width: 100,
             dataIndex: 'itemTypeName',
         },
         {
             title: '数量',
             dataIndex: 'num',
-            width: 160,
+            width: 100,
             renderText(num, record, index, action) {
                 return (
                     <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
@@ -118,6 +120,7 @@ const MedicalOrderProjectMana = () => {
         {
             title: '操作',
             key: 'option',
+            width:60,
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [
@@ -230,13 +233,13 @@ const MedicalOrderProjectMana = () => {
         }
 
         if (type == 'EDIT') {
-            console.log({ formVal })
             const resp = await editTableData({
                 id: formVal.id,
                 orderCode: currentSelectedType.code,
                 itemCode: formVal.itemCode,
                 num: currentEditRow.num
             });
+            
             if (resp) {
                 tableRef.current?.reload();
             }

+ 526 - 0
src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/match.tsx

@@ -0,0 +1,526 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-03-06 10:43:05
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-03-21 15:59:36
+ * @FilePath: /CostAccountingSys/src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/match.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import { KCIMTable } from "@/components/KCIMTable";
+import ProgressModal from "@/components/ProgressModal";
+import { createFromIconfontCN } from "@ant-design/icons";
+import { ProColumns, ProFormText } from "@ant-design/pro-components";
+import { Progress, message, Modal, Skeleton } from 'antd';
+import { useEffect, useState } from "react";
+import { getAllNeedMatchItems, getMatchCount, getReferralMatch, getSingleItem, mapItemAndStandItem, matchRequest } from "../service";
+
+import './style.less';
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+interface SignalBarProps {
+    level: number; // 信号强度级别,通常在0-4之间
+}
+
+const SignalBar: React.FC<SignalBarProps> = ({ level }) => {
+    const maxLevel = 5;
+    const signalLevel = Math.round(level * maxLevel); // 现在signalLevel是0到4之间的整数
+    const signalBars = [];
+
+    for (let i = 0; i < maxLevel; i++) {
+        signalBars.push(
+            <div
+                key={i}
+                className={`signal-bar ${i < signalLevel ? 'active' : ''}`}
+                style={{
+                    marginLeft: i > 0 ? '2px' : undefined,
+                    height: `${8 + (i * 2)}px`, // 使每个条更高一些
+                    // 定义更多样式...
+                }}
+            />
+        );
+    }
+
+    return <div className="signal-container">{signalBars}</div>;
+};
+
+
+
+export const MatchPage = (props: any) => {
+
+
+
+    const { record, single = true, closeDrawer, switchBatchHandle } = props;
+    const [matchItemInfo, set_matchItemInfo] = useState<undefined | any>(undefined);
+    const [allNeedMatchList, set_allNeedMatchList] = useState<any[]>([]);
+    const [allStandItem, set_allStandItem] = useState<any[]>([]);
+    const [matchStandItem, set_matchStandItem] = useState<any[]>([]);
+    const [dataSource, set_dataSource] = useState<any[]>([]);
+    const [chargeItemTabledataSource, set_chargeItemTabledataSource] = useState<any[]>([]);
+    const [searchText, setSearchText] = useState('');
+    const [chargeItemSearchText, setChargeItemSearchText] = useState('');
+    const [countInfo, set_countInfo] = useState<undefined | any>(undefined);
+    const [currentTablePage, set_currentTablePage] = useState(1);
+    const [openTable, set_openTable] = useState(false);
+    const [isProgressModalVisible, set_isProgressModalVisible] = useState(false);
+    const [loading, set_loading] = useState(true);
+
+    const leftTableColumns = [
+        {
+            title: '标准项目编码',
+            dataIndex: 'code',
+        },
+        {
+            title: '标准项目名称',
+            dataIndex: 'name',
+        },
+        {
+            title: '康程分类',
+            dataIndex: 'kcClassName',
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 80,
+            valueType: 'option',
+            render: (_: any, data: any) => {
+                const { code } = data;
+                return code != matchItemInfo?.standItemCode ? [
+                    <span key='btn' onClick={() => matchRequestHandle(data,1)} style={{
+                        display: 'inline-block', width: 56, height: 24, cursor: 'pointer',
+                        backgroundColor: '#FAFCFF', borderRadius: 4, border: '1px solid #DAE2F2', textAlign: 'center', color: '#17181A'
+                    }}>匹配</span>
+                ] : [
+                    <span key='btn' style={{ fontWeight: 500, fontSize: 14, color: '#00BF8F' }}>当前匹配</span>
+                ]
+            },
+        },
+    ];
+
+    const chargeTableColumns: ProColumns[] = [
+        {
+            title: '编号',
+            width: 80,
+            dataIndex: 'id',
+        },
+        {
+            title: '收费项目编码',
+            dataIndex: 'code',
+        },
+        {
+            title: '收费项目名称',
+            dataIndex: 'name',
+        },
+        {
+            title: '状态',
+            dataIndex: 'match',
+            width: 90,
+            renderText(bool, record, index, action) {
+                return <>{bool ? <span style={{ fontSize: 14, color: '#17181A' }}>已匹配</span> : <span style={{ fontSize: 14, color: '#FF8C19' }}>待匹配</span>}{matchItemInfo?.code == record.code && <IconFont style={{ color: '#3377FF', display: 'inline-block', marginLeft: 16 }} type="iconqueren" />}</>
+            },
+        },
+    ]
+
+    const getMatchInfo = async () => {
+        const { code } = record;
+        const resp = await getSingleItem(code);
+        if (resp) {
+            set_matchItemInfo(resp);
+        }
+    }
+
+    const getNeedMatchList = async () => {
+        const resp = await getAllNeedMatchItems();
+        if (resp) {
+            set_allNeedMatchList(resp);
+        }
+    }
+
+    const getReferralMatchHandle = async () => {
+        set_loading(true);
+        const { code } = matchItemInfo;
+        const resp = await getReferralMatch(code);
+        if (resp) {
+            const { allStandItem: all = [], matchStandItem: match = [] } = resp;
+            const temp = [...all];
+            const index = temp.findIndex((item: any) => item.code == matchItemInfo.standItemCode);
+            if (index !== -1) {
+                // 如果找到了符合条件的项,先将其从数组中移除
+                const [item] = temp.splice(index, 1);
+                // 然后将其添加到数组的开头
+                temp.unshift(item);
+            }
+            set_allStandItem([...temp]);
+
+            set_matchStandItem(match?Array.from(new Map(match.map((a: any) => [a.code, a])).values()):[]);
+            set_dataSource([...all]);
+            set_loading(false);
+        }
+    }
+
+    const switchNeddMatchItem = async (flag: number) => {
+
+
+
+        const currentIndex = allNeedMatchList.findIndex((a) => a.code == matchItemInfo.code);
+
+        if ((currentIndex == allNeedMatchList.length - 1) && flag > 0) {
+            message.info('已经是最后一项!');
+            return;
+        }
+        if ((currentIndex == 0) && flag < 0) {
+            message.info('没有上一项!');
+            return;
+        }
+
+        let next = undefined;
+
+        if (flag > 0) {
+            for (const item of [...allNeedMatchList].splice(currentIndex + 1, allNeedMatchList.length)) {
+                if (!item.match) {
+                    next = item
+                    break; // 满足条件后退出循环
+                }
+            }
+        }
+        if (flag < 0) {
+            for (const item of ([...allNeedMatchList].splice(0, currentIndex)).reverse()) {
+                if (!item.match) {
+                    next = item
+                    break; // 满足条件后退出循环
+                }
+            }
+        }
+
+        // console.log({switchNeddMatchItem,currentIndex,next});
+
+        if (next) {
+            set_matchItemInfo(next);
+        } else {
+            message.info('未找到未匹配项!');
+            getMatchInfo();
+            getNeedMatchList();
+        }
+    }
+
+    const matchRequestHandle = async (data: any,type:number) => {
+        try {
+            const { code: itemCode } = matchItemInfo;
+            const { code: standItemCode } = data;
+            const resp = await matchRequest(itemCode, standItemCode,type);
+            if (resp) {
+                if (!single) {
+                    switchNeddMatchItem(1);
+                    getNeedMatchList();
+                } else {
+                    getMatchInfo();
+                    getNeedMatchList();
+                }
+            }
+
+        } catch (error) {
+            console.log('matchRequestHandle_error', error);
+        }
+
+    }
+
+    const getRightsInfo = async () => {
+        const resp = await getMatchCount();
+        if (resp) {
+            set_countInfo(resp);
+        }
+    }
+
+    const openTableHandle = (bool: boolean) => {
+        if (bool) {
+            const currentIndex = allNeedMatchList.findIndex((a) => a.code == matchItemInfo.code);
+            set_currentTablePage(Math.ceil((currentIndex + 1) / 10));
+            set_chargeItemTabledataSource([...allNeedMatchList]);
+        }
+        set_openTable(bool);
+    }
+
+    const startBatchCalc = async () => {
+        set_isProgressModalVisible(true);
+        const resp = await mapItemAndStandItem();
+        if (resp) {
+            set_isProgressModalVisible(false);
+        }
+    }
+
+    const mapBtnHandle = async () => {
+
+        Modal.confirm({
+            title: '注意',
+            content: '对照操作只会自动匹配未对照的项目,是否继续操作?',
+            okText: '确定',
+            cancelText: '取消',
+            onOk: (...args) => {
+                startBatchCalc();
+            },
+        })
+    }
+
+    const goMatch = () => {
+        getReferralMatchHandle()
+    }
+
+    useEffect(() => {
+        if (matchItemInfo) {
+            getReferralMatchHandle();
+            getRightsInfo();
+        }
+    }, [matchItemInfo]);
+
+    useEffect(() => {
+        const filteredData = allStandItem.filter((item) => {
+            return item.code.includes(searchText) || item.name.includes(searchText);
+        });
+        set_dataSource(filteredData);
+    }, [searchText, allStandItem]);
+
+    useEffect(() => {
+        const filteredData = allNeedMatchList.filter((item) => {
+            return item.code.includes(chargeItemSearchText) || item.name.includes(chargeItemSearchText);
+        });
+        set_chargeItemTabledataSource(filteredData);
+    }, [chargeItemSearchText]);
+
+    useEffect(() => {
+        if (!single) getRightsInfo();
+    }, [single]);
+
+    useEffect(() => {
+        if (record) {
+            getMatchInfo();
+            getNeedMatchList();
+        }
+    }, [record])
+
+    return (
+        <div className="matchPage">
+            <ProgressModal
+                title="正在匹配"
+                type={'ITEM_BATCH_MATCH'}
+                onComplete={() => {
+                    getMatchInfo();
+                    getNeedMatchList();
+                }}
+                visible={isProgressModalVisible}
+            />
+            {
+                single && (
+                    <div className="header">
+                        <div className="title">{record ? record.standItemName : '项目'}</div>
+                        <div className="btnGroup">
+                            <IconFont onClick={() => { closeDrawer() }} type="iconquxiao" style={{ color: '#17181A', marginRight: 8, cursor: 'pointer', fontSize: 21 }} />
+                        </div>
+                    </div>
+                )
+            }
+            <div className="content" style={{ padding: single ? 16 : 0 }}>
+                <div className="left">
+                    <div className="leftRowOne">
+                        {
+                            !single && (
+                                <div className="leftRowOneHeader">
+                                    <div className="menu">
+                                        <IconFont type="iconliebiao" style={{ color: '#17181A', marginRight: 8, cursor: 'pointer' }} onClick={() => openTableHandle(!openTable)} />
+                                        当前项目:{matchItemInfo?.id}
+                                    </div>
+                                    <div className="btnGroup">
+                                        <div className="backPrev btns" onClick={() => { switchBatchHandle && switchBatchHandle(false) }}>返回上一层</div>
+                                        <div className="line"></div>
+                                        <div className="prev btns" onClick={() => switchNeddMatchItem(-1)}>上一项</div>
+                                        <div className="next btns" onClick={() => switchNeddMatchItem(1)}>下一项</div>
+                                    </div>
+                                    {
+                                        openTable && (
+                                            <div className="floatTable" style={{ width: 432 }}>
+                                                <div style={{ marginBottom: 12 }}>
+                                                    <div style={{ marginBottom: 12 }}>
+                                                        <ProFormText noStyle placeholder={'收费项目编码、名称'}
+                                                            fieldProps={{
+                                                                // value: keyword,
+                                                                suffix: <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" />,
+                                                                onChange: (e) => {
+                                                                    if (e.target.value.length != 0) {
+                                                                        setChargeItemSearchText(e.target.value);
+                                                                    } else {
+                                                                        setChargeItemSearchText('');
+                                                                    }
+                                                                }
+                                                            }}
+                                                        />
+                                                    </div>
+
+                                                    <KCIMTable columns={chargeTableColumns}
+                                                        options={{
+                                                            density: true,
+                                                            setting: {
+                                                                listsHeight: 100,
+                                                            },
+                                                        }}
+
+                                                        dataSource={[...chargeItemTabledataSource]}
+                                                        rowKey={'id'}
+                                                        onRow={(record) => {
+                                                            return {
+                                                                onClick: () => { set_matchItemInfo(record); set_openTable(false) }
+                                                            }
+                                                        }}
+                                                        tableAlertRender={false}
+                                                        rowClassName={(record) => record.code == matchItemInfo.code ? 'match' : ''}
+                                                        pagination={{ showTitle: false, showSizeChanger: true, simple: true, defaultPageSize: 10, defaultCurrent: currentTablePage }}
+
+
+                                                    />
+                                                </div>
+                                            </div>
+                                        )
+                                    }
+
+                                </div>
+                            )
+                        }
+
+                        <div className="leftRowOneContent">
+                            <div className="blocks">
+                                <div className="value">{matchItemInfo?.code}</div>
+                                <div className="label">项目编码</div>
+                            </div>
+                            <div className="blocks">
+                                <div className="value">{matchItemInfo?.name}</div>
+                                <div className="label">项目名称</div>
+                            </div>
+                            <div className="blocks">
+                                <div className="value">{matchItemInfo?.type}</div>
+                                <div className="label">项目类别</div>
+                            </div>
+                            <div className="blocks">
+                                <div className="value">{(matchItemInfo?.match) ? '已匹配' : '未匹配'}</div>
+                                <div className="label">匹配状态</div>
+                            </div>
+
+                        </div>
+
+                    </div>
+
+
+                    <div className="leftTable">
+                        <div className="leftTableTitle">手动匹配</div>
+                        <div style={{ marginBottom: 12 }}>
+                            <ProFormText noStyle placeholder={'标准项目编码、名称'}
+                                fieldProps={{
+                                    // value: keyword,
+                                    suffix: <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" />,
+                                    onChange: (e) => {
+                                        if (e.target.value.length != 0) {
+                                            setSearchText(e.target.value);
+                                        } else {
+                                            setSearchText('');
+                                        }
+                                    }
+                                }}
+                            />
+                        </div>
+                        <KCIMTable columns={leftTableColumns}
+                            options={{
+                                density: true,
+                                setting: {
+                                    listsHeight: 100,
+                                },
+                            }}
+                            loading={loading}
+                            dataSource={[...dataSource]}
+                            rowKey={'id'}
+                            tableAlertRender={false}
+                            pagination={{ showTitle: false, showSizeChanger: true, simple: true, defaultPageSize: 12 }}
+
+
+                        />
+                    </div>
+                </div>
+                <div className="right">
+                    {
+                        !single && (
+                            <div className="rightRowOne">
+                                <div className="processCycle">
+                                    <Progress type="circle" format={percent => <span style={{ color: '52c41a !important' }}>{`${percent}%`}</span>} percent={countInfo ? Math.floor((countInfo.trueMatch / countInfo.allCount) * 100) : 0} width={64} />
+                                    <div className="processInfo">
+                                        <div className="total">全部项目:{countInfo ? countInfo.allCount : 0}</div>
+                                        <div className="subInfo">
+                                            <span>已匹配:<a>{countInfo ? countInfo.trueMatch : 0}</a></span> <span>待匹配:<a>{countInfo ? countInfo.falseMatch : 0}</a></span>
+                                        </div>
+                                    </div>
+                                </div>
+                                <div className="btn" onClick={() => mapBtnHandle()}>
+                                <IconFont style={{ color: '#fff',fontSize:14,marginRight:4 }} type="iconshuoming" />智能匹配
+                                    <div className="description">
+                                        <img src={require('../../../../../../static/tanhao.png')} alt="" style={{ width: 16, height: 16, marginRight: 4 }} />
+                                        <div className="detail">
+                                            <div className="detailTitle">匹配规则</div>
+                                            <div className="detailContent">
+                                                1、逐个匹配未匹配的项目,已匹配的项目会自动跳过<br />
+                                                2、与标准项目国家编码精准匹配的项目状态设置成已匹配<br />
+                                                3、未精准匹配的项目会通过智能匹配算法形成推荐项,需用户逐个选择匹配项
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        )
+                    }
+
+                    <div className="rightContent">
+                        <div className="rightContentHeader">
+                            <span className="title">推荐匹配</span>
+                            <span className="btn" onClick={()=>switchNeddMatchItem(1)}><IconFont style={{ color: '#3376FE',paddingRight:4 }} type="iconshuangyou" />跳过该项</span>
+                        </div>
+                        <div className="content">
+                            {
+                                loading && (
+                                    <Skeleton active />
+                                )
+                            }
+                            {
+                                !loading && matchStandItem.map((item, index) => {
+                                    const { code } = item;
+                                    return (
+                                        <div className="list" key={index}>
+                                            <div className="leftDetail">
+                                                <div className="rowOne">
+                                                    <div className="title">{item.name}</div>
+                                                    <div className="Signal"><SignalBar level={item.percent ? item.percent : 0} />{item.percentDisplay}</div>
+                                                </div>
+                                                <div className="rowTwo">
+                                                    <div className="code">普通门诊诊察费</div>
+                                                    <div className="type">康程分类:诊察费/西医诊察费</div>
+                                                </div>
+                                            </div>
+                                            {code != matchItemInfo?.standItemCode ? <div className="btn" onClick={() => matchRequestHandle(item,2)}>匹配</div> : <div className="btnText">当前匹配</div>}
+                                        </div>
+                                    )
+                                })
+                            }
+                            {
+                                !loading && matchStandItem.length == 0 && (
+                                    <div className="empty">
+                                        <img src={require('../../../../../../static/empty.png')} alt="" />
+                                        <div className="title">暂无推荐项目</div>
+                                        <div className="titleSub">当前暂无推荐匹配项目,您可尝试进行对照或</div>
+                                        <a className="btn" onClick={() => goMatch()}>去匹配</a>
+                                    </div>
+                                )
+                            }
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+        </div>
+    )
+}

+ 593 - 0
src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/setting.tsx

@@ -0,0 +1,593 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-02-21 13:32:53
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-02-29 15:56:28
+ * @FilePath: /CostAccountingSys/src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/setting.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+import { KCIMTable } from '@/components/KCIMTable';
+import { ActionType, ModalForm, ProColumns, ProFormCascader, ProFormDigit, ProFormInstance, ProFormSelect, ProFormText } from '@ant-design/pro-components';
+import { Tabs } from 'antd';
+import { Key, useEffect, useRef, useState } from 'react';
+import { Popconfirm, message } from 'antd';
+import { addDrawerTableData, addDrugTableData, batchDelDrugTableData, delDrawerTableData, editDrawerTableData, getEmpsByItemCode, getEquipByItemCode, getNoValuationDrugByItemCode, getSpaceByItemCode, getValuationDrugByItemCode } from '../service';
+import { getSpaceCostTableData } from '@/pages/costLibraryManagement/basicCostManagement/spaceCostManagement/service';
+import { getEquipTableData } from '@/pages/costLibraryManagement/basicCostManagement/equipmentCostManagement/service';
+import { getLeftList } from '@/pages/costLibraryManagement/basicCostManagement/personnelClassificationMana/service';
+import TableSelecter from './tableSelector';
+
+
+const empColumns = [
+
+    {
+        title: '人员类别',
+        dataIndex: 'empTypeCodeName',
+    },
+    {
+        title: '数量',
+        dataIndex: 'num'
+    },
+    {
+        title: '执行时间(min)',
+        dataIndex: 'executeTime',
+    },
+
+];
+const equipColumns = [
+
+    {
+        title: '设备编编码',
+        dataIndex: 'equipmentCode',
+    },
+    {
+        title: '设备名称',
+        dataIndex: 'equipmentCodeName'
+    },
+    {
+        title: '数量',
+        dataIndex: 'num',
+    },
+    {
+        title: '执行时间(m)',
+        dataIndex: 'executeTime',
+    },
+
+]
+const spaceColumns = [
+
+    {
+        title: '空间编码',
+        dataIndex: 'spaceCode',
+    },
+    {
+        title: '空间名称',
+        dataIndex: 'spaceCodeName'
+    },
+    {
+        title: '数量',
+        dataIndex: 'num',
+    },
+    {
+        title: '执行时间(m)',
+        dataIndex: 'executeTime',
+    },
+
+]
+
+
+export const Setting = (props: any) => {
+    const { record, onVisibleChange } = props;
+
+    const tableRef = useRef<ActionType>();
+    const formRef = useRef<ProFormInstance>();
+    const [columns, set_columns] = useState<any[]>([]);
+    const [currentTabKey, set_currentTabKey] = useState('1');
+    const [dataSource, set_dataSource] = useState([]);
+    const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);
+    const [selectedRows, set_selectedRows] = useState<any[]>([]);
+    const [tableSelecterVisible, set_tableSelecterVisible] = useState(false);
+    const [currentEditRow,set_currentEditRow] = useState<any>(undefined);
+
+    const valuationColumns = [
+
+        {
+            title: '项目类别',
+            width: 85,
+            dataIndex: 'typeName',
+        },
+        {
+            title: '项目代码',
+            width: 85,
+            dataIndex: 'code'
+        },
+        {
+            title: '项目名称',
+            dataIndex: 'name',
+        },
+        {
+            title: '数量',
+            dataIndex: 'num',
+            width: 120,
+            renderText(num:any, record:any) {
+                return (
+                    <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
+                        {
+                            (currentEditRow && currentEditRow.id == record.id) && (
+                                <>
+                                    <ProFormDigit
+                                        width={80}
+                                        noStyle
+                                        fieldProps={{
+                                            value: num,
+                                            onChange(value) {
+                                                set_currentEditRow({ ...record,num:value});
+                                            },
+                                        }}
+                                    />
+                                    <img onClick={() => updateTable({ ...record,...currentEditRow }, 'EDIT',Number(currentTabKey))} style={{ width: 16, height: 16, display: 'inline-block', marginLeft: 8, cursor: 'pointer' }} src={require('../../../../../../static/confirmIcon.png')} />
+                                </>
+                            )
+                        }
+    
+                        {
+                            (!currentEditRow || (currentEditRow&&currentEditRow.id != record.id)) && (
+                                <>
+                                    <div>{num}</div>
+                                    <img onClick={() => {set_currentEditRow(record);}} style={{ width: 16, height: 16, display: 'inline-block', marginLeft: 8, cursor: 'pointer' }} src={require('../../../../../../static/editIcon.png')} />
+                                </>
+                            )
+                        }
+                    </div>
+                )
+            },
+        },
+    
+    ]
+
+    const columnsData = (key: number) => [
+        {
+            title: '操作',
+            key: 'option',
+            width: 160,
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                return [
+                    <UpDataActBtn key={'act'} record={record} type='EDIT' currentTabKey={key} />,
+                    <Popconfirm
+                        title="是否确认删除?"
+                        key="del"
+                        onConfirm={() => delTableData(record)}
+                    >
+                        <a>删除</a>
+                    </Popconfirm>,
+                ]
+            },
+        },
+
+    ];
+
+
+
+    const getTableData = async (tabCode: string) => {
+        let resp = undefined;
+        if (tabCode == '1') {
+            resp = await getEmpsByItemCode(record.code);
+        }
+        if (tabCode == '2') {
+            resp = await getEquipByItemCode(record.code);
+        }
+        if (tabCode == '3') {
+            resp = await getSpaceByItemCode(record.code);
+        }
+        if (tabCode == '4') {
+            resp = await getValuationDrugByItemCode(record.code);
+        }
+        if (tabCode == '5') {
+            resp = await getNoValuationDrugByItemCode(record.code);
+        }
+
+        set_dataSource(resp);
+    }
+
+    const delTableData = async (record: any) => {
+        const resp = await delDrawerTableData(record.id, Number(currentTabKey));
+        if (resp) {
+            message.success('操作成功!');
+            //tableRef.current?.reload();
+            getTableData(`${currentTabKey}`);
+            // message.success('操作成功!');
+        }
+    }
+
+    const updateTable = async (formVal: any, type: 'EDIT' | "ADD", currentTabKey: number) => {
+
+        let result = undefined;
+
+        if (type == 'ADD') {
+            if (currentTabKey == 1) {
+                result = {
+                    itemCode: record.code,
+                    empTypeCode: formVal.empType.value,
+                    empTypeCodeName: formVal.empType.label,
+                    num: formVal.num,
+                    executeTime: formVal.executeTime
+                }
+            }
+            if (currentTabKey == 2) {
+                result = {
+                    itemCode: record.code,
+                    equipmentCode: formVal.equipmentCode,
+                    num: formVal.num,
+                    executeTime: formVal.executeTime
+                }
+            }
+            if (currentTabKey == 3) {
+                result = {
+                    itemCode: record.code,
+                    spaceCode: formVal.space[formVal.space.length - 1],
+                    num: formVal.num,
+                    spaceCodePath: formVal.spaceCodePath,
+                    executeTime: formVal.executeTime
+                }
+            }
+
+            const resp = await addDrawerTableData(result, currentTabKey as number);
+            if (resp) {
+                //tableRef.current?.reload();
+                getTableData(`${currentTabKey}`);
+                message.success('操作成功!');
+            }
+
+        }
+        if (type == 'EDIT') {
+
+            try {
+
+                if (currentTabKey == 1) {
+                    result = {
+                        itemCode: record.code,
+                        empTypeCode: formVal.empType.value,
+                        empTypeCodeName: formVal.empType.label,
+                        num: formVal.num,
+                        executeTime: formVal.executeTime
+                    }
+                }
+                if (currentTabKey == 2) {
+                    result = {
+                        itemCode: record.code,
+                        equipmentCode: formVal.equipmentCode,
+                        num: formVal.num,
+                        executeTime: formVal.executeTime
+                    }
+                }
+                if (currentTabKey == 3) {
+                    result = {
+                        itemCode: record.code,
+                        spaceCode: formVal.spaceCode,
+                        num: formVal.num,
+                        spaceCodePath: formVal.spaceCodePath,
+                        executeTime: formVal.executeTime
+                    }
+                }
+                if (currentTabKey == 4||currentTabKey == 5) {
+                    result = {
+                        ...currentEditRow,
+                    }
+                }
+
+                const resp = await editDrawerTableData({ ...result, id: formVal.id }, currentTabKey);
+                if (resp) {
+                    //tableRef.current?.reload();
+                    getTableData(`${currentTabKey}`);
+                    message.success('操作成功!');
+                }
+                set_currentEditRow(undefined);
+
+            } catch (error) {
+                console.log('编辑保存:', error)
+            }
+
+
+
+
+        }
+        return true;
+
+    }
+
+    const UpDataActBtn = ({ record, type, currentTabKey }: { record: any, type: 'EDIT' | 'ADD', currentTabKey: number }) => {
+
+        const [cascaderData, set_cascaderData] = useState<any[]>([]);
+        return (
+            <ModalForm
+                title={`${type == 'EDIT' ? '编辑' : '新增'}${currentTabKey == 1 ? '参与人员' : currentTabKey == 2 ? '使用设备' : '使用空间'}`}
+                width={350}
+                formRef={formRef}
+                initialValues={type == 'EDIT' ? {
+                    ...record, empType: record.empTypeCode, space: record.spaceCodePath ? record.spaceCodePath.split(',') : []
+                } : { kcClassCode: '', kcClassName: '', kcClassPath: '', executeTime: record.executeTime }}
+                trigger={
+                    type == 'EDIT' ? <a key="edit" >编辑</a> : <a className='add'>新增</a>
+                }
+                onFinish={(val) => {
+                    return updateTable(type == 'EDIT' ? { ...record, ...val } : { ...val }, type, currentTabKey);
+                }}
+                modalProps={{ destroyOnClose: true }}
+                colProps={{ span: 24 }}
+                grid
+            >
+                {
+                    currentTabKey == 1 && (
+                        <ProFormSelect
+                            name="empType"
+                            label="人员类别:"
+                            placeholder="请选择"
+                            showSearch
+                            fieldProps={{ labelInValue: true }}
+                            request={async () => {
+                                const resp = await getLeftList();
+                                if (resp) {
+                                    return resp.map((a: any) => ({ label: a.costTypeName, value: a.costTypeCode }))
+                                } else {
+                                    return []
+                                }
+                            }}
+                            rules={[{ required: true, message: '人员类别不能为空!' }]}
+                        />
+                    )
+                }
+                {
+                    currentTabKey == 2 && (
+                        <ProFormSelect
+                            name="equipmentCode"
+                            label="设备名称:"
+                            placeholder="请选择"
+                            showSearch
+                            request={async ({ keyWords }) => {
+                                const resp = await getEquipTableData({ name: keyWords, pageSize: 500, current: 1 });
+                                if (resp) {
+                                    return resp.list.map((a: any) => ({ label: a.name, value: a.code }))
+                                } else {
+                                    return []
+                                }
+                            }}
+                            rules={[{ required: true, message: '设备名称不能为空!' }]}
+                        />
+                    )
+                }
+                {
+                    currentTabKey == 3 && (
+                        <>
+                            <ProFormText name='spaceCodePath' hidden />
+                            <ProFormText name='spaceCode' hidden />
+                            <ProFormCascader
+                                name="space"
+                                label="空间名称:"
+                                rules={[{ required: true, message: '空间名称不能为空!' }]}
+                                request={async () => {
+                                    const resp = await getSpaceCostTableData();
+                                    if (resp) {
+                                        set_cascaderData(resp);
+                                        return resp
+                                    }
+                                }}
+                                fieldProps={{
+                                    fieldNames: { label: 'name', value: 'code', children: 'childList' },
+                                    onChange: async (value: any) => {
+                                        // const a = findAllParents(cascaderData, value[value.length - 1]);
+                                        // console.log({a});
+                                        if (value.length > 0) {
+                                            formRef.current?.setFieldsValue({
+                                                spaceCodePath: value.join(','),
+                                                spaceCode: value[value.length - 1]
+                                            })
+                                        }
+                                    }
+                                }}
+                            />
+                        </>
+
+
+                    )
+                }
+
+                <ProFormDigit
+                    name="num"
+                    label="数量:"
+                    placeholder="请输入"
+                    rules={[{ required: true, message: '数量不能为空!' }]}
+                />
+                <ProFormDigit
+                    name="executeTime"
+                    label="执行时间(min):"
+                    placeholder="请输入"
+                    rules={[{ required: true, message: '执行时间不能为空!' }]}
+                />
+            </ModalForm>
+        )
+    }
+
+    const tableSelecterCommit = async (keys: Key[], rows: any[]) => {
+        //   console.log({keys,rows});
+        set_tableSelecterVisible(false);
+        const result = {
+            itemCode: record.code,
+            items: rows
+        }
+        const resp = await addDrugTableData(result, Number(currentTabKey));
+        if (resp) {
+            getTableData(`${currentTabKey}`);
+        }
+
+    }
+
+    const onSelectChange = (newSelectedRowKeys: React.Key[], selectedRows: any) => {
+        setSelectedKeys([...newSelectedRowKeys]);
+        set_selectedRows([...selectedRows]);
+
+    };
+
+    const batchDelTableData = async () => {
+        const resp = await batchDelDrugTableData(selectedRows.map((a) => a.id), Number(currentTabKey));
+        if (resp) {
+            getTableData(`${currentTabKey}`);
+            setSelectedKeys([]);
+            set_selectedRows([]);
+        }
+    }
+
+    useEffect(() => {
+        getTableData(currentTabKey);
+        set_currentEditRow(undefined);
+        if (currentTabKey == '1') {
+            set_columns([...empColumns, ...columnsData(Number(currentTabKey))])
+        }
+        if (currentTabKey == '2') {
+            set_columns([...equipColumns, ...columnsData(Number(currentTabKey))])
+        }
+        if (currentTabKey == '3') {
+            set_columns([...spaceColumns, ...columnsData(Number(currentTabKey))])
+        }
+        if (currentTabKey == '4') {
+            set_columns([...valuationColumns, {
+                title: '操作',
+                key: 'option',
+                width: 80,
+                valueType: 'option',
+                render: (_: any, record: any) => {
+                    return [
+                        <Popconfirm
+                            title="是否确认删除?"
+                            key="del"
+                            onConfirm={() => delTableData(record)}
+                        >
+                            <a>删除</a>
+                        </Popconfirm>,
+                    ]
+                },
+            },])
+        }
+        if (currentTabKey == '5') {
+            set_columns([...valuationColumns, {
+                title: '操作',
+                key: 'option',
+                width: 80,
+                valueType: 'option',
+                render: (_: any, record: any) => {
+                    return [
+                        <Popconfirm
+                            title="是否确认删除?"
+                            key="del"
+                            onConfirm={() => delTableData(record)}
+                        >
+                            <a>删除</a>
+                        </Popconfirm>,
+                    ]
+                },
+            }])
+        }
+
+        setSelectedKeys([]);
+        set_selectedRows([]);
+
+    }, [currentTabKey]);
+
+    useEffect(()=>{
+        if(currentTabKey == '4'||currentTabKey == '5')
+        set_columns([...valuationColumns, {
+            title: '操作',
+            key: 'option',
+            width: 80,
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                return [
+                    <Popconfirm
+                        title="是否确认删除?"
+                        key="del"
+                        onConfirm={() => delTableData(record)}
+                    >
+                        <a>删除</a>
+                    </Popconfirm>,
+                ]
+            },
+        }])
+    },[currentEditRow])
+
+
+    return (
+        <div className="settingDrawer">
+            <TableSelecter
+                onVisibleChange={(bool) => set_tableSelecterVisible(bool)}
+                title='添加'
+                rowKey={'code'}
+                defaultSelectedKeys={dataSource.map((a: any) => a.code)}
+                record={record}
+                open={tableSelecterVisible}
+                onFinish={(keys, rows) => tableSelecterCommit(keys, rows)}
+            />
+            <div className="header">
+                <div className="title">{record?record.standItemName:'项目'}</div>
+                <div className="btnGroup">
+                    <a className="back" onClick={() => onVisibleChange(false)}>返回</a>
+                    {(currentTabKey != '4' && currentTabKey != '5') && <UpDataActBtn key={'act'} record={record} type='ADD' currentTabKey={Number(currentTabKey)} />}
+                    {(currentTabKey == '4' || currentTabKey == '5') && <a className='add' onClick={() => set_tableSelecterVisible(true)}>添加</a>}
+                </div>
+            </div>
+
+            <div style={{ padding: '0 16px' }}>
+                <Tabs
+                    defaultActiveKey={`${currentTabKey}`}
+                    onChange={(key) => set_currentTabKey(key)}
+                    items={[
+                        {
+                            label: '参与人员',
+                            key: '1'
+                        },
+                        {
+                            label: '使用设备',
+                            key: '2'
+                        },
+                        {
+                            label: '使用空间',
+                            key: '3',
+                        },
+                        {
+                            label: '计价药材',
+                            key: '4',
+                        },
+                        {
+                            label: '不计价药材',
+                            key: '5',
+                        },
+                    ]}
+                />
+                <KCIMTable
+                    rowSelection={(currentTabKey == '4' || currentTabKey == '5') ? {
+                        alwaysShowAlert: false,
+                        selectedRowKeys: selectedKeys,
+                        onChange: onSelectChange,
+
+                    } : false}
+                    tableAlertRender={false}
+                    columns={columns}
+                    actionRef={tableRef} rowKey='id'
+                    dataSource={dataSource}
+                />
+            </div>
+            {
+                selectedKeys.length > 0 && (
+                    <div className='footer'>
+                        <div className='count'>{`已选择${selectedKeys.length}`}</div>
+                        <div className='btngroup'>
+                            <a className='cancel' onClick={() => { setSelectedKeys([]); set_selectedRows([]) }}>取消</a>
+                            <a className='confirm' onClick={() => batchDelTableData()}>批量删除</a>
+                        </div>
+                    </div>
+                )
+            }
+
+        </div>
+    )
+}

+ 522 - 0
src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/style.less

@@ -0,0 +1,522 @@
+.matchPage {
+    height: 100%;
+    background-color: #F5F7FA;
+    .header {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        // margin-bottom: 8px;
+        padding: 0 16px;
+        padding-top: 16px;
+
+        .title {
+            font-size: 16px;
+            font-weight: 500;
+            color: #17181A;
+        }
+
+        .btnGroup {
+            a {
+                display: inline-block;
+                width: 56px;
+                text-align: center;
+                line-height: 22px;
+                height: 24px;
+                border-radius: 4px;
+
+                &.back {
+                    font-weight: 400;
+                    color: #17181A;
+                    background: #FAFCFF;
+                    margin-right: 8px;
+                    border: 1px solid #DAE2F2;
+                }
+
+                &.add {
+                    font-weight: 400;
+                    color: #FFFFFF;
+                    background: #3377FF;
+                }
+            }
+        }
+    }
+
+    &>.content {
+        display: flex;
+        width: 100%;
+        height: 100%;
+        padding: 16px;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: flex-start;
+        background-color: #F5F7FA;
+
+        .left {
+            width:calc(100% - 500px);
+
+            .leftRowOne {
+                position: relative;
+                border-radius: 4px;
+                margin-bottom: 16px;
+                background-color: #FFFFFF;
+                
+
+                .leftRowOneHeader {
+                    display: flex;
+                    flex-direction: row;
+                    justify-content: space-between;
+                    align-items: center;
+                    height: 40px;
+                    padding: 0 16px;
+                    background: linear-gradient(180deg, #FCFEFF 0%, #F2F8FE 100%);
+                    border-radius: 4px 4px 0px 0px;
+                    border-bottom: 1px solid #DAE2F2;
+
+                    .menu {
+                        font-weight: 400;
+                        font-size: 14px;
+                        color: #525866;
+                    }
+
+                    .btnGroup {
+                        .btns {
+                            display: inline-block;
+                            height: 24px;
+                            padding: 0 12px;
+                            line-height: 24px;
+                            text-align: center;
+                            background: #FAFCFF;
+                            border-radius: 4px;
+                            cursor: pointer;
+                            border: 1px solid #DAE2F2;
+                            font-weight: 400;
+                            font-size: 14px;
+                            color: #17181A;
+                            margin-left: 8px;
+                        }
+
+                        .line {
+                            display: inline-block;
+                            width: 2px;
+                            height: 12px;
+                            margin-left: 8px;
+                            background: #DAE2F2;
+                        }
+                    }
+                }
+
+                .leftRowOneContent {
+                    display: flex;
+                    flex-direction: row;
+                    padding: 12px 24px;
+                    justify-content:flex-start;
+                    align-items: center;
+
+                    .blocks {
+                        text-align: left;
+                        .value {
+                            height: 16px;
+                            line-height: 16px;
+                            font-weight: 500;
+                            font-size: 16px;
+                            color: #17181A;
+                            margin-bottom: 8px;
+                            overflow: hidden;
+                            padding-right: 16px;
+                            text-overflow: ellipsis;
+                            white-space: nowrap;
+                        }
+
+                        .label {
+                            font-weight: 400;
+                            font-size: 12px;
+                            color: #7A8599;
+                            padding-right: 16px;
+                            overflow: hidden;
+                            padding-right: 16px;
+                            text-overflow: ellipsis;
+                            white-space: nowrap;
+                            
+                        }
+                        &:nth-child(1) {
+                            width: 25%;
+                        }
+                        &:nth-child(2) {
+                            width: 55%;
+                        }
+                        &:nth-child(3) {
+                            width: 12%;
+                        }
+                        &:nth-child(4) {
+                            width: 9%;
+                            text-align: right;
+                            .label {
+                                padding-right: 0;
+                            }
+                            .value {
+                                padding-right: 0;
+                            }
+                        }
+                    }
+                }
+
+                .floatTable {
+                    position: absolute;
+                    top: 50px;
+                    z-index: 10;
+                    padding: 16px;
+                    background: #FFFFFF;
+                    box-shadow: 0px 8px 16px 0px rgba(64, 85, 128, 0.1);
+                    border-radius: 4px;
+
+                    .match {
+                        background: rgba(51, 119, 255, 0.08);
+                    }
+                }
+
+            }
+
+            .leftTable {
+                padding: 16px;
+                background-color: #FFFFFF;
+
+                .leftTableTitle {
+                    font-weight: 500;
+                    font-size: 16px;
+                    color: #17181A;
+                    margin-bottom: 12px;
+                }
+
+            }
+        }
+
+        .right {
+            width:500px;
+            margin-left: 16px;
+            .rightRowOne {
+                display: flex;
+                flex-direction: row;
+                justify-content: space-between;
+                align-items: center;
+                padding: 22px 16px;
+                border-radius: 4px;
+                margin-bottom: 16px;
+                background-color: #FFFFFF;
+
+                .processCycle {
+                    display: flex;
+                    flex-direction: row;
+                    justify-content: flex-start;
+                    align-items: center;
+
+                    .processInfo {
+                        margin-left: 16px;
+
+                        .total {
+                            font-weight: 500;
+                            height: 18px;
+                            line-height: 18px;
+                            font-size: 18px;
+                            color: #17181A;
+                            margin-bottom: 10px;
+                        }
+
+                        .subInfo {
+                            span {
+                                font-weight: 400;
+                                font-size: 14px;
+                                color: #7A8599;
+
+                                &>a {
+                                    font-weight: 500;
+                                    font-size: 14px;
+                                    color: #17181A;
+                                }
+
+                                &:last-child {
+                                    &>a {
+                                        font-weight: 500;
+                                        font-size: 14px;
+                                        color: #FF8C19;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                .btn {
+                    position: relative;
+                    top:25px;
+                    cursor: pointer;
+                    display: flex;
+                    flex-direction: row;
+                    justify-content: center;
+                    align-items: center;
+                    width: 100px;
+                    height: 24px;
+                    text-align: center;
+                    background:#3377FF ;
+                    border-radius: 4px;
+                    border: 1px solid #DAE2F2;
+                    font-weight: 400;
+                    font-size: 14px;
+                    color:#FFFFFF;
+
+                    .description {
+                        position: absolute;
+                        left: -269px;
+                        top: 35px;
+                        display: none;
+                        flex-direction: row;
+                        justify-content: flex-start;
+                        align-items: flex-start;
+                        width: 380px;
+                        height: 132px;
+                        padding: 16px;
+                        background: #FFFFFF;
+                        box-shadow: 0px 8px 16px 0px rgba(64, 85, 128, 0.1);
+                        border-radius: 8px;
+
+                        .detail {
+                            display: flex;
+                            margin-left: 8px;
+                            flex-direction: column;
+                            justify-content: flex-start;
+                            align-items: flex-start;
+
+                            .detailTitle {
+                                font-weight: 500;
+                                font-size: 16px;
+                                color: #17181A;
+                                height: 16px;
+                                line-height: 16px;
+                                margin-bottom: 12px;
+                            }
+
+                            .detailContent {
+                                text-align: left;
+                                font-weight: 400;
+                                font-size: 12px;
+                                color: #525966;
+                            }
+                        }
+                    }
+
+                    &:hover {
+                        .description {
+                            display: flex;
+                        }
+                    }
+                }
+
+            }
+
+            .rightContent {
+                padding: 16px;
+                min-height: 673px;
+                background: #FFFFFF;
+                border-radius: 4px;
+                border-radius: 4px 4px 0px 0px;
+
+                .rightContentHeader {
+                    display: flex;
+                    flex-direction: row;
+                    justify-content: space-between;
+                    align-items: center;
+                    .title {
+                        font-weight: 500;
+                        font-size: 16px;
+                        height: 16px;
+                        line-height: 16px;
+                        color: #17181A;
+                        margin-bottom: 16px;
+                    }
+                    .btn {
+                        width: 100px;
+                        height: 24px;
+                        line-height: 24px;
+                        text-align: center;
+                        font-weight: 400;
+                        font-size: 14px;
+                        color: #3376FE;
+                        margin-bottom: 16px;
+                        cursor: pointer;
+                        border-radius: 4px;
+                        &:hover {
+                              background: #f2f7ff;
+                        }
+
+                    }
+                }
+
+                .content {
+                    max-height: 612px;
+                    overflow-y: scroll;
+                    background: #FFFFFF;
+
+                    .list {
+                        display: flex;
+                        flex-direction: row;
+                        justify-content: space-between;
+                        align-items: center;
+                        height: 66px;
+                        padding: 12px;
+                        background: #FFFFFF;
+                        border-radius: 4px;
+                        margin-bottom: 12px;
+                        border: 1px solid #E6EAF2;
+
+                        .leftDetail {
+                            width: 83%;
+
+                            .rowOne {
+                                display: flex;
+                                flex-direction: row;
+                                justify-content: space-between;
+                                align-items: center;
+                                margin-bottom: 5px;
+
+                                .title {
+                                    font-weight: 500;
+                                    font-size: 16px;
+                                    height: 16px;
+                                    line-height: 16px;
+                                    color: #17181A;
+                                }
+
+                                .Signal {
+                                    display: flex;
+                                    flex-direction: row;
+                                    justify-content: center;
+                                    align-items: center;
+
+                                    font-weight: 500;
+                                    font-size: 16px;
+                                    color: #17181A;
+
+                                    /* ProgressBar.css */
+                                    .signal-container {
+                                        display: flex;
+                                        align-items: flex-end;
+                                        height: 16px;
+                                        /* 信号条的最大高度 */
+                                        width: 31px;
+                                        /* 适当的宽度,确保所有信号条都能显示 */
+                                    }
+
+                                    .signal-bar {
+                                        width: 4px;
+                                        /* 单个信号条的宽度 */
+                                        border-radius: 2px;
+                                        background-color: #DAE2F2;
+                                        /* 默认的灰色背景 */
+                                        transition: background-color 0.3s ease-in-out;
+                                    }
+
+                                    .signal-bar.active {
+                                        background-color: #00CC99;
+                                        /* 信号条激活时的颜色 */
+                                    }
+                                }
+
+
+
+                            }
+
+                            .rowTwo {
+                                display: flex;
+                                flex-direction: row;
+                                justify-content: space-between;
+                                align-items: center;
+
+                                .code {
+                                    font-weight: 400;
+                                    font-size: 14px;
+                                    color: #525866;
+                                }
+
+                                .type {
+                                    font-weight: 400;
+                                    font-size: 14px;
+                                    color: #525866;
+                                }
+                            }
+                        }
+
+                        .btn {
+                            cursor: pointer;
+                            width: 56px;
+                            height: 24px;
+                            text-align: center;
+                            line-height: 21px;
+                            background: #FAFCFF;
+                            border-radius: 4px;
+                            border: 1px solid #DAE2F2;
+                            font-weight: 400;
+                            font-size: 14px;
+                            color: #17181A;
+                        }
+
+                        .btnText {
+                            font-weight: 500;
+                            font-size: 14px;
+                            color: #00BF8F;
+                        }
+
+                        &:last-child {
+                            margin-bottom: 0;
+                        }
+                    }
+
+                    .empty {
+                        display: flex;
+                        width: 100%;
+                        height: 300px;
+                        flex-direction: column;
+                        justify-content: center;
+                        align-items: center;
+
+                        &>img {
+                            width: 160px;
+                            height: 140px;
+                        }
+
+                        .title {
+                            font-weight: 500;
+                            height: 24px;
+                            font-size: 24px;
+                            color: #17181A;
+                            line-height: 25px;
+                            margin-top: 24px;
+                            margin-bottom: 10px;
+                        }
+
+                        .titleSub {
+                            font-weight: 400;
+                            font-size: 14px;
+                            color: #7A8599;
+                        }
+
+                        .btn {
+                            display: inline-block;
+                            width: 70px;
+                            height: 24px;
+                            text-align: center;
+                            line-height: 24px;
+                            background: #3377FF;
+                            border-radius: 4px;
+                            font-size: 14px;
+                            color: #FFFFFF;
+                            margin-top: 20px;
+                        }
+                    }
+                }
+            }
+
+        }
+    }
+
+
+}

+ 196 - 0
src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/tableSelector.tsx

@@ -0,0 +1,196 @@
+import React, { Key, useEffect, useState } from "react";
+import { Input, Select } from 'antd'
+import { KCIMTable } from "@/components/KCIMTable";
+import { createFromIconfontCN } from "@ant-design/icons";
+
+
+import { ModalForm, ProColumns, ProFormSelect, ProFormText } from "@ant-design/pro-components";
+
+import { set } from "lodash";
+import { getAddableTableData } from "../service";
+
+
+
+
+// import './style.less';
+
+
+interface TableSelecterProps {
+    record: any
+}
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+
+
+const TableSelecter = ({ record, open, title, onVisibleChange, rowKey = 'id', request, onFinish, defaultSelectedKeys }: {
+    record: any, open: boolean, title: string, onVisibleChange: (bool: boolean) => void, defaultSelectedKeys: Key[],
+    rowKey?: string, request?: (params: any) => Promise<any>, onFinish?: (selectedKeys: React.Key[], selectedRows: any[]) => void
+}) => {
+
+
+    const Table = React.forwardRef(({ }: TableSelecterProps, ref) => {
+
+        const [datasource, set_datasource] = useState<any[]>([]);
+        const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);
+        const [selectedRows, set_selectedRows] = useState<any[]>([]);
+        const [showList, set_showList] = useState<any[]>([]);
+        const [type, set_type] = useState<number>(1);
+        const [keyword, set_keyword] = useState<string | undefined>(undefined);
+
+
+        const columns: ProColumns[] = [
+            {
+                title: '项目代码',
+                ellipsis: true,
+                width: 85,
+                dataIndex: 'code',
+            },
+            {
+                title: '项目名称',
+                ellipsis: true,
+                dataIndex: 'name',
+            }
+        ];
+
+
+        const onSelectChange = (newSelectedRowKeys: React.Key[], selectedRows: any) => {
+            setSelectedKeys([...newSelectedRowKeys]);
+            set_selectedRows([...selectedRows]);
+
+        };
+
+        const saveHandle = async () => {
+            const selectedRowCodes = selectedRows.map((a) => a[`${rowKey}`]);
+            const rows = datasource.filter((a) => selectedRowCodes.includes(a[`${rowKey}`]));
+            console.log({selectedKeys,rows});
+            onFinish && onFinish(selectedKeys, rows);
+        }
+
+        const getTableData = async () => {
+            const resp = await getAddableTableData(type, record.code);
+            if (resp) {
+                const data = resp.filter((a: any) => {
+                    if (!(defaultSelectedKeys.includes(a[`${rowKey}`]))) {
+
+                        return {
+                            ...a,
+                        }
+                    }
+                });
+
+                set_showList(data);
+                set_datasource([...data]);
+            }
+
+
+            return Promise.resolve([]);
+        }
+
+        useEffect(() => {
+            // console.log({code, keyword});
+            const result = datasource.filter((a) => {
+                return a.name.indexOf(keyword) != -1
+            });
+
+            set_showList([...result]);
+        }, [keyword]);
+
+        useEffect(() => {
+            getTableData()
+        }, [type]);
+
+
+        return (
+            <div >
+                <div className="filter" style={{ marginBottom: 8, display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
+                    <ProFormSelect
+                        noStyle
+                        style={{ marginRight: 8 }}
+                        options={[
+                            { label: '药品', value: 1 },
+                            { label: '材料', value: 2 },
+                            // {label:'项目',value:3}
+                        ]}
+                        fieldProps={{
+                            defaultValue: 1,
+                            onChange(value, option) {
+                                set_type(value);
+                                set_keyword('');
+                                setSelectedKeys([]);
+                                set_selectedRows([]);
+                            },
+                        }}
+                    />
+                    <ProFormText noStyle placeholder={'项目名称'}
+                        fieldProps={{
+                            value: keyword,
+                            suffix: <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" />,
+                            onChange: (e) => {
+                                if (e.target.value.length != 0) {
+                                    set_keyword(e.target.value);
+                                } else {
+                                    set_keyword('');
+                                }
+                            }
+                        }}
+                    />
+                </div>
+
+                <KCIMTable columns={columns}
+                    options={{
+                        density: true,
+                        setting: {
+                            listsHeight: 100,
+                        },
+                    }}
+                    rowKey={rowKey}
+                    scroll={{ y: 400 }}
+                    tableAlertRender={false}
+                    rowSelection={{
+                        // 自定义选择项参考: https://ant.design/components/table-cn/#components-table-demo-row-selection-custom
+                        // 注释该行则默认不显示下拉选项
+                        // selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT],
+                        selectedRowKeys: selectedKeys,
+                        onChange: onSelectChange,
+                    }}
+                    pagination={{ showTitle: false, showSizeChanger: true, simple: true }}
+                    dataSource={showList}
+
+                />
+                <div className='footer'>
+                    <span className='cancel' onClick={() => close()}>取消</span>
+                    <span className='ok' onClick={() => saveHandle()}>{`确认(${selectedKeys.length > 0 && selectedKeys.length})`}</span>
+                </div>
+            </div>
+
+        )
+    });
+
+    const close = () => {
+        onVisibleChange && onVisibleChange(false);
+    }
+
+
+    return (
+        <ModalForm className="TableSelecter" title={title} width={400} submitter={{
+            render: false
+        }} open={open} modalProps={{
+            closable: false,
+        }}>
+            <Table
+                // ref={tableSelecterRef}
+                record={undefined}
+            ></Table>
+        </ModalForm>
+    )
+
+}
+
+
+
+
+export default TableSelecter

+ 341 - 116
src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-24 14:51:15
+ * @LastEditTime: 2024-03-07 16:40:34
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -15,10 +15,11 @@ import { formatMoneyNumber } from '@/utils/format';
 import { createFromIconfontCN } from '@ant-design/icons';
 import FormItem from 'antd/es/form/FormItem';
 
-import { ActionType, ProFormInstance, ProFormText } from '@ant-design/pro-components';
+import { ActionType, DrawerForm, ProFormInstance, ProFormText, ProTable, TableDropdown } from '@ant-design/pro-components';
 import { ModalForm, ProFormDigit, ProFormSelect, ProFormSwitch } from '@ant-design/pro-form'
 import { ProColumns } from '@ant-design/pro-table';
-import { Input, message, Popconfirm,Modal } from 'antd';
+import type { MenuProps } from 'antd';
+import { Input, message, Dropdown, Modal, Popconfirm, Drawer, Breadcrumb } from 'antd';
 import { useEffect, useRef, useState } from 'react';
 
 import 'moment/locale/zh-cn';
@@ -26,18 +27,24 @@ import locale from 'antd/es/date-picker/locale/zh_CN';
 
 
 
-import { addData, delData, editData, getTableDataReq, importDataPost, mapItemAndStandItem } from './service';
+import { addData, delData, editData, getAllNeedMatchItems, getTableDataReq, importDataPost, mapItemAndStandItem } from './service';
 
 import './style.less';
 import KCIMUpload from '@/components/KCIMUpload';
 import { downloadTemplateReq } from '@/utils/tooljs';
 import { getStandItemList } from '../standardProjectMana/service';
+import { getDicDataBySysId } from '@/services/getDic';
+import { KcimCenterSysId } from '@/constant';
+import { Setting } from './components/setting';
+import KCIMDrawerForm from '@/components/KCIMDrawerForm';
+import { MatchPage } from './components/match';
 
 
 const IconFont = createFromIconfontCN({
     scriptUrl: '',
 });
 
+let currentRow: any = undefined;
 
 
 export default function ChargeItemsMana() {
@@ -46,56 +53,152 @@ export default function ChargeItemsMana() {
     const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
     const tableRef = useRef<ActionType>();
     const formRef = useRef<ProFormInstance>();
-    const [stopStat,set_stopStat] = useState(0);
+    const [stopStat, set_stopStat] = useState(0);
+    const [drawerVisible, set_drawerVisible] = useState(false);
+    const [drawerType, set_drawerType] = useState(1);
+    const [currentSelectRow, set_currentSelectRow] = useState(undefined);
+    const [ifBatchMatch, set_ifBatchMatch] = useState(false);
     const columns: ProColumns[] = [
 
         {
             title: '收费项目编码',
             dataIndex: 'code',
+            width: 100
         },
         {
             title: '收费项目名称',
             dataIndex: 'name',
+            width: 260
         },
         {
             title: '国家编码',
             dataIndex: 'nationalCode',
+            width: 100
         },
         {
             title: '项目类别',
             dataIndex: 'type',
+            width: 100
+        },
+        {
+            title: '项目分类',
+            dataIndex: 'itemTypeName',
+            width: 100
         },
         {
             title: '康程分类',
             dataIndex: 'kcCodeName',
+            width: 280
         },
         {
             title: '标准项目编码',
             dataIndex: 'standItemCode',
+            width: 100
         },
         {
             title: '标准项目名称',
             dataIndex: 'standItemName',
+            width: 260
+        },
+        {
+            title: '参与人员',
+            dataIndex: 'empMaps',
+            width: 260,
+            renderText(arr, record, index, action) {
+                if (arr)
+                    return arr.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.empTypeCodeName + '*' + cur.num + '*' + cur.executeTime}`, '')
+            },
+        },
+        {
+            title: '使用设备',
+            dataIndex: 'equipmentMaps',
+            width: 260,
+            renderText(arr, record, index, action) {
+                if (arr)
+                    return arr.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.equipmentCodeName + '*' + cur.num + '*' + cur.executeTime}`, '')
+            },
+        },
+        {
+            title: '使用空间',
+            dataIndex: 'spaceMaps',
+            width: 260,
+            renderText(arr, record, index, action) {
+                if (arr)
+                    return arr.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.spaceCodeName + '*' + cur.num + '*' + cur.executeTime}`, '')
+            },
+        },
+        {
+            title: '计价药材',
+            dataIndex: 'valuation',
+            width: 260,
+            renderText(arr) {
+                if (arr)
+                    return arr.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.code + '*' + cur.name + '*' + cur.num}`, '')
+            },
+        },
+        {
+            title: '不计价药材成本',
+            dataIndex: 'noValuation',
+            width: 260,
+            renderText(arr, record, index, action) {
+                if (arr)
+                    return arr.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.code + '*' + cur.name + '*' + cur.num}`, '')
+            },
         },
         {
             title: '单价',
             dataIndex: 'price',
+            width: 90
         },
         {
             title: '操作',
             key: 'option',
             width: 120,
+            fixed: 'right',
             valueType: 'option',
             render: (_: any, record: any) => {
+                const items: MenuProps['items'] = [
+                    {
+                        key: '1',
+                        label: (
+                            <UpDataActBtn key={'act'} record={record} type='EDIT' />
+                        ),
+                    },
+                    // {
+                    //     key: '2',
+                    //     label: (
+                    //         <a >
+                    //             同步设置
+                    //         </a>
+                    //     ),
+                    // },
+                    {
+                        key: '3',
+                        label: (
+                            <Popconfirm
+                                title="是否确认删除?"
+                                key="del"
+                                onConfirm={() => delTableData(record)}
+                            >
+                                <a>删除</a>
+                            </Popconfirm>
+                        ),
+                    },
+                ];
                 return [
-                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
-                    <Popconfirm
-                        title="是否确认删除?"
-                        key="del"
-                        onConfirm={() => delTableData(record)}
-                    >
-                        <a>删除</a>
-                    </Popconfirm>
+                    // <UpDataActBtn key={'act'} record={record} type='EDIT' />,
+                    // <Popconfirm
+                    //     title="是否确认删除?"
+                    //     key="del"
+                    //     onConfirm={() => delTableData(record)}
+                    // >
+                    //     <a>删除</a>
+                    // </Popconfirm>
+                    <a key='1' onClick={() => { set_currentSelectRow(record); currentRow = record; set_drawerType(2); set_drawerVisible(true) }}>匹配</a>,
+                    <a key='2' onClick={() => { set_drawerVisible(true); currentRow = record; set_currentSelectRow(record) }}>设置</a>,
+                    <Dropdown menu={{ items }} placement="bottomLeft" arrow>
+                        <a><IconFont type="icongengduochuizhi" style={{ color: '#3377FF', width: 16, height: 16 }} /></a>
+                    </Dropdown>
                 ]
             },
         },
@@ -104,7 +207,7 @@ export default function ChargeItemsMana() {
 
 
     const getTableData = async (params: any) => {
-        const resp = await getTableDataReq({...params,type:stopStat});
+        const resp = await getTableDataReq({ ...params, type: stopStat });
         if (resp) {
             return {
                 data: resp.list,
@@ -130,8 +233,8 @@ export default function ChargeItemsMana() {
 
         const result = {
             ...formVal,
-            standItemCode:formVal.standItem?formVal.standItem.value:undefined,
-            standItemName:formVal.standItem?formVal.standItem.label:undefined,
+            standItemCode: formVal.standItem ? formVal.standItem.value : undefined,
+            standItemName: formVal.standItem ? formVal.standItem.label : undefined,
         }
 
         if (type == 'ADD') {
@@ -143,7 +246,7 @@ export default function ChargeItemsMana() {
         }
         if (type == 'EDIT') {
 
-            const resp = await editData({...result});
+            const resp = await editData({ ...result });
             if (resp) {
                 tableRef.current?.reload();
                 message.success('操作成功!');
@@ -162,7 +265,7 @@ export default function ChargeItemsMana() {
                 width={350}
                 formRef={formRef}
                 initialValues={type == 'EDIT' ? {
-                    ...record,standItem:record.standItemCode
+                    ...record, standItem: record.standItemCode
                 } : {}}
                 trigger={
                     type == 'EDIT' ? <a key="edit" >编辑</a> : <span className='add'>新增</span>
@@ -186,13 +289,27 @@ export default function ChargeItemsMana() {
                     placeholder="请输入"
                     rules={[{ required: true, message: '收费项目名称不能为空!' }]}
                 />
+                <ProFormSelect
+                    name="itemType"
+                    label="项目分类:"
+                    placeholder="请输入"
+                    request={async () => {
+                        const resp = await getDicDataBySysId(KcimCenterSysId, 'MED_SERVICE_ITEM_TYPE');
+                        if (resp) {
+                            const { dataVoList = [] } = resp;
+                            return dataVoList.map((a: any) => ({ label: a.name, value: a.code }))
+                        }
+                        return []
+                    }}
+                    rules={[{ required: false, message: '项目分类不能为空!' }]}
+                />
                 <ProFormText
                     name="type"
                     label="收费项目类别:"
                     placeholder="请输入"
-                    // rules={[{ required: true, message: '收费项目类别不能为空!' }]}
+                // rules={[{ required: true, message: '收费项目类别不能为空!' }]}
                 />
-               <ProFormText
+                <ProFormText
                     name="nationalCode"
                     label="国家编码:"
                     placeholder="请输入"
@@ -201,7 +318,10 @@ export default function ChargeItemsMana() {
                     name="standItem"
                     label="标准项目名称:"
                     placeholder="请选择"
-                    fieldProps={{labelInValue:true}}
+                    showSearch
+                    fieldProps={{
+                        labelInValue: true,
+                    }}
                     request={async ({ keyWords }) => {
                         const resp = await getStandItemList({ name: keyWords, pageSize: 100, current: 1 });
                         if (resp) {
@@ -210,7 +330,7 @@ export default function ChargeItemsMana() {
                             return []
                         }
                     }}
-               
+
                 />
                 <ProFormDigit
                     name="price"
@@ -218,7 +338,7 @@ export default function ChargeItemsMana() {
                     placeholder="请输入"
                     rules={[{ required: true, message: '单价不能为空!' }]}
                 />
-    
+
             </ModalForm>
         )
     }
@@ -235,114 +355,219 @@ export default function ChargeItemsMana() {
     const downloadTemplate = async () => {
         await downloadTemplateReq('/costAccount/setting/exportItem');
     };
-    
+
+    const closeDrawer = () => {
+        set_drawerVisible(false);
+    }
+
+    const switchBatchHandle = (bool:boolean)=>{
+        set_ifBatchMatch(bool);
+    }
+
     const importData = () => {
         return (
-          <ModalForm
-            width={360}
-            title={`导入数据`}
-            trigger={
-              <a className="import" key="3">
-                导入
-              </a>
-            }
-            submitter={{
-              render: (props, defaultDoms) => {
-                const needBtn = defaultDoms.filter((b) => {
-                  return b.key != 'rest';
-                });
-                return [
-                  ...needBtn,
-                ];
-              },
-            }}
-            onFinish={async (values) => {
-              const {
-                importFile: { fileList },
-              } = values;
-    
-              let formData = new FormData();
-              formData.append('file', fileList[0].originFileObj);
-              const resp = await importDataPost(formData);
-    
-              if (resp) {
-                tableRef.current?.reload();
-                return true;
-              }
-            }}
-          >
-            <FormItem name={'importFile'}>
-              <KCIMUpload downloadTemplateFile={() => downloadTemplate()} />
-            </FormItem>
-          </ModalForm>
+            <ModalForm
+                width={360}
+                title={`导入数据`}
+                trigger={
+                    <a className="import" key="3">
+                        导入
+                    </a>
+                }
+                submitter={{
+                    render: (props, defaultDoms) => {
+                        const needBtn = defaultDoms.filter((b) => {
+                            return b.key != 'rest';
+                        });
+                        return [
+                            ...needBtn,
+                        ];
+                    },
+                }}
+                onFinish={async (values) => {
+                    const {
+                        importFile: { fileList },
+                    } = values;
+
+                    let formData = new FormData();
+                    formData.append('file', fileList[0].originFileObj);
+                    const resp = await importDataPost(formData);
+
+                    if (resp) {
+                        tableRef.current?.reload();
+                        return true;
+                    }
+                }}
+            >
+                <FormItem name={'importFile'}>
+                    <KCIMUpload downloadTemplateFile={() => downloadTemplate()} />
+                </FormItem>
+            </ModalForm>
         );
     };
 
-    const mapBtnHandle = async () => {
+    
 
-        Modal.confirm({
-            title: '注意',
-            content: '对照操作只会自动匹配未对照的项目,是否继续操作?',
-            okText:'确定',
-            cancelText:'取消',
-            onOk: async (...args) => {
-              const resp  = await mapItemAndStandItem();
-              if (resp) {
-                message.success('操作成功!');
-                tableRef.current?.reload();
-              } 
-            },
-          })
+    const batchMatchInit = async () => {
+        const resp = await getAllNeedMatchItems();
+        if (resp) {
+            let needItem = undefined;
+            for (const item of resp) {
+                if (!item.match) {
+                  set_currentSelectRow(item);
+                  needItem = item;
+                  break; // 满足条件后退出循环
+                }
+            }
+
+            if(!needItem){
+                set_currentSelectRow(resp[0]);
+            }
+        }
     }
 
 
+
+    // const expandedRowRender = (record: any) => {
+
+    //     const { empMaps = [], equipmentMaps = [], spaceMaps = [], valuation = [], noValuation = [] } = record;
+    //     return (
+    //         <div className='tableRowInnerContent' style={{ display: 'flex', width: '100%', flexDirection: 'row', backgroundColor: '#F7F9FC', paddingLeft: 45, }}>
+    //             <div className='cell' style={{ width: '10%' }}>
+    //                 <div className='name' style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center', height: 40, fontWeight: 500, borderBottom: '1px solid #DAE2F2', borderTop: '1px solid #DAE2F2', fontSize: 14 }}>参与人员</div>
+    //                 <div className='value' style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center', height: 40, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
+    //                     {empMaps.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.empTypeCodeName}`, '')}
+    //                 </div>
+    //             </div>
+    //             <div className='cell' style={{ width: '10%' }}>
+    //                 <div className='name' style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center', height: 40, fontWeight: 500, borderBottom: '1px solid #DAE2F2', borderTop: '1px solid #DAE2F2', fontSize: 14 }}>使用设备</div>
+    //                 <div className='value' style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center', height: 40, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
+    //                     {equipmentMaps.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.equipmentCodeName}`, '')}
+    //                 </div>
+    //             </div>
+    //             <div className='cell' style={{ width: '10%' }}>
+    //                 <div className='name' style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center', height: 40, fontWeight: 500, borderBottom: '1px solid #DAE2F2', borderTop: '1px solid #DAE2F2', fontSize: 14 }}>使用空间</div>
+    //                 <div className='value' style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center', height: 40, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
+    //                     {spaceMaps.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.spaceCodeName}`, '')}
+    //                 </div>
+    //             </div>
+    //             <div className='cell' style={{ width: '20%' }}>
+    //                 <div className='name' style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center', height: 40, fontWeight: 500, borderBottom: '1px solid #DAE2F2', borderTop: '1px solid #DAE2F2', fontSize: 14 }}>计价药材</div>
+    //                 <div className='value' style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center', height: 40, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
+    //                     {valuation.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.name}`, '')}
+    //                 </div>
+    //             </div>
+    //             <div className='cell' style={{ width: '24%', }}>
+    //                 <div className='name' style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center', height: 40, fontWeight: 500, paddingLeft: '5%', borderBottom: '1px solid #DAE2F2', borderTop: '1px solid #DAE2F2', fontSize: 14 }}>不计价药材</div>
+    //                 <div className='value' style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center', height: 40, overflow: 'hidden', paddingLeft: '5%', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
+    //                     {noValuation.reduce((prev: any, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.name}`, '')}
+    //                 </div>
+    //             </div>
+    //         </div>
+    //     );
+    // };
+
+    useEffect(() => {
+        if (ifBatchMatch) {
+            batchMatchInit();
+        }
+    }, [ifBatchMatch]);
+
+
     useEffect(() => {
 
     }, [])
 
     return (
-        <KCIMPagecontainer className='ChargeItemsMana' title={false}>
-            <div className='toolBar'>
-                <div className='filter'>
-                    <div className='filterItem'>
-                        <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
-                        <Input placeholder={'项目名称/国家编码'} allowClear
-                            suffix={
-                                <IconFont type="iconsousuo"  style={{color:'#99A6BF'}} onClick={() => tableDataSearchHandle('name')} />
-                            }
-                            onChange={(e) => {
-                                set_tableDataSearchKeywords(e.target.value);
-                                if (e.target.value.length == 0) {
-                                    set_tableDataFilterParams({
-                                        ...tableDataFilterParams,
-                                        name: ''
-                                    });
-                                }
-                            }}
-                            onPressEnter={(e) => {
-                                set_tableDataFilterParams({
-                                    ...tableDataFilterParams,
-                                    name: (e.target as HTMLInputElement).value
-                                });
-                            }}
-
-                        />
-                    </div>
-                </div>
-                <div className='btnGroup'>
-                    <span style={{paddingRight:16}}><ProFormSwitch noStyle fieldProps={{size:'small',onChange:(bool)=>{
-                         set_stopStat(bool ? 1 : 0);
-                         tableRef.current?.reload();
-                    }}} />只显示未对照项目</span>
-                    <span className='mapBtn' onClick={()=>mapBtnHandle()}>对照</span>
-                    {importData()}
-                    <UpDataActBtn record type='ADD' />
-                </div>
+        <>
+            <div style={{ padding: '0 16px', paddingTop: 16 }}>
+                <Breadcrumb>
+                    <Breadcrumb.Item>收费项目设置</Breadcrumb.Item>
+                    <Breadcrumb.Item>
+                        {ifBatchMatch ? <a onClick={()=>set_ifBatchMatch(false)}>收费项目管理</a> : '收费项目管理'}
+                    </Breadcrumb.Item>
+                    {ifBatchMatch && <Breadcrumb.Item>项目匹配</Breadcrumb.Item>}
+                </Breadcrumb>
             </div>
 
-            <div style={{ marginTop: 16 }}>
-                <KCIMTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
-            </div>
-        </KCIMPagecontainer>
+            <KCIMPagecontainer className='ChargeItemsMana' title={false} style={{padding:ifBatchMatch?0:16}}>
+
+                <Drawer
+                    width={drawerType == 1 ? 800 : 1200}
+                    title={false}
+                    open={drawerVisible}
+                    afterOpenChange={bool => { set_drawerVisible(bool); if (!bool) set_currentSelectRow(undefined); tableRef.current?.reload(); }}
+                    headerStyle={{ height: 0, padding: 0, overflow: 'hidden' }}
+                    bodyStyle={{ padding: 0 }}
+                    destroyOnClose={true}
+                >
+                    {drawerType == 1 && <Setting record={currentSelectRow} onVisibleChange={(bool: boolean) => set_drawerVisible(bool)} />}
+                    {drawerType == 2 && <MatchPage closeDrawer={closeDrawer} record={currentSelectRow} onVisibleChange={(bool: boolean) => set_drawerVisible(bool)} />}
+                </Drawer>
+
+
+                {
+                    !ifBatchMatch ? (
+                        <>
+                            <div className='toolBar'>
+                                <div className='filter'>
+                                    <div className='filterItem'>
+                                        <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
+                                        <Input placeholder={'项目名称/国家编码'} allowClear
+                                            suffix={
+                                                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('name')} />
+                                            }
+                                            onChange={(e) => {
+                                                set_tableDataSearchKeywords(e.target.value);
+                                                if (e.target.value.length == 0) {
+                                                    set_tableDataFilterParams({
+                                                        ...tableDataFilterParams,
+                                                        name: ''
+                                                    });
+                                                }
+                                            }}
+                                            onPressEnter={(e) => {
+                                                set_tableDataFilterParams({
+                                                    ...tableDataFilterParams,
+                                                    name: (e.target as HTMLInputElement).value
+                                                });
+                                            }}
+
+                                        />
+                                    </div>
+                                </div>
+                                <div className='btnGroup'>
+                                    <span style={{ paddingRight: 16 }}><ProFormSwitch noStyle fieldProps={{
+                                        size: 'small', onChange: (bool) => {
+                                            set_stopStat(bool ? 1 : 0);
+                                            tableRef.current?.reload();
+                                        }
+                                    }} />只显示未对照项目</span>
+                                    {/* <span className='mapBtn' onClick={() => mapBtnHandle()}>对照</span> */}
+                                    <span className='mapBtn' onClick={() => set_ifBatchMatch(true)}>批量匹配</span>
+                                    {importData()}
+                                    <UpDataActBtn record type='ADD' />
+                                </div>
+                            </div>
+
+                            <div style={{ marginTop: 16 }}>
+                                <KCIMTable
+                                    scroll={{ x: 1500 }}
+                                    columns={columns as ProColumns[]}
+                                    actionRef={tableRef} rowKey='id' params={tableDataFilterParams}
+                                    request={(params) => getTableData(params)}
+                                    
+                                // expandable={{ expandedRowRender }}
+                                />
+                            </div>
+                        </>
+                    ):(
+                        currentSelectRow&&<MatchPage closeDrawer={closeDrawer} switchBatchHandle={switchBatchHandle} single={false} record={currentSelectRow} onVisibleChange={(bool: boolean) => set_drawerVisible(bool)} />
+                    )
+                }
+
+            </KCIMPagecontainer>
+        </>
+
     )
 }

+ 181 - 2
src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/service.ts

@@ -2,13 +2,14 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 16:31:27
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-23 13:46:35
+ * @LastEditTime: 2024-03-21 15:40:08
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
 
 
 
+import { Key } from 'react';
 import { request } from 'umi';
 
 //获取table列表数据
@@ -95,7 +96,7 @@ export const delData = (id:string) => {
 
 //对照
 export const mapItemAndStandItem = () => {
-  return request('/costAccount/setting/matchItemAndStandItem', {
+  return request('/costAccount/setting/matchItemAndStandItem?progressKey=ITEM_BATCH_MATCH', {
     method: 'POST',
   });
 };
@@ -103,6 +104,184 @@ export const mapItemAndStandItem = () => {
 
 
 
+//获取对照列表
+export const getEmpsByItemCode = (itemCode:string) => {
+  return request('/costAccount/setting/getItemEmpMap', {
+    method: 'GET',
+    params:{itemCode}
+  });
+};
+export const getEquipByItemCode = (itemCode:string) => {
+  return request('/costAccount/setting/getItemEquipmentMap', {
+    method: 'GET',
+    params:{itemCode}
+  });
+};
+export const getSpaceByItemCode = (itemCode:string) => {
+  return request('/costAccount/setting/getItemSpaceMap', {
+    method: 'GET',
+    params:{itemCode}
+  });
+};
+export const getNoValuationDrugByItemCode = (itemCode:string) => {
+  return request('/costAccount/setting/getItemNoValuationDrugMaterialMap', {
+    method: 'GET',
+    params:{itemCode}
+  });
+};
+export const getValuationDrugByItemCode = (itemCode:string) => {
+  return request('/costAccount/setting/getItemValuationDrugMaterialMap', {
+    method: 'GET',
+    params:{itemCode}
+  });
+};
+
+
+
+//添加抽屉表格数据
+
+export const addDrawerTableData = (data:any,tabKey:number) => {
+
+  let url:string = '';
+  if(tabKey == 1){url = '/costAccount/setting/addItemEmpMap';}
+  if(tabKey == 2){url = '/costAccount/setting/addItemEquipmentMap';}
+  if(tabKey == 3){url = '/costAccount/setting/addItemSpaceMap';}
+
+  return request(url, {
+    method: 'POST',
+    data
+  });
+};
+
+//编辑抽屉表格数据
+
+export const editDrawerTableData = (data:any,tabKey:number) => {
+
+  let url:string = '';
+  if(tabKey == 1){url = '/costAccount/setting/editItemEmpMap';}
+  if(tabKey == 2){url = '/costAccount/setting/editItemEquipmentMap';}
+  if(tabKey == 3){url = '/costAccount/setting/editItemSpaceMap';}
+  if(tabKey == 4){url = '/costAccount/setting/editItemValuationDrugMaterialMap';}
+  if(tabKey == 5){url = '/costAccount/setting/editItemNoValuationDrugMaterialMap';}
+
+  return request(url, {
+    method: 'POST',
+    data
+  });
+};
+
+//删除抽屉表格数据
+
+export const delDrawerTableData = (id:Key,tabKey:number) => {
+
+  let url:string = '';
+  if(tabKey == 1){url = '/costAccount/setting/deleteItemEmpMap';}
+  if(tabKey == 2){url = '/costAccount/setting/deleteItemEquipmentMap';}
+  if(tabKey == 3){url = '/costAccount/setting/deleteItemSpaceMap';}
+  if(tabKey == 4){url = '/costAccount/setting/deleteItemValuationDrugMaterialMap';}
+  if(tabKey == 5){url = '/costAccount/setting/deleteItemNoValuationDrugMaterialMap';}
+
+  return request(url, {
+    method: 'POST',
+    params:{id}
+  });
+};
+
+//获取可添加药材列表
+export const getAddableTableData = (type:number,itemCode:string,name?:string) => {
+  return request('/costAccount/setting/getItemData', {
+    method: 'GET',
+    params:{type,itemCode,name}
+  });
+};
+
+
+//添加不计价/计价药材对照
+export const addDrugTableData = (data:any,type:number) => {
+  let url = undefined;
+  if(type == 4){
+    url = '/costAccount/setting/addItemValuationDrugMaterialMap'
+  }
+  if(type == 5){
+    url = '/costAccount/setting/addItemNoValuationDrugMaterialMap'
+  }
+  return request(url as string, {
+    method: 'POST',
+    data:data
+  });
+};
+
+// //编辑不计价/计价药材对照
+// export const editDrugTableData = (data:any,type:number) => {
+//   let url = undefined;
+//   if(type == 4){
+//     url = '/costAccount/setting/editItemValuationDrugMaterialMap'
+//   }
+//   if(type == 5){
+//     url = '/costAccount/setting/editItemNoValuationDrugMaterialMap'
+//   }
+//   return request(url as string, {
+//     method: 'POST',
+//     data:data
+//   });
+// };
+
+
+
+//批量删除不计价/计价药材对照
+export const batchDelDrugTableData = (data:number[],type:number) => {
+  let url = undefined;
+  if(type == 4){
+    url = '/costAccount/setting/batchDeleteItemValuationDrugMaterialMap'
+  }
+  if(type == 5){
+    url = '/costAccount/setting/batchDeleteItemNoValuationDrugMaterialMap'
+  }
+  return request(url as string, {
+    method: 'POST',
+    data:data
+  });
+};
+
+//获取单个收费项目信息
+export const getSingleItem = (itemCode:string) => {
+  return request('/costAccount/setting/getSingleItem', {
+    method: 'GET',
+    params:{itemCode}
+  });
+};
+
+//获取所有需要匹配的项
+export const getAllNeedMatchItems = () => {
+  return request('/costAccount/setting/getSingleItemList', {
+    method: 'GET',
+  });
+};
+
+//获取标准项目及推荐项目
+export const getReferralMatch = (itemCode:string) => {
+  return request('/costAccount/setting/getReferralMatch', {
+    method: 'GET',
+    params:{itemCode}
+  });
+};
+
+
+//获取对照计数数据
+export const getMatchCount = () => {
+  return request('/costAccount/setting/getMatchCount', {
+    method: 'GET',
+  });
+};
+
+//匹配
+export const matchRequest = (itemCode:string,standItemCode:string,type:number) => {
+  return request('/costAccount/setting/matchItem', {
+    method: 'POST',
+    params:{itemCode,standItemCode,type}
+  });
+};
+
 
 
 

+ 125 - 2
src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/style.less

@@ -1,3 +1,123 @@
+.TableSelecter {
+
+  .pfm-ant-modal-footer {
+    display: none !important;
+  }
+
+  .footer {
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-end;
+    margin-top: 15px;
+
+    span {
+      display: inline-block;
+      width: 56px;
+      height: 24px;
+      font-size: 14px;
+      line-height: 23px;
+      text-align: center;
+      border-radius: 4px;
+      cursor: pointer;
+
+      &.ok {
+        color: #FFFFFF;
+        background: #3377FF;
+        margin-left: 8px;
+      }
+
+      &.cancel {
+        border: 1px solid #DAE2F2;
+      }
+    }
+
+  }
+}
+
+.settingDrawer {
+  position: relative;
+  height:calc(100% - 16px);
+  
+
+  .header {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 8px;
+    padding: 0 16px;
+    padding-top: 16px;
+
+    .title {
+      font-size: 16px;
+      font-weight: 500;
+      color: #17181A;
+    }
+
+    .btnGroup {
+      a {
+        display: inline-block;
+        width: 56px;
+        text-align: center;
+        line-height: 22px;
+        height: 24px;
+        border-radius: 4px;
+
+        &.back {
+          font-weight: 400;
+          color: #17181A;
+          background: #FAFCFF;
+          margin-right: 8px;
+          border: 1px solid #DAE2F2;
+        }
+
+        &.add {
+          font-weight: 400;
+          color: #FFFFFF;
+          background: #3377FF;
+        }
+      }
+    }
+  }
+
+  .footer {
+    display: flex;
+    width: 100%;
+    border-top: 1px solid #dae2f2;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    position: absolute;
+    bottom: -16px;
+    height: 40px;
+    padding: 0 16px;
+
+    .cancel {
+      display: inline-block;
+      width: 56px;
+      text-align: center;
+      line-height: 22px;
+      height: 24px;
+      border-radius: 4px;
+      margin-right: 8px;
+      border: 1px solid #DAE2F2;
+      color: #17181A;
+      background: #FAFCFF;
+    }
+
+    .confirm {
+      display: inline-block;
+      width: 100px;
+      text-align: center;
+      line-height: 22px;
+      height: 24px;
+      border-radius: 4px;
+      color: #FFFFFF;
+      background: #3377FF;
+    }
+  }
+}
+
 .ChargeItemsMana {
   padding: 16px;
   background: #FFFFFF;
@@ -25,7 +145,9 @@
     }
 
     .btnGroup {
-      .import,.mapBtn {
+
+      .import,
+      .mapBtn {
         cursor: pointer;
         display: inline-block;
         font-size: 14px;
@@ -38,6 +160,7 @@
         border-radius: 4px;
         border: 1px solid #DAE2F2;
       }
+
       .add {
         cursor: pointer;
         display: inline-block;
@@ -52,4 +175,4 @@
     }
 
   }
-}
+}

+ 176 - 0
src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/editTableModal.tsx

@@ -0,0 +1,176 @@
+import React, { Key, useEffect, useState } from "react";
+import { Input, Select } from 'antd'
+import { KCIMTable } from "@/components/KCIMTable";
+import { createFromIconfontCN } from "@ant-design/icons";
+
+
+import { EditableProTable, ModalForm, ProColumns, ProFormSelect, ProFormText } from "@ant-design/pro-components";
+
+import { set } from "lodash";
+import { getHasSetParamsList, getParamsSelectableList } from "./service";
+import { RecordKey } from "@ant-design/pro-utils/es/useEditableArray";
+import { getProjectShareParamsSetTableData } from "../projectShareParamsSet/service";
+
+
+// import './style.less';
+
+
+interface TableSelecterProps {
+    record: any
+}
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+const EditTableModal = ({ record, open, title, onVisibleChange, rowKey = 'id', onFinish }: {
+    record: any, open: boolean, title: string, onVisibleChange: (bool: boolean) => void,
+    rowKey?: string, onFinish?: (selectedRows: any[]) => void
+}) => {
+
+
+    const Table = React.forwardRef(({ }: TableSelecterProps, ref) => {
+
+        const [datasource, set_datasource] = useState<any[]>([]);
+        const [currentSelectedRow,set_currentSelectedRow] = useState<any>(undefined);
+
+        const columns: ProColumns[] = [
+            {
+                title: '项目名称',
+                dataIndex: 'shareParamName',
+                ellipsis:true,
+                valueType:'select',
+                request:async ()=>{
+                     const resp = await getProjectShareParamsSetTableData();
+                     if(resp){
+                           return resp.map((a:any)=>({label: a.shareParamName,value: a.shareParamCode}))
+                     }
+                     return []
+                },
+                fieldProps:{
+                    onSelect:(a: any,b: any,c:any)=>{
+                        set_currentSelectedRow(b);
+                    }
+                }
+            },
+            {
+                title: '占比',
+                dataIndex: 'percent',
+                ellipsis:true,
+                valueType:'digit'
+            }, 
+            {
+                title: '操作',
+                valueType: 'option',
+                render: (text, record, _, action) => [
+                  <a
+                    key="editable"
+                    onClick={() => {
+                      action?.startEditable?.(record.id);
+                    }}
+                  >
+                    编辑
+                  </a>,
+                  <a
+                    key="delete"
+                    onClick={() => {
+                        set_datasource(datasource.filter((item) => item.id !== record.id));
+                    }}
+                  >
+                    删除
+                  </a>,
+                ],
+              },
+        ];
+
+
+
+        const saveHandle = async () => {
+            onFinish && onFinish(datasource);
+        
+        }
+
+        useEffect(() => {
+              const {shareParamCostDetails = []} = record;
+              set_datasource([...(shareParamCostDetails?shareParamCostDetails:[])]);
+        }, [])
+
+
+        return (
+            <div >
+                <EditableProTable columns={columns}
+                    className='EditableProTable'
+                    options={false}
+                    rowKey={rowKey}
+                    scroll={{ y: 400 }}
+                    tableAlertRender={false}
+                    recordCreatorProps={
+                       {
+                        record: () => ({ id: (Math.random() * 1000000).toFixed(0) }),
+                       }
+                    }
+                    editable={{
+                        onSave: async (rowKey, data, row) => {
+                                           
+                            // console.log({rowKey,data,row,currentSelectedRow});
+                            const {index} = data;
+                            
+                            if(index > datasource.length - 1){
+                                //新增
+                                const {value,label} = currentSelectedRow;
+                                set_datasource([...datasource,{
+                                    shareParamName:label,
+                                    shareParamCode:value,
+                                    percent:data.percent,
+                                    id:data.id
+                                }]);
+                            }else {
+                                //编辑
+                                const newData = [...datasource];
+                                newData[index] = {
+                                    shareParamName:currentSelectedRow?currentSelectedRow.label:data.shareParamName,
+                                    shareParamCode:currentSelectedRow?currentSelectedRow.value:data.shareParamCode,
+                                    percent:data.percent,
+                                    id:currentSelectedRow?currentSelectedRow.id:data.id
+                                };
+                                set_datasource([...newData]);
+                            }
+                            
+                            set_currentSelectedRow(undefined);
+                        },
+                    }}
+                    value={datasource}
+                
+                />
+                <div className='footer'>
+                    <span className='cancel' onClick={() => close()}>取消</span>
+                    <span className='ok' onClick={() => saveHandle()}>{`确认`}</span>
+                </div>
+            </div>
+
+        )
+    });
+
+    const close = () => {
+        onVisibleChange && onVisibleChange(false);
+    }
+
+
+    return (
+        <ModalForm className="TableSelecter" title={title} width={550} submitter={{
+            render: false
+        }} open={open} modalProps={{
+            closable: false,
+        }}>
+            <Table
+                // ref={tableSelecterRef}
+                record={undefined}
+            ></Table>
+        </ModalForm>
+    )
+
+}
+
+
+export default EditTableModal

+ 375 - 0
src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/index.tsx

@@ -0,0 +1,375 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 11:30:33
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-02-23 15:44:45
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import KCIMPagecontainer from '@/components/KCIMPageContainer';
+import { KCIMTable } from '@/components/KCIMTable';
+
+import { createFromIconfontCN } from '@ant-design/icons';
+
+
+import { ActionType, ProFormDependency, ProFormInstance, ProFormText, ProFormSelect, ProFormTextArea, ProFormTreeSelect } from '@ant-design/pro-components';
+import { ModalForm, ProFormCascader } from '@ant-design/pro-form'
+import { ProColumns } from '@ant-design/pro-table';
+import { Input, message, Popconfirm, Tag, Tabs } from 'antd';
+import { Key, useEffect, useRef, useState } from 'react';
+
+import 'moment/locale/zh-cn';
+import locale from 'antd/es/date-picker/locale/zh_CN';
+
+
+
+import { addData, copyParamsList, delData, editData, getProjectCostShareTableData, getResponsibilityCenterSelecterList, saveParamsList } from './service';
+
+import './style.less';
+
+import { getChilds } from '@/utils/tooljs';
+import EditTableModal from './editTableModal';
+import TableSelecter from './tableSelector';
+import { getDicDataBySysId } from '@/services/getDic';
+import { getReportProjectSettingList } from '@/pages/baseSetting/otherItemSet/reportItemSet/service';
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+
+export default function AllocationParamsMap() {
+
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>(undefined);
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
+    const tableRef = useRef<ActionType>();
+    const formRef = useRef<ProFormInstance>();
+    const [currentRow, setCurrentRow] = useState<any | undefined>(undefined);
+  
+    const [editTableVisible, set_editTableVisible] = useState(false);
+    const [tableSelecterVisible, set_tableSelecterVisible] = useState(false);
+
+
+    const columns: ProColumns[] = [
+
+        {
+            title: '成本列代码',
+            ellipsis: true,
+            width:100,
+            dataIndex: 'columnCode',
+        },
+        {
+            title: '成本列名称',
+            ellipsis: true,
+            width:150,
+            dataIndex: 'columnName',
+        },
+        {
+            title: '成本列类型',
+            ellipsis: true,
+            width:100,
+            dataIndex: 'columnTypeName',
+        },
+        {
+            title: '损益表项目',
+            ellipsis: true,
+            dataIndex: 'profitPathName',
+        },
+        {
+            title: '分摊参数',
+            ellipsis: true,
+            width: 200,
+            dataIndex: 'shareParamCostDetails',
+            renderText(arr, record) {
+                if (arr) {
+                    return arr.reduce((prev: string, cur: any) => `${prev.length > 0 ? prev + '|' : prev}${cur.shareParamName}`, '')
+                }
+            },
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 160,
+            fixed: 'right',
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                return [
+                    <a key='share' onClick={() => { set_editTableVisible(true); setCurrentRow(record) }}>分摊参数</a>,
+                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
+                    <Popconfirm
+                        title="是否确认删除?"
+                        key="del"
+                        onConfirm={() => delTableData(record)}
+                    >
+                        <a>删除</a>
+                    </Popconfirm>,
+                ]
+            },
+        },
+
+    ]
+
+
+    const getTableData = async (params: any) => {
+        const resp = await getProjectCostShareTableData({ ...params });
+        if (resp) {
+            return {
+                data: resp,
+                success: true,
+            }
+        }
+        return []
+    }
+
+
+    const tableDataSearchHandle = (paramName: string) => {
+
+        set_tableDataFilterParams({
+            ...tableDataFilterParams,
+            [`${paramName}`]: tableDataSearchKeywords
+        })
+
+    }
+
+    const delTableData = async (record: any) => {
+        const resp = await delData(record.id);
+        if (resp) {
+            message.success('操作成功!');
+            tableRef.current?.reload();
+            // message.success('操作成功!');
+        }
+    }
+
+    const updateTable = async (formVal: any, type: 'EDIT' | "ADD") => {
+        
+        try {
+            const result = {
+                columnCode:formVal.columnCode,
+                columnName:formVal.columnName,
+                columnType:formVal.columnType,
+                columnTypeName:formVal.columnTypeName,
+                profitId:formVal.profitId[formVal.profitId.length -1],
+                profitNum:formVal.profitNum,
+                profitName:formVal.profitName,
+                profitPath:formVal.profitPath,
+                profitPathName:formVal.profitPathName
+            };
+
+            if (type == 'ADD') {
+                const resp = await addData(result);
+                if (resp) {
+                    tableRef.current?.reload();
+                    message.success('操作成功!');
+                }
+
+            }
+            if (type == 'EDIT') {
+
+
+                const resp = await editData({ ...result, id: formVal.id });
+                if (resp) {
+                    tableRef.current?.reload();
+                    message.success('操作成功!');
+                }
+
+
+            }
+
+        } catch (error) {
+            console.log({ error });
+        }
+
+        return true;
+
+    }
+
+
+    const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD' }) => {
+    
+        return (
+            <ModalForm
+                title={`${type == 'EDIT' ? '编辑' : '新增'}项目分摊参数对应`}
+                width={350}
+                formRef={formRef}
+                initialValues={type == 'EDIT' ? {
+                    ...record,
+                    profitId:(record.profitPath)?((record.profitPath).split(',')).map((a:string)=>Number(a)):[]
+                } : {}}
+                trigger={
+                    type == 'EDIT' ? <a key="edit" >编辑</a> : <span className='add'>新增</span>
+                }
+                onFinish={(val) => {
+                    return updateTable(type == 'EDIT' ? { ...record, ...val } : { ...val }, type);
+                }}
+                modalProps={{ destroyOnClose: true }}
+                colProps={{ span: 24 }}
+                grid
+            >
+                <ProFormText name='columnTypeName' hidden />
+                <ProFormText name='profitNum' hidden />
+                <ProFormText name='profitName' hidden />
+                <ProFormText name='profitPath' hidden />
+                <ProFormText name='profitPathName' hidden />
+                <ProFormText
+                    name="columnCode"
+                    label="成本列代码:"
+                    placeholder="请输入"
+                    rules={[{ required: true, message: '成本列代码不能为空!' }]}
+                />
+                <ProFormText
+                    name="columnName"
+                    label="成本列名称:"
+                    placeholder="请输入"
+                    rules={[{ required: true, message: '成本列名称不能为空!' }]}
+                />
+                <ProFormSelect
+                    rules={[
+                        {
+                            required:true,
+                            message: '请选择',
+                        },
+                    ]}
+                    request={async () => {
+                        const currentSys = localStorage.getItem('currentSelectedTab');
+                        const {systemId} = JSON.parse(currentSys as string);
+                        const resp = await getDicDataBySysId(systemId,'ITEM_COST_COLUNM_TYPE');
+                        if(resp){
+                             const {dataVoList = []} = resp;
+                             return dataVoList.map((a:any)=>({label:a.name,value:a.code}))
+                        }
+                        return []
+                    }}
+                    fieldProps={{
+                        onChange(value, option:any) {
+                            const {label = ''} = option;
+                            formRef.current?.setFieldValue('columnTypeName',label)
+                        },
+                    }}
+                    name="columnType"
+                    label="成本列类型:"
+                />
+                <ProFormCascader
+                    rules={[
+                        {
+                            required:true,
+                            message: '请选择',
+                        },
+                    ]}
+                    request={async () => {
+                          const resp = await getReportProjectSettingList({reportType:0});
+                          if(resp){
+                              return resp.list
+                          }
+                          return []
+                    }}
+                    fieldProps={{
+                        fieldNames:{
+                            label:'reportName',
+                            value:'id'
+                        },
+                        onChange:(value:any, selectedOptions:any)=>{
+                            //  console.log({value,selectedOptions});
+                             const {num = 0,reportName = ''} = selectedOptions[selectedOptions.length - 1]
+                             formRef.current?.setFieldValue('profitNum',num);
+                             formRef.current?.setFieldValue('profitName',reportName);
+                             formRef.current?.setFieldValue('profitPath',value.join(','));
+                             formRef.current?.setFieldValue('profitPathName',(selectedOptions.map((a:any)=>a.reportName)).join('/'));
+                        }
+                    }}
+                    name="profitId"
+                    label="损益表项目:"
+                />
+
+            </ModalForm>
+        )
+    }
+
+    const shareParamsSetCommit = async (rows: any[]) => {
+        // console.log({currentRow,rows});
+        const result = rows.map((a)=>({
+            shareParamColumnCode:currentRow.columnCode,
+            shareParamCode:a.shareParamCode,
+            shareParamName:a.shareParamName,
+            percent:a.percent
+        }));
+        const resp = await saveParamsList(result);
+        if (resp) {
+            set_editTableVisible(false);
+            message.success('操作成功!');
+            tableRef.current?.reload();
+        }
+    }
+
+    const tableSelecterCommit = async (keys: Key[], rows: any) => {
+        const { id } = currentRow;
+        const resp = await copyParamsList({ id, responsibilityIds: keys });
+        if (resp) {
+            set_tableSelecterVisible(false);
+            message.success('操作成功!');
+            tableRef.current?.reload();
+        }
+    }
+
+    return (
+        <KCIMPagecontainer className='AllocationParamsMap' title={false}>
+            <EditTableModal
+                onVisibleChange={(bool) => {set_editTableVisible(bool);if(!bool)setCurrentRow(undefined)}}
+                title='分摊参数设置'
+                rowKey={'id'}
+                record={currentRow}
+                open={editTableVisible}
+                onFinish={(rows) => shareParamsSetCommit(rows)}
+            />
+            <TableSelecter
+                onVisibleChange={(bool) => set_tableSelecterVisible(bool)}
+                title='选择复制目标'
+                rowKey={'id'}
+                defaultSelectedKeys={[]}
+                record={currentRow}
+                open={tableSelecterVisible}
+                onFinish={(keys, rows) => tableSelecterCommit(keys, rows)}
+            />
+            <div className='toolBar' >
+                <div className='filter'>
+                    <div className='filterItem'>
+                        <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
+                        <Input placeholder={'成本列代码/名称'} allowClear
+                            suffix={
+                                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('filter')} />
+                            }
+                            onChange={(e) => {
+                                set_tableDataSearchKeywords(e.target.value);
+                                if (e.target.value.length == 0) {
+                                    set_tableDataFilterParams({
+                                        ...tableDataFilterParams,
+                                        filter: ''
+                                    });
+                                }
+                            }}
+                            onPressEnter={(e) => {
+
+                                set_tableDataFilterParams({
+                                    ...tableDataFilterParams,
+                                    filter: (e.target as HTMLInputElement).value
+                                });
+                            }}
+
+                        />
+                    </div>
+                </div>
+                <div className='btnGroup'>
+                    <UpDataActBtn record type='ADD' />
+                </div>
+            </div>
+
+            <div>
+                <KCIMTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+            </div>
+        </KCIMPagecontainer>
+    )
+}

+ 134 - 0
src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/service.ts

@@ -0,0 +1,134 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 16:31:27
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-02-23 10:10:41
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import { Key } from 'react';
+import { request } from 'umi';
+
+//获取table列表数据
+export const getProjectCostShareTableData = (params:any) => {
+  return request('/costAccount/setting/itemCostShareList', {
+    method: 'GET',
+    params:{...params},
+  });
+}
+
+
+//获取当前成本已用本的分摊参数列表
+export const getHasSetParamsList = (id:number)=>{
+  return request(`/costAccount/costaccountshare/getShareParamById`, {
+    method: 'GET',
+    params:{
+         id:id
+    },
+  });
+
+}
+
+
+//获取可选复制目标列表
+export async function getCopyableToList(params:any) {
+  return request(`/costAccount/costaccountshare/getResponsibilityCalType`, {
+    method: 'GET',
+    params:{...params},
+  });
+
+}
+
+
+//获取添加分摊参数时可选列表
+export async function getParamsSelectableList(params:any) {
+  return request(`/costAccount/costaccountshare/getAllShareParamStatusById`, {
+    method: 'GET',
+    params:{
+        ...params
+    },
+  });
+
+}
+
+
+
+//新增
+export type AddTableDataType = any
+
+export const addData = (data:AddTableDataType) => {
+  return request('/costAccount/setting/addItemCostShare', {
+    method: 'POST',
+    data:{...data}
+  });
+};
+
+
+
+//编辑表格数据
+
+export type TableRowEditType = {
+  id:number;
+}&AddTableDataType
+
+export const editData = (data:any) => {
+  return request('/costAccount/setting/updateItemCostShare', {
+    method: 'POST',
+    data
+  });
+};
+
+
+//保存成本分摊参数
+export const saveParamsList = (data:any) => {
+  return request(`/costAccount/setting/addItemCostShareDetail`, {
+    method: 'POST',
+    data
+  });
+}
+
+
+
+//删除表格操作
+export const delData = (id:Key) => {
+  return request('/costAccount/setting/deleteItemCostShare', {
+    method: 'POST',
+    params:{id}
+  });
+};
+
+
+
+
+
+//获取责任中心选择列表
+export const  getResponsibilityCenterSelecterList = ()=> {
+  // const {shareParamName,current,pageSize} = params;
+  return request('/costAccount/responsibility/getLevelTwo', {
+    method: 'GET'
+  });
+}
+
+
+//复制数据
+export const copyParamsList = (body:any) => {
+  return request(`/costAccount/costaccountshare/copyAccountShareData`, {
+    method: 'POST',
+    data:body,
+  });
+
+}
+
+
+
+
+
+
+
+
+
+
+

+ 90 - 0
src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/style.less

@@ -0,0 +1,90 @@
+
+.TableSelecter {
+
+  .pfm-ant-modal-footer {
+    display: none !important;
+  }
+  
+  .footer {
+       display: flex;
+       flex-direction:row;
+       justify-content: flex-end;
+       margin-top: 15px;
+       span {
+           display: inline-block;
+           width: 56px;
+           height: 24px;  
+           font-size: 14px;
+           line-height: 23px;
+           text-align: center;
+           border-radius: 4px;
+           cursor: pointer;
+
+           &.ok {
+               color: #FFFFFF;
+               background:#3377FF;
+               margin-left: 8px;
+           }
+           &.cancel {
+               border: 1px solid #DAE2F2;
+           }
+       }
+
+  }
+}
+
+.EditableProTable {
+     .cost-ant-table-tbody {
+         .cost-ant-table-row {
+               .cost-ant-table-cell {
+                      &>div {
+                          display: flex;
+                          justify-content: left !important;
+                      }
+               }
+         }
+     }
+}
+
+.AllocationParamsMap {
+  padding: 16px;
+  background: #FFFFFF;
+  border-radius: 4px;
+
+
+  .toolBar {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 16px;
+
+    .filter {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: center;
+
+      .filterItem {
+        display: flex;
+        flex-direction: row;
+        justify-content: center;
+        align-items: center;
+      }
+    }
+
+    .btnGroup {
+        .add {
+          cursor: pointer;
+          display: inline-block;
+          font-size: 14px;
+          font-weight: 400;
+          color: #FFFFFF;
+          line-height: 24px;
+          padding: 0 14px;
+          background: #3377FF;
+          border-radius: 4px;
+        }
+    }
+  }
+}

+ 186 - 0
src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/tableSelector.tsx

@@ -0,0 +1,186 @@
+import React, { Key, useEffect, useState } from "react";
+import { Input, Select } from 'antd'
+import { KCIMTable } from "@/components/KCIMTable";
+import { createFromIconfontCN } from "@ant-design/icons";
+
+
+import { ModalForm, ProColumns, ProFormSelect, ProFormText } from "@ant-design/pro-components";
+
+import { set } from "lodash";
+import { getCopyableToList } from "./service";
+
+
+// import './style.less';
+
+
+interface TableSelecterProps {
+    record: any
+}
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+
+
+const TableSelecter = ({ record, open, title, onVisibleChange, rowKey = 'id', request, onFinish, defaultSelectedKeys }: {
+    record: any, open: boolean, title: string, onVisibleChange: (bool: boolean) => void, defaultSelectedKeys: Key[],
+    rowKey?: string, request?: (params: any) => Promise<any>, onFinish?: (selectedKeys: React.Key[], selectedRows: any[]) => void
+}) => {
+
+
+    const Table = React.forwardRef(({ }: TableSelecterProps, ref) => {
+
+        const [datasource, set_datasource] = useState<any[]>([]);
+        const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);
+        const [selectedRows, set_selectedRows] = useState<any[]>([]);
+        const [showList, set_showList] = useState<any[]>([]);
+        const [filter, set_filter] = useState<undefined | any>(undefined);
+        const [code, set_code] = useState<undefined | any>(undefined);
+        const [keyword, set_keyword] = useState<string | undefined>(undefined);
+
+
+        const columns: ProColumns[] = [
+            {
+                title: '责任中心Id',
+                dataIndex: 'id',
+            },
+            {
+                title: '责任中心名',
+                dataIndex: 'responsibilityName',
+            },
+        ];
+
+
+        const onSelectChange = (newSelectedRowKeys: React.Key[], selectedRows: any) => {
+            setSelectedKeys([...newSelectedRowKeys]);
+            set_selectedRows([...selectedRows]);
+
+        };
+
+        const saveHandle = async () => {
+            const selectedRowkeys = selectedRows.map((a) => a[`${rowKey}`]);
+            const rows = datasource.filter((a) => selectedRowkeys.includes(a[`${rowKey}`]));
+            onFinish && onFinish(selectedKeys, rows);
+        }
+
+        const getTableData = async () => {
+
+            // const resp = await getAddableTableData(record.costTypeCode);
+
+            const {id:accountShareId} = record;
+            const resp = await getCopyableToList({accountShareId});
+
+            let selectedKeys: string[] = [];
+            let selectedRows: any[] = [];
+            if (resp) {
+                const data = resp.map((a: any) => {
+                    if (defaultSelectedKeys.includes(a[`${rowKey}`])) {
+                        selectedKeys.push(a[`${rowKey}`]);
+                        selectedRows.push(a);
+                        const needItem = record.departList.filter((b: any) => a[`${rowKey}`] == b[`${rowKey}`]);
+
+                        return {
+                            ...a,
+                        }
+                    } else {
+                        return a
+                    }
+                });
+
+                set_showList(data);
+                set_selectedRows([...selectedRows]);
+                setSelectedKeys([...selectedKeys]);
+                set_datasource([...datasource, ...data]);
+            }
+
+
+            return Promise.resolve([]);
+        }
+
+        useEffect(() => {
+            // console.log({code, keyword});
+            const result = datasource.filter((a) => {
+                 return a.responsibilityName?a.responsibilityName.indexOf(keyword) != -1:false
+            });
+
+            set_showList([...result]);
+        }, [keyword])
+
+        useEffect(() => {
+            getTableData()
+        }, [])
+
+
+        return (
+            <div >
+                <div className="filter" style={{ display: 'flex', flexDirection: 'row', marginBottom: 8 }}>
+                    <ProFormText noStyle placeholder={'请输入'}
+                        fieldProps={{
+                            suffix: <IconFont style={{ color: '#99A6BF' }} type="iconsousuo" />,
+                            onChange: (e) => {
+                                if (e.target.value.length != 0) {
+                                    set_keyword(e.target.value);
+                                } else {
+                                    set_keyword('');
+                                }
+                            }
+                        }}
+                    />
+                </div>
+
+                <KCIMTable columns={columns}
+                    options={{
+                        density: true,
+                        setting: {
+                            listsHeight: 100,
+                        },
+                    }}
+                    rowKey={rowKey}
+                    scroll={{ y: 400 }}
+                    tableAlertRender={false}
+                    rowSelection={{
+                        // 自定义选择项参考: https://ant.design/components/table-cn/#components-table-demo-row-selection-custom
+                        // 注释该行则默认不显示下拉选项
+                        // selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT],
+                        selectedRowKeys: selectedKeys,
+                        onChange: onSelectChange,
+                    }}
+                    pagination={{ showTitle: false, showSizeChanger: false,simple:true }}
+                    dataSource={showList}
+
+                />
+                <div className='footer'>
+                    <span className='cancel' onClick={() => close()}>取消</span>
+                    <span className='ok' onClick={() => saveHandle()}>{`确认(${selectedKeys.length > 0 && selectedKeys.length})`}</span>
+                </div>
+            </div>
+
+        )
+    });
+
+    const close = () => {
+        onVisibleChange && onVisibleChange(false);
+    }
+
+
+    return (
+        <ModalForm className="TableSelecter" title={title} width={400} submitter={{
+            render: false
+        }} open={open} modalProps={{
+            closable: false,
+        }}>
+            <Table
+                // ref={tableSelecterRef}
+                record={undefined}
+            ></Table>
+        </ModalForm>
+    )
+
+}
+
+
+
+
+export default TableSelecter

+ 307 - 0
src/pages/costLibraryManagement/projectCostManagement/projectShareParamsSet/index.tsx

@@ -0,0 +1,307 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 11:30:33
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-02-22 17:13:33
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import KCIMPagecontainer from '@/components/KCIMPageContainer';
+import { KCIMTable } from '@/components/KCIMTable';
+import { formatMoneyNumber } from '@/utils/format';
+import { createFromIconfontCN } from '@ant-design/icons';
+import FormItem from 'antd/es/form/FormItem';
+
+import { ActionType, ProFormInstance, ProFormText } from '@ant-design/pro-components';
+import { ModalForm, ProFormCascader, ProFormDependency, ProFormDigit, ProFormSelect, ProFormSwitch } from '@ant-design/pro-form'
+import { ProColumns } from '@ant-design/pro-table';
+import { Input, message, Popconfirm, Modal } from 'antd';
+import { useEffect, useRef, useState } from 'react';
+
+import 'moment/locale/zh-cn';
+import locale from 'antd/es/date-picker/locale/zh_CN';
+
+
+
+import { addData, delData, editData, getSourceItems, getProjectShareParamsSetTableData } from './service';
+
+import './style.less';
+import KCIMUpload from '@/components/KCIMUpload';
+import { downloadTemplateReq } from '@/utils/tooljs';
+import { getStandItemList } from '../standardProjectMana/service';
+import { getDicDataBySysId } from '@/services/getDic';
+import { CostAccountingSysId, KcimCenterSysId } from '@/constant';
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+
+export default function ProjectShareParamsSet() {
+
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
+    const tableRef = useRef<ActionType>();
+    const formRef = useRef<ProFormInstance>();
+    const [stopStat, set_stopStat] = useState(0);
+    const columns: ProColumns[] = [
+
+        {
+            title: '分摊参数代码',
+            dataIndex: 'shareParamCode',
+        },
+        {
+            title: '分摊参数名称',
+            dataIndex: 'shareParamName',
+        },
+        {
+            title: '来源类型',
+            dataIndex: 'sourceTypeName',
+        },
+        {
+            title: '来源项目',
+            dataIndex: 'sourceName',
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 90,
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                return [
+                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
+                    <Popconfirm
+                        title="是否确认删除?"
+                        key="del"
+                        onConfirm={() => delTableData(record)}
+                    >
+                        <a>删除</a>
+                    </Popconfirm>
+                ]
+            },
+        },
+
+    ]
+
+
+    const getTableData = async (params: any) => {
+        const resp = await getProjectShareParamsSetTableData({ ...params});
+        if (resp) {
+            return {
+                data: resp,
+                success: true,
+                total: resp.totalCount,
+                pageSize: resp.pageSize,
+                totalPage: resp.totalPage,
+            }
+        }
+        return []
+    }
+
+    const delTableData = async (record: any) => {
+        const resp = await delData(record.id);
+        if (resp) {
+            message.success('操作成功!');
+            tableRef.current?.reload();
+            // message.success('操作成功!');
+        }
+    }
+
+    const updateTable = async (formVal: any, type: 'EDIT' | "ADD") => {
+
+        const result = {
+            shareParamCode:formVal.shareParamCode,
+            shareParamName:formVal.shareParamName,
+            sourceType:formVal.sourceType,
+            sourceCode:formVal.sourceCode,
+            sourceName:formVal.sourceName
+        }
+
+        if (type == 'ADD') {
+            const resp = await addData(result);
+            if (resp) {
+                tableRef.current?.reload();
+                message.success('操作成功!');
+            }
+        }
+        if (type == 'EDIT') {
+
+            const resp = await editData({ ...result,id:formVal.id });
+            if (resp) {
+                tableRef.current?.reload();
+                message.success('操作成功!');
+            }
+        }
+        return true;
+
+    }
+
+
+    const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD' }) => {
+
+        return (
+            <ModalForm
+                title={`${type == 'EDIT' ? '编辑' : '新增'}项目分摊参数`}
+                width={350}
+                formRef={formRef}
+                initialValues={type == 'EDIT' ? {
+                    ...record,
+                    source:record.sourceCode?record.sourceCode.split('|'):[]
+                } : {}}
+                trigger={
+                    type == 'EDIT' ? <a key="edit" >编辑</a> : <span className='add'>新增</span>
+                }
+                onFinish={(val) => {
+                    return updateTable(type == 'EDIT' ? { ...record, ...val } : { ...val }, type);
+                }}
+                modalProps={{ destroyOnClose: true }}
+                colProps={{ span: 24 }}
+                grid
+            >
+                <ProFormText
+                    name="shareParamCode"
+                    label="分摊参数代码:"
+                    placeholder="请输入"
+                    rules={[{ required: true, message: '分摊参数代码不能为空!' }]}
+                />
+                <ProFormText
+                    name="shareParamName"
+                    label="分摊参数名称:"
+                    placeholder="请输入"
+                    rules={[{ required: true, message: '分摊参数名称不能为空!' }]}
+                />
+                <ProFormSelect
+                    name="sourceType"
+                    label="来源类型:"
+                    placeholder="请输入"
+                    request={async () => {
+                        const resp = await getDicDataBySysId(CostAccountingSysId, 'ITEM_ALLOCATE_PARAM_SOURCE_TYPE');
+                        if (resp) {
+                            const { dataVoList = [] } = resp;
+                            return dataVoList.map((a: any) => ({ label: a.name, value: a.code }))
+                        }
+                        return []
+                    }}
+                    rules={[{ required: true, message: '来源类型不能为空!' }]}
+                />
+                <ProFormText name={'sourceCode'} hidden />
+                <ProFormText name={'sourceName'} hidden />
+                <ProFormDependency name={['sourceType']}>
+                    {
+                        ({ sourceType }) => {
+                            return sourceType?(
+                                <ProFormSelect
+                                    allowClear
+                                    label="来源项目:"
+                                    name="source"
+                                    params={{sourceType}}
+                                    placeholder="请选择"
+                                    rules={[{ required: true, message: '来源项目不能为空!' }]}
+                                    request={async ({sourceType}) => {
+                                        const resp = await getSourceItems(sourceType);
+                                        if (resp) {
+                                         
+                                            const arr = resp.sort((a:any, b:any) => {
+                                                // Convert code values to integers
+                                                const codeA = parseInt(a.code);
+                                                const codeB = parseInt(b.code);
+                                                if (codeA === 0) return -1;
+                                                if (codeB === 0) return 1;
+                                        
+                                                return codeA - codeB;
+                                              });
+
+
+                                            return arr.map((a:any)=>({label:a.name,value:a.code}))
+                                        }
+                                        return [];
+                                    }}
+                                    
+                                    fieldProps={{
+                                        mode:'multiple',
+                                        maxTagCount:4,
+                                        maxTagPlaceholder:'...',
+                                        // labelInValue:true,
+                                        onChange(value: any, option: any) {
+        
+                                             if(value.findIndex((a:any)=>a == '0') != -1){
+                                                formRef.current?.setFieldValue('sourceCode','0');
+                                                formRef.current?.setFieldValue('sourceName','全部');
+                                                formRef.current?.setFieldValue('source',['0']);
+                                             }else{
+                                                formRef.current?.setFieldValue('sourceCode',(option.map((a:any)=>a.value)).join('|'));
+                                                formRef.current?.setFieldValue('sourceName',(option.map((a:any)=>a.label)).join('|'));
+                                             }
+                                             
+                                        },
+                                    }}
+                                />
+                            ):null
+                        }
+                    }
+                </ProFormDependency>
+
+            </ModalForm>
+        )
+    }
+
+    const tableDataSearchHandle = (paramName: string) => {
+
+        set_tableDataFilterParams({
+            ...tableDataFilterParams,
+            [`${paramName}`]: tableDataSearchKeywords
+        })
+
+    }
+
+
+
+    useEffect(() => {
+
+    }, [])
+
+    return (
+        <KCIMPagecontainer className='ProjectShareParamsSet' title={false}>
+            <div className='toolBar'>
+                <div className='filter'>
+                    <div className='filterItem'>
+                        <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
+                        <Input placeholder={'分摊参数代码/名称'} allowClear
+                            suffix={
+                                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('filter')} />
+                            }
+                            onChange={(e) => {
+                                set_tableDataSearchKeywords(e.target.value);
+                                if (e.target.value.length == 0) {
+                                    set_tableDataFilterParams({
+                                        ...tableDataFilterParams,
+                                        filter: ''
+                                    });
+                                }
+                            }}
+                            onPressEnter={(e) => {
+                                set_tableDataFilterParams({
+                                    ...tableDataFilterParams,
+                                    filter: (e.target as HTMLInputElement).value
+                                });
+                            }}
+
+                        />
+                    </div>
+                </div>
+                <div className='btnGroup'>
+                    <UpDataActBtn record type='ADD' />
+                </div>
+            </div>
+
+            <div style={{ marginTop: 16 }}>
+                <KCIMTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+            </div>
+        </KCIMPagecontainer>
+    )
+}

+ 95 - 0
src/pages/costLibraryManagement/projectCostManagement/projectShareParamsSet/service.ts

@@ -0,0 +1,95 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 16:31:27
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-02-22 17:13:21
+ * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+
+
+import { request } from 'umi';
+
+//获取table列表数据
+
+export type TableDataType = {
+  id:number,
+  hospId:number,
+  shareParamCode:string,
+  shareParamName:string,
+  sourceType:string,
+  sourceTypeName:string,
+  sourceCode:string,
+  sourceName:string,
+}
+
+
+export const getProjectShareParamsSetTableData = (params?:any) => {
+  return request('/costAccount/setting/shareParamTypeMapList', {
+    method: 'GET',
+    params:{...params}
+  });
+};
+
+
+//新增
+export type AddTableDataType = {
+  shareParamCode:string,
+  shareParamName:string,
+  sourceType:string,
+  // sourceTypeName:string,
+  sourceCode:string,
+  sourceName:string,
+}
+
+export const addData = (data:AddTableDataType) => {
+  return request('/costAccount/setting/addShareParamTypeMap', {
+    method: 'POST',
+    data
+  });
+};
+
+
+
+
+//编辑表格数据
+
+export type TableRowEditType = {
+  id:number;
+}&AddTableDataType
+
+export const editData = (data:any) => {
+  return request('/costAccount/setting/updateShareParamTypeMap', {
+    method: 'POST',
+    data
+  });
+};
+
+//删除表格操作
+export const delData = (id:string) => {
+  return request('/costAccount/setting/deleteShareParamTypeMap', {
+    method: 'POST',
+    params:{id}
+  });
+};
+
+
+//获取来源项目
+export const getSourceItems = (type:string) => {
+  return request('/costAccount/setting/getShareParamSourceItem', {
+    method: 'GET',
+    params:{type}
+  });
+};
+
+
+
+
+
+
+
+
+
+
+

+ 15 - 7
src/pages/costAccounting/patientCostCalc/style.less → src/pages/costLibraryManagement/projectCostManagement/projectShareParamsSet/style.less

@@ -1,7 +1,4 @@
-
-
-.patientCostCalc {
-  position: relative;
+.ProjectShareParamsSet {
   padding: 16px;
   background: #FFFFFF;
   border-radius: 4px;
@@ -28,12 +25,23 @@
     }
 
     .btnGroup {
-      
-      .calc {
+      .import,.mapBtn {
+        cursor: pointer;
+        display: inline-block;
+        font-size: 14px;
+        font-weight: 400;
+        color: #17181A;
+        line-height: 24px;
+        padding: 0 14px;
+        margin-right: 8px;
+        background: #FAFCFF;
+        border-radius: 4px;
+        border: 1px solid #DAE2F2;
+      }
+      .add {
         cursor: pointer;
         display: inline-block;
         font-size: 14px;
-        font-family: SourceHanSansCN-Normal, SourceHanSansCN;
         font-weight: 400;
         color: #FFFFFF;
         line-height: 24px;

+ 60 - 23
src/pages/costLibraryManagement/projectCostManagement/standardProjectMana/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-24 14:49:59
+ * @LastEditTime: 2024-01-12 13:53:06
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -33,6 +33,8 @@ import KCIMUpload from '@/components/KCIMUpload';
 import { downloadTemplateReq, findAllParents } from '@/utils/tooljs';
 import React from 'react';
 import DrawerActBtn from './drawer';
+import { getDicDataBySysId } from '@/services/getDic';
+import { KcimCenterSysId } from '@/constant';
 
 
 const IconFont = createFromIconfontCN({
@@ -54,26 +56,36 @@ export default function StandardProjectMana() {
         {
             title: '项目编码',
             dataIndex: 'code',
+            width:80,
             ellipsis:true
         },
         {
             title: '项目名称',
             dataIndex: 'name',
-            ellipsis:true
+            ellipsis:true,
+            width:300
         },
         {
             title: '国家编码',
             dataIndex: 'nationalCode',
-            ellipsis:true
+            ellipsis:true,
+            width:120,
+        },
+        {
+            title: '项目分类',
+            dataIndex: 'itemTypeName',
+            ellipsis:true,
+            width:120,
         },
         {
             title: '康程分类',
             dataIndex: 'kcClassLevelName',
-            ellipsis:true
+            ellipsis:true,
+            width:250
         },
         {
             title: '执行时间(min)',
-            width:150,
+            width:130,
             dataIndex: 'executeTime',
         },
         {
@@ -100,10 +112,23 @@ export default function StandardProjectMana() {
                 return arr?arr.reduce((prev:string,cur:any)=>`${prev.length>0?prev+'|':prev}${cur.spaceCodeName}*${cur.num}*${cur.executeTime}`,''):'-'
             },
         },
+        {
+            title: '技术难度',
+            dataIndex: 'technicalDifficulty',
+            ellipsis:true,
+            width:90
+        },
+        {
+            title: '风险程度',
+            dataIndex: 'riskDegree',
+            ellipsis:true,
+            width:90
+        },
         {
             title: '操作',
             key: 'option',
             width: 160,
+            fixed:'right',
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [
@@ -157,7 +182,9 @@ export default function StandardProjectMana() {
             kcClassPath:formVal.kcClassPath,
             kcClassLevelName:formVal.kcClassLevelName,
             executeTime:formVal.executeTime,
-            accounts:formVal.accounts
+            riskDegree:formVal. riskDegree,
+            itemType:formVal.itemType,
+            technicalDifficulty:formVal.technicalDifficulty
         }
 
         if (type == 'ADD') {
@@ -222,6 +249,20 @@ export default function StandardProjectMana() {
                     placeholder="请输入"
                     rules={[{ required: true, message: '国家编码不能为空!' }]}
                 />
+                <ProFormSelect
+                    name="itemType"
+                    label="项目分类:"
+                    placeholder="请输入"
+                    request={async ()=>{
+                           const resp = await getDicDataBySysId(KcimCenterSysId,'MED_SERVICE_ITEM_TYPE');
+                           if(resp){
+                               const {dataVoList = []} = resp;
+                               return dataVoList.map((a:any)=>({label:a.name,value:a.code}))
+                           }
+                           return []
+                    }}
+                    rules={[{ required: true, message: '项目分类不能为空!' }]}
+                />
                 <ProFormText name='kcClassCode' hidden />
                 <ProFormText name='kcClassName'hidden />
                 <ProFormText name='kcClassPath' hidden/>
@@ -252,28 +293,24 @@ export default function StandardProjectMana() {
                          }
                     }}
                 />
-                <ProFormSelect
-                    name="accounts"
-                    label="会计科目:"
-                    placeholder="请选择"
-                    showSearch
-                    request={ async ()=>{
-                           const resp = await getCostAccountingDict();
-                           if(resp){
-                               return resp.map((a:any)=>({label:a.accountingName,value:a.accountingCode}))
-                           }else{
-                               return []
-                           }
-                    }}
-                    // rules={[{ required: true, message: '会计科目不能为空!' }]}
-                />
                 <ProFormDigit
                     name="executeTime"
                     label="执行时间:"
                     placeholder="请输入"
                     rules={[{ required: true, message: '执行时间不能为空!' }]}
                 />
-
+                <ProFormDigit
+                    name="technicalDifficulty"
+                    label="技术难度:"
+                    placeholder="请输入"
+                    rules={[{ required: true, message: '技术难度不能为空!' }]}
+                />
+                <ProFormDigit
+                    name="riskDegree"
+                    label="风险程度:"
+                    placeholder="请输入"
+                    rules={[{ required: true, message: '风险程度不能为空!' }]}
+                />
 
 
             </ModalForm>
@@ -384,7 +421,7 @@ export default function StandardProjectMana() {
             </div>
 
             <div style={{ marginTop: 16 }}>
-                <KCIMTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+                <KCIMTable scroll={{x:2500}} columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
             </div>
         </KCIMPagecontainer>
     )

+ 3 - 2
src/pages/costLibraryManagement/projectCostManagement/standardProjectMana/service.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 16:31:27
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-16 10:12:12
+ * @LastEditTime: 2023-12-20 13:57:54
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/service.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -56,7 +56,8 @@ export type AddTableDataType = {
   kcClassName:string, //康程分类名称
   kcClassPath:string, //康程分类路径
   executeTime:number, //执行时间(m)
-  accounts:string //会计科目代码
+  riskDegree:number,
+  technicalDifficulty:number
 }
 
 export const addData = (data: AddTableDataType) => {

+ 382 - 0
src/pages/costLibraryManagement/reportMana/reportColumnMana/UpDateActBtn.tsx

@@ -0,0 +1,382 @@
+import { KCIMTable } from "@/components/KCIMTable";
+import SQLEditor from "@/components/SQLEditor";
+import { FormInstance, ModalForm, ProColumns, ProFormDependency, ProFormDigit, ProFormInstance, ProFormRadio, ProFormSelect, ProFormText, ProFormTextArea } from "@ant-design/pro-components";
+import { useEffect, useRef, useState } from "react";
+import { addData, editData, getReportListTableData, getReportListType } from "./service";
+import { Form, Switch, Input, message } from 'antd'
+
+
+
+
+import React from 'react';
+import { createFromIconfontCN } from "@ant-design/icons";
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+interface UpDataActBtnProps {
+    record: any;  // 根据实际情况定义类型
+    type: 'EDIT' | 'ADD' | 'EDIT_CHILD';
+    tableRef?: any,
+    onUpdated?: () => void
+}
+
+
+
+const getTableData_form = async (params: any) => {
+    const resp = await getReportListTableData(params);
+    if (resp) {
+        return {
+            data: resp.list,
+            success: true,
+            total: resp.totalCount,
+            pageSize: resp.pageSize,
+            totalPage: resp.totalPage,
+        }
+    }
+    return []
+}
+
+const UpDateActBtn: React.FC<UpDataActBtnProps> = ({ record, type, tableRef, onUpdated }) => {
+    // 组件逻辑
+    const [tableDataSearchKeywords_form, set_tableDataSearchKeywords_form] = useState<string>('');
+    const [tableDataFilterParams_form, set_tableDataFilterParams_form] = useState<any | undefined>();
+    const [initialValues, set_initialValues] = useState<any | undefined>(undefined);
+    const [isModalVisible, setIsModalVisible] = useState(false);
+
+    const formRef = useRef<ProFormInstance>();
+    const columnsTwo: ProColumns[] = [
+        {
+            title: '列代码',
+            width: 80,
+            dataIndex: 'code',
+        },
+        // {
+        //     title: '列名称',
+        //     dataIndex: 'name',
+        //     ellipsis: true
+        // },
+        {
+            title: '列标题',
+            dataIndex: 'headerText',
+            ellipsis: true
+        },
+        {
+            title: '列类型',
+            dataIndex: 'typeName',
+            ellipsis: true,
+            // render:(_:any)=>_ == 1?'指标':'自定义SQL'
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 50,
+            valueType: 'option',
+            render: (_: any, record: any) => {
+
+                return [
+                    <a key='edit_child' onClick={() => {
+                        const _formula = formRef.current?.getFieldValue('formula');
+                        formRef.current?.setFieldValue('formula', `${_formula ? _formula : ''}[${record.code}]`)
+                    }}>选择</a>,
+                ]
+            },
+        },
+
+    ];
+
+    const tableDataSearchHandle_form = (paramName: string) => {
+
+        set_tableDataFilterParams_form({
+            ...tableDataFilterParams_form,
+            [`${paramName}`]: tableDataSearchKeywords_form
+        })
+
+    }
+
+    const updateTable = async (formVal: any, type: 'EDIT' | "ADD" | 'EDIT_CHILD') => {
+
+        let result = {
+            name: formVal.name,
+            headerText: formVal.headerText,
+            type: formVal.type,
+            dataType: formVal.dataType,
+            dataSource: formVal.dataSource,
+            formula: formVal.dataSource == 1 ? formVal.formula : '',
+            sql: formVal.dataSource == 2 ? formVal.sql : '',
+            decimalPlace: (formVal.dataType == 3 || formVal.dataType == 2) ? formVal.decimalPlace : undefined,
+            permil: formVal.dataType == 3 ? (formVal.permil ? '1' : '0') : undefined
+        }
+
+        if (type == 'ADD') {
+            const resp = await addData({ ...result });
+            if (resp) {
+                tableRef.current?.reload();
+                message.success('操作成功!');
+            }
+        }
+        if (type == 'EDIT') {
+            const resp = await editData({ ...result, id: formVal.id });
+            if (resp) {
+                tableRef?.current?.reload();
+                message.success('操作成功!');
+            }
+        }
+        setIsModalVisible(false);
+        onUpdated && onUpdated();
+        return true;
+
+    }
+
+
+    const setFormInit = async (record: any) => {
+        const { columnHeaderText, columnCode } = record;
+        const resp = await getReportListTableData({ columnName: columnHeaderText, pageSize: 500 });
+        if (resp) {
+            const { list } = resp;
+            if (list.length > 1) {
+                const result = list.filter((a) => a.code == columnCode);
+                set_initialValues(result[0]);
+            } else {
+                set_initialValues(list[0]);
+            }
+        }
+
+    }
+
+
+
+    const openModal = async () => {
+        
+        if (record) {
+            const { request } = record;
+            if (request) {
+                await setFormInit(record);
+            } else {
+                set_initialValues(type === 'EDIT' ? { ...record, permil: record.permil === '1' ? true : false } : { decimalPlace: 2, dataSource: 2, permil: false });
+            }
+        }
+
+        setIsModalVisible(true);  // 在状态更新后显示模态框
+    };
+
+
+    return (
+        <>
+            {type === 'EDIT_CHILD' ?
+                <a key="edit_child" onClick={openModal}>子列</a> :
+                type === 'EDIT' ?
+                    <a key="edit" onClick={openModal}>编辑</a> :
+                    <span className='add' onClick={openModal}>新增</span>
+            }
+            {
+              (
+                    <ModalForm
+                        title={`${type == 'EDIT' ? '编辑' : '新增'}报表列`}
+                        width={880}
+                        open={isModalVisible}
+                        formRef={formRef}
+                        initialValues={initialValues}
+                        onOpenChange={bool=>setIsModalVisible(bool)}
+                        onFinish={(val) => {
+                            return updateTable(type == 'EDIT' ? (record.request?{...val,id:initialValues.id, sql: val.sql ? val.sql : ''}:{ ...record, ...val, sql: val.sql ? val.sql : '', }) : { ...val }, type);
+                        }}
+                        colProps={{ span: 24 }}
+
+                        modalProps={{
+                            destroyOnClose: true,
+                            afterClose: () => setIsModalVisible(false),
+                        }}
+                        grid
+                    >
+                        {
+                            (type != 'EDIT_CHILD') && (
+                                <div className='formContent' style={{ display: 'flex', flexDirection: 'row', justifyContent: 'center', alignItems: 'flex-start' }}>
+                                    <div className='left' style={{ marginRight: 16, width: 240 }}>
+                                        <ProFormText
+                                            name="name"
+                                            label="列名称:"
+                                            placeholder="请输入"
+                                            rules={[{ required: true, message: '列名称不能为空!' }]}
+                                        />
+                                        <ProFormText
+                                            name="headerText"
+                                            label="列标题:"
+                                            placeholder="请输入"
+                                            rules={[{ required: true, message: '列标题不能为空!' }]}
+                                        />
+                                        <ProFormSelect
+                                            name="type"
+                                            label="列类型:"
+                                            placeholder="请选择"
+                                            request={async () => {
+                                                const resp = await getReportListType();
+                                                if (resp) {
+                                                    return resp.map((a: any) => ({ label: a.name, value: a.code }));
+                                                }
+                                                return []
+                                            }}
+                                            rules={[{ required: true, message: '列类型不能为空!' }]}
+                                        />
+
+
+                                        <ProFormRadio.Group
+                                            name="dataType"
+                                            label="数据格式:"
+                                            options={[
+                                                {
+                                                    label: '文本',
+                                                    value: 1,
+                                                },
+                                                {
+                                                    label: '百分比',
+                                                    value: 2,
+                                                },
+                                                {
+                                                    label: '数值',
+                                                    value: 3,
+                                                },
+                                            ]}
+                                            rules={[{ required: true, message: '取数格式不能为空!' }]}
+                                        />
+                                        <ProFormDependency name={['dataType']}>
+                                            {
+                                                ({ dataType }) => (dataType == 3 || dataType == 2) && (
+                                                    <div style={{ display: 'flex', flexDirection: 'row' }}>
+                                                        <ProFormDigit
+                                                            name="decimalPlace"
+                                                            label="小数位:"
+                                                            colProps={{ span: 14 }}
+                                                            placeholder="例:([1]+[2])/[3]"
+                                                            rules={[{ required: true, message: '小数位不能为空!' }]}
+                                                        />
+                                                        {
+                                                            dataType == 3 && (
+                                                                <>
+                                                                    <Form.Item name='permil'>
+                                                                        <Switch size='small' style={{ marginTop: 26, marginLeft: 8 }} />
+                                                                    </Form.Item>
+                                                                    <span style={{ marginTop: 23, marginLeft: 4 }}>千分号</span>
+                                                                </>
+                                                            )
+                                                        }
+                                                    </div>
+
+                                                )
+                                            }
+                                        </ProFormDependency>
+
+
+                                        <ProFormSelect
+                                            name="dataSource"
+                                            label="取数类型:"
+                                            placeholder="请选择"
+                                            options={[
+                                                { label: '计算公式', value: 1 },
+                                                { label: '自定义SQL', value: 2 }
+                                            ]}
+                                            rules={[{ required: true, message: '取数类型不能为空!' }]}
+                                        />
+                                    </div>
+                                    <div className='right' style={{ width: 'calc(880px - 288px)' }}>
+                                        <ProFormDependency name={['dataSource']}>
+                                            {
+                                                ({ dataSource }) => dataSource == 1 && (
+                                                    <>
+                                                        <ProFormTextArea
+                                                            name="formula"
+                                                            label={<>计算公式:</>}
+                                                            // colProps={{ span: 16 }}
+                                                            placeholder="例:([1]+[2])/[3]"
+                                                            rules={[{ required: true, message: '计算公式不能为空!' }]}
+                                                        />
+                                                        <div style={{ padding: '0 4px' }}>
+                                                            <div className='toolBar' style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
+                                                                <div>计算公式插入列:</div>
+                                                                <div>
+                                                                    <div className='filter' style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
+                                                                        <div className='filterItem' style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }} >
+                                                                            <ProFormSelect noStyle placeholder={'列类型'}
+                                                                                width={160}
+                                                                                request={async () => {
+                                                                                    const resp = await getReportListType();
+                                                                                    if (resp) {
+                                                                                        return resp.map((a: any) => ({ label: a.name, value: a.code }));
+                                                                                    }
+                                                                                    return []
+                                                                                }}
+                                                                                fieldProps={{
+                                                                                    onChange(value, option) {
+                                                                                        set_tableDataFilterParams_form({
+                                                                                            ...tableDataFilterParams_form,
+                                                                                            columnType: value
+                                                                                        });
+                                                                                    },
+                                                                                }}
+                                                                            />
+                                                                        </div>
+                                                                        <div className='filterItem' style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', marginLeft: 8 }} >
+                                                                            <Input placeholder={'列标题'} allowClear width={160}
+                                                                                suffix={
+                                                                                    <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle_form('columnName')} />
+                                                                                }
+                                                                                onChange={(e) => {
+                                                                                    set_tableDataSearchKeywords_form(e.target.value);
+                                                                                    if (e.target.value.length == 0) {
+                                                                                        set_tableDataFilterParams_form({
+                                                                                            ...tableDataFilterParams_form,
+                                                                                            columnName: ''
+                                                                                        });
+                                                                                    }
+                                                                                }}
+                                                                                onPressEnter={(e) => {
+
+                                                                                    set_tableDataFilterParams_form({
+                                                                                        ...tableDataFilterParams_form,
+                                                                                        columnName: (e.target as HTMLInputElement).value
+                                                                                    });
+                                                                                }}
+
+                                                                            />
+                                                                        </div>
+                                                                    </div>
+                                                                </div>
+                                                            </div>
+
+                                                            <KCIMTable pagination={{ simple: true, pageSize: 7 }} columns={columnsTwo as ProColumns[]} rowKey='id' params={tableDataFilterParams_form} request={(params) => getTableData_form(params)} />
+                                                        </div>
+                                                    </>
+                                                )
+                                            }
+                                        </ProFormDependency>
+                                        <ProFormDependency name={['dataSource']}>
+                                            {
+                                                ({ dataSource }) => dataSource == 2 && (
+                                                    <SQLEditor
+                                                        name="sql"
+                                                        label="SQL:"
+                                                        rules={[{ required: true, message: 'SQL不能为空!' }]}
+                                                        form={formRef}
+                                                        height={'500px'}
+                                                    />
+                                                    // <ProFormTextArea name={'sql'} label='取数来源:' rules={[{ required: true, message: '取数来源不能为空!' }]} />
+                                                )
+                                            }
+                                        </ProFormDependency>
+                                    </div>
+                                </div>
+                            )
+                        }
+
+                    </ModalForm>
+                )
+            }
+        </>
+    );
+};
+
+export default UpDateActBtn;
+
+

+ 19 - 204
src/pages/costLibraryManagement/reportMana/reportColumnMana/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-16 17:40:55
+ * @LastEditTime: 2024-01-11 15:06:53
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -11,10 +11,10 @@
 
 import { createFromIconfontCN } from '@ant-design/icons';
 
-import { ActionType, ProFormInstance, ProFormRadio } from '@ant-design/pro-components';
-import { ModalForm, ProFormDependency, ProFormDigit, ProFormSelect, ProFormSwitch, ProFormText, ProFormTextArea } from '@ant-design/pro-form'
+import { ActionType} from '@ant-design/pro-components';
+import { ProFormSelect} from '@ant-design/pro-form'
 import { ProColumns } from '@ant-design/pro-table';
-import { Input, message, Popconfirm, Modal, Switch, Form } from 'antd';
+import { Input, message, Popconfirm, Modal} from 'antd';
 import { Key, useEffect, useRef, useState } from 'react';
 
 import { addChildReportList, addData, delData, editData, getReportListTableData, getReportListType } from './service';
@@ -26,7 +26,9 @@ import React from 'react';
 import KCIMPagecontainer from '@/components/KCIMPageContainer';
 import { KCIMTable } from '@/components/KCIMTable';
 import TableTransfer from './transform';
-import { getTargetDic } from '@/services/auth';
+import UpDateActBtn from './UpDateActBtn';
+
+
 const IconFont = createFromIconfontCN({
     scriptUrl: '',
 });
@@ -36,19 +38,18 @@ let currentEditRow: any = undefined;
 const reportColumnMana = () => {
 
     const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
+    
     const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
+    
     const tableRef = useRef<ActionType>();
 
-    //const [currentEditRow, set_currentEditRow] = useState<any | undefined>(undefined);
-
-    const [ifShowModal, set_ifShowModal] = useState(false);
-
     const ref = React.createRef<{ save: any; getSelectedKeys: any }>();
 
     const columns: ProColumns[] = [
         {
             title: '列代码',
             dataIndex: 'code',
+            width:80
         },
         {
             title: '列名称',
@@ -108,7 +109,7 @@ const reportColumnMana = () => {
 
                 return [
                     <a key='edit_child' onClick={() => { currentEditRow = record; addReportColumnChild(record) }}>子列</a>,
-                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
+                    <UpDateActBtn key={'act'} record={record} type='EDIT' tableRef={tableRef} />,
                     <Popconfirm
                         title="是否确认删除?"
                         key="del"
@@ -120,7 +121,8 @@ const reportColumnMana = () => {
             },
         },
 
-    ]
+    ];
+    
 
     const transferTableColumn: ProColumns[] = [
         {
@@ -151,6 +153,7 @@ const reportColumnMana = () => {
         }
         return []
     }
+    
 
     const delTableData = async (record: any) => {
         const resp = await delData(record.id);
@@ -161,197 +164,7 @@ const reportColumnMana = () => {
         }
     }
 
-    const updateTable = async (formVal: any, type: 'EDIT' | "ADD" | 'EDIT_CHILD') => {
-
-        let result = {
-            name: formVal.name,
-            headerText: formVal.headerText,
-            type: formVal.type,
-            dataType: formVal.dataType,
-            dataSource: formVal.dataSource,
-            formula: formVal.dataSource == 1 ? formVal.formula : '',
-            sql: formVal.dataSource == 2 ? formVal.sql : '',
-            decimalPlace: (formVal.dataType == 3||formVal.dataType == 2) ? formVal.decimalPlace : undefined,
-            permil: formVal.dataType == 3 ? (formVal.permil ? '1' : '0') : undefined
-        }
-
-        if (type == 'ADD') {
-            const resp = await addData({ ...result });
-            if (resp) {
-                tableRef.current?.reload();
-                message.success('操作成功!');
-            }
-        }
-        if (type == 'EDIT') {
-            const resp = await editData({ ...result, id: formVal.id });
-            if (resp) {
-                tableRef.current?.reload();
-                message.success('操作成功!');
-            }
-        }
-        return true;
-
-    }
-
-    const formRef = useRef<ProFormInstance>();
-
-    const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD' | 'EDIT_CHILD' }) => {
-
-        return (
-            <ModalForm
-                title={`${type == 'EDIT' ? '编辑' : '新增'}报表列`}
-                width={352}
-                formRef={formRef}
-                initialValues={type == 'EDIT' ? { ...record, permil: record.permil == '1' ? true : false } : { decimalPlace: 2 }}
-                trigger={
-                    type == 'EDIT_CHILD' ? <a key="edit_child" >子列</a> : type == 'EDIT' ? <a key="edit" >编辑</a> : <span className='add'>新增</span>
-                }
-                onFinish={(val) => {
-                    return updateTable(type == 'EDIT' ? { ...record, ...val, sql: val.sql ? val.sql : '', } : { ...val }, type);
-                }}
-                colProps={{ span: 24 }}
-                modalProps={{
-                    destroyOnClose: true
-                }}
-                grid
-            >
-                {
-                    (type != 'EDIT_CHILD') && (
-                        <>
-                            <ProFormText
-                                name="name"
-                                label="列名称:"
-                                placeholder="请输入"
-                                rules={[{ required: true, message: '列名称不能为空!' }]}
-                            />
-                            <ProFormText
-                                name="headerText"
-                                label="列标题:"
-                                placeholder="请输入"
-                                rules={[{ required: true, message: '列标题不能为空!' }]}
-                            />
-                            <ProFormSelect
-                                name="type"
-                                label="列类型:"
-                                placeholder="请选择"
-                                request={async () => {
-                                    const resp = await getReportListType();
-                                    if (resp) {
-                                        return resp.map((a: any) => ({ label: a.name, value: a.code }));
-                                    }
-                                    return []
-                                }}
-                                rules={[{ required: true, message: '列类型不能为空!' }]}
-                            />
-
-
-                            <ProFormRadio.Group
-                                name="dataType"
-                                label="数据格式:"
-                                options={[
-                                    {
-                                        label: '文本',
-                                        value: 1,
-                                    },
-                                    {
-                                        label: '百分比',
-                                        value: 2,
-                                    },
-                                    {
-                                        label: '数值',
-                                        value: 3,
-                                    },
-                                ]}
-                                rules={[{ required: true, message: '取数格式不能为空!' }]}
-                            />
-                            <ProFormDependency name={['dataType']}>
-                                {
-                                    ({ dataType }) => (dataType == 3 || dataType == 2) && (
-                                        <>
-                                            <ProFormDigit
-                                                name="decimalPlace"
-                                                label="小数位:"
-                                                colProps={{ span: 18 }}
-                                                placeholder="例:([1]+[2])/[3]"
-                                                rules={[{ required: true, message: '小数位不能为空!' }]}
-                                            />
-                                            {
-                                                dataType == 3 && (
-                                                    <>
-                                                    <Form.Item name='permil'>
-                                                        <Switch size='small' style={{ marginTop: 26, marginLeft: 8 }} />
-                                                    </Form.Item>
-                                                    <span style={{ marginTop: 23, marginLeft: 4 }}>千分号</span>
-                                                    </>
-                                                )
-                                            }
-                                        </>
-
-                                    )
-                                }
-                            </ProFormDependency>
-
-
-                            <ProFormSelect
-                                name="dataSource"
-                                label="取数类型:"
-                                placeholder="请选择"
-                                options={[
-                                    { label: '计算公式', value: 1 },
-                                    { label: '自定义SQL', value: 2 }
-                                ]}
-                                rules={[{ required: true, message: '取数类型不能为空!' }]}
-                            />
-
-                            <ProFormDependency name={['dataSource']}>
-                                {
-                                    ({ dataSource }) => dataSource == 1 && (
-                                        <>
-                                            <ProFormSelect
-                                                label={<><span style={{ color: '#ff4d4f', fontSize: 17, fontWeight: 300, paddingRight: 5 }}>*</span>计算公式:</>}
-                                                name='line'
-                                                placeholder="插入列"
-                                                showSearch
-                                                request={async () => {
-                                                    const resp = await getReportListTableData({ pageSize: 500, current: 1 });
-                                                    if (resp) {
-                                                        return resp.list.map((a) => ({ label: a.name, value: a.code }))
-                                                    }
-                                                    return []
-                                                }}
-                                                fieldProps={{
-                                                    onChange(value, option) {
-                                                        const _formula = formRef.current?.getFieldValue('formula');
-                                                        formRef.current?.setFieldValue('formula', `${_formula ? _formula : ''}[${value}]`)
-                                                    },
-                                                }}
-                                            // rules={[{ required: , message: '计算公式不能为空!' }]}
-                                            />
-                                            <ProFormTextArea
-                                                name="formula"
-                                                // colProps={{ span: 16 }}
-                                                placeholder="例:([1]+[2])/[3]"
-                                                rules={[{ required: true, message: '计算公式不能为空!' }]}
-                                            />
-
-                                        </>
-                                    )
-                                }
-                            </ProFormDependency>
-                            <ProFormDependency name={['dataSource']}>
-                                {
-                                    ({ dataSource }) => dataSource == 2 && (
-                                        <ProFormTextArea name={'sql'} label='取数来源:' rules={[{ required: true, message: '取数来源不能为空!' }]} />
-                                    )
-                                }
-                            </ProFormDependency>
-                        </>
-                    )
-                }
-
-            </ModalForm>
-        )
-    }
+    
 
     const tableDataSearchHandle = (paramName: string) => {
 
@@ -362,6 +175,8 @@ const reportColumnMana = () => {
 
     }
 
+   
+
     const onSaveHandle = async (keys: Key[], rows: any[]) => {
         const result = {
             parentCode: currentEditRow.code,
@@ -436,7 +251,7 @@ const reportColumnMana = () => {
                         <span className='label' style={{ whiteSpace: 'nowrap' }}> 列标题:</span>
                         <Input placeholder={'请输入'} allowClear width={160}
                             suffix={
-                                <IconFont type="iconsousuo" style={{color:'#99A6BF'}} onClick={() => tableDataSearchHandle('columnName')} />
+                                <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle('columnName')} />
                             }
                             onChange={(e) => {
                                 set_tableDataSearchKeywords(e.target.value);
@@ -459,7 +274,7 @@ const reportColumnMana = () => {
                     </div>
                 </div>
                 <div className='btnGroup'>
-                    <UpDataActBtn record type='ADD' />
+                    <UpDateActBtn record type='ADD' tableRef={tableRef} />
                 </div>
             </div>
 

+ 5 - 0
src/pages/costLibraryManagement/reportMana/reportColumnMana/style.less

@@ -29,12 +29,17 @@
 }
 
 
+// .cost-ant-modal .cost-ant-modal-content {
+//   padding: 0 !important;
+// }
+
 .reportColumnMana {
   padding: 16px;
   background: #FFFFFF;
   border-radius: 4px;
 
 
+
   .toolBar {
     display: flex;
     flex-direction: row;

+ 24 - 11
src/pages/costLibraryManagement/reportMana/reportListMana/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-16 17:41:08
+ * @LastEditTime: 2024-01-11 19:51:27
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -12,10 +12,10 @@ import { createFromIconfontCN } from '@ant-design/icons';
 import { ActionType, arrayMoveImmutable, useRefFunction } from '@ant-design/pro-components';
 import { ModalForm, ProFormSelect, ProFormText } from '@ant-design/pro-form';
 import { ProColumns } from '@ant-design/pro-table';
-import { Dropdown, Input, MenuProps, message, Modal, Switch, Tooltip, Popconfirm } from 'antd';
-import { ColumnsType, TableRowSelection } from 'antd/es/table/interface';
-import Transfer, { TransferItem, TransferProps } from 'antd/es/transfer';
-import React, { Key } from 'react';
+import { Dropdown, Input, MenuProps, message, Switch, Tooltip, Popconfirm } from 'antd';
+import { ColumnsType } from 'antd/es/table/interface';
+import { TransferItem, TransferProps } from 'antd/es/transfer';
+import { Key } from 'react';
 import { useEffect, useRef, useState } from 'react';
 
 
@@ -32,6 +32,7 @@ import KCIMPagecontainer from '@/components/KCIMPageContainer';
 import { KCIMTable } from '@/components/KCIMTable';
 import { getTargetDic } from '@/services/auth';
 import TableSelecter from './tableSelector';
+import UpDateActBtn from '../reportColumnMana/UpDateActBtn';
 const IconFont = createFromIconfontCN({
     scriptUrl: '',
 });
@@ -41,6 +42,8 @@ let _currentSelectedType: any = undefined;
 
 const reportListMana = () => {
 
+
+
     const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
     const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
     const [selectedRowKeys, set_selectedRowKeys] = useState<Key[]>([]);
@@ -80,38 +83,48 @@ const reportListMana = () => {
         {
             title: '主键',
             dataIndex: 'primaryKey',
-            render: (_: any, record: any) => {
-                return <Switch disabled={!ifEditTable} size='small' checked={_} onChange={(bool) => switchChangeHandle(bool, record, 'primaryKey')} />
+            renderText: (_: any, record: any) => {
+
+                return <Switch disabled={!ifEditTable} size='small' checked={_?true:false} onChange={(bool) => switchChangeHandle(bool, record, 'primaryKey')} />
             }
         },
         {
             title: '隐藏',
             dataIndex: 'hide',
-            render: (_: any, record: any) => {
+            renderText: (_: any, record: any) => {
                 return <Switch disabled={!ifEditTable} size='small' checked={_} onChange={(bool) => switchChangeHandle(bool, record, 'hide')} />
             }
         },
         {
             title: '冻结',
             dataIndex: 'freeze',
-            render: (_: any, record: any) => {
+            renderText: (_: any, record: any) => {
                 return <Switch disabled={!ifEditTable} size='small' checked={_ == '1'} onChange={(bool) => switchChangeHandle(bool, record, 'freeze')} />
             }
         },
         {
             title: '排序',
             dataIndex: 'sortStatus',
-            render: (_: any, record: any) => {
+            renderText: (_: any, record: any) => {
                 return <Switch disabled={!ifEditTable} size='small' checked={_ == '1'} onChange={(bool) => switchChangeHandle(bool, record, 'sortStatus')} />
             }
         },
+        {
+            title: '检索',
+            dataIndex: 'search',
+            renderText: (_: any, record: any) => {
+                return <Switch disabled={!ifEditTable} size='small' checked={_ == '1'} onChange={(bool) => switchChangeHandle(bool, record, 'search')} />
+            }
+        },
         {
             title: '操作',
             key: 'option',
+            width:90,
             valueType: 'option',
-            render: (_: any, record: any) => {
+            renderText: (_: any, record: any) => {
 
                 return [
+                    <UpDateActBtn record={{...record,id:null,request:true}} type='EDIT' onUpdated={()=>getTableData({ reportCode: _currentSelectedType.code })}  />,
                     <Popconfirm
                         title="是否确认删除?"
                         key="del"

+ 3 - 1
src/pages/costLibraryManagement/reportMana/reportListMana/style.less

@@ -82,7 +82,7 @@ box-shadow: 0px -8px 16px 0px rgba(64,85,128,0.1);
     border-radius: 4px;
     width: 220px;
     height: calc(100vh - 80px);
-    overflow: scroll;
+    overflow: hidden;
     margin-right: 16px;
     padding: 16px 8px;
     background: #FFFFFF;
@@ -114,6 +114,8 @@ box-shadow: 0px -8px 16px 0px rgba(64,85,128,0.1);
 
     .wrap {
       margin-top: 16px;
+      height: calc(100% - 45px);
+      overflow-y: scroll;
 
       .type {
         cursor: pointer;

+ 2 - 2
src/pages/costLibraryManagement/reportMana/reportNavSet/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2023-11-16 17:41:22
+ * @LastEditTime: 2024-01-05 14:33:46
  * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -73,7 +73,7 @@ export default function ReportNavSet() {
         {
             title: '操作',
             key: 'option',
-            width: 120,
+            width: 90,
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [

+ 387 - 0
src/pages/monthlyInfoCollection/components/leftAndRighrStructure.tsx

@@ -0,0 +1,387 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-03-19 10:55:39
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-04-07 15:42:38
+ * @FilePath: /CostAccountingSys/src/pages/monthlyInfoCollection/components/leftAndRighrStructure.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+import { KCIMLeftList } from "@/components/KCIMLeftList"
+import { KCIMTable } from "@/components/KCIMTable";
+import { beforeCollectionSearch, beforeCostShareSearch } from "@/pages/costAccounting/calcPageTemplate/columns";
+import { getCalcPageTableData } from "@/pages/costAccounting/calcPageTemplate/service";
+import { ActionType, ProColumns } from "@ant-design/pro-components";
+import { useEffect, useRef, useState } from "react";
+import { Input } from 'antd'
+
+
+import './style.less';
+import { createFromIconfontCN } from "@ant-design/icons";
+import CostAllocationParamsDeal from "@/pages/baseSetting/costAllocationSet/costAllocationParamsDeal";
+import PatientInfoImport from "@/pages/monthlyInfoSearch/patientInfoImport";
+import PatientChargeItemsImport from "@/pages/monthlyInfoSearch/patientChargeItemsImport";
+import { getCostDepartmentList, getCostShareDepartmentList, getIncomeDepartmentList, getPatientChargeItemList, getPatientInfoDepartmentList } from "../service";
+import { formatMoneyNumber } from "@/utils/format";
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+export interface LeftAndRighrStructure {
+    tabKey: string,
+    computeDate: string,
+    btnPerm: string,
+    cancelHandle: () => Promise<boolean>,
+    getHandle:() => Promise<boolean>,
+    reload:boolean
+}
+
+
+let _currentSelectedLeftObj: any = undefined;
+export const LeftAndRighrStructure = (props: LeftAndRighrStructure) => {
+
+    const { tabKey, computeDate, btnPerm = '1|1', cancelHandle,getHandle,reload } = props;
+
+    const tableRef = useRef<ActionType>();
+    const [currentSelectedLeftObj, set_currentSelectedLeftObj] = useState<undefined | any>(undefined);
+    const [tableColumn, set_tableColumn] = useState<ProColumns[]>([]);
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>(undefined);
+    const [scrollX, set_scrollX] = useState<number|undefined>(1000);
+    const [tabSearchKey, set_tabSearchKey] = useState('');
+    const [currentLeftTab, set_currentLeftTab] = useState(1);
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState('');
+    const [tableSearchKey, set_tableSearchKey] = useState('');
+
+    const [leftListData, set_leftListData] = useState<any[]>([]);
+    const [ifShowGetBtn, set_ifShowGetBtn] = useState(false);
+    const [ifShowCancelBtn, set_ifShowCancelBtn] = useState(false);
+
+    const [leftListSearchPlaceHolder, set_leftListSearchPlaceHolder] = useState('请输入');
+
+    const [totalAmount, set_totalAmount] = useState(0);
+    const [currentResp, set_currentResp] = useState<any>(undefined);
+
+
+    const getTableData = async (params: any) => {
+
+        if (tabKey == '1') {
+            const resp = await getCalcPageTableData({ calcPageKey: 'beforeCollectionSearch', ...tableDataFilterParams, computeDate, type: currentLeftTab, departmentCode: _currentSelectedLeftObj.subText });
+            if (resp) {
+                // set_totalAmount(resp.totalAmount);
+                set_currentResp(resp);
+                return {
+                    data: resp.list,
+                    success: true,
+                    total: resp.totalCount,
+                    pageSize: resp.pageSize,
+                    totalPage: resp.totalPage,
+                }
+            }
+        }
+        if (tabKey == '3'&&_currentSelectedLeftObj) {
+            const resp = await getCalcPageTableData({...params, calcPageKey: 'beforeCostShareSearch', ...tableDataFilterParams, computeDate, departmentCode: _currentSelectedLeftObj.subText });
+            if (resp) {
+                set_currentResp(resp);
+                return {
+                    data: resp.list,
+                    success: true,
+                    total: resp.totalCount,
+                    pageSize: resp.pageSize,
+                    totalPage: resp.totalPage,
+                }
+            }
+        }
+        return {
+            data: [],
+            success: true
+        }
+    }
+
+    const onLeftChange = (item: any) => {
+        set_currentSelectedLeftObj(item);
+        _currentSelectedLeftObj = item;
+
+    }
+
+    const tableDataSearchHandle = (paramName: string) => {
+
+
+        set_tableDataFilterParams({
+            ...tableDataFilterParams,
+            [`${paramName}`]: tableDataSearchKeywords
+        })
+    }
+
+    const inComeLeftData = async () => {
+        const resp = await getIncomeDepartmentList({ computeDate, type: currentLeftTab });
+        if (resp) {
+            const arr = resp.map((a: any) => ({
+                name: a.departmentName,
+                subText: a.departmentCode,
+
+            }));
+            set_leftListData([...arr]);
+        }
+    }
+    const costLeftData = async () => {
+        const resp = await getCostDepartmentList({ computeDate, type: currentLeftTab });
+        if (resp) {
+            const arr = resp.map((a: any) => ({
+                name: a.departmentName,
+                subText: a.departmentCode,
+
+            }));
+            set_leftListData([...arr]);
+        }
+    }
+    const costShareLeftData = async () => {
+        const resp = await getCostShareDepartmentList();
+        if (resp) {
+            set_leftListData([...(resp)]);
+        }
+    }
+
+    const getPatientInfoDepartments = async () => {
+        const resp = await getPatientInfoDepartmentList(computeDate, Number(currentLeftTab));
+        if (resp) {
+            const arr = resp.map((a: any) => ({
+                name: a.departmentName,
+                subText: a.departmentCode,
+
+            }));
+            set_leftListData([...arr]);
+        }
+    }
+
+    const getPatientChargeItemReq =async () => {
+        const resp = await getPatientChargeItemList(computeDate);
+        if(resp){
+            const arr = resp.map((a: any) => ({
+                name: a.name,
+                subText: a.patientNo,
+
+            }));
+            set_leftListData([...arr]);
+        }
+    }
+
+    const getLeftDatas = ()=>{
+        if (tabKey == '1') {
+            inComeLeftData();
+        }
+        if (tabKey == '2') {
+            costShareLeftData();
+        }
+        if (tabKey == '3') {
+            costLeftData();
+        }
+        if(tabKey == '5'){
+            getPatientInfoDepartments();
+        }
+        if(tabKey == '6'){
+            getPatientChargeItemReq()
+        }
+    }
+
+
+    useEffect(() => {
+        set_currentSelectedLeftObj(undefined);
+        _currentSelectedLeftObj = undefined;
+        set_currentResp(undefined);
+        
+        if (tabKey == '1') {
+            set_tableColumn([...beforeCollectionSearch]);
+            set_scrollX(1300);
+            set_tabSearchKey('name');
+            set_tableSearchKey('filter');
+            inComeLeftData();
+        }
+        if (tabKey == '2') {
+            costShareLeftData();
+            set_scrollX(undefined);
+        }
+
+        if (tabKey == '3') {
+            set_tableColumn([...beforeCostShareSearch]);
+            set_scrollX(undefined);
+            set_tabSearchKey('name');
+            set_tableSearchKey('filter');
+            costLeftData();
+        }
+
+        if (tabKey == '5') {
+            set_scrollX(1300);
+            set_tabSearchKey('name');
+            set_tableSearchKey('');
+            getPatientInfoDepartments();
+        }
+        if (tabKey == '6') {
+            set_scrollX(1300);
+            set_tabSearchKey('name');
+            set_tableSearchKey('filter');
+            set_leftListSearchPlaceHolder('患者ID/姓名');
+            getPatientChargeItemReq()
+        }
+
+    }, [tabKey]);
+
+
+
+    useEffect(() => {
+        getLeftDatas();
+        tableRef.current?.reload();
+    }, [computeDate]);
+
+    useEffect(() => {
+        if (btnPerm) {
+            const [a, b] = btnPerm.split('|');
+            set_ifShowCancelBtn(b == '1');
+            set_ifShowGetBtn(a == '1')
+        }
+    }, [btnPerm]);
+
+    useEffect(() => {
+        if (currentSelectedLeftObj) {
+            tableRef.current?.reload();
+        }
+
+    }, [currentSelectedLeftObj]);
+
+    useEffect(() => {
+        if (reload) {
+            getLeftDatas();
+            tableRef.current?.reload();
+        }
+
+    }, [reload]);
+
+    useEffect(() => {
+        if (tabKey == '1') {
+            inComeLeftData();
+        }
+        if (tabKey == '5') {
+            getPatientInfoDepartments();
+        }
+    }, [currentLeftTab])
+
+
+
+    return (
+        <div className="LeftAndRighrStructure">
+            {
+                (tabKey != '2' && tabKey != '5' && tabKey != '6') && (
+                    <div className="line">
+                        <div className="info">
+                            <img src={require('../../../../static/multiblock.png')} alt="" />
+                            全部科室合计:
+                            <span>{currentResp?formatMoneyNumber(currentResp.totalAmount):'0.00'}元</span>
+                        </div>
+                        <div className="lineBtnGroup">
+                            {ifShowCancelBtn && <span onClick={()=>cancelHandle().then((isOk)=>{
+                                  if(isOk){
+                                    set_currentResp(undefined);
+                                        // getLeftDatas();
+                                        // tableRef.current?.reload();
+                                  }
+                            })}>撤销</span>}
+                            {ifShowGetBtn && <span onClick={()=>getHandle().then((isOk)=>{
+                                  if(isOk){
+                                        // getLeftDatas();
+                                        // tableRef.current?.reload();
+                                  }
+                            })}>获取</span>}
+                        </div>
+                    </div>
+                )
+            }
+
+            <div className="contentWrapper">
+
+                <div className="left">
+                    {
+                        (tabKey == '1') && (
+                            <div className="leftTab">
+                                <div onClick={() => set_currentLeftTab(1)} className={currentLeftTab == 1 ? 'tab on' : 'tab'}>按开单</div>
+                                <div onClick={() => set_currentLeftTab(2)} className={currentLeftTab == 2 ? 'tab on' : 'tab'}>按执行</div>
+                            </div>
+                        )
+                    }
+                    {
+                        (tabKey == '5') && (
+                            <div className="leftTab">
+                                <div onClick={() => set_currentLeftTab(1)} className={currentLeftTab == 1 ? 'tab on' : 'tab'}>门诊</div>
+                                <div onClick={() => set_currentLeftTab(2)} className={currentLeftTab == 2 ? 'tab on' : 'tab'}>急诊</div>
+                                <div onClick={() => set_currentLeftTab(3)} className={currentLeftTab == 3 ? 'tab on' : 'tab'}>住院</div>
+                            </div>
+                        )
+                    }
+
+                    <KCIMLeftList
+                        fieldNames={{title:'responsibilityName',key:'responsibilityCode',children:'child'}}
+                        rowKey={(tabKey == '1' || tabKey == '3'||tabKey == '5'||tabKey == '6') ? 'subText' : ''}
+                        dataSource={leftListData} searchKey={tabSearchKey} onChange={onLeftChange}
+                        placeholder={leftListSearchPlaceHolder} listType={tabKey == '2' ? 'tree' : 'list'}
+                        icon={tabKey == '6' ? require('../../../../static/empInfo.png') : undefined}
+                    />
+                </div>
+                <div className="right">
+                    <div className="toolBar" style={{ display: (tabKey == '1' || tabKey == '3') ? 'flex' : 'none' }}>
+                        <div className="leftTool">当前科室合计:<span>{currentResp?formatMoneyNumber(currentResp.departmentAmount)?currentResp.departmentAmount:'0.00':'0.00'}元</span></div>
+                        <div className="rightTool">
+                            <div className='filterItem' style={{ marginLeft: 16, width: 233 }}>
+                                <span className='label' style={{ whiteSpace: 'nowrap' }}> 检索:</span>
+                                <Input placeholder={'收入项目代码/名称'} allowClear
+                                    suffix={
+                                        <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle(`${tableSearchKey}`)} />
+                                    }
+                                    onChange={(e) => {
+                                        set_tableDataSearchKeywords(e.target.value);
+                                        if (e.target.value.length == 0) {
+                                            set_tableDataFilterParams({
+                                                ...tableDataFilterParams,
+                                                [`${tableSearchKey}`]: ''
+                                            });
+                                        }
+                                    }}
+                                    onPressEnter={(e) => {
+                                        set_tableDataFilterParams({
+                                            ...tableDataFilterParams,
+                                            [`${tableSearchKey}`]: ((e.target) as HTMLInputElement).value
+                                        });
+                                    }}
+
+                                />
+                            </div>
+                        </div>
+                    </div>
+                    {(tabKey != '2' && tabKey != '5' && tabKey != '6'&&currentSelectedLeftObj) && <KCIMTable actionRef={tableRef} columns={tableColumn}
+                        rowKey='id'
+                        request={(params) => getTableData(params)}
+                        tableAlertRender={false}
+                        scroll={{ x: scrollX }}
+                        params={tableDataFilterParams}
+                    />}
+                 
+                    {(tabKey == '2') && <CostAllocationParamsDeal date={computeDate} ifShowGetBtn ifShowCancelBtn 
+                    responsibilityCode={currentSelectedLeftObj?.responsibilityCode}  cancelHandle={cancelHandle}
+                     getHandle={getHandle}
+                     />}
+                    {(tabKey == '5') && <PatientInfoImport date={computeDate} ifShowGetBtn ifShowCancelBtn currentSlectedDepCode = {currentSelectedLeftObj?.subText} type={currentLeftTab}
+                       cancelHandle={cancelHandle}
+                       getHandle={getHandle}
+                    />}
+                    {(tabKey == '6') && <PatientChargeItemsImport date={computeDate} 
+                     cancelHandle={cancelHandle}
+                     getHandle={getHandle}
+                     ifShowGetBtn ifShowCancelBtn currentSlectedPatientNo = {currentSelectedLeftObj?.subText} 
+                     />}
+
+                </div>
+            </div>
+
+        </div>
+    )
+}

+ 180 - 0
src/pages/monthlyInfoCollection/components/style.less

@@ -0,0 +1,180 @@
+.LeftAndRighrStructure {
+    width: 100%;
+    padding: 16px;
+
+    .line {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        height: 40px;
+        background: #F0FCFC;
+        border-radius: 4px;
+        margin-bottom: 16px;
+        padding: 0 12px;
+
+        .info {
+            display: flex;
+            flex-direction: row;
+            justify-content: flex-start;
+            align-items: center;
+            font-weight: 500;
+            font-size: 16px;
+            color: #17181A;
+
+            &>img {
+                width: 16px;
+                height: 16px;
+                margin-right: 8px;
+
+            }
+
+            &>span {
+                font-weight: 500;
+                font-size: 16px;
+                color: #00B3B3;
+                padding-left: 4px;
+            }
+        }
+
+        .lineBtnGroup {
+            &>span {
+                display: inline-block;
+                width: 56px;
+                height: 24px;
+                line-height: 24px;
+                background: #FFFFFF;
+                border-radius: 4px;
+                text-align: center;
+                font-weight: 400;
+                font-size: 14px;
+                color: #00B3B3;
+                cursor: pointer;
+
+                &:first-child {
+                    margin-right: 8px;
+                }
+            }
+        }
+
+
+    }
+
+    .contentWrapper {
+        display: flex;
+        width: 100%;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: flex-start;
+
+        .left {
+            width: 220px;
+            border-radius: 4px;
+            padding-top: 16px;
+            border: 1px solid #DAE2F2;
+
+            .leftTab {
+                display: flex;
+                margin: 0 16px;
+                flex-direction: row;
+                justify-content: flex-start;
+                align-items: center;
+                border-radius: 4px;
+                margin-bottom: 4px;
+                border: 1px solid #DAE2F2;
+                overflow: hidden;
+
+                .tab {
+                    flex: 1;
+                    cursor: pointer;
+                    text-align: center;
+                    height: 24px;
+                    line-height: 24px;
+                    font-weight: 400;
+                    font-size: 14px;
+                    color: #17181A;
+
+                    &.on {
+                        color: #FFFFFF;
+                        background: #3377FF;
+                    }
+                }
+            }
+        }
+
+        .right {
+            width: calc(100% - 236px);
+
+            .cost-ant-pro-page-container {
+                border:none !important;
+            }
+
+            .toolBar {
+                display: flex;
+                flex-direction: row;
+                justify-content: space-between;
+                align-items: center;
+                margin-bottom: 12px;
+
+                .leftTool {
+                    font-weight: 500;
+                    font-size: 14px;
+                    color: #17181A;
+
+                    &>span {
+                        color: #3477FF;
+                    }
+
+                    &::before {
+                        position: relative;
+                        display: inline-block;
+                        content: '';
+                        width: 8px;
+                        height: 8px;
+                        background: #3377FF;
+                        border-radius: 2px;
+                        margin-right: 8px;
+                        margin-left: 4px;
+
+                    }
+                }
+
+                .rightTool {
+                    .filterItem {
+                        display: flex;
+                        flex-direction: row;
+                        justify-content: center;
+                        align-items: center;
+                    }
+                }
+
+                .btnGroup {
+
+                    .import,
+                    .normal {
+                        cursor: pointer;
+                        display: inline-block;
+                        font-size: 14px;
+                        font-family: SourceHanSansCN-Normal, SourceHanSansCN;
+                        font-weight: 400;
+                        color: #FFFFFF;
+                        line-height: 24px;
+                        padding: 0 14px;
+                        background: #3377FF;
+                        border-radius: 4px;
+                    }
+
+                    .normal {
+                        display: inline-block;
+                        color: #17181A;
+                        border: 1px solid #DAE2F2;
+                        background: #FAFCFF;
+                        margin-right: 8px;
+                    }
+                }
+
+            }
+        }
+    }
+
+}

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff