Преглед на файлове

完成截止到20240722的任务

code4eat преди 1 година
родител
ревизия
3050ad185b
променени са 65 файла, в които са добавени 4624 реда и са изтрити 936 реда
  1. BIN
      .DS_Store
  2. 63 2
      .umirc.ts
  3. 351 100
      src/app.tsx
  4. 64 0
      src/authWrapper.tsx
  5. 144 136
      src/components/KCIMLeftList/index.tsx
  6. 6 4
      src/components/KCIMLeftList/style.less
  7. 19 24
      src/components/KCIMTable/style.less
  8. 1 0
      src/components/KCIMUpload/index.tsx
  9. 71 0
      src/components/ResizableContainer/index.tsx
  10. 24 0
      src/components/ResizableContainer/style.less
  11. 1 0
      src/global.less
  12. 0 0
      src/pages/404.tsx
  13. 246 37
      src/pages/baseSetting/accountingAccountSet/accountingSubMana/index.tsx
  14. 9 1
      src/pages/baseSetting/accountingAccountSet/accountingSubMana/service.ts
  15. 4 4
      src/pages/baseSetting/accountingAccountSet/accountingSubMana/style.less
  16. 98 9
      src/pages/baseSetting/accountingAccountSet/accountingSubMap/index.tsx
  17. 5 1
      src/pages/baseSetting/costAllocationSet/allocationParamsMap/editTableModal.tsx
  18. 2 2
      src/pages/baseSetting/costAllocationSet/costAllocationParamsDeal/index.tsx
  19. 1 1
      src/pages/baseSetting/costAllocationSet/costAllocationParamsSet/index.tsx
  20. 31 4
      src/pages/baseSetting/costAllocationSet/idleCostSetting/index.tsx
  21. 9 1
      src/pages/baseSetting/costAllocationSet/idleCostSetting/service.ts
  22. 592 0
      src/pages/baseSetting/otherItemSet/departmentCostCalc/index.tsx
  23. 130 0
      src/pages/baseSetting/otherItemSet/departmentCostCalc/service.ts
  24. 113 0
      src/pages/baseSetting/otherItemSet/departmentCostCalc/style.less
  25. 301 0
      src/pages/baseSetting/otherItemSet/departmentCostCalc/transform.tsx
  26. 63 66
      src/pages/baseSetting/otherItemSet/diySqlMana/index.tsx
  27. 28 34
      src/pages/baseSetting/otherItemSet/reportItemSet/index.tsx
  28. 6 5
      src/pages/baseSetting/otherItemSet/reportItemSet/transform.tsx
  29. 223 68
      src/pages/baseSetting/responsibilityCenterSet/responsibilityCenter/index.tsx
  30. 15 1
      src/pages/baseSetting/responsibilityCenterSet/responsibilityCenter/service.ts
  31. 50 7
      src/pages/baseSetting/responsibilityCenterSet/responsibilityCenterConnect/index.tsx
  32. 48 48
      src/pages/costAccounting/calcPageTemplate/columns.tsx
  33. 98 2
      src/pages/costAccounting/calcPageTemplate/config.ts
  34. 106 80
      src/pages/costAccounting/calcPageTemplate/index.tsx
  35. 49 1
      src/pages/costAccounting/calcPageTemplate/service.ts
  36. 8 6
      src/pages/costLibraryManagement/basicCostManagement/materialCostManagement/index.tsx
  37. 9 10
      src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/match.tsx
  38. 22 9
      src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/setting.tsx
  39. 58 51
      src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/index.tsx
  40. 26 17
      src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/service.ts
  41. 116 64
      src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/index.tsx
  42. 12 1
      src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/service.ts
  43. 351 0
      src/pages/incomeCollectionAction/index.tsx
  44. 23 0
      src/pages/incomeCollectionAction/service.ts
  45. 214 0
      src/pages/incomeCollectionAction/style.less
  46. 44 18
      src/pages/monthlyInfoCollection/components/leftAndRighrStructure.tsx
  47. 1 1
      src/pages/monthlyInfoCollection/components/style.less
  48. 43 14
      src/pages/monthlyInfoCollection/index.tsx
  49. 10 1
      src/pages/monthlyInfoCollection/service.ts
  50. 2 1
      src/pages/monthlyInfoSearch/empCostDataImport/index.tsx
  51. 2 1
      src/pages/monthlyInfoSearch/incomeCostDataImport/index.tsx
  52. 2 2
      src/pages/monthlyInfoSearch/patientChargeItemsImport/index.tsx
  53. 2 2
      src/pages/monthlyInfoSearch/patientInfoImport/index.tsx
  54. 81 45
      src/pages/monthlyInfoSearch/wholeHospIncomeAndCost/index.tsx
  55. 121 0
      src/pages/monthlyInfoSearch/wholeHospIncomeAndCost/style.less
  56. BIN
      src/pages/noAccess/images/noAccess.png
  57. 30 0
      src/pages/noAccess/index.tsx
  58. 49 0
      src/pages/noAccess/style.less
  59. 42 53
      src/pages/reportExport/report/index.tsx
  60. 246 0
      src/pages/specialDataImport/index.tsx
  61. 70 0
      src/pages/specialDataImport/service.ts
  62. 57 0
      src/pages/specialDataImport/style.less
  63. 1 1
      src/pages/static/index.tsx
  64. 11 1
      src/services/getDic.ts
  65. BIN
      成本核算系统_2024_04_01.zip

BIN
.DS_Store


+ 63 - 2
.umirc.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2022-12-14 14:14:32
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-04-07 13:30:11
+ * @LastEditTime: 2024-07-17 15:38:48
  * @FilePath: /BudgetManaSystem/.umirc.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -77,6 +77,10 @@ export default defineConfig({
       path: '/',
       redirect: '/baseSetting/otherItemSet',
     },
+    {
+      path: '/noAccess',
+      component: './noAccess',
+    },
     {
       path: '/home',
       component: './Home/index',
@@ -93,11 +97,13 @@ export default defineConfig({
               path: '/baseSetting/responsibilityCenterSet/responsibilityCenter',
               name: '责任中心管理',
               component: './baseSetting/responsibilityCenterSet/responsibilityCenter/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/baseSetting/responsibilityCenterSet/responsibilityCenterConnect',
               name: '责任中心对应',
               component: './baseSetting/responsibilityCenterSet/responsibilityCenterConnect/index',
+              wrappers: ['@/authWrapper'],
             },
           ],
         },
@@ -109,21 +115,25 @@ export default defineConfig({
               path: '/baseSetting/accountingAccountSet/costIncomeProjectMana',
               name: '会计收入项目管理',
               component: './baseSetting/accountingAccountSet/costIncomeProjectMana/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/baseSetting/accountingAccountSet/accountingSubMana',
               name: '会计科目管理',
               component: './baseSetting/accountingAccountSet/accountingSubMana/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/baseSetting/accountingAccountSet/accountingSubMap',
               name: '会计科目对应',
               component: './baseSetting/accountingAccountSet/accountingSubMap/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/baseSetting/accountingAccountSet/chargeItemMap',
               name: '收费项目对应',
               component: './baseSetting/accountingAccountSet/chargeItemMap/index',
+              wrappers: ['@/authWrapper'],
             },
           ],
         },
@@ -136,31 +146,37 @@ export default defineConfig({
               path: '/baseSetting/costAllocationSet/allocationLevelSet',
               name: '分摊层级设置',
               component: './baseSetting/costAllocationSet/allocationLevelSet/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/baseSetting/costAllocationSet/idleCostSetting',
               name: '闲置成本设置',
               component: './baseSetting/costAllocationSet/idleCostSetting/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/baseSetting/costAllocationSet/costAllocationParamsSet',
               name: '成本分摊参数设置',
               component: './baseSetting/costAllocationSet/costAllocationParamsSet/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/baseSetting/costAllocationSet/costAllocationParamsDeal',
               name: '成本分摊参数处理',
               component: './baseSetting/costAllocationSet/costAllocationParamsDeal/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/baseSetting/costAllocationSet/allocationParamsMap',
               name: '分摊参数对应',
               component: './baseSetting/costAllocationSet/allocationParamsMap/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/baseSetting/costAllocationSet/revenueImputationSet',
               name: '收入归集设置',
               component: './baseSetting/costAllocationSet/revenueImputationSet/index',
+              wrappers: ['@/authWrapper'],
             },
           ],
         },
@@ -173,21 +189,31 @@ export default defineConfig({
               path: '/baseSetting/otherItemSet/diySqlMana',
               name: '自定义SQl管理',
               component: './baseSetting/otherItemSet/diySqlMana/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/baseSetting/otherItemSet/reportItemSet',
               name: '报表项目设置',
               component: './baseSetting/otherItemSet/reportItemSet/index',
+              wrappers: ['@/authWrapper'],
+            },
+            {
+              path: '/baseSetting/otherItemSet/departmentCostCalc',
+              name: '科室损益计算',
+              component: './baseSetting/otherItemSet/departmentCostCalc/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/baseSetting/otherItemSet/visitsAndBedDayCostSetting',
               name: '诊次/床日成本设置',
               component: './baseSetting/otherItemSet/visitsAndBedDayCostSetting/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/baseSetting/otherItemSet/wholeHospCostAndIncomeSet',
               name: '全院其他收支设置',
               component: './baseSetting/otherItemSet/wholeHospCostAndIncomeSet/index',
+              wrappers: ['@/authWrapper'],
             },
           ],
         },
@@ -196,7 +222,20 @@ export default defineConfig({
     {
       path:'/monthlyInfoCollection',
       name: '月度信息采集2',
-      component:'./monthlyInfoCollection/index'
+      component:'./monthlyInfoCollection/index',
+      wrappers: ['@/authWrapper'],
+    },
+    {
+      path:'/specialDataImport',
+      name: '填报数据导入',
+      component:'./specialDataImport/index',
+      wrappers: ['@/authWrapper'],
+    },
+    {
+      path:'/incomeCollectionAction',
+      name: '收入归集',
+      component:'./incomeCollectionAction/index',
+      wrappers: ['@/authWrapper'],
     },
     {
       path: '/monthlyInfoSearch',
@@ -206,26 +245,31 @@ export default defineConfig({
           path: '/monthlyInfoSearch/wholeHospIncomeAndCost',
           name: '全院其他收支',
           component: './monthlyInfoSearch/wholeHospIncomeAndCost/index',
+          wrappers: ['@/authWrapper'],
         },
         {
           path: '/monthlyInfoSearch/empCostDataImport',
           name: '人事成本数据导入',
           component: './monthlyInfoSearch/empCostDataImport/index',
+          wrappers: ['@/authWrapper'],
         },
         {
           path: '/monthlyInfoSearch/patientChargeItemsImport',
           name: '患者收费项目导入',
           component: './monthlyInfoSearch/patientChargeItemsImport/index',
+          wrappers: ['@/authWrapper'],
         },
         {
           path: '/monthlyInfoSearch/patientInfoImport',
           name: '患者信息导入',
           component: './monthlyInfoSearch/patientInfoImport/index',
+          wrappers: ['@/authWrapper'],
         },
         {
           path: '/monthlyInfoSearch/incomeCostDataImport',
           name: '收入成本数据导入',
           component: './monthlyInfoSearch/incomeCostDataImport/index',
+          wrappers: ['@/authWrapper'],
         },
       ],
     },
@@ -236,6 +280,7 @@ export default defineConfig({
         {
           path: '/costAccounting/:calcPageKey',
           component: './costAccounting/calcPageTemplate/index',
+          wrappers: ['@/authWrapper'],
         }
       ],
     },
@@ -249,6 +294,7 @@ export default defineConfig({
             {
               path: '/reportExport/:reportType/:reportCode',
               component: './reportExport/report',
+              wrappers: ['@/authWrapper'],
             },
           ]
         }
@@ -274,26 +320,31 @@ export default defineConfig({
               path: '/costLibraryManagement/basicCostManagement/personnelClassificationMana',
               name: '人事分类管理',
               component: './costLibraryManagement/basicCostManagement/personnelClassificationMana/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/costLibraryManagement/basicCostManagement/drugCostManagement',
               name: '药品成本管理',
               component: './costLibraryManagement/basicCostManagement/drugCostManagement/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/costLibraryManagement/basicCostManagement/materialCostManagement',
               name: '材料成本管理',
               component: './costLibraryManagement/basicCostManagement/materialCostManagement/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/costLibraryManagement/basicCostManagement/equipmentCostManagement',
               name: '设备成本管理',
               component: './costLibraryManagement/basicCostManagement/equipmentCostManagement/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/costLibraryManagement/basicCostManagement/spaceCostManagement',
               name: '空间成本管理',
               component: './costLibraryManagement/basicCostManagement/spaceCostManagement/index',
+              wrappers: ['@/authWrapper'],
             },
           ],
         },
@@ -305,21 +356,25 @@ export default defineConfig({
               path: '/costLibraryManagement/projectCostManagement/chargeItemsMana',
               name: '收费项目管理',
               component: './costLibraryManagement/projectCostManagement/chargeItemsMana/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/costLibraryManagement/projectCostManagement/standardProjectMana',
               name: '标准项目管理',
               component: './costLibraryManagement/projectCostManagement/standardProjectMana/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/costLibraryManagement/projectCostManagement/projectShareParamsSet',
               name: '项目分摊参数设置',
               component: './costLibraryManagement/projectCostManagement/projectShareParamsSet/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/costLibraryManagement/projectCostManagement/projectCostShareSet',
               name: '项目成本分摊设置',
               component: './costLibraryManagement/projectCostManagement/projectCostShareSet/index',
+              wrappers: ['@/authWrapper'],
             },
           ],
         },
@@ -331,6 +386,7 @@ export default defineConfig({
               path: '/costLibraryManagement/medicalOrderProject/medicalOrderProjectMana',
               name: '收费项目管理',
               component: './costLibraryManagement/medicalOrderProject/medicalOrderProjectMana/index',
+              wrappers: ['@/authWrapper'],
             },
           ],
         },
@@ -342,11 +398,13 @@ export default defineConfig({
               path: '/costLibraryManagement/diseaseCostManagement/diseaseMana',
               name: '病种管理',
               component: './costLibraryManagement/diseaseCostManagement/diseaseMana/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/costLibraryManagement/diseaseCostManagement/diseaseDiagnosisComparison',
               name: '病种诊断对照',
               component: './costLibraryManagement/diseaseCostManagement/diseaseDiagnosisComparison/index',
+              wrappers: ['@/authWrapper'],
             },
           ],
         },
@@ -365,15 +423,18 @@ export default defineConfig({
               path: '/costLibraryManagement/reportMana/reportColumnMana',
               name: '报表列管理',
               component: './costLibraryManagement/reportMana/reportColumnMana/index',
+              wrappers: ['@/authWrapper'],
             },
             {
               path: '/costLibraryManagement/reportMana/reportListMana',
               name: '报表管理',
+              wrappers: ['@/authWrapper'],
               component: './costLibraryManagement/reportMana/reportListMana/index',
             },
             {
               path: '/costLibraryManagement/reportMana/reportNavSet',
               name: '报表跳转',
+              wrappers: ['@/authWrapper'],
               component: './costLibraryManagement/reportMana/reportNavSet/index',
             },
           ],

+ 351 - 100
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: 2024-03-28 18:02:27
+ * @LastEditTime: 2024-06-11 16:15:45
  * @FilePath: /BudgetManaSystem/src/app.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -15,7 +15,7 @@
 
 
 import { AxiosResponse, history } from '@umijs/max';
-import { message, notification, Modal } from 'antd';
+import { message, notification, Modal, Menu } from 'antd';
 import type { RequestConfig } from 'umi';
 
 import iconEnum from './menuIcons.js';
@@ -34,6 +34,7 @@ import { Key, useEffect, useState } from 'react';
 import './utils/zhongtaiC'
 import { RuntimeAntdConfig } from '@umijs/max';
 import { useLocation } from '@umijs/max';
+import ResizableContainer from './components/ResizableContainer/index';
 
 
 const IconFont = createFromIconfontCN({
@@ -67,6 +68,62 @@ interface UserData {
   youshuToken?: string
 }
 
+interface TransformResult {
+  newTree: any[];
+  firstLeafNode: any | null;
+  firstLeafNodePath: any[];
+}
+
+
+function transformTree(tree: any[]): TransformResult {
+  let firstLeafNode: any | null = null;
+  let firstLeafNodePath: any[] = [];
+
+  function traverse(node: any, path: any[]): any {
+    const newNode: any = {
+      ...node,
+      label: node.name,
+    };
+
+    const newPath = [...path, newNode];
+
+    if (node.children && node.children.length > 0) {
+      newNode.children = node.children.map((child: any) => traverse(child, newPath));
+    } else {
+      if (!firstLeafNode) {
+        firstLeafNode = newNode;
+        firstLeafNodePath = newPath;
+      }
+    }
+
+    // Remove children property if it is an empty array
+    if (node.children && node.children.length === 0) {
+      newNode.children = null;
+    }
+
+    return newNode;
+  }
+
+  const newTree = tree.map(node => traverse(node, []));
+
+  return { newTree, firstLeafNode, firstLeafNodePath };
+}
+
+const findItemByKey: any = (tree: any[], key: string, keyName: string) => {
+  for (const node of tree) {
+    if (node[`${keyName}`] === key) {
+      return node;
+    }
+    if (node.children) {
+      const result = findItemByKey(node.children, key, keyName);
+      if (result) {
+        return result;
+      }
+    }
+  }
+  return null;
+}
+
 
 
 export async function getInitialState(): Promise<{
@@ -134,7 +191,7 @@ export const request: RequestConfig = {
         if (status == 200) {
           // 网络请求成功
           if (errorMessage && errorMessage.indexOf('Token') != -1) {
-            console.log({response,errorMessage});
+            console.log({ response, errorMessage });
             localStorage.removeItem('tokenExpired');
 
             return false;
@@ -152,10 +209,12 @@ export const request: RequestConfig = {
 
             } else {
               notification.error({
-                message: '',
+                top:72,
+                message: '提示',
                 description: errorMessage || msg,
                 placement: 'topRight',
-                icon: <></>
+                icon:<IconFont type="icon-jinggaotishi"  />,
+                style:{padding:16,borderRadius:8}
               })
               return false
             }
@@ -170,10 +229,12 @@ export const request: RequestConfig = {
               } else {
 
                 notification.error({
-                  message: '',
+                  top:72,
+                  message: '提示',
                   description: errorMessage || msg,
                   placement: 'topRight',
-                  icon: <></>
+                  icon:<IconFont type="icon-jinggaotishi"  />,
+                  style:{padding:16,borderRadius:8}
                 })
                 return false;
               }
@@ -273,7 +334,7 @@ export function patchClientRoutes({ routes }: { routes: any }) {
       lanhuPagePaths.forEach((a: any) => {
         treeData.routes.push(a);
       });
-      
+
     }
     if (treeData.routes && treeData.routes.length > 0) {
       treeData.routes.forEach((a: any) => {
@@ -283,10 +344,10 @@ export function patchClientRoutes({ routes }: { routes: any }) {
 
   }
 
- 
+
 
   treeLoop(routes[0]);
- 
+
 }
 
 
@@ -296,85 +357,245 @@ export function patchClientRoutes({ routes }: { routes: any }) {
 export const layout = ({ initialState, setInitialState }: { initialState: any, setInitialState: any }) => {
 
   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; // 如果在子菜单中找到匹配项,提前终止搜索
-              }
-            }
+  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]);
-        }
+      search(menu); // 从顶层菜单开始搜索
+      return result;
+    }
 
-  },[currentPath])
+    // const matchedItem = findMenuItemByPath(menuData, currentPath);
+    // if (matchedItem) {
+
+    //   set_selectedKeys([matchedItem.key]);
+    // }
+
+  }, [currentPath])
 
 
   return {
     menuHeaderRender: false,
-    token: {
-      sider: {
+    // token: {
+    //   sider: {
+
+    //     colorMenuBackground: '#fff',
+    //     colorTextMenuActive: '#3376FE',
+    //     colorTextMenuSelected: '#3376FE',
+    //     colorTextMenuTitle: '#17181A',
+    //     colorTextMenu: '#17181A',
+    //     //colorBgMenuItemHover:'##f0f2f5',
+    //     colorBgMenuItemSelected: '#F2F6FF',
+
+    //     // colorBgMenuItemCollapsedHover:'#f0f2f5',
+    //     // //colorBgMenuItemCollapsedSelected:'blue'
+
+    //   }
+
+    // },
+
+    disableMobile: true,
+    // menuProps: {
+    //   openKeys: [...openKeys],
+    //   selectedKeys: [...selectedKeys],
+    //   onSelect: ({ selectedKeys }: { selectedKeys: string[] }) => {
+    //     set_selectedKeys(selectedKeys);
+    //     localStorage.setItem('selectedKeys', JSON.stringify(selectedKeys));
+    //   },
+    //   onOpenChange: (keys: string[]) => {
+    //     set_openKeys([...keys]);
+    //     localStorage.setItem('openKeys', JSON.stringify(keys));
+    //   },
+    // },
+    menu: {
+      locale: false,
+      // request: async () => {
+      //   const userData = localStorage.getItem('userData');
+      //   const currentSelectedTab = localStorage.getItem('currentSelectedTab');
+      //   if (currentSelectedTab) {
+      //     const { menuId } = JSON.parse(currentSelectedTab);
+      //     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);
+      //         set_openKeys(_openKeys);
+      //         set_selectedKeys(_selectedKeys);
+      //       } else {
+      //         if (data[0].children && data[0].children.length > 0) {
+
+      //           const childs = data[0].children;
+      //           set_openKeys([data[0].key]);
+      //           set_selectedKeys([childs[0].key]);
+      //           localStorage.setItem('openKeys', JSON.stringify([data[0].key]));
+      //           localStorage.setItem('selectedKeys', JSON.stringify([childs[0].key]));
+      //           history.push(`${childs[0].path}`);
+
+      //         } else {
+      //           if (data[0]) {
+      //             set_openKeys([data[0].key]);
+      //             set_selectedKeys([data[0].key]);
+      //             localStorage.setItem('openKeys', JSON.stringify([data[0].key]));
+      //             localStorage.setItem('selectedKeys', JSON.stringify([data[0].key]));
+      //             history.push(`${data[0].path}`);
+      //           }
+      //         }
+      //       }
+
+
+      //       function processMenuItem(item: any) {
+      //         if (!item) return null;
+
+      //         let newItem = { ...item };  // 深拷贝当前节点
+
+      //         // 如果是叶子节点
+      //         if (!item.children || item.children.length === 0) {
+      //           let queryParams = [];
+
+      //           if (newItem.softUrl) {
+      //             queryParams.push(`softUrl=${newItem.softUrl}`);
+      //           }
+
+      //           if (newItem.youshuUrl) {
+      //             queryParams.push(`youshuUrl=${newItem.youshuUrl}`);
+      //           }
+
+      //           if (queryParams.length > 0) {
+      //             newItem.path = `${newItem.path}?${queryParams.join('&')}`;
+      //           }
+
+      //           return newItem; // 返回新的叶子节点
+      //         }
+
+      //         // 否则,递归处理子节点
+      //         newItem.children = newItem.children.map(processMenuItem);
+      //         return newItem;
+      //       }
+
+      //       function processMenu(menuArray: any[]) {
+      //         if (!menuArray) return [];
+      //         return menuArray.map(processMenuItem);
+      //       }
+
+      //       const _menu = processMenu(data);
+
+      //       setInitialState((t: any) => ({ ...t, spacicalPageParamsType: _menu, memuData: data, userData: JSON.parse(userData as string) }));
+
+
+      //       function addIconToPath(node: any, paths: string[]) {
+      //         if (paths.includes(node.path)) {
+      //           if (node.path == '/home') {
+      //             node.icon = <Icon component={imgNode}  />;
+      //           }
+      //           if (node.path == '/baseSetting') {
+
+      //             node.icon = <Icon component={setting} />;
+      //           }
+      //           if (node.path == '/monthlyInfoSearch') {
+      //             node.icon = <Icon component={()=><IconFont type='icon-yueduxinxicaiji' />} />;
+      //           }
+      //           if (node.path == '/costAccounting') {
+      //             node.icon = <Icon component={()=><IconFont type='icon-jixiaoguanli' />} />;
+      //           }
+      //           if (node.path == '/reportExport') {
+      //             node.icon = <Icon component={()=><IconFont type='icon-jixiaoguanli' />} />;
+      //           }
+      //           if (node.path == '/costLibraryManagement') {
+      //             node.icon = <Icon component={()=><IconFont type='icon-chengbenkuguanli' />} />;
+      //           }
+      //           if (node.path == '/static') {
+      //             node.icon = <Icon component={()=><IconFont type='icon-baobiaochaxun' />} />;
+      //           }
+      //         }
+      //         if (node.children) {
+      //           node.children.forEach((child: any) => addIconToPath(child, paths));
+      //         }
+      //       }
+
+      //       _menu.forEach((item: any) => {
+      //         addIconToPath(item, ['/home', '/baseInfoMana', '/costAccounting','/monthlyInfoSearch','/static','/reportExport','/costLibraryManagement','/baseSetting']);
+      //       });
+
+
+
+      //       return _menu
+      //     }
+      //   }
+
+      // },
+    },
+    onPageChange: () => { },
+    collapsedButtonRender: () => {
+      return (
+        <div style={{
+          position: 'absolute', zIndex: 10, right: 17, bottom: 12,
+          display: 'flex', justifyContent: 'center', alignItems: 'center',
+          cursor: 'pointer', width: 24, height: 24
+        }} onClick={
+          () => {
+            onCollapse(isCollapsed ? false : true);
+          }
+        }><IconFont className='menuCollapseIcon' type={isCollapsed ? 'icon-celanzhankai' : 'icon-celanshouqi'} /></div>
+      )
+    },
+    // collapsed: isCollapsed,
+    // fixSiderbar:false,
+    menuRender: (props: any) => {
+
+
+      const { location } = props;
+      const [menu, set_menu] = useState<any[]>([]);
+
+      const [slectedKey, set_slectedKey] = useState<string[]>([]);
+      const [openKeys, set_openKeys] = useState<string[]>([]);
+
+      // const currentSelectedItem = findItemByKey(menuData,location.pathname,'path');
 
-        colorMenuBackground: '#fff',
-        colorTextMenuActive: '#3376FE',
-        colorTextMenuSelected: '#3376FE',
-        colorTextMenuTitle: '#17181A',
-        colorTextMenu: '#17181A',
-        //colorBgMenuItemHover:'##f0f2f5',
-        colorBgMenuItemSelected: '#F2F6FF',
+      const menuClickHandle = (info: any) => {
+        const foundItem = findItemByKey(menu, info.key, 'key');
+        // console.log({foundItem,info});
+        if (foundItem) {
+          set_slectedKey([`${info.key}`]);
+          history.push(foundItem.path);
 
-        // colorBgMenuItemCollapsedHover:'#f0f2f5',
-        // //colorBgMenuItemCollapsedSelected:'blue'
+        }
 
       }
 
-    },
-    
-    siderWidth: 200,
-    menuProps: {
-      openKeys: [...openKeys],
-      selectedKeys: [...selectedKeys],
-      onSelect: ({ selectedKeys }: { selectedKeys: string[] }) => {
-        set_selectedKeys(selectedKeys);
-        localStorage.setItem('selectedKeys', JSON.stringify(selectedKeys));
-      },
-      onOpenChange: (keys: string[]) => {
-        set_openKeys([...keys]);
-        localStorage.setItem('openKeys', JSON.stringify(keys));
-      },
-    },
-    menu: {
-      locale: false,
-      request: async () => {
+      const onOpenChangeHandle = (openKeys: string[]) => {
+        set_openKeys(openKeys);
+      }
+
+      const getMenu = async () => {
         const userData = localStorage.getItem('userData');
         const currentSelectedTab = localStorage.getItem('currentSelectedTab');
         if (currentSelectedTab) {
@@ -382,21 +603,21 @@ 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);
               set_openKeys(_openKeys);
-              set_selectedKeys(_selectedKeys);
+              set_slectedKey(_selectedKeys);
             } else {
               if (data[0].children && data[0].children.length > 0) {
 
                 const childs = data[0].children;
                 set_openKeys([data[0].key]);
-                set_selectedKeys([childs[0].key]);
+                set_slectedKey([childs[0].key]);
                 localStorage.setItem('openKeys', JSON.stringify([data[0].key]));
                 localStorage.setItem('selectedKeys', JSON.stringify([childs[0].key]));
                 history.push(`${childs[0].path}`);
@@ -404,7 +625,7 @@ export const layout = ({ initialState, setInitialState }: { initialState: any, s
               } else {
                 if (data[0]) {
                   set_openKeys([data[0].key]);
-                  set_selectedKeys([data[0].key]);
+                  set_slectedKey([data[0].key]);
                   localStorage.setItem('openKeys', JSON.stringify([data[0].key]));
                   localStorage.setItem('selectedKeys', JSON.stringify([data[0].key]));
                   history.push(`${data[0].path}`);
@@ -448,33 +669,33 @@ export const layout = ({ initialState, setInitialState }: { initialState: any, s
             }
 
             const _menu = processMenu(data);
-            
+
             setInitialState((t: any) => ({ ...t, spacicalPageParamsType: _menu, memuData: data, userData: JSON.parse(userData as string) }));
 
 
             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') {
-                  
+
                   node.icon = <Icon component={setting} />;
                 }
                 if (node.path == '/monthlyInfoSearch') {
-                  node.icon = <Icon component={()=><IconFont type='icon-yueduxinxicaiji' />} />;
+                  node.icon = <Icon component={() => <IconFont type='icon-yueduxinxicaiji' />} />;
                 }
                 if (node.path == '/costAccounting') {
-                  node.icon = <Icon component={()=><IconFont type='icon-jixiaoguanli' />} />;
+                  node.icon = <Icon component={() => <IconFont type='icon-jixiaoguanli' />} />;
                 }
                 if (node.path == '/reportExport') {
-                  node.icon = <Icon component={()=><IconFont type='icon-jixiaoguanli' />} />;
+                  node.icon = <Icon component={() => <IconFont type='icon-jixiaoguanli' />} />;
                 }
                 if (node.path == '/costLibraryManagement') {
-                  node.icon = <Icon component={()=><IconFont type='icon-chengbenkuguanli' />} />;
+                  node.icon = <Icon component={() => <IconFont type='icon-chengbenkuguanli' />} />;
                 }
                 if (node.path == '/static') {
-                  node.icon = <Icon component={()=><IconFont type='icon-baobiaochaxun' />} />;
+                  node.icon = <Icon component={() => <IconFont type='icon-baobiaochaxun' />} />;
                 }
               }
               if (node.children) {
@@ -483,33 +704,63 @@ export const layout = ({ initialState, setInitialState }: { initialState: any, s
             }
 
             _menu.forEach((item: any) => {
-              addIconToPath(item, ['/home', '/baseInfoMana', '/costAccounting','/monthlyInfoSearch','/static','/reportExport','/costLibraryManagement','/baseSetting']);
+              addIconToPath(item, ['/home', '/baseInfoMana', '/costAccounting', '/monthlyInfoSearch', '/static', '/reportExport', '/costLibraryManagement', '/baseSetting']);
             });
 
+            const { newTree, firstLeafNode, firstLeafNodePath } = transformTree(_menu);
+            // set_openKeys(firstLeafNodePath.map(a => `${a.key}`));
+            // set_slectedKey([`${firstLeafNode.key}`]);
+            set_menu(newTree);
 
-
-            return _menu
           }
         }
+      }
+
+      useEffect(() => {
+
+        const foundItem = findItemByKey(menu, location.pathname, 'path');
+
+        if (foundItem) {
+          set_slectedKey(foundItem.key);
+
+        }
+
+      }, [menu]);
+
+      useEffect(() => {
+        getMenu();
+      }, [])
 
-      },
-    },
-    onPageChange: () => { },
-    collapsedButtonRender: () => {
       return (
-        <div style={{
-          position: 'absolute', zIndex: 10, right: 17, bottom: 12,
-          display: 'flex', justifyContent: 'center', alignItems: 'center',
-          cursor: 'pointer', width: 24, height: 24
-        }} onClick={
-          () => {
-            onCollapse(isCollapsed ? false : true);
-          }
-        }><IconFont className='menuCollapseIcon' type={isCollapsed ? 'icon-celanzhankai' : 'icon-celanshouqi'} /></div>
-      )
+        <ResizableContainer width={isCollapsed ? 64 : 200} minWidth={0} maxWidth={600} height={'calc(100vh - 58px)'}>
+          <div style={{ height: '100%', background: '#fff', position: 'relative' }}>
+            <div className='menuWrapper' style={{ height: 'calc(100% - 40px)', overflowY: 'scroll', overflowX: 'hidden' }}>
+              <Menu
+
+                onClick={menuClickHandle}
+                onOpenChange={onOpenChangeHandle}
+                style={{ width: '100%' }}
+                openKeys={openKeys}
+                selectedKeys={slectedKey}
+                mode="inline"
+                items={menu}
+                inlineCollapsed={isCollapsed}
+              />
+            </div>
+
+            <div style={{
+              position: 'absolute', zIndex: 10, right: 17, bottom: 9,
+              display: 'flex', justifyContent: 'center', alignItems: 'center',
+              cursor: 'pointer', width: 24, height: 24
+            }} onClick={
+              () => {
+                onCollapse(isCollapsed ? false : true);
+              }
+            }><IconFont className='menuCollapseIcon' type={isCollapsed ? 'icon-celanzhankai' : 'icon-celanshouqi'} /></div>
+          </div>
+        </ResizableContainer>
+      );
     },
-    collapsed: isCollapsed,
-    // fixSiderbar:false,
     contentStyle: {
       // border: '16px solid #F7F9FC',
       //height: '94.5vh',  //以去除顶部导航高度

+ 64 - 0
src/authWrapper.tsx

@@ -0,0 +1,64 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-07-17 10:36:43
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-07-18 16:44:36
+ * @FilePath: /BudgetManaSystem/src/authWrapper.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+// src/components/AuthWrapper.tsx
+import React, { useEffect, useState } from 'react';
+import { history, useModel } from 'umi';
+import type { IRoute } from 'umi';
+import { Outlet } from '@umijs/max';
+
+// 权限检查函数
+function checkAccess(menu: IRoute[], pathname: string): boolean {
+    for (const item of menu) {
+      if (item.path === pathname) {
+        return true;
+      }
+      if (item.children) {
+        const hasAccess = checkAccess(item.children, pathname);
+        if (hasAccess) {
+          return true;
+        }
+      }
+    }
+    return false;
+}
+
+function removePrefix(input: string, prefix: string): string {
+    if (input.startsWith(prefix)) {
+        return input.slice(prefix.length);
+    }
+    return input;
+}
+
+// 权限包装组件
+const AuthWrapper: React.FC = (props) => {
+  const { initialState } = useModel('@@initialState');
+  const [loading, setLoading] = useState(true);
+  const [dataLoaded, setDataLoaded] = useState(false);
+
+  useEffect(() => {
+    if (!dataLoaded) {
+      const menu = initialState?.memuData ?? [];
+      if (menu.length > 0) {
+          setDataLoaded(true);
+          const { pathname } = history.location;
+        const hasAccess = checkAccess(menu, removePrefix(pathname, '/CostAccountingSys'));
+      //   console.log({ hasAccess, menu, pathname });
+        if (!hasAccess) {
+          history.push('/noAccess');
+        }
+        setLoading(false);
+      }
+    }
+  }, [initialState,dataLoaded]);
+
+  return loading ? <>loading...</> : <Outlet />;
+};
+
+export default AuthWrapper;
+export { checkAccess };

+ 144 - 136
src/components/KCIMLeftList/index.tsx

@@ -2,14 +2,14 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2024-03-19 10:27:43
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-29 14:46:08
+ * @LastEditTime: 2024-06-05 15:20:23
  * @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 { 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';
@@ -27,88 +27,91 @@ const IconFont = createFromIconfontCN({
 
 
 interface ListItem {
-     name:string,
-     subText:string,
-     [key:string]:any
+    name: string,
+    subText: string,
+    [key: string]: any
 }
 
 interface TreeNodeItem {
-    [key:string]:any
+    [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
+    dataSource?: any[],
+    searchKey: string,
+    placeholder?: string,
+    listType?: 'list' | 'tree',
+    icon?: string,
+    contentH?: number|string,
+    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;
+function searchTreeAndKeepHierarchy(tree: any[], keyword: string, searchKey: string, children: string) {
+    function search(node: any) {
+        // 深度复制节点,避免修改原始树
+        let newNode = { ...node };
+        if (node[`${searchKey}`].includes(keyword)) {
+            // 如果节点名称包含关键字,返回整个节点及其子节点
+            return newNode;
+        } else if (node[`${children}`] && node[`${children}`].length > 0) {
+            // 如果当前节点不匹配但有子节点,递归搜索子节点
+            let filteredChildren = node[`${children}`].map(search).filter((child: any) => child !== null); // 递归并过滤掉null
+            if (filteredChildren.length > 0) {
+                // 如果有子节点匹配,只返回匹配的子节点
+                newNode[`${children}`] = filteredChildren;
+                return newNode;
+            }
         }
-      }
-      // 如果节点和其子节点都不匹配,返回null
-      return null;
+        // 如果节点和其子节点都不匹配,返回null
+        return null;
     }
-  
+
     // 对树的每个根节点进行搜索,并过滤掉不匹配的节点
     return tree.map(search).filter(node => node !== null);
-  }
+}
+
+
+
+const findFirstLeafNodeWithParents: any = (node: any, children: string) => {
+    // 定义一个内部递归函数来处理节点和跟踪父节点
+    const findNode: any = (currentNode: any, parents: any[]) => {
+        // 打印当前节点信息,用于调试
+        // console.log({ currentNode });
+
+        // 检查当前节点是否为叶子节点(无子节点或子节点为空数组)
+        if (!currentNode[children] || currentNode[children].length === 0) {
+            return { leafNode: currentNode, parents };
+        }
+
+        // 添加当前节点到父节点列表
+        parents.push(currentNode);
+
+        // 递归查找第一个子节点的第一个叶子节点
+        return findNode(currentNode[children][0], parents);
+    };
+
+    // 调用内部函数,初始父节点列表为空
+    return findNode(node, []);
+}
 
 
 
-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)=>{
+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 { 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 [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 [defaultSelectedKeys, set_defaultSelectedKeys] = useState<Key[]>([]);
 
 
 
@@ -116,106 +119,111 @@ export const KCIMLeftList = (props:KCIMLeftListProps)=>{
     const onSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
         // console.log('selected', selectedKeys, info);
         const { node } = info;
-        set_currentSelected(node);
+        if (!node[fieldNames.children as keyof typeof node] || (node[fieldNames.children as keyof typeof node] as any[]).length === 0) {
+            set_currentSelected(node);
+        }
+        
     };
 
     const onExpand = (newExpandedKeys: React.Key[]) => {
+        console.log({newExpandedKeys});
         setExpandedKeys(newExpandedKeys);
         setAutoExpandParent(false);
     };
-    
 
-    useEffect(()=>{
-        onChange&&onChange(currentSelected);
-    },[currentSelected])
 
-    useEffect(()=>{
-        if(showList.length>0){
-              if(listType =='list'){
+    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}`]]);
-              }
+            }
+            if (listType == 'tree') {
+                const result = findFirstLeafNodeWithParents(showList[0], fieldNames.children ? fieldNames.children : 'children');
+                // console.log({ result });
         
-        }else{
-              set_currentSelected(undefined);
+                setExpandedKeys([...(result.parents.map((parent:any) => parent[fieldNames.key as string]))]);
+                set_currentSelected(result.leafNode);
+                set_defaultSelectedKeys([result.leafNode[`${fieldNames.key}`]]);
+            }
+
+        } else {
+            set_currentSelected(undefined);
         }
-    },[showList]);
+    }, [showList]);
 
 
-    useEffect(()=>{
+    useEffect(() => {
         set_dataSource([...data]);
         set_showList([...data]);
-    },[data]);
-     
+    }, [data]);
+
 
     return (
         <div className="KCIMLeftList">
-              <div className='toolbar'>
-                    <Input placeholder={placeholder} allowClear
-                        suffix={
-                            <IconFont style={{color:'#99A6BF'}} type="iconsousuo" />
+            <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, searchKey, fieldNames.children as string);
+                            set_showList(result);
                         }
-                        // 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' /> */}
+
+                    }}
+
+                />
+                {/* <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='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>
+                            </div>
                         )
-                    }
-        
-                    {
-                     listType == 'tree'&&dataSource.length > 0 && currentSelected && defaultSelectedKeys.length>0&& (
+                    })
+                }
+
+                {
+                    (!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}
@@ -266,7 +274,7 @@ export const KCIMLeftList = (props:KCIMLeftListProps)=>{
                         />
                     )
                 }
-                </div>
+            </div>
 
         </div>
     )

+ 6 - 4
src/components/KCIMLeftList/style.less

@@ -3,8 +3,10 @@
 
 .KCIMLeftList {
     border-radius: 4px;
-    padding:8px 8px;
+    padding:8px 0;
     width: 100%;
+    height:100%;
+    overflow-y: hidden;
     // padding-top: 16px;
     // border: 1px solid #DAE2F2;
     .toolbar {
@@ -12,7 +14,7 @@
         flex-direction: row;
         justify-content: space-between;
         align-items: center;
-        padding: 0 8px;
+        padding: 0 16px;
   
         .add {
           cursor: pointer;
@@ -34,7 +36,6 @@
   
       .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;
@@ -45,7 +46,8 @@
             font-weight: bold;
         }
 
-        .DirectoryTree {
+        .KC-DirectoryTree {
+          padding: 0 16px;
           // .cost-ant-tree-treenode-selected {
           //      .cost-ant-tree-title {
           //         color:#17181A !important;

+ 19 - 24
src/components/KCIMTable/style.less

@@ -169,36 +169,31 @@
         &.cost-ant-table-bordered {
             .cost-ant-table-container {
                 border-left: none !important;
-                .cost-ant-table-header {
-                    table {
-                        border-top: none !important;
-                    }
-                    .cost-ant-table-thead {
-                        &>tr {
-                            &>th {
-                                border-right: 1px solid #dae2f2 !important;
-                                border-bottom: 1px solid #dae2f2 !important;
-                                border-top: none !important;
-    
-                                &.cost-ant-table-cell-scrollbar {
-                                    border: none !important;
-                                }
+                .cost-ant-table-thead {
+                    &>tr {
+                        &>th {
+                            border-right: 1px solid #dae2f2 !important;
+                            border-bottom: 1px solid #dae2f2 !important;
+                            border-top: none !important;
+
+                            &.cost-ant-table-cell-scrollbar {
+                                border: none !important;
+                            }
 
-                                &::after {
-                                    border: none !important;
-                                }
+                            &::after {
+                                border: none !important;
                             }
-    
-                            &:last-child {
-                                &>th {
-                                    border-top:none !important;
-                                }
+                        }
+
+                        &:last-child {
+                            &>th {
+                                border-top:none !important;
                             }
                         }
                     }
                 }
-                .cost-ant-table-body {
-                    table > tbody > tr > td {
+                .cost-ant-table-tbody{
+                    tr > td {
                         border-right: 1px solid #dae2f2 !important;
                         &::after {
                             border: none !important;

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

@@ -40,6 +40,7 @@ const KCIMUpload = (props: KCIMUploadPropsType) => {
         //onChange:onChange?onChange:()=>{},
         onChange: (fileInfo) => {
             onChange && onChange(fileInfo);
+            
         },
         onDrop(e) {
             console.log('Dropped files', e.dataTransfer.files);

+ 71 - 0
src/components/ResizableContainer/index.tsx

@@ -0,0 +1,71 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-05-16 10:57:51
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-06-07 17:17:38
+ * @FilePath: /BudgetManaSystem/src/components/ResizableContainer/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import React, { useState, useCallback, useEffect, useRef } from 'react';
+import './style.less';
+
+interface ResizableContainerProps {
+    width?: number;
+    minWidth?: number;
+    maxWidth?: number;
+    height?:string;
+}
+
+const ResizableContainer: React.FC<React.PropsWithChildren<ResizableContainerProps>> = ({
+    width = 250,
+    minWidth = 100,
+    maxWidth = 800,
+    height = '800px',
+    children,
+}) => {
+    const [containerWidth, setContainerWidth] = useState(width);
+    const isResizing = useRef(false);
+
+    const handleMouseMove = useCallback((e: MouseEvent) => {
+        if (isResizing.current) {
+            const newWidth = Math.min(Math.max(e.clientX, minWidth), maxWidth);
+            setContainerWidth(newWidth);
+        }
+    }, [minWidth, maxWidth]);
+
+    const handleMouseUp = useCallback(() => {
+        isResizing.current = false;
+        document.removeEventListener('mousemove', handleMouseMove);
+        document.removeEventListener('mouseup', handleMouseUp);
+        document.body.style.userSelect = 'auto'; // 恢复文本选择
+    }, [handleMouseMove]);
+
+    const handleMouseDown = useCallback(() => {
+        isResizing.current = true;
+        document.addEventListener('mousemove', handleMouseMove);
+        document.addEventListener('mouseup', handleMouseUp);
+        document.body.style.userSelect = 'none'; // 禁用文本选择
+    }, [handleMouseMove, handleMouseUp]);
+
+    useEffect(() => {
+        return () => {
+            document.removeEventListener('mousemove', handleMouseMove);
+            document.removeEventListener('mouseup', handleMouseUp);
+        };
+    }, [handleMouseMove, handleMouseUp]);
+
+    useEffect(() => {
+        setContainerWidth(width);
+    }, [width]);
+
+    return (
+        <div className="ResizableContainer">
+            <div className="resizable" style={{ width: `${containerWidth}px`, height: `${height}` }}>
+                {children}
+            </div>
+            <div className="resizer" onMouseDown={handleMouseDown} />
+        </div>
+    );
+};
+
+export default ResizableContainer;

+ 24 - 0
src/components/ResizableContainer/style.less

@@ -0,0 +1,24 @@
+
+
+.ResizableContainer {
+    position: relative;
+    height:100%;
+    .resizable {
+        height: 100%;
+        overflow: hidden;
+    }
+    
+    .resizer {
+        position: absolute;
+        z-index: 999;
+        right: 0;
+        top:0;
+        width: 5px;
+        height:90vh;
+        cursor: ew-resize;
+        background-color:transparent;
+    }
+   
+}
+
+

+ 1 - 0
src/global.less

@@ -619,6 +619,7 @@ textarea {
 
 .cost-ant-pro-layout .cost-ant-pro-layout-container {
     flex: 1;
+    overflow-y: scroll;
     background: #F7F9FC !important;
 }
 

+ 0 - 0
src/pages/404.tsx


+ 246 - 37
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: 2024-04-07 14:24:36
+ * @LastEditTime: 2024-05-28 15:45:55
  * @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,7 +15,7 @@ import { KCIMTable } from '@/components/KCIMTable';
 import { createFromIconfontCN } from '@ant-design/icons';
 
 
-import { ActionType, ProFormDependency, ProFormInstance, ProFormText, ProFormSelect } from '@ant-design/pro-components';
+import { ActionType, ProFormDependency, ProFormInstance, ProFormText, ProFormSelect, ProFormRadio } from '@ant-design/pro-components';
 import { ModalForm } from '@ant-design/pro-form'
 import { ProColumns } from '@ant-design/pro-table';
 import { Input, message, Popconfirm, Tag, Tabs } from 'antd';
@@ -26,7 +26,7 @@ import locale from 'antd/es/date-picker/locale/zh_CN';
 
 
 
-import { addData, delData, editData, getAccountingSubjectList } from './service';
+import { addData, delData, editData, getAccountingSubjectList, getAccountTypeDictReq } from './service';
 
 import './style.less';
 import { renameChildListToChildren } from '@/utils/tooljs';
@@ -36,14 +36,45 @@ const IconFont = createFromIconfontCN({
     scriptUrl: '',
 });
 
-let currentRow:any = undefined;
+let currentRow: any = undefined;
 
+ export const searchTree = (tree:any[], searchTerm:string) => {
+    const searchTermLower = searchTerm.toLowerCase();
 
+    function searchNode(node:any) {
+        const matchedChildren: any[] = [];
+
+        if (node.children && node.children.length > 0) {
+            node.children.forEach((child: any) => {
+                const matchedChild = searchNode(child);
+                if (matchedChild) {
+                    matchedChildren.push(matchedChild);
+                }
+            });
+        }
+
+        if (node.accountingName.toLowerCase().includes(searchTermLower) || node.accountingCode.toLowerCase().includes(searchTermLower)) {
+            return {
+                ...node,
+                children: matchedChildren.length > 0 ? matchedChildren : node.children
+            };
+        } else if (matchedChildren.length > 0) {
+            return {
+                ...node,
+                children: matchedChildren
+            };
+        }
+
+        return null;
+    }
+
+    return tree.map(rootNode => searchNode(rootNode)).filter(node => node !== null);
+ }
 
 
 export default function AccountingSubMana() {
 
-    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>({accountType:1});
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>({ accountType: 1 });
     const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
     const tableRef = useRef<ActionType>();
     const formRef = useRef<ProFormInstance>();
@@ -54,16 +85,54 @@ export default function AccountingSubMana() {
 
         {
             title: '会计科目名称',
+            width: 400,
+            ellipsis: true,
+            fixed: 'left',
             dataIndex: 'accountingName',
         },
         {
             title: '会计科目编码',
             dataIndex: 'accountingCode',
         },
+        {
+            title: '会计科目类别',
+            dataIndex: 'typeName',
+        },
+        {
+            title: '成本类别',
+            hideInTable: accountType == 1,
+            dataIndex: 'costType',
+            renderText(type) {
+                return type == 1 ? '医疗成本' : type == 2 ? '医疗全成本' : '医院全成本'
+            },
+        },
+        {
+            title: '成本属性',
+            hideInTable: accountType == 1,
+            dataIndex: 'isBaseCost',
+            renderText(type) {
+                return type == 1 ? '固定成本' : '变动成本'
+            },
+        },
+        {
+            title: '可控类型',
+            dataIndex: 'controlType',
+            renderText(type) {
+                return type == 1 ? '不可控' : '可控'
+            },
+        },
+        {
+            title: '诊别',
+            dataIndex: 'medicalType',
+            renderText(type) {
+                return type == 0 ? '全院' : type == 1 ? '门诊' : '住院'
+            },
+        },
         {
             title: '操作',
             key: 'option',
             width: 120,
+            fixed: 'right',
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [
@@ -84,10 +153,17 @@ export default function AccountingSubMana() {
 
 
     const getTableData = async (params: any) => {
-        const resp = await getAccountingSubjectList({ ...params,accountType });
+        const {filter} = params;
+        const resp = await getAccountingSubjectList({ ...params, accountType });
         if (resp) {
+            let data = [];
+            if(filter){
+                 data = searchTree(renameChildListToChildren(resp.list, 'child'),filter) 
+            }else{
+                data = renameChildListToChildren(resp.list, 'child')
+            }
             return {
-                data: renameChildListToChildren(resp.list,'child'),
+                data:data,
                 success: true,
                 total: resp.totalCount,
                 pageSize: resp.pageSize,
@@ -113,20 +189,20 @@ export default function AccountingSubMana() {
             let id = 0;
             (type == 'ADDCHILD') && (id = formVal.id);
 
-            const result = accountType == 1?{ ...formVal,accountingType:accountType, id: id}:{...formVal,accountingType:accountType, id: 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') {
             try {
-                const resp = await editData({ ...formVal,isIncomeGroutSetSelect:false,isShareParamSelect:false,accountType });
+                const resp = await editData({ ...formVal, isIncomeGroutSetSelect: false, isShareParamSelect: false, accountType });
                 if (resp) {
                     tableRef.current?.reload();
                     message.success('操作成功!');
@@ -150,17 +226,18 @@ export default function AccountingSubMana() {
                 formRef={formRef}
                 initialValues={type == 'EDIT' ? {
                     ...record
-                } : {}}
+                } : { controlType: 1, medicalType: 0 }}
                 trigger={
-                    type == 'EDIT' ? <a key="edit" >编辑</a> :type == 'ADDCHILD'?<a className='add'>添加</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 } :type == 'ADDCHILD'?{...val,id:record.id}:{ ...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='typeName' hidden />
                 <ProFormText
                     label="会计科目编码"
                     disabled={type == 'EDIT'}
@@ -186,30 +263,125 @@ export default function AccountingSubMana() {
                     {
                         ({ accountingCode }) => {
                             return accountType == 2 ? (
-                                <ProFormSelect
-                                    rules={[
-                                        {
-                                            required: true,
-                                            message: '',
-                                        },
-                                    ]}
-                                    options={[
-                                        {
-                                            value: 0,
-                                            label: '不是',
-                                        },
-                                        {
-                                            value: 1,
-                                            label: '是',
-                                        },
-                                    ]}
-                                    name="isBaseCost"
-                                    label="是否固定成本"
-                                />
+                                <>
+                                    <ProFormSelect
+                                        rules={[
+                                            {
+                                                required: true,
+                                                message: '',
+                                            },
+                                        ]}
+                                        options={[
+                                            {
+                                                value: 0,
+                                                label: '不是',
+                                            },
+                                            {
+                                                value: 1,
+                                                label: '是',
+                                            },
+                                        ]}
+                                        name="isBaseCost"
+                                        label="是否固定成本"
+                                    />
+                                    <ProFormRadio.Group
+                                        name="costType"
+                                        label="成本类别"
+                                        rules={[
+                                            {
+                                                required: true,
+                                                message: '成本类别是必填项',
+                                            },
+                                        ]}
+                                        options={[
+                                            {
+                                                label: '医疗成本',
+                                                value: 1,
+                                            },
+                                            {
+                                                label: '医疗全成本',
+                                                value: 2,
+                                            },
+                                            {
+                                                label: '医院全成本',
+                                                value: 3,
+                                            },
+                                        ]}
+                                    />
+                                </>
                             ) : <></>
                         }
                     }
                 </ProFormDependency>
+                <ProFormSelect
+                    rules={[
+                        {
+                            required: true,
+                            message: '请选择会计科目类别',
+                        },
+                    ]}
+                    request={async () => {
+                        const resp = await getAccountTypeDictReq(accountType as number);
+                        if (resp) {
+                            return resp.map((a: any) => ({ label: a.name, value: a.code }))
+                        }
+                        return []
+
+                    }}
+                    fieldProps={{
+                        onChange(value, option: any) {
+                            const { label } = option;
+                            formRef.current?.setFieldValue('typeName', label);
+                        },
+                    }}
+                    name="type"
+                    label="会计科目类别"
+                />
+                <ProFormRadio.Group
+                    name="controlType"
+                    label="可控类型"
+                    rules={[
+                        {
+                            required: true,
+                            message: '可控类型是必填项',
+                        },
+                    ]}
+                    options={[
+                        {
+                            label: '不可控',
+                            value: 1,
+                        },
+                        {
+                            label: '可控',
+                            value: 2,
+                        },
+                    ]}
+                />
+                <ProFormRadio.Group
+                    name="medicalType"
+                    label="就诊类别"
+                    rules={[
+                        {
+                            required: true,
+                            message: '就诊类别是必填项',
+                        },
+                    ]}
+                    options={[
+                        {
+                            label: '全院',
+                            value: 0,
+                        },
+                        {
+                            label: '门诊',
+                            value: 1,
+                        },
+                        {
+                            label: '住院',
+                            value: 3,
+                        },
+                    ]}
+                />
+
             </ModalForm>
         )
     }
@@ -219,6 +391,15 @@ export default function AccountingSubMana() {
         tableRef.current?.reload();
     }
 
+    const tableDataSearchHandle = (paramName: string) => {
+
+        set_tableDataFilterParams({
+            ...tableDataFilterParams,
+            [`${paramName}`]: tableDataSearchKeywords
+        })
+
+    }
+
     useEffect(() => {
         set_tabs([
             {
@@ -234,20 +415,48 @@ export default function AccountingSubMana() {
 
     return (
         <KCIMPagecontainer className='AccountingSubMana' title={false}>
-            <div className='toolBar' style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
+            <div className='toolBar' >
                 <Tabs
                     defaultActiveKey={tabs.length > 0 ? tabs[0].key : undefined}
                     items={tabs}
                     key={'key'}
                     onChange={(key) => onTabChanged(key)}
                 />
-                <div className='btnGroup'>
-                    <UpDataActBtn record type='ADD' />
+                <div className='filter' style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center',marginBottom:16 }}>
+                    <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 className='btnGroup'>
+                        <UpDataActBtn record type='ADD' />
+                    </div>
                 </div>
+
             </div>
 
             <div>
-                <KCIMTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+                <KCIMTable columns={columns as ProColumns[]} scroll={{ y: 'calc(100vh - 270px)' }} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
             </div>
         </KCIMPagecontainer>
     )

+ 9 - 1
src/pages/baseSetting/accountingAccountSet/accountingSubMana/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 17:20:53
+ * @LastEditTime: 2024-05-17 11:09:19
  * @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
  */
@@ -59,6 +59,14 @@ export const delData = (id:string) => {
   });
 };
 
+//获取会计科目类别字典 
+export const getAccountTypeDictReq = (type:number) => {
+  return request('/costAccount/accounting/getAccountTypeDict', {
+    method: 'GET',
+    params:{type}
+  });
+};
+
 
 
 

+ 4 - 4
src/pages/baseSetting/accountingAccountSet/accountingSubMana/style.less

@@ -6,10 +6,10 @@
 
 
   .toolBar {
-    display: flex;
-    flex-direction: row;
-    justify-content: space-between;
-    align-items: center;
+    // display: flex;
+    // flex-direction: row;
+    // justify-content: space-between;
+    // align-items: center;
 
     .filter {
       display: flex;

+ 98 - 9
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: 2024-01-05 13:36:31
+ * @LastEditTime: 2024-07-19 13:27:55
  * @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
  */
@@ -31,6 +31,7 @@ import { getAccountProductConnectableList, getAccountProductConnectList, saveAcc
 import './style.less';
 import TableSelecter from '@/components/KCIMTableSelector';
 import { renameChildListToChildren } from '@/utils/tooljs';
+import { searchTree } from '../accountingSubMana';
 
 
 const IconFont = createFromIconfontCN({
@@ -66,7 +67,8 @@ export default function AccountingSubMap() {
 
         {
             title: '会计科目名称',
-            width:200,
+            width: 400,
+            ellipsis: true,
             dataIndex: 'accountingName',
         },
         {
@@ -75,7 +77,7 @@ export default function AccountingSubMap() {
             dataIndex: 'accountingCode',
         },
         {
-            title: '成本列表',
+            title: '收入项目',
             dataIndex: 'productVOs',
             renderText(productVOs, record) {
                 if (Array.isArray(productVOs)) {
@@ -107,13 +109,67 @@ export default function AccountingSubMap() {
         },
 
     ]
+    const columnsTwo: ProColumns[] = [
+
+        {
+            title: '会计科目名称',
+            width: 400,
+            ellipsis: true,
+            dataIndex: 'accountingName',
+        },
+        {
+            title: '会计科目编码',
+            width:120,
+            dataIndex: 'accountingCode',
+        },
+        {
+            title: '成本项目',
+            dataIndex: 'productVOs',
+            renderText(productVOs, record) {
+                if (Array.isArray(productVOs)) {
+                    return productVOs.map((item, index) => { return <Tag key={index}>{item.productName}</Tag> })
+                } else {
+                    return <></>
+                }
+            },
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 80,
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                const { isParent } = record;
+                return !isParent ? [
+                  <a
+                    key="config"
+                    onClick={() => {
+                      currentRow = record;
+                      set_tableSelecterVisible(true);
+                    }}
+                  >
+                    设置对应
+                  </a>,
+                ] : []
+            },
+        },
+
+    ]
+
 
 
     const getTableData = async (params: any) => {
+        const {filter} = params;
         const resp = await getAccountProductConnectList({ ...params, accountType });
         if (resp) {
+            let data = [];
+            if(filter){
+                 data = searchTree(renameChildListToChildren(resp.list, 'child'),filter) 
+            }else{
+                data = renameChildListToChildren(resp.list, 'child')
+            }
             return {
-                data: renameChildListToChildren(resp.list,'child'),
+                data: data,
                 success: true,
                 total: resp.totalCount,
                 pageSize: resp.pageSize,
@@ -150,6 +206,15 @@ export default function AccountingSubMap() {
         }
     }
 
+    const tableDataSearchHandle = (paramName: string) => {
+
+        set_tableDataFilterParams({
+            ...tableDataFilterParams,
+            [`${paramName}`]: tableDataSearchKeywords
+        })
+
+    }
+
     useEffect(() => {
         set_tabs([
             {
@@ -176,20 +241,44 @@ export default function AccountingSubMap() {
                 open={tableSelecterVisible}
                 onFinish={(keys, rows) => tableSelecterCommit(keys, rows)}
             />
-            <div className='toolBar' style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
+            <div className='toolBar' >
                 <Tabs
                     defaultActiveKey={tabs.length > 0 ? tabs[0].key : undefined}
                     items={tabs}
                     key={'key'}
                     onChange={(key) => onTabChanged(key)}
                 />
-                {/* <div className='btnGroup'>
-                    <UpDataActBtn record type='ADD' />
-                </div> */}
+               <div className='filter' style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
+                    <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>
 
             <div>
-                <KCIMTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+                <KCIMTable columns={(accountType == 1?columns:columnsTwo) as ProColumns[]} scroll={{ y: 'calc(100vh - 230px)' }} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
             </div>
         </KCIMPagecontainer>
     )

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

@@ -48,6 +48,10 @@ const EditTableModal = ({ record, open, title, onVisibleChange, rowKey = 'id', o
                      return []
                 },
                 fieldProps:{
+                    showSearch:true,
+                    style: {
+                        width: '160px', // 设置你想要的宽度
+                    },
                     onSelect:(a: any,b: any,c:any)=>{
                         currentSelectedRow = b;
                     }
@@ -120,7 +124,7 @@ const EditTableModal = ({ record, open, title, onVisibleChange, rowKey = 'id', o
                     }
                     editable={{
                         onSave: async (rowKey, data, row) => {
-                            console.log({rowKey, data, row,currentSelectedRow,datasource});                        
+                            // console.log({rowKey, data, row,currentSelectedRow,datasource});                        
                            
                             const {index} = data;
           

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

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-29 14:41:03
+ * @LastEditTime: 2024-06-11 11:09: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
  */
@@ -491,7 +491,7 @@ export default function CostAllocationParamsDeal(
             </div>
 
             <div>
-                <KCIMTable  columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+                <KCIMTable scroll={{y:`calc(100vh - 343px)`}}  columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
             </div>
         </KCIMPagecontainer>
     )

+ 1 - 1
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: 2024-01-05 13:46:21
+ * @LastEditTime: 2024-07-19 10:35:08
  * @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
  */

+ 31 - 4
src/pages/baseSetting/costAllocationSet/idleCostSetting/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-04-09 13:36:13
+ * @LastEditTime: 2024-04-26 11:31:57
  * @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,7 +26,7 @@ import locale from 'antd/es/date-picker/locale/zh_CN';
 
 
 
-import { addData, delData, editData, getAccountList, getIdleCostTableList, getShareParamList } from './service';
+import { addData, delData, editData, getAccountList, getIdleCostTableList, getIdleResponsibleList, getShareParamList } from './service';
 
 import './style.less';
 import { getAccountingSubjectList } from '../../accountingAccountSet/accountingSubMana/service';
@@ -94,6 +94,10 @@ export default function IdleCostSetting() {
             title: '实际检查时间参数',
             dataIndex: 'actualParamName',
         },
+        {
+            title: '归属责任中心',
+            dataIndex: 'freeResponsibilityName',
+        },
         {
             title: '操作',
             key: 'option',
@@ -151,7 +155,7 @@ export default function IdleCostSetting() {
 
     const updateTable = async (formVal: any, type: 'EDIT' | "ADD") => {
     
-        const { freeAccount = [], account, canParam, actualParam } = formVal;
+        const { freeAccount = [], account, canParam, actualParam,freeResponsibility } = formVal;
             const result = {
                 freeAccountCode: freeAccount.accountingCode,
                 freeAccountName: freeAccount.accountingName,
@@ -161,6 +165,8 @@ export default function IdleCostSetting() {
                 canParamName: canParam.shareParamName,
                 actualParamCode: actualParam.shareParamCode,
                 actualParamName: actualParam.shareParamName,
+                freeResponsibilityName:freeResponsibility.responsibilityName,
+                freeResponsibilityCode:freeResponsibility.responsibilityCode,
             };
 
         if (type == 'ADD') {
@@ -201,7 +207,8 @@ export default function IdleCostSetting() {
                     freeAccount:record.freeAccountCode,
                     account:record.accountCode,
                     canParam: record.canParamCode,
-                    actualParam: record.actualParamCode
+                    actualParam: record.actualParamCode,
+                    freeResponsibility:record.freeResponsibilityCode
                 } : {}}
                 trigger={
                     type == 'EDIT' ? <a key="edit" >编辑</a> : <span className='add'>新增</span>
@@ -340,6 +347,26 @@ export default function IdleCostSetting() {
                     name="actualParam"
                     label="实际检查时间参数"
                 />
+                <ProFormSelect
+                    rules={[
+                        {
+                            required: true,
+                            message: '请选择归属责任中心',
+                        },
+                    ]}
+                    request={async () => {
+                        const resp = await getIdleResponsibleList({ pageSize: 500, current: 1 });
+                        return resp
+                    }}
+
+                    fieldProps={{
+                        labelInValue: true,
+                        showSearch: true,
+                        fieldNames: { label: 'responsibilityName', value: 'responsibilityCode' },
+                    }}
+                    name="freeResponsibility"
+                    label="归属责任中心"
+                />
 
             </ModalForm>
         )

+ 9 - 1
src/pages/baseSetting/costAllocationSet/idleCostSetting/service.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 16:31:27
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-04-07 15:31:38
+ * @LastEditTime: 2024-04-26 11:31:11
  * @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
  */
@@ -37,6 +37,14 @@ export const getShareParamList = (params:any) => {
   });
 }
 
+//获取闲置责任中心
+export const getIdleResponsibleList = (params:any) => {
+  return request('/costAccount/freeCost/getResponsibilityList', {
+    method: 'GET',
+    params:{...params},
+  });
+}
+
 
 
 //新增

+ 592 - 0
src/pages/baseSetting/otherItemSet/departmentCostCalc/index.tsx

@@ -0,0 +1,592 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 11:30:33
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-07-12 15:53:48
+ * @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 } from '@ant-design/pro-form'
+import { ProColumns } from '@ant-design/pro-table';
+import { Modal, message, Drawer, Tabs, Input, DatePicker } from 'antd';
+import { Key, useEffect, useRef, useState } from 'react';
+import * as XLSX from 'xlsx';
+import { saveAs } from 'file-saver';
+import moment from 'moment';
+import 'moment/locale/zh-cn';
+import locale from 'antd/es/date-picker/locale/zh_CN';
+
+
+
+import { addData, computeProfitReq, copyDataToSelectedType, delData, editData, getReportDataReq, getReportProjectSettingList, getResponsibleCenters, saveReportRelation } from './service';
+
+import './style.less';
+import TableTransfer from './transform';
+import React from 'react';
+import { cleanTree, getStringWidth } from '@/utils/tooljs';
+import { getDicDataBySysId } from '@/services/getDic';
+import { KCIMLeftList } from '@/components/KCIMLeftList';
+import { formatMoneyNumber } from '@/utils/format';
+
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+let currentRow: any = undefined;
+
+function findAllParents(tree: any[]) {
+    let parents: any[] = [];
+    // 递归函数来遍历树并找到所有父节点
+    function traverse(nodes: any[]) {
+        for (const node of nodes) {
+            // 检查节点是否有子节点
+            if (node.children && node.children.length > 0) {
+                parents.push(node); // 添加到父节点列表
+                traverse(node.children); // 递归遍历子节点
+            }
+        }
+    }
+
+    traverse(tree); // 开始遍历树
+    return parents; // 返回所有父节点的数组
+}
+
+
+function searchTree(tree: any[], searchTerm: string) {
+    // 定义结果数组
+    let results = [];
+
+    // 定义递归函数来搜索匹配的节点
+    function searchNode(node: any) {
+        // 创建一个变量来标记当前节点或其子节点是否匹配
+        let isMatch = false;
+
+        // 检查当前节点的 name 或 code 是否包含搜索词
+        if (node.reportName.includes(searchTerm)) {
+            isMatch = true;
+        }
+
+        // 复制当前节点,避免修改原始数据
+        let newNode = { ...node, children: [] };
+
+        // 如果有子节点,递归搜索每个子节点
+        if (node.children) {
+            for (let child of node.children) {
+                let childMatch = searchNode(child);
+                // 如果子节点或其子树匹配,添加到新节点的子节点数组中
+                if (childMatch) {
+                    newNode.children.push(childMatch);
+                    isMatch = true;
+                }
+            }
+        }
+
+        // 如果当前节点或其任何子节点匹配,返回新节点
+        // 如果children为空,则不包含children属性
+        if (isMatch) {
+            if (newNode.children.length === 0) {
+                delete newNode.children;
+            }
+            return newNode;
+        } else {
+            return null;
+        }
+    }
+
+    // 遍历树的每个顶级节点
+    for (let node of tree) {
+        let result = searchNode(node);
+        if (result) {
+            results.push(result);
+        }
+    }
+
+    return results;
+}
+
+function processTree(originalData: any[]) {
+    return originalData.map(node => {
+        // 深复制当前节点
+        const newNode = JSON.parse(JSON.stringify(node));
+
+        // 如果当前节点有profitList,处理它
+        if (newNode.profitList && Array.isArray(newNode.profitList)) {
+            newNode.profitList.forEach((profit: any) => {
+                // 添加新的键值对到新节点
+                newNode[`${profit.reportId}`] = formatMoneyNumber(profit.value);
+            });
+            // 如果不需要保留profitList,可以删除
+            // delete newNode.profitList;
+        }
+
+        // 如果节点有子节点,递归处理子节点
+        if (node.child && Array.isArray(node.child)) {
+            newNode.children = processTree(node.child);
+        }
+
+        return newNode;
+    });
+}
+
+// 递归函数,用于处理多层级标题
+function generateColumns(item: any, titleIndex = 0) {
+    const column: any = {
+        title: item.reportName,
+        dataIndex: `${item.reportId}`,
+        key: `${item.reportId}`,
+        align: 'center',
+
+    };
+
+    if (item.childTitle && Array.isArray(item.childTitle) && item.childTitle.length > 0) {
+        column.children = item.childTitle.map((a: any, aindex: number) => generateColumns(a, titleIndex + 1));
+    }
+
+    return column;
+}
+
+// 主函数,生成表格列
+const generateTableColumns = (title: any[]) => {
+    return title.map((item: any, titleIndex: number) => generateColumns(item, titleIndex));
+};
+
+
+export default function DepartmentCostCalc() {
+
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>({ reportType: 0 });
+    const tableRef = useRef<ActionType>();
+    const formRef = useRef<ProFormInstance>();
+    const [tabs, set_tabs] = useState<any[]>([]);
+
+    const [computeDate, set_computeDate] = useState<string>(`${new Date().getFullYear()}-${(new Date().getMonth() + 1).toString().padStart(2, '0')}`);
+    const [responsibleCenters, set_responsibleCenters] = useState<any[]>([]);
+    const [currentTabKey, set_currentTabKey] = useState<any | undefined>(undefined);
+    const [currentTab, set_currentTab] = useState<any | undefined>(undefined);
+    const [currentSelectedRespon, set_currentSelectedRespon] = useState<any | undefined>(undefined);
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState('');
+    const [allParentsKeys, set_allParentsKeys] = useState<Key[]>([]);
+    const [drawerTableVisible, set_drawerTableVisible] = useState(false);
+    const [dataSource, set_dataSource] = useState<any[]>([]);
+    const [tableColumns, set_tableColumns] = useState<any[]>([]);
+    const columns: ProColumns[] = [
+
+        {
+            title: '报表项目名称',
+            dataIndex: 'reportName',
+            width: '50%'
+        },
+        {
+            title: '金额(元)',
+            dataIndex: 'amount',
+            renderText(num) {
+                return formatMoneyNumber(num);
+            },
+        },
+        {
+            title: '占比',
+            dataIndex: 'percent',
+            renderText(num) {
+                return `${((num * 100).toFixed(2)).replace(/(\.\d*?)0+$/, '$1').replace(/\.$/, '')}%`
+            },
+        },
+    ]
+
+
+    const getTableData = async (params: any) => {
+        const { responsibilityCode, filter = undefined } = params;
+        if (!responsibilityCode) return []
+        const resp = await getReportProjectSettingList({ ...params });
+
+        if (resp) {
+            if (filter) {
+                const filterData = searchTree(resp, filter);
+                const allParents = findAllParents(filterData);
+
+                set_allParentsKeys([...(allParents.map((a: any) => a.id))])
+                return {
+                    data: filterData,
+                    success: true,
+                }
+            }
+            const allParents = findAllParents(resp);
+            set_allParentsKeys([...(allParents.map((a: any) => a.id))])
+            return {
+                data: resp,
+                success: true,
+            }
+        }
+        return []
+    }
+
+
+
+
+    const onTabChanged = (key: Key) => {
+        set_currentTabKey(key);
+        const needItem = tabs.filter((a) => a.key == key);
+        if (needItem.length > 0) set_currentTab(needItem[0])
+    }
+
+    const getTabs = async () => {
+
+        const { systemId } = JSON.parse((localStorage.getItem('currentSelectedTab')) as string)
+        const resp = await getDicDataBySysId(systemId, 'PROFIT_REPORT_TYPE');
+        if (resp) {
+            const { dataVoList } = resp;
+            const tempArr = dataVoList.map((a: any) => ({ label: a.name, key: Number(a.code), value: a.value }));
+            const arr = (tempArr.filter((a: any) => a.value != '2'));
+            set_tabs([...arr]);
+            set_currentTabKey(arr[0].key);
+            set_currentTab(arr[0]);
+        }
+    }
+
+    const getResponsibleCenterList = async (reportType: string) => {
+        const resp = await getResponsibleCenters(reportType);
+        if (resp) {
+            set_responsibleCenters(resp);
+        }
+    }
+
+    const onLeftChange = (currentSelected: any) => {
+        set_currentSelectedRespon(currentSelected);
+    }
+
+    const tableDataSearchHandle = (paramName: string) => {
+
+        set_tableDataFilterParams({
+            ...tableDataFilterParams,
+            [`${paramName}`]: tableDataSearchKeywords
+        })
+    }
+
+    const computeProfitHandle = async () => {
+
+        Modal.confirm({
+            title: '注意',
+            content: '计算操作会覆盖当月已计算的数据,是否继续操作?',
+            okText: '确定',
+            cancelText: '取消',
+            onOk: async (...args) => {
+
+                const resp = await computeProfitReq(computeDate, currentTabKey);
+                if (resp) {
+                    message.success('操作成功!');
+                    tableRef.current?.reload();
+                }
+            },
+        })
+    }
+
+    const openTableDataDrawer = async () => {
+        const resp = await getReportDataReq(currentTabKey, computeDate);
+        if (resp) {
+            const { title = [], data = [] } = resp;
+            const defaultColumns = [{
+                title: '科室名称',
+                dataIndex: 'responsibilityName',
+                key: 'responsibilityName',
+                width: 220,
+                fixed: 'left'
+            }];
+
+            const tableColumns = generateTableColumns(title);
+
+            const dataSource = processTree(data);
+            set_tableColumns([...defaultColumns, ...tableColumns]);
+
+            set_dataSource(dataSource);
+            set_drawerTableVisible(true);
+            console.log({ columns: [...defaultColumns, ...tableColumns], dataSource })
+
+        }
+
+    }
+
+
+const getHeaderRows = (columns: any[], level = 0, headerRows:any[] = [], maxLevel = 0) => {
+    headerRows[level] = headerRows[level] || [];
+    columns.forEach((col: { title: any; children: any; }) => {
+        const colSpan = getColSpan(col);
+        headerRows[level].push({ title: col.title, colSpan, rowSpan: col.children ? 1 : maxLevel - level });
+        if (col.children) {
+            getHeaderRows(col.children, level + 1, headerRows, maxLevel);
+        } else {
+            // 填充空白单元格
+            for (let i = level + 1; i < maxLevel; i++) {
+                headerRows[i] = headerRows[i] || [];
+                headerRows[i].push({ title: '', colSpan: 1, rowSpan: 1 });
+            }
+        }
+    });
+    return headerRows;
+};
+
+const getColSpan:any = (col: { children: any[]; }) => {
+    if (!col.children) return 1;
+    return col.children.reduce((sum, child) => sum + getColSpan(child), 0);
+};
+
+const getMaxLevel = (col: any) => {
+    if (!col.children) return 1;
+    return 1 + Math.max(...col.children.map(getMaxLevel));
+};
+
+const extractLeafColumns = (columns: any[]) => {
+    let leafColumns: any[] = [];
+    columns.forEach(col => {
+        if (col.children) {
+            leafColumns = leafColumns.concat(extractLeafColumns(col.children));
+        } else {
+            leafColumns.push(col);
+        }
+    });
+    return leafColumns;
+};
+
+const addRowWithIndentation = (record: any, level: number, leafColumns: any[], worksheetData: any[]) => {
+    const row = leafColumns.map(col => record[col.dataIndex] ?? '');
+    row[0] = ' '.repeat(level * 4) + row[0]; // 在第一列前添加缩进空格以表示层级
+    worksheetData.push(row);
+    if (record.children) {
+        record.children.forEach((child: any) => addRowWithIndentation(child, level + 1, leafColumns, worksheetData));
+    }
+};
+
+const handleExport = () => {
+    try {
+        const workbook = XLSX.utils.book_new();
+        const worksheetData: any[] = [];
+
+        // 获取最大层级
+        const maxLevel = tableColumns.reduce((max, col) => Math.max(max, getMaxLevel(col)), 0);
+
+        // 生成多层级表头
+        const headerRows = getHeaderRows(tableColumns, 0, [], maxLevel);
+
+        // 构建表头行
+        headerRows.forEach((row: any, rowIndex) => {
+            const rowData: string[] = [];
+            row.forEach((cell: { title: any; colSpan: number; rowSpan: number; }) => {
+                rowData.push(cell.title);
+                for (let i = 1; i < cell.colSpan; i++) {
+                    rowData.push('');
+                }
+            });
+            worksheetData.push(rowData);
+        });
+
+        // 填充单层表头的空白行
+        if (maxLevel > 1) {
+            const numColumns = headerRows[0].reduce((sum: any, cell: { colSpan: any; }) => sum + cell.colSpan, 0);
+            for (let i = 1; i < maxLevel; i++) {
+                while (worksheetData[i].length < numColumns) {
+                    worksheetData[i].push('');
+                }
+            }
+        }
+
+        // 提取最内层表头列
+        const leafColumns = extractLeafColumns(tableColumns);
+
+        // 添加数据并处理树结构
+        dataSource.forEach(record => addRowWithIndentation(record, 0, leafColumns, worksheetData));
+
+        const worksheet = XLSX.utils.aoa_to_sheet(worksheetData);
+
+        // 初始化合并单元格数组
+        worksheet['!merges'] = worksheet['!merges'] || [];
+
+        // 合并单元格
+        headerRows.forEach((row: any, rowIndex) => {
+            let colIndex = 0;
+            row.forEach((cell: { colSpan: number; rowSpan: number; }) => {
+                if (cell.colSpan > 1 || cell.rowSpan > 1) {
+                    worksheet['!merges'].push({
+                        s: { r: rowIndex, c: colIndex },
+                        e: { r: rowIndex + cell.rowSpan - 1, c: colIndex + cell.colSpan - 1 }
+                    });
+                }
+                colIndex += cell.colSpan;
+            });
+        });
+
+        // 设置单元格对齐方式
+        Object.keys(worksheet).forEach(cell => {
+            if (cell[0] !== '!') {
+                worksheet[cell].s = {
+                    alignment: { vertical: 'center', horizontal: 'center' }
+                };
+            }
+        });
+
+        XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
+
+        const wbout = XLSX.write(workbook, { bookType: 'xlsx', type: 'binary' });
+        const s2ab = (s: string) => {
+            const buf = new ArrayBuffer(s.length);
+            const view = new Uint8Array(buf);
+            for (let i = 0; i < s.length; i++) view[i] = s.charCodeAt(i) & 0xFF;
+            return buf;
+        };
+
+        saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), currentTab ? `${currentTab.label}.xlsx` : 'table_data.xlsx');
+    } catch (error) {
+        console.error('Export failed:', error);
+    }
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    useEffect(() => {
+        if (computeDate && currentTabKey != undefined) {
+            getResponsibleCenterList(currentTabKey);
+        }
+    }, [computeDate, currentTabKey]);
+
+    useEffect(() => {
+        if (currentSelectedRespon) {
+            set_tableDataFilterParams({
+                ...tableDataFilterParams,
+                responsibilityCode: currentSelectedRespon.responsibilityCode,
+                reportType: currentTabKey,
+                computeDate: computeDate
+            })
+        }
+    }, [currentSelectedRespon])
+
+
+    useEffect(() => {
+        getTabs();
+    }, [])
+
+    return (
+        <KCIMPagecontainer className='DepartmentCostCalc' title={false}>
+
+            <Drawer className='drawerTable' contentWrapperStyle={{}} bodyStyle={{ padding: 16 }} title={false} open={drawerTableVisible} width={1000} headerStyle={{ display: 'none' }}>
+                <div className='header'>
+                    <div className='title'>{currentTab ? currentTab.label : ''}(单位:元)</div>
+                    <div className='btns'>
+                        <span onClick={() => handleExport()}>导出</span>
+                        <span onClick={() => set_drawerTableVisible(false)}>关闭</span>
+                    </div>
+                </div>
+                {dataSource.length > 0 ? <KCIMTable expandable={{ defaultExpandAllRows: true }} className='departmentCostCalcReportTable' dataSource={dataSource} bordered pagination={false} scroll={{ x: 6000, y: '65vh' }} columns={tableColumns as ProColumns[]} rowKey='responsibilityCode' /> : <></>}
+            </Drawer>
+
+            <div className='header'>
+                <div className="search">
+                    <span>核算年月:</span>
+                    <DatePicker
+                        onChange={(data, dateString) => {
+                            set_computeDate(dateString);
+                            set_tableDataFilterParams({
+                                ...tableDataFilterParams,
+                                computeDate: dateString,
+                            });
+                        }}
+                        picker="month"
+                        locale={locale}
+                        defaultValue={moment(computeDate, 'YYYY-MM')}
+                        format="YYYY-MM"
+                        placeholder="选择年月"
+                    />
+                </div>
+            </div>
+            <div className='content'>
+                <Tabs
+                    defaultActiveKey={tabs.length > 0 ? tabs[0].key : undefined}
+                    items={tabs}
+                    key={'key'}
+                    onChange={(key) => onTabChanged(key)}
+                />
+                <div className='inner'>
+                    <div className='left'>
+                        <KCIMLeftList
+                            fieldNames={{ title: 'responsibilityName', key: 'responsibilityCode', children: 'children' }}
+                            rowKey={'responsibilityCode'}
+                            dataSource={responsibleCenters} searchKey={'responsibilityName'}
+                            onChange={onLeftChange}
+                            contentH={`100%`}
+                            // placeholder={leftListSearchPlaceHolder} 
+                            listType={'tree'}
+
+                        />
+                    </div>
+                    <div className='right'>
+                        <div className='toolBar'>
+                            <div className='filterItem' style={{ width: 228 }}>
+                                <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 className='btnGroup'>
+                                <span className='btn' onClick={() => openTableDataDrawer()}>报表数据</span>
+                                <span className='calc' onClick={() => computeProfitHandle()}>计算</span>
+                            </div>
+                        </div>
+                        <KCIMTable pagination={false} expandable={{
+                            defaultExpandAllRows: true, expandedRowKeys: allParentsKeys,
+                            onExpand(expanded, record) {
+                                const { id } = record;
+                                if (!expanded) {
+                                    const expandedKeys = allParentsKeys.filter(a => a != id);
+                                    set_allParentsKeys([...expandedKeys]);
+                                } else {
+                                    set_allParentsKeys([...allParentsKeys, id]);
+                                }
+                            },
+                        }} columns={columns as ProColumns[]} scroll={{ y: `calc(100vh - 300px)` }} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+                    </div>
+                </div>
+
+
+            </div>
+        </KCIMPagecontainer>
+    )
+}

+ 130 - 0
src/pages/baseSetting/otherItemSet/departmentCostCalc/service.ts

@@ -0,0 +1,130 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 16:31:27
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-04-24 14:49:44
+ * @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/costdepartmentprofit/getComputeProfitList', {
+    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},
+  });
+}
+
+//获取执行责任中心
+export const getResponsibleCenters = (reportType:string) => {
+  return request('/costAccount/costdepartmentprofit/getProfitResponsibility', {
+    method: 'GET',
+    params:{reportType}
+  });
+}
+
+
+//获取报表数据
+export const getReportDataReq = (reportType:string,computeDate:string) => {
+  return request('/costAccount/costdepartmentprofit/computeProfitReport', {
+    method: 'GET',
+    params:{reportType,computeDate}
+  });
+}
+
+//损益计算
+
+export const computeProfitReq = (computeDate:string,reportType:string) => {
+  return request('/costAccount/costdepartmentprofit/computeProfit', {
+    method: 'POST',
+    params: {computeDate,reportType},
+  });
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 113 - 0
src/pages/baseSetting/otherItemSet/departmentCostCalc/style.less

@@ -0,0 +1,113 @@
+.drawerTable {
+  .header {
+    display: flex;
+    width: 100%;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 16px;
+
+    .title {
+      font-weight: 500;
+      font-size: 16px;
+      color: #17181A;
+    }
+    .btns {
+      span {
+        display: inline-block;
+        cursor: pointer;
+        padding: 0 14px;
+        height: 24px;
+        line-height: 24px;
+        background: #FAFCFF;
+        border-radius: 4px;
+        font-weight: 400;
+        font-size: 14px;
+        color: #17181A;
+        border: 1px solid #DAE2F2;
+      }
+    }
+  }
+}
+
+.DepartmentCostCalc {
+  background: #FFFFFF;
+  border-radius: 4px;
+
+  .header {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    border-radius: 4px;
+    padding: 16px;
+    background-color: #fff;
+    border-bottom: 16px solid #F7F9FC;
+  }
+
+  .content {
+    padding: 16px;
+    padding-top: 0;
+
+    .inner {
+      display: flex;
+      width: 100%;
+      flex-direction: row;
+      justify-content: flex-start;
+      align-items: flex-start;
+
+      .left {
+        width: 220px;
+        height: calc(734px - 44px);
+
+        border-radius: 4px;
+        padding-top: 16px;
+        margin-right: 16px;
+        border: 1px solid #DAE2F2;
+
+      }
+
+      .right {
+        width: calc(100% - 236px);
+
+        .toolBar {
+          display: flex;
+          flex-direction: row;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 12px;
+
+          .filterItem {
+            display: flex;
+            flex-direction: row;
+            justify-content: center;
+            align-items: center;
+          }
+
+          .btnGroup {
+            &>span {
+              cursor: pointer;
+              display: inline-block;
+              color: #17181A;
+              line-height: 24px;
+              padding: 0 14px;
+              border-radius: 4px;
+              border: 1px solid #DAE2F2;
+              background: #FAFCFF;
+              margin-right: 8px;
+              font-weight: 400;
+              font-size: 14px;
+              color: #17181A;
+
+              &.calc {
+                color: #fff;
+                background: #3377FF;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+}

+ 301 - 0
src/pages/baseSetting/otherItemSet/departmentCostCalc/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
+
+

+ 63 - 66
src/pages/baseSetting/otherItemSet/diySqlMana/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-22 11:34:26
+ * @LastEditTime: 2024-04-12 11:19:08
  * @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
  */
@@ -20,7 +20,7 @@ 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 { Input, message, Popconfirm, Switch } from 'antd';
 import { useEffect, useRef, useState } from 'react';
 import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
 
@@ -41,7 +41,7 @@ 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 [showList, set_showList] = useState<any[]>([]);
 
     const SortableItem = SortableElement((props: any) => <tr {...props} />);
     const SortContainer = SortableContainer((props: any) => <tbody {...props} />);
@@ -63,7 +63,7 @@ export default function DiySqlMana() {
         },
         {
             title: 'SQL代码',
-            width:150,
+            width: 150,
             ellipsis: true,
             dataIndex: 'sqlCode',
         },
@@ -80,18 +80,18 @@ export default function DiySqlMana() {
         },
         {
             title: '启用',
-            width:80,
+            width: 80,
             dataIndex: 'status',
             renderText: (_: any, record: any) => {
 
-                return <Switch size='small' checked={_?true:false} onChange={(bool) => switchChangeHandle(bool, record, 'status')} />
+                return <Switch size='small' checked={_ ? true : false} onChange={(bool) => switchChangeHandle(bool, record, 'status')} />
             }
         },
         {
             title: '操作',
             key: 'option',
             width: 120,
-            fixed:'right',
+            fixed: 'right',
             valueType: 'option',
             render: (_: any, record: any) => {
                 return [
@@ -123,7 +123,7 @@ export default function DiySqlMana() {
         const resp = await delData(record.id);
         if (resp) {
             message.success('操作成功!');
-            getTableData({sqlType:currentSelectedType.code});
+            getTableData({ sqlType: currentSelectedType.code });
             // message.success('操作成功!');
         }
     }
@@ -138,45 +138,45 @@ export default function DiySqlMana() {
         });
 
         set_dataSource([...newData]);
-        updateTable({...record, [`${key}`]: checked ? 1 : 0 }, 'EDIT')
+        updateTable({ ...record, [`${key}`]: checked ? 1 : 0 }, 'EDIT')
     }
 
-    const updateTable = async (formVal: any, type: 'EDIT' |'ADD'|'ADD_NEXT') => {
+    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
+                sqlType: currentSelectedType.code,
+                sort: dataSource.length + 1,
+                status: 1
             });
             if (resp) {
-                
-                getTableData({sqlType:currentSelectedType.code});
+
+                getTableData({ sqlType: currentSelectedType.code });
                 message.success('操作成功!');
             }
 
         }
         if (type == 'ADD_NEXT') {
-            const {sort} = formVal;
+            const { sort } = formVal;
 
             const temp = [...dataSource];
 
-            const index = temp.findIndex(a=>a.sort == sort);
+            const index = temp.findIndex(a => a.sort == sort);
 
-            const objectToInsert =  {
+            const objectToInsert = {
                 sqlCode: formVal.sqlCode,
                 sql: formVal.sql,
                 sqlDefinition: formVal.sqlDefinition,
-                sqlType:currentSelectedType.code,
-                status:1
+                sqlType: currentSelectedType.code,
+                status: 1
             }
-        
-            temp.splice(index+1,0, objectToInsert);
-            const arr = temp.map((a,index)=>({...a,sort:index+1}));
-  
+
+            temp.splice(index + 1, 0, objectToInsert);
+            const arr = temp.map((a, index) => ({ ...a, sort: index + 1 }));
+
             updateTableSortHandle(arr);
 
 
@@ -189,10 +189,10 @@ export default function DiySqlMana() {
                 sqlDefinition: formVal.sqlDefinition,
                 sqlType: formVal.sqlType,
                 sort: formVal.sort,
-                status:formVal.status
+                status: formVal.status
             });
             if (resp) {
-                getTableData({sqlType:currentSelectedType.code});
+                getTableData({ sqlType: currentSelectedType.code });
                 message.success('操作成功!');
             }
         }
@@ -202,46 +202,43 @@ export default function DiySqlMana() {
 
     const formRef = useRef();
 
-    const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD'|'ADD_NEXT' }) => {
+    const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD' | 'ADD_NEXT' }) => {
 
         return (
             <ModalForm
-                title={`${type == 'EDIT' ? '编辑' : type == 'ADD_NEXT'?'插入':'新增'}自定义SQL`}
-                width={880}
+                title={`${type == 'EDIT' ? '编辑' : type == 'ADD_NEXT' ? '插入' : '新增'}自定义SQL`}
+                width={1200}
                 formRef={formRef}
                 initialValues={type == 'EDIT' ? { ...record } : {}}
                 trigger={
-                    type == 'EDIT' ? <a key="edit" >编辑</a> :type == 'ADD_NEXT'?<a>插入</a>: <span className='add'>新增</span>
+                    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);
+                    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 className='formContent' style={{ display: 'flex', width: '100%', flexDirection: 'row', alignContent: 'flex-start', overflow: 'hidden' }}>
+                    <div className='left' style={{ width: 240, minWidth: 240, marginRight: 16 ,marginBottom:'-15px'}}>
+                        <ProFormText
+                            name="sqlCode"
+                            label="SQL代码:"
+                            placeholder="请输入"
+                            disabled={type == 'EDIT'}
+                            rules={[{ required: true, message: 'SQL代码不能为空!' }]}
+                        />
+                        <ProFormTextArea  fieldProps={{rows:18}} placeholder="请输入" name={'sqlDefinition'} label='SQL说明:' rules={[{ required: true, message: '说明不能为空!' }]} />
                     </div>
-                    <div className='right' style={{ width: 'calc(880px - 288px)' }}>
+                    <div className='right' style={{ width: 'calc(1200px - 288px)', marginBottom: '-15px' }}>
                         {/* <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'}
+                            height={'435px'}
                         />
                     </div>
                 </div>
@@ -249,8 +246,8 @@ export default function DiySqlMana() {
         )
     }
 
-    const tableDataSearchHandle = (key:string) => {
-        const result = dataSource.filter((a)=>a.sqlDefinition.indexOf(tableDataSearchKeywords) != -1);
+    const tableDataSearchHandle = (key: string) => {
+        const result = dataSource.filter((a) => a.sqlDefinition.indexOf(tableDataSearchKeywords) != -1);
         set_showList(result);
     }
 
@@ -262,11 +259,11 @@ export default function DiySqlMana() {
         }
     }
 
-    const updateTableSortHandle = async (data:any[]) => {
-          const resp = await updateTableSort(data);
-          if(resp){
-            getTableData({sqlType:currentSelectedType.code});
-          }
+    const updateTableSortHandle = async (data: any[]) => {
+        const resp = await updateTableSort(data);
+        if (resp) {
+            getTableData({ sqlType: currentSelectedType.code });
+        }
     }
 
     const onSortEnd = useRefFunction(
@@ -278,7 +275,7 @@ export default function DiySqlMana() {
                     toIndex: newIndex,
                 }).filter((el) => !!el);
 
-                const updatedSortArr = newData.map((item: any, index: number) => ({ ...item, sort: index+1 }))
+                const updatedSortArr = newData.map((item: any, index: number) => ({ ...item, sort: index + 1 }))
                 set_dataSource([...updatedSortArr]);
                 updateTableSortHandle(updatedSortArr);
             }
@@ -304,18 +301,18 @@ export default function DiySqlMana() {
         return <SortableItem index={index} {...restProps} />;
     };
 
-    
-    useEffect(()=>{
-         if(showTypeListArr.length>0){
-              set_currentSelectedType(showTypeListArr[0]);
-         }
-    },[showTypeListArr]);
 
-    useEffect(()=>{
-           if(currentSelectedType){
-               getTableData({sqlType:currentSelectedType.code});
-           }
-    },[currentSelectedType]);
+    useEffect(() => {
+        if (showTypeListArr.length > 0) {
+            set_currentSelectedType(showTypeListArr[0]);
+        }
+    }, [showTypeListArr]);
+
+    useEffect(() => {
+        if (currentSelectedType) {
+            getTableData({ sqlType: currentSelectedType.code });
+        }
+    }, [currentSelectedType]);
 
 
     useEffect(() => {
@@ -396,7 +393,7 @@ export default function DiySqlMana() {
                                     set_tableDataSearchKeywords(e.target.value);
                                     if (e.target.value.length == 0) {
                                         set_tableDataSearchKeywords('');
-                                        getTableData({sqlType:currentSelectedType.code});
+                                        getTableData({ sqlType: currentSelectedType.code });
                                     }
                                 }}
 

+ 28 - 34
src/pages/baseSetting/otherItemSet/reportItemSet/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-02-23 14:56:00
+ * @LastEditTime: 2024-06-21 10:32:54
  * @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
  */
@@ -32,6 +32,7 @@ import './style.less';
 import TableTransfer from './transform';
 import React from 'react';
 import { cleanTree } from '@/utils/tooljs';
+import { getDicDataBySysId } from '@/services/getDic';
 
 
 
@@ -117,9 +118,8 @@ export default function ReportItemSet() {
     const tableRef = useRef<ActionType>();
     const formRef = useRef<ProFormInstance>();
     const [tabs, set_tabs] = useState<any[]>([]);
-    const [reportType, set_reportType] = useState<Key>(0);
+    const [reportType, set_reportType] = useState<Key|undefined>(undefined);
     const columns: ProColumns[] = [
-
         {
             title: '报表项目名',
             dataIndex: 'reportName',
@@ -212,11 +212,11 @@ export default function ReportItemSet() {
             dataIndex: 'sort',
             width: 80
         },
-        {
-            title: '比率基数',
-            width: 80,
-            dataIndex: 'ratioBase',
-        },
+        // {
+        //     title: '比率基数',
+        //     width: 80,
+        //     dataIndex: 'ratioBase',
+        // },
         {
             title: '操作',
             key: 'option',
@@ -270,7 +270,9 @@ export default function ReportItemSet() {
 
 
     const getTableData = async (params: any) => {
-        const resp = await getReportProjectSettingList({ ...params, reportType });
+        const {reportType} = params;
+        if(reportType == undefined)return []
+        const resp = await getReportProjectSettingList({ ...params });
         if (resp) {
             return {
                 data: cleanTree(resp.list),
@@ -331,13 +333,13 @@ export default function ReportItemSet() {
         Modal.confirm({
             title: settingType == 1 ? `选择会计科目` : settingType == 2 ? '选择分摊层级' : '选择责任中心',
             icon: <></>,
-            width: 750,
+            width: 1000,
             centered: true,
             okText: '确定',
             cancelText: '取消',
             content: <TableTransfer
                 ref={ref}
-                keyName="id"
+                keyName={settingType == 1 ? `accountingCode` : settingType == 2 ? 'id' : 'responsibilityCode'}
                 record={record}
                 settingType={settingType}                                                                                                                                                                                                             
                 onSave={(keys, rows, settingType) => onSaveHandle(keys, rows, record, settingType)}
@@ -360,8 +362,6 @@ export default function ReportItemSet() {
 
             (type == 'ADDCHILD') && (parentId = formVal.id);
 
-            console.log({formVal});
-
             const result = {
                 ...formVal,
                 calcType,
@@ -551,16 +551,7 @@ export default function ReportItemSet() {
                             name="toReportType"
                             label="复制到"
                             width="sm"
-                            options={[
-                                {
-                                    label: '损益表',
-                                    value: 0,
-                                },
-                                {
-                                    label: '全院损益表',
-                                    value: 3,
-                                }
-                            ]}
+                            options={tabs.map((a)=>({label:a.label,value:a.key}))}
                             placeholder="请选择"
                             rules={[{ required: true, message: '请选择复制到目标!' }]}
                         />
@@ -572,23 +563,26 @@ export default function ReportItemSet() {
 
     const onTabChanged = (key: Key) => {
         set_reportType(key);
-        tableRef.current?.reload();
+        set_tableDataFilterParams({...tableDataFilterParams,reportType:key})
+    }
+
+    const getTabs = async ()=>{
+          
+          const {systemId} = JSON.parse((localStorage.getItem('currentSelectedTab')) as string)
+          const resp = await getDicDataBySysId(systemId,'PROFIT_REPORT_TYPE');
+          if(resp){
+              const {dataVoList} = resp;
+              set_tabs(dataVoList.map((a:any)=>({label:a.name,key:Number(a.code)})));
+              set_tableDataFilterParams({...tableDataFilterParams,reportType:dataVoList.length>0?dataVoList[0].code:undefined});
+              set_reportType(dataVoList.length>0?dataVoList[0].code:undefined);
+          }
     }
 
 
 
 
     useEffect(() => {
-        set_tabs([
-            {
-                label: '损益表',
-                key: 0,
-            },
-            {
-                label: '全院损益表',
-                key: 3,
-            }
-        ])
+        getTabs();
     }, [])
 
     return (

+ 6 - 5
src/pages/baseSetting/otherItemSet/reportItemSet/transform.tsx

@@ -107,9 +107,10 @@ const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, keyName, re
                 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)
+                    // console.log(flattenTreeData(resp.list));
+                    const hasSelectedRows = flattenTreeData(resp.list,'children').filter((a: any) => hasSelectedKeys.includes(a.accountingCode));
+                    const selectedKeys = hasSelectedRows.map((a: any) => a.accountingCode);
+                    // console.log({hasSelectedRows,hasSelectedKeys,a:flattenTreeData(resp.list,'children')});
                     // setSelectedKeys(selectedKeys);
                     setTargetKeys(selectedKeys);
                 }
@@ -142,8 +143,8 @@ const TableTransfer = React.forwardRef(({ leftColumns, rightColumns, keyName, re
                 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)
+                    const hasSelectedRows = flattenTreeData(resp.list,'child').filter((a: any) => hasSelectedKeys.includes(a.responsibilityCode));
+                    const selectedKeys = hasSelectedRows.map((a: any) => a.responsibilityCode)
                     // setSelectedKeys(selectedKeys);
                     setTargetKeys(selectedKeys);
                 }

+ 223 - 68
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: 2024-03-08 11:06:30
+ * @LastEditTime: 2024-06-19 10:51: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
  */
@@ -26,7 +26,7 @@ import locale from 'antd/es/date-picker/locale/zh_CN';
 
 
 
-import { addData, delData, editData, getApportionmentLevelListNoPage, getResponsibilityCenterList } from './service';
+import { addData, delData, editData, getApportionmentLevelListNoPage, getResponsibilityCenterList, getResponsibilityTypeReq, getStandardShareLevelReq } from './service';
 
 import './style.less';
 import KCIMUpload from '@/components/KCIMUpload';
@@ -37,8 +37,42 @@ const IconFont = createFromIconfontCN({
     scriptUrl: '',
 });
 
-let selectableLevelList:any[] = [];
-let currentRow:any = undefined;
+let selectableLevelList: any[] = [];
+let currentRow: any = undefined;
+
+export const searchTree = (tree: any[], searchTerm: string) => {
+    const searchTermLower = searchTerm.toLowerCase();
+
+    function searchNode(node: any) {
+        const matchedChildren: any[] = [];
+
+        if (node.children && node.children.length > 0) {
+            node.children.forEach((child: any) => {
+                const matchedChild = searchNode(child);
+                if (matchedChild) {
+                    matchedChildren.push(matchedChild);
+                }
+            });
+        }
+
+        if (node.responsibilityName.toLowerCase().includes(searchTermLower) || (node.responsibilityCode && node.responsibilityCode.toLowerCase().includes(searchTermLower))) {
+            return {
+                ...node,
+                children: matchedChildren.length > 0 ? matchedChildren : node.children
+            };
+        } else if (matchedChildren.length > 0) {
+            return {
+                ...node,
+                children: matchedChildren
+            };
+        }
+
+        return null;
+    }
+
+    return tree.map(rootNode => searchNode(rootNode)).filter(node => node !== null);
+}
+
 
 export default function ResponsibilityCenter() {
 
@@ -52,6 +86,7 @@ export default function ResponsibilityCenter() {
             title: '责任中心名称',
             dataIndex: 'responsibilityName',
             ellipsis: true,
+            width: 200,
             renderText(_, record) {
                 const { isDefault, responsibilityName } = record;
                 return isDefault == 1 ? <Tag>{`${responsibilityName}(是)`}</Tag> : responsibilityName
@@ -74,18 +109,65 @@ export default function ResponsibilityCenter() {
             ellipsis: true,
             dataIndex: 'responsibilityType',
             renderText(num, record) {
-                  return num == 1?'收益中心':num == 2?'成本(费用)中心':'半收益中心'
+                if (record.isGatherCenter != 1) {
+                    return num == 1 ? '收益中心' : num == 2 ? '成本(费用)中心' : '半收益中心'
+                } else {
+                    return '-'
+                }
+
             },
         },
         {
             title: '分摊级别',
             ellipsis: true,
             dataIndex: 'shareLevel',
+            renderText(num, record) {
+                if (record.isGatherCenter != 1) {
+                    return num
+                } else {
+                    return '-'
+                }
+
+            },
         },
         {
             title: '分摊级别名称',
             ellipsis: true,
             dataIndex: 'shareName',
+            renderText(name, record) {
+                if (record.isGatherCenter != 1) {
+                    return name
+                } else {
+                    return '-'
+                }
+
+            },
+        },
+        {
+            title: '标准分级',
+            ellipsis: true,
+            dataIndex: 'standardShareLevelName',
+            renderText(name, record) {
+                if (record.isGatherCenter != 1) {
+                    return name
+                } else {
+                    return '-'
+                }
+
+            },
+        },
+        {
+            title: '责任中心类型',
+            ellipsis: true,
+            dataIndex: 'typeName',
+            renderText(name, record) {
+                if (record.isGatherCenter != 1) {
+                    return name
+                } else {
+                    return '-'
+                }
+
+            },
         },
         {
             title: '操作',
@@ -93,10 +175,10 @@ export default function ResponsibilityCenter() {
             width: 120,
             valueType: 'option',
             render: (_: any, record: any) => {
-                const {isGatherCenter} = record;
-                return isGatherCenter == 1?[
+                const { isGatherCenter } = record;
+                return isGatherCenter == 1 ? [
                     <UpDataActBtn key={'act'} record={record} type='ADDCHILD' />,
-                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
+                    <UpDataActBtn key={'act1'} record={record} type='EDIT' />,
                     <Popconfirm
                         title="是否确认删除?"
                         key="del"
@@ -104,8 +186,8 @@ export default function ResponsibilityCenter() {
                     >
                         <a>删除</a>
                     </Popconfirm>,
-                ]:[
-                    <UpDataActBtn key={'act'} record={record} type='EDIT' />,
+                ] : [
+                    <UpDataActBtn key={'act2'} record={record} type='EDIT' />,
                     <Popconfirm
                         title="是否确认删除?"
                         key="del"
@@ -121,10 +203,20 @@ export default function ResponsibilityCenter() {
 
 
     const getTableData = async (params: any) => {
+        const { filter } = params;
         const resp = await getResponsibilityCenterList({ ...params });
         if (resp) {
+            let data = [];
+
+            if (filter) {
+                const result = searchTree(renameChildListToChildren(resp.list, 'child'), filter);
+                data = result
+            } else {
+                data = renameChildListToChildren(resp.list, 'child')
+            }
+
             return {
-                data: renameChildListToChildren(resp.list,'child'),
+                data: data,
                 success: true,
                 total: resp.totalCount,
                 pageSize: resp.pageSize,
@@ -144,6 +236,7 @@ export default function ResponsibilityCenter() {
     }
 
     const updateTable = async (formVal: any, type: 'EDIT' | "ADD" | "ADDCHILD") => {
+  
 
         if (type == 'ADD' || type == 'ADDCHILD') {
 
@@ -152,7 +245,7 @@ export default function ResponsibilityCenter() {
 
             const { isDefault = 0, selectedSharelevel } = formVal;
 
-            const result = { ...formVal, shareName: selectedSharelevel ? selectedSharelevel.shareName : '', shareId: selectedSharelevel ? selectedSharelevel.id : 0, shareLevel: selectedSharelevel ? selectedSharelevel.leverSort : 0, isDefault, id,selectedSharelevel:null };
+            const result = {responsibilityType:1,...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) {
@@ -167,13 +260,13 @@ export default function ResponsibilityCenter() {
                 let body = {};
                 if (!selectedSharelevel) {
                     //没有修改分摊层级
-                    body = { ...formVal }
+                    body = {responsibilityType:1, ...formVal }
                 }
 
                 if (Object.prototype.toString.call(selectedSharelevel) == '[object Object]') {
                     //修改了分摊层级
                     //  console.log('修改了分摊层级');
-                    body = { ...formVal, shareId: selectedSharelevel.id, shareName: selectedSharelevel.shareName, shareLevel: selectedSharelevel.leverSort,selectedSharelevel:null }
+                    body = {responsibilityType:1, ...formVal, shareId: selectedSharelevel.id, shareName: selectedSharelevel.shareName, shareLevel: selectedSharelevel.leverSort, selectedSharelevel: null }
                 }
 
                 const resp = await editData({ ...body });
@@ -202,10 +295,10 @@ export default function ResponsibilityCenter() {
                     ...record,
                 } : { selectedSharelevel: 0 }}
                 trigger={
-                    type == 'EDIT' ? <a key="edit" >编辑</a> : type == 'ADDCHILD'?<a className='add'>添加</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 } :type == 'ADDCHILD'?{...val,id:record.id}:{ ...val }, type);
+                    return updateTable(type == 'EDIT' ? { ...record, ...val } : type == 'ADDCHILD' ? { ...val, id: record.id } : { ...val }, type);
                 }}
                 modalProps={{ destroyOnClose: true }}
                 colProps={{ span: 24 }}
@@ -286,62 +379,100 @@ export default function ResponsibilityCenter() {
                         }
                     }
                 </ProFormDependency>
-                <ProFormSelect
-                    rules={[
-                        {
-                            required: true,
-                            message: '请选择责任类型',
-                        },
-                    ]}
-                    options={[
-                        {
-                            value: 1,
-                            label: '收益中心',
-                        },
-                        {
-                            value: 2,
-                            label: '成本(费用)中心',
-                        },
-                        {
-                            value: 3,
-                            label: '半收益中心',
-                        },
-                    ]}
-                    name="responsibilityType"
-                    label="选择责任类型"
-                />
+
                 <ProFormDependency name={['isGatherCenter']}>
                     {
                         ({ isGatherCenter }) => {
                             return isGatherCenter != 1 && (
-                                <ProFormSelect
-                                    rules={[
-                                        {
-                                            required: true,
-                                            message: '请选择分摊级别',
-                                        },
-                                    ]}
-                                    fieldProps={{
-                                        onChange: (val) => {
-                                            // console.log({val});
-                                            const needItem = selectableLevelList.filter((item: any) => item.id == val);
-                                            if (formRef.current) {
-                                                formRef.current.setFieldsValue({ selectedSharelevel: needItem[0] })
+                                <>
+                                    <ProFormSelect
+                                        rules={[
+                                            {
+                                                required: true,
+                                                message: '请选择责任类别',
+                                            },
+                                        ]}
+                                        options={[
+                                            {
+                                                value: 1,
+                                                label: '收益中心',
+                                            },
+                                            {
+                                                value: 2,
+                                                label: '成本(费用)中心',
+                                            },
+                                            {
+                                                value: 3,
+                                                label: '半收益中心',
+                                            },
+                                        ]}
+                                        name="responsibilityType"
+                                        label="选择责任类别"
+                                    />
+                                    <ProFormSelect
+                                        rules={[
+                                            {
+                                                required: true,
+                                                message: '请选择分摊级别',
+                                            },
+                                        ]}
+                                        fieldProps={{   
+                                            onChange: (val) => {
+                                                const needItem = selectableLevelList.filter((item: any) => item.leverSort == val);
+                                                console.log({needItem});
+                                                if (formRef.current) {
+                                                    formRef.current.setFieldsValue({ selectedSharelevel: needItem[0] })
+                                                }
+                                            },
+                                        }}
+                                        request={async () => {
+                                            const resp = await getApportionmentLevelListNoPage();
+                                            if (resp) {
+                                                selectableLevelList = resp.list;
+                                                return resp.list.map((item: any) => ({ label: `级别${item.leverSort}-${item.shareName}`, value: item.leverSort }))
+                                            } else {
+                                                return []
+                                            }
+                                        }}
+                                        name='shareLevel'
+                                        label="选择分摊级别"
+                                    />
+                                    <ProFormSelect
+                                        rules={[
+                                            {
+                                                required: true,
+                                                message: '请选择标准分级',
+                                            },
+                                        ]}
+                                        request={async () => {
+                                            const resp = await getStandardShareLevelReq();
+                                            if (resp) {
+                                                return resp.map((a: any) => ({ label: a.name, value: a.code }))
                                             }
-                                        },
-                                    }}
-                                    request={async () => {
-                                        const resp = await getApportionmentLevelListNoPage();
-                                        if (resp) {
-                                            selectableLevelList = resp.list;
-                                            return resp.list.map((item: any) => ({ label: `级别${item.leverSort}-${item.shareName}`, value: item.id }))
-                                        } else {
                                             return []
-                                        }
-                                    }}
-                                    name='shareLevel'
-                                    label="选择分摊级别"
-                                />
+                                        }}
+                                        name="standardShareLevel"
+                                        label="标准分级"
+                                    />
+                                    <ProFormSelect
+                                        rules={[
+                                            {
+                                                required: true,
+                                                message: '请选择责任中心类型',
+                                            },
+                                        ]}
+                                        request={async () => {
+                                            const resp = await getResponsibilityTypeReq();
+                                            if (resp) {
+                                                return resp.map((a: any) => ({ label: a.name, value: a.code }))
+                                            }
+                                            return []
+                                        }}
+                                        name="type"
+                                        label="责任中心类型"
+                                    />
+                                </>
+
                             )
                         }
                     }
@@ -368,7 +499,31 @@ export default function ResponsibilityCenter() {
         <KCIMPagecontainer className='ResponsibilityCenter' 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' />
@@ -376,7 +531,7 @@ export default function ResponsibilityCenter() {
             </div>
 
             <div style={{ marginTop: 16 }}>
-                <KCIMTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+                <KCIMTable columns={columns as ProColumns[]} scroll={{ y: 'calc(100vh - 232px)' }} actionRef={tableRef} rowKey='responsibilityCode' params={tableDataFilterParams} request={(params) => getTableData(params)} />
             </div>
         </KCIMPagecontainer>
     )

+ 15 - 1
src/pages/baseSetting/responsibilityCenterSet/responsibilityCenter/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-09 18:59:56
+ * @LastEditTime: 2024-05-17 13:57:28
  * @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
  */
@@ -30,6 +30,20 @@ export const getApportionmentLevelListNoPage = () => {
   });
 }
 
+//获取标准分摊层级
+export const getStandardShareLevelReq = () => {
+  return request('/costAccount/responsibility/getStandardShareLevel', {
+    method: 'GET',
+  });
+}
+
+//获取责任中心类型
+export const getResponsibilityTypeReq = () => {
+  return request('/costAccount/responsibility/getResponsibilityType', {
+    method: 'GET',
+  });
+}
+
 
 //新增
 export type AddTableDataType = {

+ 50 - 7
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: 2024-01-05 13:33:39
+ * @LastEditTime: 2024-05-28 15:58: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
  */
@@ -33,6 +33,7 @@ import KCIMUpload from '@/components/KCIMUpload';
 import { downloadTemplateReq, renameChildListToChildren } from '@/utils/tooljs';
 import React from 'react';
 import TableTransfer from './transform';
+import { searchTree } from '../responsibilityCenter';
 
 
 const IconFont = createFromIconfontCN({
@@ -52,7 +53,7 @@ const transferTableColumn:ProColumns[] = [
         ellipsis: true,
         dataIndex: 'departmentName',
         renderText(text, record) {
-            return `${text}(${record.departmentCode})`
+            return record.departmentCode?`${text}(${record.departmentCode})`:text
         },
     },
 ]
@@ -72,7 +73,7 @@ export default function ResponsibilityCenterConnect() {
             title: '责任中心名称',
             dataIndex: 'responsibilityName',
             ellipsis: true,
-            width:120,
+            width:200,
             renderText(_,record) {
                 const { isDefault, responsibilityName } = record;
                 return isDefault == 1 ? <Tag>{`${responsibilityName}(是)`}</Tag> : responsibilityName
@@ -122,10 +123,18 @@ export default function ResponsibilityCenterConnect() {
 
 
     const getTableData = async (params: any) => {
+        const {filter} = params;
         const resp = await getResponsibilityCenterConnectList({...params});
         if (resp) {
+            let data = [];
+            if(filter){
+                const result = searchTree(renameChildListToChildren(resp.list, 'child'),filter);
+                data = result
+            }else{
+                data = renameChildListToChildren(resp.list, 'child')
+            }
             return {
-                data:renameChildListToChildren(resp.list,'child'),
+                data:data,
                 success: true,
                 total: resp.totalCount,
                 pageSize: resp.pageSize,
@@ -169,6 +178,15 @@ export default function ResponsibilityCenterConnect() {
         })
     }
 
+    const tableDataSearchHandle = (paramName: string) => {
+
+        set_tableDataFilterParams({
+            ...tableDataFilterParams,
+            [`${paramName}`]: tableDataSearchKeywords
+        })
+
+    }
+
 
 
     useEffect(() => {
@@ -177,15 +195,40 @@ export default function ResponsibilityCenterConnect() {
 
     return (
         <KCIMPagecontainer className='ResponsibilityCenterConnect' title={false}>
-            <div className='toolBar'>
-                <div className='filter'>
+            <div className='toolBar' style={{marginBottom:16}}>
+            <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'>
                 </div>
             </div>
 
             <div style={{ }}>
-                <KCIMTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='responsibilityId' params={tableDataFilterParams} request={(params) => getTableData(params)} />
+                <KCIMTable columns={columns as ProColumns[]} scroll={{y:'calc(100vh - 232px)'}} actionRef={tableRef} rowKey='responsibilityId' params={tableDataFilterParams} request={(params) => getTableData(params)} />
             </div>
         </KCIMPagecontainer>
     )

+ 48 - 48
src/pages/costAccounting/calcPageTemplate/columns.tsx

@@ -982,51 +982,51 @@ export const wholeHospOperatingReport: ProColumns[] = [
 ];
 
 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',
-    }
-];
+// 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',
+//     }
+// ];

+ 98 - 2
src/pages/costAccounting/calcPageTemplate/config.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-11-01 11:13:38
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-01-17 15:11:17
+ * @LastEditTime: 2024-06-28 14:29:20
  * @FilePath: /CostAccountingSys/src/pages/costAccounting/calcPageTemplate/config.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -306,7 +306,103 @@ export const projectCostCalcFilterConf = [
         placeholder:'项目代码/名称',
         key:'itemFilter'
     }
-]
+];
+
+export const PatientItemCalcFilterConf = [
+    {
+        type:'input',
+        label:'科室名称:',
+        placeholder:'请输入',
+        key:'departmentFilter'
+    },
+    {
+        type:'input',
+        label:'患者名称:',
+        placeholder:'请输入',
+        key:'patientFilter'
+    }
+];
+
+export const standardItemCostCalcFilterConf = [
+    {
+        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 patientStandItemCostCalcFilterConf = [
+    {
+        type:'input',
+        label:'科室名称:',
+        placeholder:'请输入',
+        key:'departmentFilter'
+    },
+    {
+        type:'input',
+        label:'患者名称:',
+        placeholder:'请输入',
+        key:'patientFilter'
+    }
+];
+
+export const standItemShareCostCalcFilterConf = [
+    {
+        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'
+    }
+];
 
 
 

+ 106 - 80
src/pages/costAccounting/calcPageTemplate/index.tsx

@@ -2,14 +2,14 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-19 14:26:21
+ * @LastEditTime: 2024-06-28 14:29:32
  * @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, Table, Button } from 'antd';
+import { DatePicker, Input, Modal, message, Table, Button, Tabs } from 'antd';
 import { useEffect, useRef, useState } from 'react';
 
 import { calculateReq, cancelAllocation, cancelIncomeCollection, downloadTemplateReq, generateReportHandle, getAfterCostShareSearchTableData, getAfterIncomeCollectionTableData, getCalcPageTableData, startAllocation, startIncomeCollection } from './service';
@@ -23,16 +23,18 @@ import { KCIMTable } from '@/components/KCIMTable';
 
 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 { 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 { afterCollectionSearch, afterCostShareSearch, beforeCollectionSearch, beforeCostShareSearch, chargeItemCostCalc, clinicalPathway, costShare, costShareReportTable, departmentCostCalculate, departmentOperatingReport, diseaseCostCalculation, DRG_DIPCostCalc, incomeCollection, medicalMaterialCostCalc, medicalOrderItem, patientCostCalc, projectShareParamsCalc, unitPersonnelCostCalc, wholeHospCostCalculate, wholeHospOperatingReport } from './columns';
+import { afterCollectionSearchFilterConf, afterCostShareSearchFilterConf, beforeCollectionSearchFilterConf, beforeCostShareSearchFilterConf, chargeItemCostCalcFilterConf, clinicalPathwayFilterConf, departmentCostCalculateFilterConf, diseaseCostCalculationFilterConf, DRG_DIPCostCalcFilterConf, medicalMaterialCostCalcFilterConf, medicalOrderItemFilterConf, patientCostCalcFilterConf, PatientItemCalcFilterConf, patientStandItemCostCalcFilterConf, projectCostCalcFilterConf, projectShareParamsCalcFilterConf, standardItemCostCalcFilterConf, standItemShareCostCalcFilterConf, unitPersonnelCostCalcFilterConf } from './config';
+
 import ProgressModal from '@/components/ProgressModal';
-import { useAccess } from '@umijs/max';
+
 import ExportProgressModal from '@/pages/reportExport/report/ExportProgressModal';
 import exportTableToExcel from '@/utils/tableToExcel';
 
+import { useAccess, useParams } from '@umijs/max'
+
 
 const IconFont = createFromIconfontCN({
   scriptUrl: '',
@@ -43,7 +45,7 @@ const currentData = `${new Date().getFullYear()}-${(new Date().getMonth() + 1).t
 const calTypeStr = `ITEM_COST_CALCULATE${(new Date()).getTime()}`;
 
 let currentPage = 0;
-let totalTableData:any[] = [];
+let totalTableData: any[] = [];
 
 export default function calcPageTemplate() {
   const [computeDate, set_computeDate] = useState(currentData);
@@ -58,63 +60,63 @@ export default function calcPageTemplate() {
   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 [btnAccessStr, set_btnAccessStr] = useState<undefined | string>(undefined);
 
   const access = useAccess();
 
   const [isModalVisible, setIsModalVisible] = useState(false);
-  const [openProcessModal,set_openProcessModal] = useState(false);
+  const [openProcessModal, set_openProcessModal] = useState(false);
 
 
   const getTableData = async (params: any) => {
     const resp = await getCalcPageTableData({ ...params, ...tableDataFilterParams });
     if (resp) {
       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,      
+        if (params.calcPageKey == 'projectShareParamsCalc' || params.calcPageKey == 'projectCostCalc' || params.calcPageKey == 'patientItemCalc' || params.calcPageKey == 'standardItemCostCalc' || params.calcPageKey == 'patientStandItemCostCalc' || params.calcPageKey == 'standItemShareCostCalc') {
+          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
               }
             });
-            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 { ...item, ...rowData, id: Math.random(), columns }
+          });
 
-            return {
-              data: data,
-              success: true,
-              total: totalCount,
-              pageSize: pageSize,
-              totalPage: totalPage,
-            }
+          return {
+            data: data,
+            success: true,
+            total: totalCount,
+            pageSize: pageSize,
+            totalPage: totalPage,
+          }
 
         }
         let data = (resp.list && resp.list != null) ? resp.list : (Array.isArray(resp) ? resp : []);
@@ -186,11 +188,11 @@ export default function calcPageTemplate() {
 
   const a = async () => {
     setIsModalVisible(true);
-    const resp = await calculateReq(computeDate, params.calcPageKey,calTypeStr);
+    const resp = await calculateReq(computeDate, params.calcPageKey, calTypeStr);
 
-    if(resp){
+    if (resp) {
       setIsModalVisible(false);
-    }else{
+    } else {
       setIsModalVisible(false);
     }
     tableRef.current?.reload();
@@ -264,6 +266,7 @@ export default function calcPageTemplate() {
             <ProFormCascader
               noStyle
               allowClear
+
               placeholder="请选择"
               request={async () => {
                 const resp = await request();
@@ -273,6 +276,7 @@ export default function calcPageTemplate() {
                 return [];
               }}
               fieldProps={{
+                showSearch: true,
                 fieldNames: { label: 'responsibilityName', value: 'responsibilityCode', children: 'child' },
                 onChange(value: any, option: any) {
                   set_tableDataFilterParams({ ...tableDataFilterParams, [`${key}`]: value ? value[value.length - 1] : null })
@@ -331,7 +335,7 @@ export default function calcPageTemplate() {
           cancelText: '取消',
           onOk: async (...args) => {
             set_loading(true);
-            const resp = await startAllocation({ year, month});
+            const resp = await startAllocation({ year, month });
             if (resp) {
 
               set_loading(false);
@@ -435,22 +439,20 @@ export default function calcPageTemplate() {
 
   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');
+      const resp = await generateReportHandle({ date: `${computeDate}-01`, 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');
+      const resp = await generateReportHandle({ date: `${computeDate}-01`, 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');
+      const resp = await generateReportHandle({ date: `${computeDate}-01`, reportType: 0 }, '/costAccount/hospProfitAndLoss/report');
       if (resp) {
         tableRef.current?.reload();
       }
@@ -462,7 +464,7 @@ export default function calcPageTemplate() {
     setIsModalVisible(false);
   };
 
-  const handleExportCompletion = ()=>{
+  const handleExportCompletion = () => {
     currentPage = 0;
     set_openProcessModal(false);
     exportHandle();
@@ -472,7 +474,7 @@ export default function calcPageTemplate() {
 
     let headers: { [key: string]: any } = {};
     let data: any[] = [];
-    
+
     columns.forEach(a => {
       headers[`${a.dataIndex}`] = a.title;
     });
@@ -485,28 +487,28 @@ export default function calcPageTemplate() {
       data.push(_temp);
     });
 
-    exportTableToExcel(data, columns as any[],'项目成本计算');
+    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];
+
+    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,
+        currentCount: totalTableData.length,
+        totalCount: total,
       }
 
-    }else{
-      return { currentCount:0, totalCount:0};
+    } else {
+      return { currentCount: 0, totalCount: 0 };
     }
   };
 
@@ -520,6 +522,29 @@ export default function calcPageTemplate() {
       set_ifShowCalcBtn(true);
       set_scrollX(1500);
     }
+    if (calcPageKey == "standardItemCostCalc") {
+
+      set_filterConf(standardItemCostCalcFilterConf);
+      set_ifShowCalcBtn(true);
+      set_scrollX(1500);
+    }
+    if (calcPageKey == "patientStandItemCostCalc") {
+
+      set_filterConf(patientStandItemCostCalcFilterConf);
+      set_ifShowCalcBtn(true);
+      set_scrollX(1500);
+    }
+    if (calcPageKey == "standItemShareCostCalc") {
+
+      set_filterConf(standItemShareCostCalcFilterConf);
+      set_ifShowCalcBtn(true);
+      set_scrollX(1500);
+    }
+    if (calcPageKey == "patientItemCalc") {
+      set_scrollX(1500);
+      set_filterConf(PatientItemCalcFilterConf);
+      set_ifShowCalcBtn(true);
+    }
     if (calcPageKey == "patientCostCalc") {
       set_columns(patientCostCalc);
       set_scrollX(1500);
@@ -566,7 +591,7 @@ export default function calcPageTemplate() {
       set_columns([...incomeCollection, {
         title: '操作',
         dataIndex: 'option',
-        width:90,
+        width: 90,
         renderText(text, record) {
           const { isCollection } = record;
           return <a style={{ fontSize: 14 }} onClick={() => {
@@ -689,11 +714,11 @@ export default function calcPageTemplate() {
       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}`,'');
+      const a = tabs.reduce((prev: any, cur: any) => `${prev},${cur.code}`, '');
       set_btnAccessStr(a);
       set_ifShowCalcBtn(a.indexOf('calculate') != -1);
       set_scrollX(1200);
@@ -745,18 +770,19 @@ export default function calcPageTemplate() {
           {generateFilterItems(filterConf)}
         </div>
         <div className="btnGroup">
-          {(params.calcPageKey == 'projectCostCalc'&&btnAccessStr?.indexOf('export') != -1) && <a className='export' onClick={() => set_openProcessModal(true)}>导出</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 }}>
+
         <KCIMTable
           columns={columns}
           actionRef={tableRef}
           rowKey="id"
-          scroll={{ x: scrollX }}
+          scroll={{ x: scrollX, y: `calc(100vh - 230px)` }}
           params={tableDataFilterParams}
           request={(params) => getTableData(params)}
         />

+ 49 - 1
src/pages/costAccounting/calcPageTemplate/service.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 16:31:27
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-19 14:25:42
+ * @LastEditTime: 2024-06-28 14:17: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
  */
@@ -144,6 +144,30 @@ export const getCalcPageTableData = (params: any) => {
       params:{...next}
     });
   }
+  if(calcPageKey == 'patientItemCalc'){
+    return request('/costAccount/calculate/getPatientItemCostList', {
+      method: 'GET',
+      params:{...next}
+    });
+  }
+  if(calcPageKey == 'standardItemCostCalc'){
+    return request('/costAccount/calculate/getStandItemCostList', {
+      method: 'GET',
+      params:{...next}
+    });
+  }
+  if(calcPageKey == 'patientStandItemCostCalc'){
+    return request('/costAccount/calculate/getPatientStandItemCostList', {
+      method: 'GET',
+      params:{...next}
+    });
+  }
+  if(calcPageKey == 'standItemShareCostCalc'){
+    return request('/costAccount/calculate/getStandShareParamCostList', {
+      method: 'GET',
+      params:{...next}
+    });
+  }
 };
 
 //计算
@@ -160,6 +184,12 @@ export const calculateReq = (computeDate: string,calcPageKey: string | undefined
       params:{computeDate}
     });
   }
+  if(calcPageKey == 'patientItemCalc'){
+    return request('/costAccount/calculate/computePatientItemCost', {
+      method: 'POST',
+      params:{computeDate}
+    });
+  }
   if(calcPageKey == 'chargeItemCostCalc'){
     return request('/costAccount/calculate/itemCostCalculate', {
       method: 'POST',
@@ -220,6 +250,24 @@ export const calculateReq = (computeDate: string,calcPageKey: string | undefined
       params:{computeDate}
     });
   }
+  if(calcPageKey == 'standardItemCostCalc'){
+    return request('/costAccount/calculate/computeStandItemCost', {
+      method: 'POST',
+      params:{computeDate}
+    });
+  }
+  if(calcPageKey == 'patientStandItemCostCalc'){
+    return request('/costAccount/calculate/computeStandPatientItemCost', {
+      method: 'POST',
+      params:{computeDate}
+    });
+  }
+  if(calcPageKey == 'standItemShareCostCalc'){
+    return request('/costAccount/calculate/computeStandShareParamCost', {
+      method: 'POST',
+      params:{computeDate}
+    });
+  }
   
 };
 

+ 8 - 6
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: 2024-01-05 14:38:28
+ * @LastEditTime: 2024-06-28 17:50: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
  */
@@ -62,11 +62,8 @@ export default function MaterialCostManagement() {
         },
         {
             title: '项目类型',
-            dataIndex: 'type',
+            dataIndex: 'typeName',
             width:90,
-            renderText(num) {
-                return num == 1?'不计价材料':'高值材料'
-            },
         },
         {
             title: '单价',
@@ -208,6 +205,10 @@ export default function MaterialCostManagement() {
                         {
                             label: '高值材料',
                             value: 2
+                        },
+                        {
+                            label: '低值材料',
+                            value: 3
                         }
                     ]}
                     rules={[{ required: true, message: '项目类型不能为空!' }]}
@@ -339,7 +340,8 @@ export default function MaterialCostManagement() {
                             width={160}
                             options={[
                                 {label:'不计价材料',value:1},
-                                {label:'高值材料',value:2}
+                                {label:'高值材料',value:2},
+                                {label:'低值材料',value:3}
                             ]}
                             fieldProps={{
                                 onChange:(value, option)=>{

+ 9 - 10
src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/match.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2024-03-06 10:43:05
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-21 15:59:36
+ * @LastEditTime: 2024-06-20 21:03:12
  * @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
  */
@@ -126,7 +126,7 @@ export const MatchPage = (props: any) => {
 
     const getMatchInfo = async () => {
         const { code } = record;
-        const resp = await getSingleItem(code);
+        const resp = await getSingleItem(code,record.departmentCode);
         if (resp) {
             set_matchItemInfo(resp);
         }
@@ -141,8 +141,8 @@ export const MatchPage = (props: any) => {
 
     const getReferralMatchHandle = async () => {
         set_loading(true);
-        const { code } = matchItemInfo;
-        const resp = await getReferralMatch(code);
+        const { code,departmentCode } = matchItemInfo;
+        const resp = await getReferralMatch(code,single?record.departmentCode:departmentCode);
         if (resp) {
             const { allStandItem: all = [], matchStandItem: match = [] } = resp;
             const temp = [...all];
@@ -163,8 +163,6 @@ export const MatchPage = (props: any) => {
 
     const switchNeddMatchItem = async (flag: number) => {
 
-
-
         const currentIndex = allNeedMatchList.findIndex((a) => a.code == matchItemInfo.code);
 
         if ((currentIndex == allNeedMatchList.length - 1) && flag > 0) {
@@ -175,7 +173,7 @@ export const MatchPage = (props: any) => {
             message.info('没有上一项!');
             return;
         }
-
+        
         let next = undefined;
 
         if (flag > 0) {
@@ -207,10 +205,11 @@ export const MatchPage = (props: any) => {
     }
 
     const matchRequestHandle = async (data: any,type:number) => {
+      
         try {
-            const { code: itemCode } = matchItemInfo;
+            const { code: itemCode,departmentCode } = matchItemInfo;
             const { code: standItemCode } = data;
-            const resp = await matchRequest(itemCode, standItemCode,type);
+            const resp = await matchRequest(itemCode, standItemCode,type,departmentCode);
             if (resp) {
                 if (!single) {
                     switchNeddMatchItem(1);
@@ -318,7 +317,7 @@ export const MatchPage = (props: any) => {
                         <div className="btnGroup">
                             <IconFont onClick={() => { closeDrawer() }} type="iconquxiao" style={{ color: '#17181A', marginRight: 8, cursor: 'pointer', fontSize: 21 }} />
                         </div>
-                    </div>
+                    </div>                     
                 )
             }
             <div className="content" style={{ padding: single ? 16 : 0 }}>

+ 22 - 9
src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/components/setting.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2024-02-21 13:32:53
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-02-29 15:56:28
+ * @LastEditTime: 2024-06-12 11:21:53
  * @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
  */
@@ -17,6 +17,7 @@ import { getSpaceCostTableData } from '@/pages/costLibraryManagement/basicCostMa
 import { getEquipTableData } from '@/pages/costLibraryManagement/basicCostManagement/equipmentCostManagement/service';
 import { getLeftList } from '@/pages/costLibraryManagement/basicCostManagement/personnelClassificationMana/service';
 import TableSelecter from './tableSelector';
+import { fetchAllDepartments } from '..';
 
 
 const empColumns = [
@@ -173,19 +174,19 @@ export const Setting = (props: any) => {
     const getTableData = async (tabCode: string) => {
         let resp = undefined;
         if (tabCode == '1') {
-            resp = await getEmpsByItemCode(record.code);
+            resp = await getEmpsByItemCode(record.code,record.departmentCode);
         }
         if (tabCode == '2') {
-            resp = await getEquipByItemCode(record.code);
+            resp = await getEquipByItemCode(record.code,record.departmentCode);
         }
         if (tabCode == '3') {
-            resp = await getSpaceByItemCode(record.code);
+            resp = await getSpaceByItemCode(record.code,record.departmentCode);
         }
         if (tabCode == '4') {
-            resp = await getValuationDrugByItemCode(record.code);
+            resp = await getValuationDrugByItemCode(record.code,record.departmentCode);
         }
         if (tabCode == '5') {
-            resp = await getNoValuationDrugByItemCode(record.code);
+            resp = await getNoValuationDrugByItemCode(record.code,record.departmentCode);
         }
 
         set_dataSource(resp);
@@ -233,7 +234,7 @@ export const Setting = (props: any) => {
                 }
             }
 
-            const resp = await addDrawerTableData(result, currentTabKey as number);
+            const resp = await addDrawerTableData({...result,departmentCode:formVal.departmentCode}, currentTabKey as number);
             if (resp) {
                 //tableRef.current?.reload();
                 getTableData(`${currentTabKey}`);
@@ -277,7 +278,7 @@ export const Setting = (props: any) => {
                     }
                 }
 
-                const resp = await editDrawerTableData({ ...result, id: formVal.id }, currentTabKey);
+                const resp = await editDrawerTableData({ ...result, id: formVal.id,departmentCode:formVal.departmentCode }, currentTabKey);
                 if (resp) {
                     //tableRef.current?.reload();
                     getTableData(`${currentTabKey}`);
@@ -318,6 +319,14 @@ export const Setting = (props: any) => {
                 colProps={{ span: 24 }}
                 grid
             >
+                <ProFormSelect
+                    name="departmentCode"
+                    label="科室:"
+                    placeholder="请输入"
+                    request={fetchAllDepartments}
+                    fieldProps={{labelInValue:false}}
+                    rules={[{ required: false, message: '科室不能为空!' }]}
+                />
                 {
                     currentTabKey == 1 && (
                         <ProFormSelect
@@ -571,7 +580,11 @@ export const Setting = (props: any) => {
 
                     } : false}
                     tableAlertRender={false}
-                    columns={columns}
+                    columns={[{
+                        title: '科室',
+                        width:120,
+                        dataIndex: 'departmentName',
+                    },...columns]}
                     actionRef={tableRef} rowKey='id'
                     dataSource={dataSource}
                 />

+ 58 - 51
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: 2024-03-07 16:40:34
+ * @LastEditTime: 2024-07-05 14:20: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
  */
@@ -27,7 +27,7 @@ import locale from 'antd/es/date-picker/locale/zh_CN';
 
 
 
-import { addData, delData, editData, getAllNeedMatchItems, getTableDataReq, importDataPost, mapItemAndStandItem } from './service';
+import { addData, delData, editData, getAllNeedMatchItems, getDepartmentListsReq, getTableDataReq, importDataPost, mapItemAndStandItem } from './service';
 
 import './style.less';
 import KCIMUpload from '@/components/KCIMUpload';
@@ -47,6 +47,31 @@ const IconFont = createFromIconfontCN({
 let currentRow: any = undefined;
 
 
+export const fetchAllDepartments = async (params:any) => {
+    const {keyWords} = params;
+    let currentPage = 1;
+    const pageSize = 500;
+    let allDepartments: any[] = [];
+    let hasMore = true;
+
+    do {
+        const resp = await getDepartmentListsReq({ current: currentPage, pageSize,departName:keyWords });
+        if (resp) {
+            const { list = [] } = resp;
+            allDepartments = [...allDepartments, ...list];
+            if (list.length < pageSize) {
+                hasMore = false; // 如果返回的数据少于每页数量,说明已经是最后一页
+            } else {
+                currentPage++; // 否则继续请求下一页
+            }
+        } else {
+            hasMore = false; // 如果请求失败,终止循环
+        }
+    } while (hasMore);
+
+    return allDepartments.map((a: any) => ({ label:`${a.name}(${a.code})`, value: a.code }));
+};
+
 export default function ChargeItemsMana() {
 
     const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
@@ -59,7 +84,14 @@ export default function ChargeItemsMana() {
     const [currentSelectRow, set_currentSelectRow] = useState(undefined);
     const [ifBatchMatch, set_ifBatchMatch] = useState(false);
     const columns: ProColumns[] = [
-
+        {
+            title: '科室',
+            dataIndex: 'departmentName',
+            width: 160,
+            renderText(text, record, index, action) {
+                return `[${record.departmentCode}]${record.departmentName}`
+            },
+        },
         {
             title: '收费项目编码',
             dataIndex: 'code',
@@ -195,7 +227,7 @@ export default function ChargeItemsMana() {
                     //     <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>,
+                    <a key='2' onClick={() => { currentRow = record; set_drawerType(1); set_currentSelectRow(record);set_drawerVisible(true); }}>设置</a>,
                     <Dropdown menu={{ items }} placement="bottomLeft" arrow>
                         <a><IconFont type="icongengduochuizhi" style={{ color: '#3377FF', width: 16, height: 16 }} /></a>
                     </Dropdown>
@@ -229,12 +261,17 @@ export default function ChargeItemsMana() {
         }
     }
 
+   
+
     const updateTable = async (formVal: any, type: 'EDIT' | "ADD") => {
 
         const result = {
             ...formVal,
-            standItemCode: formVal.standItem ? formVal.standItem.value : undefined,
+            standItemCode: formVal.standItem ? formVal.standItem.label : undefined,
             standItemName: formVal.standItem ? formVal.standItem.label : undefined,
+            departmentCode: formVal.department ? formVal.department.value : undefined,
+            departmentName: formVal.department ? formVal.department.label : undefined,
+            department:null
         }
 
         if (type == 'ADD') {
@@ -265,7 +302,8 @@ export default function ChargeItemsMana() {
                 width={350}
                 formRef={formRef}
                 initialValues={type == 'EDIT' ? {
-                    ...record, standItem: record.standItemCode
+                    ...record, standItem: record.standItemCode,
+                    department:record.departmentCode
                 } : {}}
                 trigger={
                     type == 'EDIT' ? <a key="edit" >编辑</a> : <span className='add'>新增</span>
@@ -277,6 +315,15 @@ export default function ChargeItemsMana() {
                 colProps={{ span: 24 }}
                 grid
             >
+                <ProFormSelect
+                    name="department"
+                    label="科室:"
+                    placeholder="请输入"
+                    params={['departName']}
+                    request={fetchAllDepartments}
+                    fieldProps={{labelInValue:true,showSearch:true}}
+                    rules={[{ required: false, message: '科室不能为空!' }]}
+                />
                 <ProFormText
                     name="code"
                     label="收费项目编码:"
@@ -427,46 +474,6 @@ export default function ChargeItemsMana() {
     }
 
 
-
-    // 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();
@@ -474,10 +481,6 @@ export default function ChargeItemsMana() {
     }, [ifBatchMatch]);
 
 
-    useEffect(() => {
-
-    }, [])
-
     return (
         <>
             <div style={{ padding: '0 16px', paddingTop: 16 }}>
@@ -496,7 +499,11 @@ export default function ChargeItemsMana() {
                     width={drawerType == 1 ? 800 : 1200}
                     title={false}
                     open={drawerVisible}
-                    afterOpenChange={bool => { set_drawerVisible(bool); if (!bool) set_currentSelectRow(undefined); tableRef.current?.reload(); }}
+                    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}

+ 26 - 17
src/pages/costLibraryManagement/projectCostManagement/chargeItemsMana/service.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 16:31:27
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-21 15:40:08
+ * @LastEditTime: 2024-06-12 11:26:39
  * @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
  */
@@ -105,34 +105,34 @@ export const mapItemAndStandItem = () => {
 
 
 //获取对照列表
-export const getEmpsByItemCode = (itemCode:string) => {
+export const getEmpsByItemCode = (itemCode:string,departmentCode:string) => {
   return request('/costAccount/setting/getItemEmpMap', {
     method: 'GET',
-    params:{itemCode}
+    params:{itemCode,departmentCode}
   });
 };
-export const getEquipByItemCode = (itemCode:string) => {
+export const getEquipByItemCode = (itemCode:string,departmentCode:string) => {
   return request('/costAccount/setting/getItemEquipmentMap', {
     method: 'GET',
-    params:{itemCode}
+    params:{itemCode,departmentCode}
   });
 };
-export const getSpaceByItemCode = (itemCode:string) => {
+export const getSpaceByItemCode = (itemCode:string,departmentCode:string) => {
   return request('/costAccount/setting/getItemSpaceMap', {
     method: 'GET',
-    params:{itemCode}
+    params:{itemCode,departmentCode}
   });
 };
-export const getNoValuationDrugByItemCode = (itemCode:string) => {
+export const getNoValuationDrugByItemCode = (itemCode:string,departmentCode:string) => {
   return request('/costAccount/setting/getItemNoValuationDrugMaterialMap', {
     method: 'GET',
-    params:{itemCode}
+    params:{itemCode,departmentCode}
   });
 };
-export const getValuationDrugByItemCode = (itemCode:string) => {
+export const getValuationDrugByItemCode = (itemCode:string,departmentCode:string) => {
   return request('/costAccount/setting/getItemValuationDrugMaterialMap', {
     method: 'GET',
-    params:{itemCode}
+    params:{itemCode,departmentCode}
   });
 };
 
@@ -244,10 +244,10 @@ export const batchDelDrugTableData = (data:number[],type:number) => {
 };
 
 //获取单个收费项目信息
-export const getSingleItem = (itemCode:string) => {
+export const getSingleItem = (itemCode:string,departmentCode:string) => {
   return request('/costAccount/setting/getSingleItem', {
     method: 'GET',
-    params:{itemCode}
+    params:{itemCode,departmentCode}
   });
 };
 
@@ -259,10 +259,10 @@ export const getAllNeedMatchItems = () => {
 };
 
 //获取标准项目及推荐项目
-export const getReferralMatch = (itemCode:string) => {
+export const getReferralMatch = (itemCode:string,departmentCode:string) => {
   return request('/costAccount/setting/getReferralMatch', {
     method: 'GET',
-    params:{itemCode}
+    params:{itemCode,departmentCode}
   });
 };
 
@@ -275,10 +275,19 @@ export const getMatchCount = () => {
 };
 
 //匹配
-export const matchRequest = (itemCode:string,standItemCode:string,type:number) => {
+export const matchRequest = (itemCode:string,standItemCode:string,type:number,departmentCode:string) => {
   return request('/costAccount/setting/matchItem', {
     method: 'POST',
-    params:{itemCode,standItemCode,type}
+    params:{itemCode,standItemCode,type,departmentCode}
+  });
+};
+
+
+//获取科室列表
+export const getDepartmentListsReq = (params:any) => {
+  return request('/centerSys/sysdepartment/getList', {
+    method: 'GET',
+    params:{...params}
   });
 };
 

+ 116 - 64
src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-02-23 15:44:45
+ * @LastEditTime: 2024-06-12 17:45: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
  */
@@ -19,14 +19,14 @@ import { ActionType, ProFormDependency, ProFormInstance, ProFormText, ProFormSel
 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 { Key, ReactNode, 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 { addData, copyParamsList, delData, editData, getProfitReportType, getProjectCostShareTableData, getResponsibilityCenterSelecterList, saveParamsList } from './service';
 
 import './style.less';
 
@@ -35,6 +35,7 @@ import EditTableModal from './editTableModal';
 import TableSelecter from './tableSelector';
 import { getDicDataBySysId } from '@/services/getDic';
 import { getReportProjectSettingList } from '@/pages/baseSetting/otherItemSet/reportItemSet/service';
+import { KcimCenterSysId } from '@/constant';
 
 
 const IconFont = createFromIconfontCN({
@@ -50,31 +51,41 @@ export default function AllocationParamsMap() {
     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: 'itemTypeName',
+        },
         {
             title: '成本列代码',
             ellipsis: true,
-            width:100,
+            width: 100,
             dataIndex: 'columnCode',
         },
         {
             title: '成本列名称',
             ellipsis: true,
-            width:150,
+            width: 150,
             dataIndex: 'columnName',
         },
         {
             title: '成本列类型',
             ellipsis: true,
-            width:100,
+            width: 100,
             dataIndex: 'columnTypeName',
         },
+        {
+            title: '损益表类型',
+            ellipsis: true,
+            dataIndex: 'reportTypeName',
+        },
         {
             title: '损益表项目',
             ellipsis: true,
@@ -146,18 +157,20 @@ export default function AllocationParamsMap() {
     }
 
     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
+                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,
+                itemType:formVal.itemType,
+                reportType:formVal.reportType,
             };
 
             if (type == 'ADD') {
@@ -190,7 +203,7 @@ export default function AllocationParamsMap() {
 
 
     const UpDataActBtn = ({ record, type }: { record: any, type: 'EDIT' | 'ADD' }) => {
-    
+
         return (
             <ModalForm
                 title={`${type == 'EDIT' ? '编辑' : '新增'}项目分摊参数对应`}
@@ -198,7 +211,7 @@ export default function AllocationParamsMap() {
                 formRef={formRef}
                 initialValues={type == 'EDIT' ? {
                     ...record,
-                    profitId:(record.profitPath)?((record.profitPath).split(',')).map((a:string)=>Number(a)):[]
+                    profitId: (record.profitPath) ? ((record.profitPath).split(',')).map((a: string) => Number(a)) : []
                 } : {}}
                 trigger={
                     type == 'EDIT' ? <a key="edit" >编辑</a> : <span className='add'>新增</span>
@@ -215,6 +228,20 @@ export default function AllocationParamsMap() {
                 <ProFormText name='profitName' hidden />
                 <ProFormText name='profitPath' hidden />
                 <ProFormText name='profitPathName' hidden />
+                <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="columnCode"
                     label="成本列代码:"
@@ -230,72 +257,98 @@ export default function AllocationParamsMap() {
                 <ProFormSelect
                     rules={[
                         {
-                            required:true,
+                            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}))
+                        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)
+                        onChange(value, option: any) {
+                            const { label = '' } = option;
+                            formRef.current?.setFieldValue('columnTypeName', label)
                         },
                     }}
                     name="columnType"
                     label="成本列类型:"
                 />
-                <ProFormCascader
-                    rules={[
-                        {
-                            required:true,
-                            message: '请选择',
-                        },
-                    ]}
+                <ProFormSelect
+                    name="reportType"
+                    label="损益表类型:"
+                    placeholder="请输入"
                     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('/'));
+                        const { systemId } = JSON.parse((localStorage.getItem('currentSelectedTab')) as string)
+                        const resp = await getDicDataBySysId(systemId,'PROFIT_REPORT_TYPE');
+                        if (resp) {
+                            const { dataVoList = [] } = resp;
+                            return dataVoList.map((a: any) => ({ label: a.name, value: a.code }))
                         }
+                        return []
                     }}
-                    name="profitId"
-                    label="损益表项目:"
+                    rules={[{ required: true, message: '损益表类型不能为空!' }]}
                 />
-
+                <ProFormDependency name={['reportType']}>
+                    {
+                        ({reportType}) => {
+                            return reportType? (
+                                <ProFormCascader
+                                rules={[
+                                    {
+                                        required: true,
+                                        message: '请选择',
+                                    },
+                                ]}
+                                params={{reportType}}
+                                request={async (params) => {
+                                    console.log({params});
+                                    const {reportType} = params;
+                                    const resp = await getReportProjectSettingList({ reportType });
+                                    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="损益表项目:"
+                            />
+                            ):<></>
+                        }
+                    }
+                </ProFormDependency>
+            
             </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 result = rows.map((a) => ({
+            shareParamColumnCode: currentRow.columnCode,
+            shareParamCode: a.shareParamCode,
+            shareParamName: a.shareParamName,
+            percent: a.percent
         }));
         const resp = await saveParamsList(result);
         if (resp) {
@@ -318,7 +371,7 @@ export default function AllocationParamsMap() {
     return (
         <KCIMPagecontainer className='AllocationParamsMap' title={false}>
             <EditTableModal
-                onVisibleChange={(bool) => {set_editTableVisible(bool);if(!bool)setCurrentRow(undefined)}}
+                onVisibleChange={(bool) => { set_editTableVisible(bool); if (!bool) setCurrentRow(undefined) }}
                 title='分摊参数设置'
                 rowKey={'id'}
                 record={currentRow}
@@ -352,7 +405,6 @@ export default function AllocationParamsMap() {
                                 }
                             }}
                             onPressEnter={(e) => {
-
                                 set_tableDataFilterParams({
                                     ...tableDataFilterParams,
                                     filter: (e.target as HTMLInputElement).value

+ 12 - 1
src/pages/costLibraryManagement/projectCostManagement/projectCostShareSet/service.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 16:31:27
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-02-23 10:10:41
+ * @LastEditTime: 2024-06-11 16:04: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
  */
@@ -123,6 +123,17 @@ export const copyParamsList = (body:any) => {
 }
 
 
+//获取损益报表类型
+export const getProfitReportType = (params:any) => {
+  return request(`/centerSys/sysdictdata/getAllDictBySystemId`, {
+    method: 'GET',
+    params
+  });
+
+}
+
+
+
 
 
 

+ 351 - 0
src/pages/incomeCollectionAction/index.tsx

@@ -0,0 +1,351 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2024-03-18 15:52:26
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-07-18 17:11:41
+ * @FilePath: /CostAccountingSys/src/pages/monthlyInfoCollection/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import KCIMPagecontainer from "@/components/KCIMPageContainer"
+import { DatePicker, message, Input, Modal, Table } from 'antd';
+import { Key, useEffect, useRef, useState } from "react";
+
+
+import moment from 'moment';
+import 'moment/locale/zh-cn';
+import locale from 'antd/es/date-picker/locale/zh_CN';
+import './style.less';
+import { KCIMLeftList } from "@/components/KCIMLeftList";
+import { formatMoneyNumber } from "@/utils/format";
+import { createFromIconfontCN } from "@ant-design/icons";
+import { KCIMTable } from "@/components/KCIMTable";
+import { ActionType, ProColumns } from "@ant-design/pro-components";
+import { getResponsibilityCenterList } from "../baseSetting/responsibilityCenterSet/responsibilityCenter/service";
+import { getIncomeCollectionReq, getTableDataReq } from "./service";
+import { cancelIncomeCollection, getAfterIncomeCollectionTableData, startIncomeCollection } from "../costAccounting/calcPageTemplate/service";
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+const tableColumn: ProColumns[] = [
+    {
+        title: '科室代码',
+        ellipsis: true,
+        dataIndex: 'departmentCode',
+    },
+    {
+        title: '科室名称',
+        ellipsis: true,
+        dataIndex: 'departmentName',
+    },
+    {
+        title: '会计科目',
+        ellipsis: true,
+        dataIndex: 'accountingName',
+    },
+    {
+        title: '收入项目',
+        ellipsis: true,
+        dataIndex: 'productName',
+    },
+    {
+        title: '金额',
+        ellipsis: true,
+        dataIndex: 'amount',
+    },
+];
+const currentDate = `${new Date().getFullYear()}-${(new Date().getMonth() + 1).toString().padStart(2, '0')}`;
+
+const IncomeCollectionAction = () => {
+    const tableRef = useRef<ActionType>();
+
+    const [computeDate, set_computeDate] = useState<string>(currentDate);
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>({ computeDate: currentDate });
+    const [incomeCollectionData,set_incomeCollectionData] = useState<any>(undefined);
+    const [loading, set_loading] = useState(false);
+
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState('');
+    const [leftTreeData, set_leftTreeData] = useState<any[]>([]);
+    const [currentResp, set_currentResp] = useState<any>(undefined);
+    const [currentSelectedLeftObj, set_currentSelectedLeftObj] = useState<any>(undefined);
+
+
+    const onLeftChange = (item: any) => {
+        set_currentSelectedLeftObj(item);
+        // _currentSelectedLeftObj = item;
+    }
+
+    const getIncomeCollection = async ()=>{
+          const resp = await getIncomeCollectionReq({computeDate,current:1,pageSize:100});
+ 
+          if(resp&&resp.list.length>0){
+
+            set_incomeCollectionData(resp.list[0])
+          }else{
+            set_incomeCollectionData(undefined)
+          }
+    }
+
+    const getTableData = async (params: any) => {
+        const { computeDate, responsibilityCode } = params;
+        if (!computeDate && !responsibilityCode) return [];
+        const resp = await getTableDataReq({ ...params, ...tableDataFilterParams });
+        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 tableDataSearchHandle = (paramName: string) => {
+        set_tableDataFilterParams({
+            ...tableDataFilterParams,
+            [`${paramName}`]: tableDataSearchKeywords
+        })
+    }
+
+    const getTreeData = async () => {
+        let totalData: any[] = [];
+        let page = 1;
+        const pageSize = 500;
+
+        const fetchPage = async (page: number) => {
+            const resp = await getResponsibilityCenterList({ pageSize, current: page });
+            if (resp && resp.list.length > 0) {
+                totalData = totalData.concat(resp.list);
+                // 如果返回的数据量等于每页的大小,说明可能还有下一页
+                if (resp.list.length === pageSize) {
+                    await fetchPage(page + 1);
+                }
+            }
+        };
+
+        await fetchPage(page);
+        set_leftTreeData([...totalData]);
+        return totalData;
+    };
+
+    const openDataTable = async () => {
+        set_loading(true);
+        try {
+            const { responsibilityCode = null } = tableDataFilterParams;
+
+            const resp = await getAfterIncomeCollectionTableData(
+                { 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 optionBtnGroupshandle = async () => {
+        const { year, month } = incomeCollectionData?incomeCollectionData:{year:(computeDate.split('-'))[0],month:(computeDate.split('-'))[1]};
+          if (incomeCollectionData&&incomeCollectionData.isCollection) {
+            const resp = await cancelIncomeCollection({ year, month });
+            if (resp) {
+              message.success('操作成功!');
+              getIncomeCollection();
+              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();
+                  getIncomeCollection();
+                } else {
+                  set_loading(false);
+                }
+              },
+            })
+          }
+    }
+
+    useEffect(() => {
+        if (currentSelectedLeftObj) {
+            set_tableDataFilterParams({ ...tableDataFilterParams, responsibilityCode: currentSelectedLeftObj.responsibilityCode,accountFilter:'' })
+            set_tableDataSearchKeywords('');
+        }
+    }, [currentSelectedLeftObj]);
+
+
+    useEffect(()=>{
+        getIncomeCollection();
+    },[computeDate])
+
+    useEffect(() => {
+        getTreeData();
+        getIncomeCollection();
+    }, [])
+
+
+    return (
+        <KCIMPagecontainer className="IncomeCollectionAction" title={false}>
+
+            <div className="header">
+                <div className="search">
+                    <span>核算年月:</span>
+                    <DatePicker
+                        onChange={(data, dateString) => {
+                            set_computeDate(dateString);
+                            set_tableDataFilterParams({
+                                ...tableDataFilterParams,
+                                computeDate: dateString,
+                                accountFilter:''
+                            });
+                            set_tableDataSearchKeywords('');
+                        }}
+                        picker="month"
+                        locale={locale}
+                        defaultValue={moment(computeDate, 'YYYY-MM')}
+                        format="YYYY-MM"
+                        placeholder="选择年月"
+                    />
+                </div>
+                <div className="btnGroup">
+                    <span className="check" onClick={() => openDataTable()}>报表数据</span>
+                    <span className="oneKeyGet" onClick={() => optionBtnGroupshandle()}>{(incomeCollectionData&&incomeCollectionData.isCollection) ? '撤销归集' : '开始归集'}</span>
+                </div>
+            </div>
+            <div className="pageContent">
+                <div className="line">
+                    <div className="info">
+                        <img src={require('../../../static/multiblock.png')} alt="" />
+                        全部科室合计:
+                        <span>{currentResp ? formatMoneyNumber(currentResp.totalAmount) : '0.00'}元</span>
+                    </div>
+                </div>
+                <div className="contentWrapper">
+
+                    <div className="left">
+                        <KCIMLeftList
+                            fieldNames={{ title: 'responsibilityName', key: 'responsibilityCode', children: 'child' }}
+                            rowKey={'responsibilityCode'}
+                            contentH={`calc(100vh - 270px)`}
+                            dataSource={leftTreeData} searchKey={'responsibilityName'} onChange={onLeftChange}
+                            placeholder={'责任中心'} listType={'tree'}
+                            icon={undefined}
+                        />
+                    </div>
+                    <div className="right">
+                        <div className="toolBar" style={{ display: 'flex' }}>
+                            <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 value={tableDataSearchKeywords}
+                                        suffix={
+                                            <IconFont type="iconsousuo" style={{ color: '#99A6BF' }} onClick={() => tableDataSearchHandle(`accountFilter`)} />
+                                        }
+                                        onChange={(e) => {
+                                            set_tableDataSearchKeywords(e.target.value);
+                                            if (e.target.value.length == 0) {
+                                                set_tableDataFilterParams({
+                                                    ...tableDataFilterParams,
+                                                    'accountFilter': ''
+                                                });
+                                            }
+                                        }}
+                                        onPressEnter={(e) => {
+                                            set_tableDataFilterParams({
+                                                ...tableDataFilterParams,
+                                                'accountFilter': ((e.target) as HTMLInputElement).value
+                                            });
+                                        }}
+
+                                    />
+                                </div>
+                            </div>
+                        </div>
+                        <KCIMTable actionRef={tableRef} columns={tableColumn}
+                            rowKey='id'
+                            request={(params) => getTableData(params)}
+                            tableAlertRender={false}
+                            scroll={{ x: scrollX,y:`calc(100vh - 270px)` }}
+                            params={tableDataFilterParams}
+                        />
+                    </div>
+                </div>
+            </div>
+
+        </KCIMPagecontainer>
+    )
+
+}
+
+export default IncomeCollectionAction

+ 23 - 0
src/pages/incomeCollectionAction/service.ts

@@ -0,0 +1,23 @@
+
+
+
+import { request } from 'umi';
+
+
+//获取表格数据
+export const getTableDataReq = (params: any) => {
+
+    return request('/costAccount/incomeCollection/collectList', {
+        method: 'GET',
+        params: { ...params, date: (params.computeDate).replace('-', ''), computeDate: null }
+    });
+};
+
+//获取收入归集数据
+export const getIncomeCollectionReq = (params: any) => {
+    return request('/costAccount/incomeCollection/getCollections', {
+        method: 'GET',
+        params: { ...params, date: (params.computeDate).replace('-', ''), computeDate: null }
+    });
+};
+

+ 214 - 0
src/pages/incomeCollectionAction/style.less

@@ -0,0 +1,214 @@
+.IncomeCollectionAction {
+    width: 100%;
+    padding: 16px;
+    padding-top: 0;
+    background: #FFFFFF;
+
+    .header {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        height: 56px;
+        border-radius: 4px;
+        background-color: #fff;
+
+        .btnGroup {
+            span {
+                display: inline-block;
+                height: 24px;
+                padding: 0px 14px;
+                border-radius: 4px;
+                font-size: 14px;
+                margin-left: 8px;
+                cursor: pointer;
+
+                &.check {
+                    background: #FAFCFF;
+                    border: 1px solid #DAE2F2;
+                }
+
+                &.oneKeyGet {
+                    color: #FFFFFF;
+                    background: #3377FF;
+                }
+            }
+        }
+    }
+
+
+    .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;
+                height: 24px;
+                padding: 0 14px;
+                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: 9px;
+            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;
+                    }
+                }
+
+            }
+        }
+    }
+}

+ 44 - 18
src/pages/monthlyInfoCollection/components/leftAndRighrStructure.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2024-03-19 10:55:39
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-04-07 15:42:38
+ * @LastEditTime: 2024-06-11 11:36:50
  * @FilePath: /CostAccountingSys/src/pages/monthlyInfoCollection/components/leftAndRighrStructure.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -13,7 +13,7 @@ import { beforeCollectionSearch, beforeCostShareSearch } from "@/pages/costAccou
 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 { Input,Modal } from 'antd'
 
 
 import './style.less';
@@ -21,7 +21,7 @@ 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 { calcIdleCostReq, getCostDepartmentList, getCostShareDepartmentList, getIncomeDepartmentList, getPatientChargeItemList, getPatientInfoDepartmentList } from "../service";
 import { formatMoneyNumber } from "@/utils/format";
 
 
@@ -61,7 +61,7 @@ export const LeftAndRighrStructure = (props: LeftAndRighrStructure) => {
 
     const [leftListSearchPlaceHolder, set_leftListSearchPlaceHolder] = useState('请输入');
 
-    const [totalAmount, set_totalAmount] = useState(0);
+    const [leftContentH, set_leftContentH] = useState<string|undefined>(undefined);
     const [currentResp, set_currentResp] = useState<any>(undefined);
 
 
@@ -81,7 +81,7 @@ export const LeftAndRighrStructure = (props: LeftAndRighrStructure) => {
                 }
             }
         }
-        if (tabKey == '3'&&_currentSelectedLeftObj) {
+        if (tabKey == '2'&&_currentSelectedLeftObj) {
             const resp = await getCalcPageTableData({...params, calcPageKey: 'beforeCostShareSearch', ...tableDataFilterParams, computeDate, departmentCode: _currentSelectedLeftObj.subText });
             if (resp) {
                 set_currentResp(resp);
@@ -172,10 +172,10 @@ export const LeftAndRighrStructure = (props: LeftAndRighrStructure) => {
         if (tabKey == '1') {
             inComeLeftData();
         }
-        if (tabKey == '2') {
+        if (tabKey == '3') {
             costShareLeftData();
         }
-        if (tabKey == '3') {
+        if (tabKey == '2') {
             costLeftData();
         }
         if(tabKey == '5'){
@@ -198,18 +198,22 @@ export const LeftAndRighrStructure = (props: LeftAndRighrStructure) => {
             set_tabSearchKey('name');
             set_tableSearchKey('filter');
             inComeLeftData();
+            set_leftContentH(`calc(100vh - 380px)`);
         }
-        if (tabKey == '2') {
+        if (tabKey == '3') {
             costShareLeftData();
+            set_tabSearchKey('responsibilityName');
             set_scrollX(undefined);
+            set_leftContentH('calc(100vh - 294px)');
         }
 
-        if (tabKey == '3') {
+        if (tabKey == '2') {
             set_tableColumn([...beforeCostShareSearch]);
             set_scrollX(undefined);
             set_tabSearchKey('name');
             set_tableSearchKey('filter');
             costLeftData();
+            set_leftContentH('calc(100vh - 351px)');
         }
 
         if (tabKey == '5') {
@@ -217,17 +221,36 @@ export const LeftAndRighrStructure = (props: LeftAndRighrStructure) => {
             set_tabSearchKey('name');
             set_tableSearchKey('');
             getPatientInfoDepartments();
+            set_leftContentH(`calc(100vh - 324px)`);
         }
         if (tabKey == '6') {
             set_scrollX(1300);
             set_tabSearchKey('name');
             set_tableSearchKey('filter');
             set_leftListSearchPlaceHolder('患者ID/姓名');
-            getPatientChargeItemReq()
+            getPatientChargeItemReq();
+            set_leftContentH(`calc(100vh - 292px)`);
         }
 
     }, [tabKey]);
 
+    const calcIdleCost = async ()=>{
+        Modal.confirm({
+            title:'注意',
+            content:'计算操作会覆盖已有的闲置成本数据,确定要继续操作?',
+            okText:'确定',
+            cancelText:'取消',
+            onOk:async (...args)=> {
+                const resp = await calcIdleCostReq(computeDate);
+                if(resp){
+                    costLeftData();
+                }
+                return true;
+            },
+        })
+        
+    }
+
 
 
     useEffect(() => {
@@ -265,14 +288,15 @@ export const LeftAndRighrStructure = (props: LeftAndRighrStructure) => {
         if (tabKey == '5') {
             getPatientInfoDepartments();
         }
-    }, [currentLeftTab])
+    }, [currentLeftTab]);
+
 
 
 
     return (
         <div className="LeftAndRighrStructure">
             {
-                (tabKey != '2' && tabKey != '5' && tabKey != '6') && (
+                (tabKey != '3' && tabKey != '5' && tabKey != '6') && (
                     <div className="line">
                         <div className="info">
                             <img src={require('../../../../static/multiblock.png')} alt="" />
@@ -280,6 +304,7 @@ export const LeftAndRighrStructure = (props: LeftAndRighrStructure) => {
                             <span>{currentResp?formatMoneyNumber(currentResp.totalAmount):'0.00'}元</span>
                         </div>
                         <div className="lineBtnGroup">
+                            {tabKey == '2'&&<span onClick={()=>calcIdleCost()}>计算闲置成本</span>}
                             {ifShowCancelBtn && <span onClick={()=>cancelHandle().then((isOk)=>{
                                   if(isOk){
                                     set_currentResp(undefined);
@@ -320,15 +345,16 @@ export const LeftAndRighrStructure = (props: LeftAndRighrStructure) => {
                     }
 
                     <KCIMLeftList
+                        contentH={leftContentH}
                         fieldNames={{title:'responsibilityName',key:'responsibilityCode',children:'child'}}
-                        rowKey={(tabKey == '1' || tabKey == '3'||tabKey == '5'||tabKey == '6') ? 'subText' : ''}
+                        rowKey={(tabKey == '1' || tabKey == '2'||tabKey == '5'||tabKey == '6') ? 'subText' : ''}
                         dataSource={leftListData} searchKey={tabSearchKey} onChange={onLeftChange}
-                        placeholder={leftListSearchPlaceHolder} listType={tabKey == '2' ? 'tree' : 'list'}
+                        placeholder={leftListSearchPlaceHolder} listType={tabKey == '3' ? '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="toolBar" style={{ display: (tabKey == '1' || tabKey == '2') ? '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 }}>
@@ -357,15 +383,15 @@ export const LeftAndRighrStructure = (props: LeftAndRighrStructure) => {
                             </div>
                         </div>
                     </div>
-                    {(tabKey != '2' && tabKey != '5' && tabKey != '6'&&currentSelectedLeftObj) && <KCIMTable actionRef={tableRef} columns={tableColumn}
+                    {(tabKey != '3' && tabKey != '5' && tabKey != '6'&&currentSelectedLeftObj) && <KCIMTable actionRef={tableRef} columns={tableColumn}
                         rowKey='id'
                         request={(params) => getTableData(params)}
                         tableAlertRender={false}
-                        scroll={{ x: scrollX }}
+                        scroll={{ x: scrollX,y:`calc(100vh - 324px)` }}
                         params={tableDataFilterParams}
                     />}
                  
-                    {(tabKey == '2') && <CostAllocationParamsDeal date={computeDate} ifShowGetBtn ifShowCancelBtn 
+                    {(tabKey == '3') && <CostAllocationParamsDeal date={computeDate} ifShowGetBtn ifShowCancelBtn 
                     responsibilityCode={currentSelectedLeftObj?.responsibilityCode}  cancelHandle={cancelHandle}
                      getHandle={getHandle}
                      />}

+ 1 - 1
src/pages/monthlyInfoCollection/components/style.less

@@ -40,8 +40,8 @@
         .lineBtnGroup {
             &>span {
                 display: inline-block;
-                width: 56px;
                 height: 24px;
+                padding: 0 14px;
                 line-height: 24px;
                 background: #FFFFFF;
                 border-radius: 4px;

+ 43 - 14
src/pages/monthlyInfoCollection/index.tsx

@@ -2,12 +2,12 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2024-03-18 15:52:26
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-25 16:46:13
+ * @LastEditTime: 2024-06-28 15:03:53
  * @FilePath: /CostAccountingSys/src/pages/monthlyInfoCollection/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
 import KCIMPagecontainer from "@/components/KCIMPageContainer"
-import { DatePicker, message, Tabs } from 'antd';
+import { DatePicker, message, Tabs, Modal, Spin } from 'antd';
 import { Key, useEffect, useState } from "react";
 
 
@@ -32,6 +32,7 @@ const MonthlyInfoCollection = () => {
     const [currentSelectedTab, set_currentSelectedTab] = useState<any>(undefined);
     const [tableSelecterVisible, set_tableSelecterVisible] = useState(false);
     const [reload, set_reload] = useState(false);
+    const [isModalOpen, set_isModalOpen] = useState(false);
 
 
     const onTabChanged = (key: string) => {
@@ -43,6 +44,7 @@ const MonthlyInfoCollection = () => {
         const resp = await getDicDataBySysId(systemId, 'DATA_COLLECT_TYPE');
         if (resp) {
             const { dataVoList } = resp;
+            const dataVoListSort = dataVoList.sort((a: any, b: any) => a.sort - b.sort);
             const tabs = dataVoList.map((a: any) => ({ ...a, label: a.name, key: a.code }));
             const showTabs = tabs.filter((a: any) => a.expandOne == '1')
             set_tabs([{ label: '月度数据导入', key: '0' }, ...showTabs]);
@@ -75,19 +77,40 @@ const MonthlyInfoCollection = () => {
     }
 
     //获取请求
-    const getHandle = async () => {
-        const resp = await getReq(computeDate, Number(currentTabKey));
-        if (resp) {
-            message.success('获取成功!');
-            set_reload(true);
-            setTimeout(() => {
-                set_reload(false);
-            }, 1000)
-            return Promise.resolve(true);
+    const getHandle = async (): Promise<boolean> => {
+        let timeoutFlag = false;
+        // 创建一个定时器,2秒后设置标志位并开启Modal
+        const timeout = setTimeout(() => {
+            timeoutFlag = true;
+            set_isModalOpen(true);
+        }, 2000);
+    
+        try {
+            const resp = await getReq(computeDate, Number(currentTabKey));
+            // 请求成功,清除定时器并关闭Modal
+            clearTimeout(timeout);
+    
+            if (resp) {
+                if (timeoutFlag) {
+                    set_isModalOpen(false);
+                }
+                message.success('获取成功!');
+                set_reload(true);
+                setTimeout(() => {
+                    set_reload(false);
+                }, 1000);
+                return true;
+            }
+            set_isModalOpen(false);
+            return false;
+        } catch (error) {
+            // 请求失败,清除定时器并处理错误
+            clearTimeout(timeout);
+            console.error(error);
+            return false;
         }
-        return Promise.resolve(false);
-    }
-
+    };
+    
     useEffect(() => {
         const needTab = tabs.filter((a) => a.key == currentTabKey);
         set_currentSelectedTab(needTab[0]);
@@ -104,6 +127,11 @@ const MonthlyInfoCollection = () => {
 
     return (
         <KCIMPagecontainer className="MonthlyInfoCollection" title={false}>
+            <Modal title={'拼力获取中...'} open={isModalOpen} footer={false} width={180} closable={false} >
+                <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
+                    <Spin />
+                </div>
+            </Modal>
             <TableSelecter
                 onVisibleChange={(bool) => set_tableSelecterVisible(bool)}
                 title='异常详情'
@@ -152,6 +180,7 @@ const MonthlyInfoCollection = () => {
                     {currentTabKey == '4' && <EmpCostDataImport cancelHandle={cancelHandle} getHandle={getHandle} date={computeDate} btnPerm={currentSelectedTab ? currentSelectedTab.expandTwo : '0|0'} />}
                     {currentTabKey == '7' && <WholeHospIncomeAndCost cancelHandle={cancelHandle} getHandle={getHandle} date={computeDate} btnPerm={currentSelectedTab ? currentSelectedTab.expandTwo : '0|0'} />}
                 </div>
+                
             </div>
         </KCIMPagecontainer>
     )

+ 10 - 1
src/pages/monthlyInfoCollection/service.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 16:31:27
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-22 18:06:34
+ * @LastEditTime: 2024-04-17 15:49: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
  */
@@ -92,6 +92,15 @@ export const getReq = (computeDate:string,type:number) => {
     });
 };
 
+//计算闲置成本
+export const calcIdleCostReq = (computeDate:string) => {
+  return request('/costAccount/freeCost/computeFreeCost', {
+    method: 'POST',
+    params:{computeDate}
+  });
+};
+
+
 
 
 

+ 2 - 1
src/pages/monthlyInfoSearch/empCostDataImport/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-29 14:21:33
+ * @LastEditTime: 2024-06-11 11:26: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
  */
@@ -250,6 +250,7 @@ export default function EmpCostDataImport(
           columns={columns}
           actionRef={tableRef}
           rowKey="id"
+          scroll={{y:`calc(100vh - 345px)`}}
           params={tableDataFilterParams}
           request={(params) => getTableData(params)}
         />

+ 2 - 1
src/pages/monthlyInfoSearch/incomeCostDataImport/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-29 14:56:30
+ * @LastEditTime: 2024-06-11 10:44: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
  */
@@ -491,6 +491,7 @@ export default function IncomeCostDataImport({ date, btnPerm }: { date: string,
           columns={columns}
           actionRef={tableRef}
           rowKey="id"
+          scroll={{y:`calc(100vh - 259px)`}}
           params={tableDataFilterParams}
           request={(params) => getTableData(params)}
         />

+ 2 - 2
src/pages/monthlyInfoSearch/patientChargeItemsImport/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-29 14:23:11
+ * @LastEditTime: 2024-06-11 13:33:14
  * @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
  */
@@ -369,7 +369,7 @@ export default function PatientChargeItemsImport(
           columns={columns}
           actionRef={tableRef}
           rowKey="id"
-          scroll={{ x: 2500 }}
+          scroll={{ x: 2500,y:`calc(100vh - 275px)` }}
           params={tableDataFilterParams}
           request={(params) => getTableData(params)}
         />

+ 2 - 2
src/pages/monthlyInfoSearch/patientInfoImport/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-29 17:43:03
+ * @LastEditTime: 2024-06-11 11:31: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
  */
@@ -386,7 +386,7 @@ export default function PatientInfoImport(
           columns={columns}
           actionRef={tableRef}
           rowKey="id"
-          scroll={{ x: type == 3?4000:2000 }}
+          scroll={{ x: type == 3?4000:2000,y:`calc(100vh - 305px)` }}
           params={tableDataFilterParams}
           request={(params) => getTableData(params)}
         />

+ 81 - 45
src/pages/monthlyInfoSearch/wholeHospIncomeAndCost/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-03-03 11:30:33
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-03-29 14:56:58
+ * @LastEditTime: 2024-04-12 16:14: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
  */
@@ -41,7 +41,7 @@ const IconFont = createFromIconfontCN({
 
 
 
-export default function WholeHospIncomeAndCost({ date, btnPerm,cancelHandle,getHandle }: { date: string, btnPerm: string,cancelHandle:()=>Promise<boolean>,getHandle:()=>Promise<boolean> }) {
+export default function WholeHospIncomeAndCost({ date, btnPerm, cancelHandle, getHandle }: { date: string, btnPerm: string, cancelHandle: () => Promise<boolean>, getHandle: () => Promise<boolean> }) {
 
     const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
     const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
@@ -50,6 +50,9 @@ export default function WholeHospIncomeAndCost({ date, btnPerm,cancelHandle,getH
 
     const [ifShowGetBtn, set_ifShowGetBtn] = useState(false);
     const [ifShowCancelBtn, set_ifShowCancelBtn] = useState(false);
+    const [currentType, set_currentType] = useState(0);
+    const [cardData, set_cardData] = useState<any[]>([]);
+    const [showCardData, set_showCardData] = useState<any[]>([]);
 
     const columns: ProColumns[] = [
         {
@@ -93,24 +96,18 @@ export default function WholeHospIncomeAndCost({ date, btnPerm,cancelHandle,getH
 
 
     const getTableData = async (params: any) => {
-        const resp = await getWholeHospCostList({ ...params });
+        const resp = await getWholeHospCostList({ ...params, pageSize: 500, current: 1 });
         if (resp) {
-            return {
-                data: resp.list,
-                success: true,
-                total: resp.totalCount,
-                pageSize: resp.pageSize,
-                totalPage: resp.totalPage,
-            }
+            set_cardData([...resp.list]);
+            set_showCardData([...resp.list]);
         }
-        return []
     }
 
     const delTableData = async (record: any) => {
         const resp = await delData([record.id]);
         if (resp) {
             message.success('操作成功!');
-            tableRef.current?.reload();
+            getTableData({...tableDataFilterParams});
             // message.success('操作成功!');
         }
     }
@@ -126,7 +123,7 @@ export default function WholeHospIncomeAndCost({ date, btnPerm,cancelHandle,getH
         if (type == 'ADD') {
             const resp = await addData(result);
             if (resp) {
-                tableRef.current?.reload();
+                getTableData({...tableDataFilterParams});
                 message.success('操作成功!');
             }
 
@@ -135,7 +132,7 @@ export default function WholeHospIncomeAndCost({ date, btnPerm,cancelHandle,getH
 
             const resp = await editData({ ...result, id: formVal.id });
             if (resp) {
-                tableRef.current?.reload();
+                getTableData({...tableDataFilterParams});
                 message.success('操作成功!');
             }
         }
@@ -158,9 +155,14 @@ export default function WholeHospIncomeAndCost({ date, btnPerm,cancelHandle,getH
                         label: record.paymentsName,
                         value: record.paymentsType
                     }
-                } : { status: 0,dateTime:date }}
+                } : { status: 0, dateTime: date }}
                 trigger={
-                    type == 'EDIT' ? <a key="edit" >编辑</a> : <span className='add'>新增</span>
+                    type == 'EDIT' ? <a key="edit" >编辑</a> : (
+                        <div className='list'>
+                            <IconFont type="iconzhankai" style={{ color: '#17181A' }} />
+                            <span>新增收支</span>
+                        </div>
+                    )
                 }
                 onFinish={(val) => {
                     return updateTable(type == 'EDIT' ? { ...record, ...val } : { ...val }, type);
@@ -243,50 +245,84 @@ export default function WholeHospIncomeAndCost({ date, btnPerm,cancelHandle,getH
             set_ifShowCancelBtn(b == '1');
             set_ifShowGetBtn(a == '1')
         }
-    }, [btnPerm])
+    }, [btnPerm]);
 
+    useEffect(()=>{
+        if(currentType == 0){
+            set_showCardData([...cardData]);
+        }
+        if(currentType == 1){
+          set_showCardData([...cardData.filter((a)=>a.paymentsType == 1)]);
+        }
+        if(currentType == 2){
+          set_showCardData([...cardData.filter((a)=>a.paymentsType == 2)]);
+        }
+    },[cardData])
 
-    useEffect(() => {
 
-    }, [])
+    useEffect(() => {
+        if (tableDataFilterParams) {
+            getTableData({ ...tableDataFilterParams });
+        }
+    }, [tableDataFilterParams]);
+
+    useEffect(()=>{
+          if(currentType == 0){
+              set_showCardData([...cardData]);
+          }
+          if(currentType == 1){
+            set_showCardData([...cardData.filter((a)=>a.paymentsType == 1)]);
+          }
+          if(currentType == 2){
+            set_showCardData([...cardData.filter((a)=>a.paymentsType == 2)]);
+          }
+    },[currentType])
 
     return (
         <KCIMPagecontainer className='WholeHospIncomeAndCost' title={false}>
             <div className='toolBar'>
                 <div className='filter'>
-                    {/* <div className="filterItem">
-                        {
-                            <div className="search">
-                                <span>核算年月:</span>
-                                <DatePicker
-                                    onChange={(data, dateString) => {
-                                        set_tableDataFilterParams({
-                                            ...tableDataFilterParams,
-                                            dateTime: dateString,
-                                        });
-                                    }}
-                                    picker="month"
-                                    locale={locale}
-                                    format="YYYY-MM"
-                                    placeholder="选择年月"
-                                />
-                            </div>
-                        }
-                    </div> */}
+                    <div className={currentType == 0 ? 'tab on' : 'tab'} onClick={()=>set_currentType(0)}>全部</div>
+                    <div className={currentType == 1 ? 'tab on' : 'tab'} onClick={()=>set_currentType(1)}>收入</div>
+                    <div className={currentType == 2 ? 'tab on' : 'tab'} onClick={()=>set_currentType(2)}>支出</div>
                 </div>
                 <div className='btnGroup'>
-                    {ifShowCancelBtn && <span onClick={()=>cancelHandle().then((isok)=>{
-                          if(isok)tableRef.current?.reload()
+                    {ifShowCancelBtn && <span onClick={() => cancelHandle().then((isok) => {
+                        if (isok) tableRef.current?.reload()
                     })}>撤销</span>}
-                    {ifShowGetBtn && <span onClick={()=>getHandle().then((isok)=>{
-                          if(isok)tableRef.current?.reload()
+                    {ifShowGetBtn && <span onClick={() => getHandle().then((isok) => {
+                        if (isok) tableRef.current?.reload()
                     })}>获取</span>}
-                    <UpDataActBtn record type='ADD' />
+                    {/* <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 className='content' style={{ marginTop: 16 }}>
+                <UpDataActBtn key={'act'} record={undefined} type='ADD' />
+                {
+                    showCardData.map((item, index) => (
+                        <div className='list' key={index}>
+                            <div className='rowOne'>
+                                <span className={item.paymentsType == 1 ? 'tag income' : 'tag cost'}>{item.paymentsType == 1 ? '收入' : '支出'}</span>
+                                <span className='date'>{date}</span>
+                            </div>
+                            <div className='rowTwo'>{formatMoneyNumber(item.totalAmount)}</div>
+                            <div className='rowThree'>
+                                <span className='name'>{item.paymentsName}</span>
+                                <span className='btns'>
+                                    <UpDataActBtn key={'act'} record={item} type='EDIT' />
+                                    <Popconfirm
+                                        title="是否确认删除?"
+                                        key="del"
+                                        onConfirm={() => delTableData(item)}
+                                    >
+                                        <a style={{ fontSize: 14, marginLeft: 12 }}>删除</a>
+                                    </Popconfirm>
+                                </span>
+                            </div>
+                        </div>
+                    ))
+                }
             </div>
         </KCIMPagecontainer>
     )

+ 121 - 0
src/pages/monthlyInfoSearch/wholeHospIncomeAndCost/style.less

@@ -22,6 +22,29 @@
         justify-content: center;
         align-items: center;
       }
+
+      .tab {
+        width: 56px;
+        height: 24px;
+        cursor: pointer;
+        line-height: 24px;
+        font-weight: 400;
+        font-size: 14px;
+        color: #525866;
+        text-align: center;
+        background: #F5F7FA;
+        border-radius: 12px;
+        margin-right: 8px;
+
+        &.on {
+          color: #3377FF;
+          background: rgba(51, 119, 255, 0.08);
+        }
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
     }
 
     .btnGroup {
@@ -65,4 +88,102 @@
     }
 
   }
+
+  .content {
+    display: flex;
+    width: 100%;
+    flex-direction: row;
+    justify-content: flex-start;
+    align-items: center;
+
+    .list {
+      width: 264px;
+      height: 102px;
+      background: #FFFFFF;
+      border-radius: 8px;
+      padding: 12px;
+      border: 1px solid #E6EAF2;
+      margin-right: 16px;
+
+
+      .rowOne {
+        display: flex;
+        width: 100%;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+
+        .tag {
+          display: inline-block;
+          width: 40px;
+          height: 20px;
+          text-align: center;
+          line-height: 20px;
+          font-weight: 400;
+          font-size: 12px;
+          border-radius: 4px;
+
+          &.income {
+            color: #FF8000;
+            background: #FFF5EB;
+          }
+
+          &.cost {
+            color: #009966;
+            background: #E8FCF6;
+          }
+
+        }
+
+        .date {
+          font-weight: 400;
+          font-size: 12px;
+          color: #7A8599;
+        }
+      }
+
+      .rowTwo {
+        height: 24px;
+        line-height: 24px;
+        font-weight: bold;
+        font-size: 24px;
+        color: #17181A;
+        margin-top: 8px;
+        margin-bottom: 8px;
+      }
+
+      .rowThree {
+        display: flex;
+        width: 100%;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+
+        .name {
+          font-weight: 400;
+          font-size: 14px;
+          color: #525866;
+        }
+      }
+
+      &:first-child {
+        display: flex;
+        cursor: pointer;
+        justify-content: center;
+        align-items: center;
+
+        &>span {
+          font-weight: 400;
+          font-size: 14px;
+          color: #525866;
+          padding-left: 4px;
+        }
+
+      }
+
+      &:nth-child(4n) {
+        margin-right: 0;
+      }
+    }
+  }
 }

BIN
src/pages/noAccess/images/noAccess.png


+ 30 - 0
src/pages/noAccess/index.tsx

@@ -0,0 +1,30 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2022-12-14 14:14:32
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-07-17 15:33:14
+ * @FilePath: /BudgetManaSystem/src/pages/noAccess/index.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+import KCIMPagecontainer from '@/components/KCIMPageContainer';
+import { history, Link } from 'umi';
+import './style.less';
+const NoAccessPage: React.FC = () => {
+
+  return (
+    <KCIMPagecontainer
+      className='NoAccessPage'
+      title={false}
+    >
+         <div className='content'>
+              <img className='flagIcon' src={require('./images/noAccess.png')} alt="" />
+              <div className='title'>暂无权限</div>
+              <div className='subTitle'>当前功能暂无权限,请联系管理员分配权限</div>
+              <Link to='/home' replace ><div className='btn'>返回首页</div></Link>
+         </div>
+    </KCIMPagecontainer>
+  );
+};
+
+export default NoAccessPage;

+ 49 - 0
src/pages/noAccess/style.less

@@ -0,0 +1,49 @@
+.NoAccessPage {
+    .content {
+        display: flex;
+        height: 91vh;
+        flex-direction: column;
+        justify-content: flex-start;
+        align-items: center;
+        background: #fff;
+        padding-top: 200px;
+        box-sizing: border-box;
+
+        .flagIcon {
+            width: 160px;
+            height: 140px;
+        }
+
+        .title {
+            font-weight: 500;
+            font-size: 24px;
+            height: 24px;
+            color: #17181A;
+            line-height: 24px;
+            margin-top: 24px;
+            margin-bottom: 16px;
+        }
+
+        .subTitle {
+            font-weight: 400;
+            font-size: 14px;
+            height: 14px;
+            color: #7A8599;
+            line-height: 14px;
+            margin-bottom: 24px;
+        }
+
+        .btn {
+            cursor: pointer;
+            width: 80px;
+            height: 24px;
+            line-height: 24px;
+            text-align: center;
+            background: #3377FF;
+            border-radius: 4px;
+            font-weight: 400;
+            font-size: 14px;
+            color: #FFFFFF;
+        }
+    }
+}

+ 42 - 53
src/pages/reportExport/report/index.tsx

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-01-04 14:12:31
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-01-19 13:59:20
+ * @LastEditTime: 2024-06-28 16:00:46
  * @FilePath: /BudgetManaSystem/src/pages/budgetMana/oneBatch/index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -32,6 +32,7 @@ import { KCIMTable } from '@/components/KCIMTable';
 import { getStringWidth } from '@/utils/tooljs';
 
 import ExportProgressModal from './ExportProgressModal';
+import { getParamsDataBySysId } from '@/services/getDic';
 
 
 const IconFont = createFromIconfontCN({
@@ -42,29 +43,6 @@ interface Searchable {
   [key: string]: string;
 }
 
-function multiAttributeSearchOptimized(
-  objects: Searchable[],
-  properties: string[],
-  keys: string[]
-): Searchable[] {
-  // 将 keys 转换为 Set,以便更快地检查是否存在
-  const keysSet = new Set(keys);
-
-  // 只处理包含指定属性的对象
-  return objects.filter(obj => {
-    // 从对象中提取需要的属性
-    const relevantProps = properties.map(prop => obj[prop]).filter(Boolean);
-
-    // 检查这些属性中是否至少有一个包含关键字
-    return relevantProps.some(propValue => {
-      // 如果 propValue 是字符串,检查是否包含任何一个关键字
-      if (typeof propValue === 'string') {
-        return [...keysSet].some(key => propValue.includes(key));
-      }
-      return false;
-    });
-  });
-}
 
 let searchKeys: any[] = [];
 let totalTableData: any[] = [];
@@ -83,7 +61,7 @@ const ReportExport = () => {
 
   const [tableColumn, set_tableColumn] = useState<ProColumns[] | any[]>([]);
 
-  const [tableData, set_tableData] = useState<any[]>([]);
+  const [tableScrollX, set_tableScrollX] = useState<number>(1000);
 
   const [currentComputeDate, set_currentComputeDate] = useState<string | undefined>(currentTimeStr);
 
@@ -105,6 +83,8 @@ const ReportExport = () => {
   const [openProcessModal, set_openProcessModal] = useState(false);
 
 
+
+
   const reportJumphandle = (reportData: any) => {
 
     let parameter: { [key: string]: any } = {};
@@ -149,11 +129,14 @@ const ReportExport = () => {
 
   const getTableData = async (params: any) => {
 
-    const { parameter, pageSize=100, current,reportCode } = params;
+    const { systemId } = JSON.parse(localStorage.getItem('currentSelectedTab') as string)
+    const paramsData = await getParamsDataBySysId(systemId, '1806523783696224256');
+    
+    const { parameter, pageSize = paramsData.value?Number(paramsData.value):100, current, reportCode } = params;
     searchKeys = [];
     let resp: any = undefined;
 
-     
+
     if (step != 0) {
       //报表跳转
       resp = await getRedirReportData(
@@ -176,15 +159,20 @@ const ReportExport = () => {
 
       const { title, data: assignmentData, reportName, current, totalCount, totalPage, pageSize } = resp;
       set_reportName(reportName);
+
+      let scrollX = 0;
       const columns: ProColumns[] = title.map((item: any, index: number) => {
         if (item.search) {
           searchKeys.push({ name: item.name, key: item.columnName });
         }
+        const wid = (item.name.length * 17) > 100 ? (item.name.length * 17): 100;
+        scrollX = scrollX + wid;
+        // console.log({[`${item.name}`]:wid});
         return {
           title: item.name,
           dataIndex: `${item.columnName}`,
           key: `${item.columnName}`,
-          width: getStringWidth(item.name, '14px'),
+          width:wid ,
           ellipsis: true,
           fixed: item.freeze ? true : false,
           hideInTable: item.hide,
@@ -242,6 +230,7 @@ const ReportExport = () => {
       });
 
       set_tableColumn([...columns]);
+      set_tableScrollX(scrollX);
 
       const data = assignmentData.map((item: any) => {
 
@@ -265,9 +254,9 @@ const ReportExport = () => {
         item.forEach((b: any) => {
           const needTitle = title.filter((a: any) => a.code == b.code);
           if (needTitle.length > 0) {
-            if(needTitle[0].dataType == 2&&typeof b.value == 'number'){
+            if (needTitle[0].dataType == 2 && typeof b.value == 'number') {
               rowData[`${needTitle[0].columnName}`] = `${(b.value * 100).toFixed(needTitle[0].decimalPlace ? needTitle[0].decimalPlace : 2)}%`
-            }else{
+            } else {
               rowData[`${needTitle[0].columnName}`] = b.value
             }
           }
@@ -280,18 +269,18 @@ const ReportExport = () => {
       // set_tableData(data);
       set_loading(false);
 
-      
 
-      if(openProcessModal){
-        totalTableData = [...totalTableData,...exportdata];
+
+      if (openProcessModal) {
+        totalTableData = [...totalTableData, ...exportdata];
         return {
-          currentCount:totalTableData.length,
+          currentCount: totalTableData.length,
           totalCount,
           totalPage
         }
       }
 
-      if(!openProcessModal){
+      if (!openProcessModal) {
         return {
           data: data,
           success: true,
@@ -302,7 +291,7 @@ const ReportExport = () => {
       }
 
     }
-    return openProcessModal?{currentCount:0,totalCount:0}:[]
+    return openProcessModal ? { currentCount: 0, totalCount: 0 } : []
   }
 
 
@@ -338,7 +327,7 @@ const ReportExport = () => {
 
     let headers: { [key: string]: any } = {};
     let data: any[] = [];
-    
+
     tableColumn.forEach(a => {
       if (a.hideInTable != 1) {
         headers[`${a.dataIndex}`] = a.title;
@@ -358,7 +347,7 @@ const ReportExport = () => {
       ...data
     ];
 
-    const _columns = tableColumn.filter(a=>a.hideInTable != 1);
+    const _columns = tableColumn.filter(a => a.hideInTable != 1);
 
     exportTableToExcel(excelTableData, _columns as any[], reportName);
     currentPage = 0;
@@ -369,24 +358,24 @@ const ReportExport = () => {
 
 
   const fetchExportData = async () => {
-    
-    currentPage  = currentPage + 1 ;
 
-    const resp:any = await getTableData({...tableDataFilterParams,current:currentPage});
-    
-    if(resp){
-      const { currentCount=0, totalCount=0,totalPage}= resp;
-      
+    currentPage = currentPage + 1;
+
+    const resp: any = await getTableData({ ...tableDataFilterParams, current: currentPage });
+
+    if (resp) {
+      const { currentCount = 0, totalCount = 0, totalPage } = resp;
+
       maxFetchCount = totalPage;
-      return { currentCount, totalCount};
-    }else{
-      return { currentCount:0, totalCount:0};
+      return { currentCount, totalCount };
+    } else {
+      return { currentCount: 0, totalCount: 0 };
     }
   };
 
-  const handleCompletion = ()=>{
-        set_openProcessModal(false);
-        exportHandle();
+  const handleCompletion = () => {
+    set_openProcessModal(false);
+    exportHandle();
 
   }
 
@@ -503,9 +492,9 @@ const ReportExport = () => {
           {currentComputeDate && <KCIMTable actionRef={tableRef} rowKey='id' columns={tableColumn as ProColumns[]}
             params={tableDataFilterParams}
             // loading={loading}
-            scroll={{ x: 100 * tableColumn.length, y: tableH }}
+            scroll={{ x: tableScrollX, y: tableH }}
             // dataSource={tableData}
-            pagination={{ pageSizeOptions: [10, 20, 50, 100, 1000], showSizeChanger: true, defaultPageSize: 100 }}
+            pagination={{ pageSizeOptions: [10, 20, 50, 100, 1000], showSizeChanger: true }}
             request={(params, sort, filter) => getTableData(params)}
           />}
         </div>

+ 246 - 0
src/pages/specialDataImport/index.tsx

@@ -0,0 +1,246 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 11:30:33
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-06-05 17:52: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
+ */
+
+
+
+
+import { createFromIconfontCN } from '@ant-design/icons';
+
+import { ActionType } from '@ant-design/pro-components';
+import { ModalForm, ProFormDatePicker, ProFormSelect, ProFormText, ProFormTextArea } from '@ant-design/pro-form'
+import { ProColumns } from '@ant-design/pro-table';
+import { Input, message, Popconfirm, DatePicker } from 'antd';
+import { useEffect, useRef, useState } from 'react'
+
+import {afterImport, getData, getSpecialImportTable, tableDataImport } from './service';
+import FormItem from 'antd/es/form/FormItem';
+
+import './style.less';
+import '../../utils/zhongtaiA'
+import moment from 'moment';
+import 'moment/locale/zh-cn';
+import locale from 'antd/es/date-picker/locale/zh_CN';
+import { getComputeDate } from '@/pages/Home/service';
+import KCIMUpload from '@/components/KCIMUpload';
+import KCIMPagecontainer from '@/components/KCIMPageContainer';
+import { KCIMTable } from '@/components/KCIMTable';
+
+
+const IconFont = createFromIconfontCN({
+    scriptUrl: '',
+});
+
+
+const currentDate = `${new Date().getFullYear()}-${(new Date().getMonth() + 1).toString().padStart(2, '0')}`;
+
+export default function DicClassfication() {
+
+    const [tableDataFilterParams, set_tableDataFilterParams] = useState<any | undefined>();
+    const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState<string>('');
+    const [currentComputeDate, set_currentComputeDate] = useState<string>(currentDate);
+    const tableRef = useRef<ActionType>();
+
+
+
+
+    const columns: ProColumns[] = [
+
+        {
+            title: '所属年月',
+            dataIndex: 'computeDate',
+            ellipsis: true
+        },
+        {
+            title: '数据库表名称',
+            dataIndex: 'tableNameDisplay',
+            ellipsis: true
+        },
+        {
+            title: '文件名称',
+            dataIndex: 'fileName',
+            ellipsis: true,
+            renderText(text, record, index, action) {
+                return <a href={record.url} target='_blank'>{record.fileName}</a>
+            },
+        },
+        {
+            title: '导入时间',
+            dataIndex: 'createTime',
+            ellipsis: true
+        },
+        {
+            title: '导入人员',
+            dataIndex: 'createUserName',
+            ellipsis: true
+        },
+        {
+            title: '操作',
+            key: 'option',
+            width: 120,
+            valueType: 'option',
+            render: (_: any, record: any) => {
+                return [
+                    <Popconfirm
+                        title={`是否${record.importStatus == 1?'复原导入':'撤销导入'}?`}
+                        key="del"
+                        onConfirm={() => afterImportHandle(record)}
+                    >
+                        <a>{record.importStatus == 1?'复原导入':'撤销导入'}</a>
+                    </Popconfirm>
+                ]
+            },
+        },
+
+    ];
+
+
+    const afterImportHandle =async (record:any) => {
+         const {importStatus} = record;
+         const resp = await afterImport(record.id,importStatus?'RECOVERY':'CANCEL');
+         if(resp){
+            message.success('操作成功!');
+            tableRef.current?.reload();
+         }
+    }
+
+
+    const getTableData = async (params: any) => {
+        const { computeDate } = params;
+        const resp = await getData({ ...params, computeDate: computeDate?computeDate:currentComputeDate });
+        if (resp) {
+            return {
+                data: resp.list,
+                success: true,
+                total: resp.totalCount,
+                pageSize: resp.pageSize,
+                totalPage: resp.totalPage,
+            }
+        }
+        return []
+    }
+
+
+    const importData = () => {
+
+        function downloadTemplate(): void {
+           
+        }
+
+        return (
+            <ModalForm
+                className='SpecialDataImport-Modal'
+                width={360}
+                title={`导入数据`}
+                trigger={
+                    <span key="3" className='importBtn'>导入</span>
+                }
+                submitter={{
+                    render: (props, defaultDoms) => {
+                        const needBtn = defaultDoms.filter((b) => {
+                            return b.key != 'rest'
+                        })
+                        return [
+                            ...needBtn,
+                        ];
+                    },
+                }}
+                onFinish={async (values) => {
+                    // console.log({values});
+                    const { importFile: { fileList } } = values;
+
+                    let formData = new FormData();
+                    formData.append('file', fileList[0].originFileObj);
+                    formData.append('computeDate', values.computeDate);
+                    formData.append('tableName', values.tableName);
+
+                    const resp = await tableDataImport(formData);
+
+                    if (resp) {
+                        tableRef.current?.reload();
+                        return true;
+                    }
+
+                }}
+            >
+                <div className='tip'>本操作为追加导入,会保留已有的数据并将文件的所有记录追加到数据表</div>
+                <ProFormDatePicker.Month label='所属年月' name='computeDate' width={326} rules={[{ required: true, message: '所属年月不能为空!' }]} />
+                <ProFormSelect label='数据库表名称' name='tableName' width={326}
+                    request={async () => {
+                        const resp = await getSpecialImportTable();
+                        if (resp) {
+                            
+                            return resp.map((a: any) => ({
+                                label: a.name,
+                                value: a.code
+                            }))
+                        }
+                        return []
+                    }}
+                    rules={[{ required: true, message: '数据库表名称不能为空!' }]} />
+                <FormItem name={'importFile'}>
+                    {currentComputeDate && <KCIMUpload downloadTemplateFile={() => downloadTemplate()} ifShowTip={false} ifShowTemplateDownload={false} />}
+                </FormItem>
+
+            </ModalForm>
+        )
+    }
+
+
+    return (
+        <KCIMPagecontainer className='SpecialDataImport' title={false} >
+            <div className='toolBar'>
+                <div className='filter'>
+                    <div className='filterItem'>
+                        {(<div className='search'>
+                            <span>所属年月:</span>
+                            <DatePicker
+                                onChange={(data, dateString) => {
+                                    set_tableDataFilterParams({ ...tableDataFilterParams, computeDate: dateString })
+                                }}
+                                picker='month'
+                                locale={locale}
+                                defaultValue={moment(currentComputeDate, '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 getSpecialImportTable();
+                                if (resp) {
+                                    return resp.map((a: any) => ({
+                                        label: a.name,
+                                        value: a.code
+                                    }))
+                                }
+                                return []
+                            }}
+                            fieldProps={{
+                                onChange(value, option) {
+                                    set_tableDataFilterParams({ ...tableDataFilterParams,tableName: value })
+                                },
+                            }}
+                        />
+                    </div>
+                </div>
+                <div className='btnGroup'>
+                    {importData()}
+                </div>
+            </div>
+            <div style={{ marginTop: 16 }}>
+                {currentComputeDate && <KCIMTable columns={columns as ProColumns[]} actionRef={tableRef} rowKey='id' params={tableDataFilterParams} request={(params, sort, filter) => getTableData(params)} />}
+            </div>
+        </KCIMPagecontainer>
+    )
+}

+ 70 - 0
src/pages/specialDataImport/service.ts

@@ -0,0 +1,70 @@
+/*
+ * @Author: code4eat awesomedema@gmail.com
+ * @Date: 2023-03-03 16:31:27
+ * @LastEditors: code4eat awesomedema@gmail.com
+ * @LastEditTime: 2024-06-05 16:34:31
+ * @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 PubDicClassType = any
+
+
+export const getData = (params?:any) => {
+  return request('/costAccount/import/list', {
+    method: 'GET',
+    params:{...params}
+  }); 
+};
+
+
+//获取特殊导入数据表
+
+export const getSpecialImportTable = () => {
+  return request('/costAccount/import/getTableList?current=1&pageSize=500&typeCode=SPECIAL_SHEET_MAP', {
+    method: 'GET',
+  });
+};
+
+
+//数据导入
+
+export const tableDataImport = (data:any) => {
+  return request('/costAccount/import', {
+    method: 'POST',
+    data
+  });
+};
+
+//导入后的撤销/复原操作
+
+export const afterImport = (id:number,type:'CANCEL'|'RECOVERY') => {
+  if(type == 'CANCEL'){
+    return request('/costAccount/import/removeImport', {
+      method: 'POST',
+      params:{id}
+    });
+  }
+  if(type == 'RECOVERY'){
+    return request('/costAccount/import/recoverImport', {
+      method: 'POST',
+      params:{id}
+    });
+  }
+  
+};
+
+
+
+
+
+
+
+
+

+ 57 - 0
src/pages/specialDataImport/style.less

@@ -0,0 +1,57 @@
+.SpecialDataImport-Modal {
+  .tip {
+    font-size: 12px;
+    color: #FF9933;
+    line-height: 16px;
+    background: #FFF9F2;
+    padding: 8px 8px;
+    border-radius: 4px;
+    margin-bottom: 16px;
+  }
+}
+
+.SpecialDataImport {
+  padding: 16px;
+  padding-top: 0;
+  background: #FFFFFF;
+  border-radius: 4px;
+
+
+  .toolBar {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    margin-top: 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 {
+      .importBtn {
+        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;
+      }
+    }
+
+  }
+}

+ 1 - 1
src/pages/static/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-10-26 17:52:50
+ * @LastEditTime: 2024-06-06 17:23: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
  */

+ 11 - 1
src/services/getDic.ts

@@ -2,7 +2,7 @@
  * @Author: code4eat awesomedema@gmail.com
  * @Date: 2023-04-20 14:06:17
  * @LastEditors: code4eat awesomedema@gmail.com
- * @LastEditTime: 2024-01-12 13:37:35
+ * @LastEditTime: 2024-06-28 14:47:20
  * @FilePath: /BudgetManaSystem/src/services/getDic.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -26,6 +26,16 @@ export const getDicDataBySysId =  (systemId:string,dictType?:string) => {
 }
 
 
+//根据系统id+参数code获取制定参数数据
+export const getParamsDataBySysId =  (systemId:string,parameterCode?:string) => {
+    
+  return request('/centerSys/parameter/getParameterByCode', {
+      method: 'GET',
+      params:{systemId,parameterCode}
+  });    
+}
+
+
 //从公共字典获取数据
 export const getPubDicData =  () => {
     

BIN
成本核算系统_2024_04_01.zip