Bläddra i källkod

support old browser

Xiaopeng Zhang 5 månader sedan
förälder
incheckning
67c7d3857e
27 ändrade filer med 10355 tillägg och 539 borttagningar
  1. 1429 521
      package-lock.json
  2. 25 9
      package.json
  3. 1448 0
      src/App2.js
  4. 71 0
      src/Bjhz.js
  5. 900 0
      src/Djcs3.js
  6. 72 0
      src/Editable.js
  7. 78 0
      src/EditableSelect.js
  8. 95 0
      src/EditableSelectGC.js
  9. 81 0
      src/Fbrgycl.js
  10. 73 0
      src/Gfsj.js
  11. 377 0
      src/Home2.js
  12. 72 0
      src/Jrg.js
  13. 1438 0
      src/Qingdan3.js
  14. 73 0
      src/Qtxm.js
  15. 679 0
      src/Qufei.js
  16. 118 0
      src/Rcjhz.js
  17. 2372 0
      src/Service.js
  18. 1 0
      src/Tabulator.css
  19. 71 0
      src/Tbxx.js
  20. 50 0
      src/Test.js
  21. 75 0
      src/Zcbfwf.js
  22. 288 0
      src/Zjcs2.js
  23. 73 0
      src/Zlje.js
  24. 73 0
      src/Zygczgj.js
  25. 178 0
      src/editor.js
  26. 19 9
      src/index.js
  27. 126 0
      src/utils.js

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1429 - 521
package-lock.json


+ 25 - 9
package.json

@@ -3,20 +3,35 @@
   "version": "0.1.0",
   "private": true,
   "dependencies": {
+    "@emotion/react": "^11.14.0",
+    "@emotion/styled": "^11.14.1",
+    "@mui/icons-material": "^5.18.0",
+    "@mui/lab": "^5.0.0-alpha.75",
+    "@mui/material": "^5.5.3",
+    "@mui/x-data-grid": "^6.20.4",
+    "@mui/x-tree-view": "^6.17.0",
     "@testing-library/dom": "^10.4.0",
     "@testing-library/jest-dom": "^6.6.3",
-    "@testing-library/react": "^16.3.0",
+    "@testing-library/react": "^12.0.0",
     "@testing-library/user-event": "^13.5.0",
-    "react": "^19.1.0",
-    "react-dom": "^19.1.0",
+    "antd": "^5.26.1",
+    "react": "^17.0.2",
+    "react-dom": "^17.0.2",
+    "react-router": "^6.30.1",
+    "react-router-dom": "^6.30.1",
     "react-scripts": "5.0.1",
+    "rsuite": "^5.83.2",
+    "serve": "^14.2.4",
+    "source-map-explorer": "^2.5.3",
+    "tabulator-tables": "^6.3.1",
     "web-vitals": "^2.1.4"
   },
   "scripts": {
-    "start": "react-scripts start",
+    "start": "GENERATE_SOURCEMAP=true react-scripts start",
     "build": "react-scripts build",
     "test": "react-scripts test",
-    "eject": "react-scripts eject"
+    "eject": "react-scripts eject",
+    "analyze": "source-map-explorer 'build/static/js/*.js'"
   },
   "eslintConfig": {
     "extends": [
@@ -26,14 +41,15 @@
   },
   "browserslist": {
     "production": [
-      ">0.2%",
-      "not dead",
-      "not op_mini all"
+      "last 100 chrome version",
+      "last 100 firefox version",
+      "last 100 safari version",
+      "last 100 edge version"
     ],
     "development": [
       "last 1 chrome version",
       "last 1 firefox version",
-      "last 1 safari version"
+      "last 100 safari version"
     ]
   }
 }

+ 1448 - 0
src/App2.js

@@ -0,0 +1,1448 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { styled, alpha } from '@mui/material/styles';
+import Paper from '@mui/material/Paper';
+import TextField from '@mui/material/TextField';
+import InputAdornment from '@mui/material/InputAdornment';
+import CancelIcon from '@mui/icons-material/Cancel';
+import Autocomplete from '@mui/material/Autocomplete';
+import { debounce } from '@mui/material/utils';
+import throttle from 'lodash/throttle';
+import {Tree as Tree_2} from 'rsuite';
+import Grid from '@mui/material/Grid';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Qingdan3 from './Qingdan3';
+import Gfsj from './Gfsj';
+import Tbxx from './Tbxx';
+import Bjhz from './Bjhz';
+import Zjcs2 from './Zjcs2';
+import Djcs3 from './Djcs3';
+import Service from './Service';
+import Qufei from './Qufei';
+import Rcjhz from './Rcjhz';
+import Qtxm from './Qtxm';
+import Zlje from './Zlje';
+import Zygczgj from './Zygczgj';
+import Jrg from './Jrg';
+import Zcbfwf from './Zcbfwf';
+import Fbrgycl from './Fbrgycl';
+import {useLocation, useParams} from "react-router";
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import Typography from '@mui/material/Typography';
+import InputLabel from '@mui/material/InputLabel';
+import MenuItem from '@mui/material/MenuItem';
+import FormControl from '@mui/material/FormControl';
+import Select from '@mui/material/Select';
+import Accordion from '@mui/material/Accordion';
+import AccordionActions from '@mui/material/AccordionActions';
+import AccordionSummary from '@mui/material/AccordionSummary';
+import AccordionDetails from '@mui/material/AccordionDetails';
+import Stack from '@mui/material/Stack';
+import { DataGrid, zhCN , GridToolbarQuickFilter} from '@mui/x-data-grid';
+import Backdrop from '@mui/material/Backdrop';
+import CircularProgress from '@mui/material/CircularProgress';
+import { TreeItem, treeItemClasses } from '@mui/x-tree-view/TreeItem';
+import Dialog from '@mui/material/Dialog';
+import DialogTitle from '@mui/material/DialogTitle';
+import DialogContent from '@mui/material/DialogContent';
+import DialogActions from '@mui/material/DialogActions';
+import IconButton from '@mui/material/IconButton';
+import CloseIcon from '@mui/icons-material/Close';
+import SearchIcon from '@mui/icons-material/Search';
+import Button from '@mui/material/Button';
+
+
+import Tooltip from '@mui/material/Tooltip';
+
+const MUI_X_PRODUCTS = [
+    {
+      id: 'grid',
+      label: 'Data Grid',
+      children: [
+        { id: 'grid-community', label: '@mui/x-data-grid' },
+        { id: 'grid-pro', label: '@mui/x-data-grid-pro' },
+        { id: 'grid-premium', label: '@mui/x-data-grid-premium' },
+      ],
+    },
+    {
+      id: 'pickers',
+      label: 'Date and Time Pickers',
+      children: [
+        { id: 'pickers-community', label: '@mui/x-date-pickers' },
+        { id: 'pickers-pro', label: '@mui/x-date-pickers-pro' },
+      ],
+    },
+    {
+      id: 'charts',
+      label: 'Charts',
+      children: [
+        { id: 'charts-community', label: '@mui/x-charts' },
+        { id: 'charts-pro', label: '@mui/charts-pro' },
+      ],
+    },
+    {
+      id: 'tree-view',
+      label: 'Tree View',
+      children: [
+        { id: 'tree-view-community', label: '@mui/x-tree-view' },
+        { id: 'tree-view-pro', label: '@mui/x-tree-view-pro' },
+      ],
+    },
+  ];
+
+  const INFO = [
+
+                      ['名称', '金额', '暂估价', '安全文明施工费', '规费'],
+                     
+  ];
+
+
+  const CustomTreeItem = styled(TreeItem)(({ theme }) => ({
+    
+    [`& .${treeItemClasses.content}`]: {
+      
+      padding: theme.spacing(0.5, 1),
+      margin: theme.spacing(0.2, 0),
+      [`& .${treeItemClasses.label}`]: {
+        fontSize: '0.8rem',
+        fontWeight: 500,
+      },
+    }
+    
+    
+   
+  }));
+
+
+
+
+
+  const StyledTextField = styled(TextField)(({ theme, ownerState }) => ({
+    gridArea: '1 / 1',
+    overflowX: 'clip',
+    width: ownerState.expanded ? 260 : 'var(--trigger-width)',
+    opacity: ownerState.expanded ? 1 : 0,
+    transition: theme.transitions.create(['width', 'opacity']),
+  }));
+  
+
+
+
+
+  export default function App2() {
+
+
+    const [outline, setOutline] = React.useState([]);
+    const [peibishu, setPeibishu] = React.useState([]);
+    const [outlineDes, setOutlineDes] = React.useState([]);
+    const [columnHeaders, setColumnHeaders] = React.useState([]);
+    const [detail, setDetail] = React.useState(INFO);
+    const [deXilie, setDeXilie] = React.useState([]);
+    const [pbXilie, setPbXilie] = React.useState([]);
+    const [nestDetail, setNestDetail] = React.useState(INFO);
+    const [nest, setNest] = React.useState(false);
+    const [qingdan, setQingdan] = React.useState(false);
+    const [cuoshi, setCuoshi] = React.useState(false);
+    const [tbxx, setTbxx] = React.useState(false);
+    const [qufei, setQufei] = React.useState(false);
+    const [rcjhz, setRcjhz] = React.useState(false);
+    const [gfsj, setGfsj] = React.useState(false);
+    const [bjhz, setBjhz] = React.useState(false);
+    const [qtxm, setQtxm] = React.useState(false);
+    const [zlje, setZlje] = React.useState(false);
+    const [zygczgj, setZygczgj] = React.useState(false);
+    const [jrg, setJrg] = React.useState(false);
+    const [zcbfwf, setZcbfwf] = React.useState(false);
+    const [fbrgycl, setFbrgycl] = React.useState(false);
+    const [jrgData, setJrgData] = React.useState([]);
+    const [fbrgyclData, setFbrgyclData] = React.useState([]);
+    const [zcbfwfData, setZcbfwfData] = React.useState([]);
+    const [zygczgjData, setZygczgjData] = React.useState([]);
+    const [zljeData, setZljeData] = React.useState([]);
+    const [gfsjData, setGfsjData] = React.useState([]);
+    const [qtxmData, setQtxmData] = React.useState([]);
+    const [bjhzData, setBjhzData] = React.useState([]);
+    const [tbxxData, setTbxxData] = React.useState([]);
+    const [qdbt, setQdbt] = React.useState([]);
+    const [qdbh, setQdbh] = React.useState(null);
+    const [value, setValue] = React.useState('1');
+    const [dwgc, setDwgc] = React.useState(null);
+    const [zhuanye, setZhuanye] = React.useState(10);
+    const [zhuanye2, setZhuanye2] = React.useState(10);
+    const [expandedQd, setExpandedQd] = React.useState(true);
+    const [expandedPb, setExpandedPb] = React.useState(false);
+    const [expandedDe, setExpandedDe] = React.useState(false);
+    const [zylb, setZylb] = React.useState('');
+    const [selectedItems, setSelectedItems] = React.useState(null);
+    const [expandedItems, setExpandedItems] = React.useState([]);
+    const [rgde, setRgde] = React.useState(null);
+    const [beizhu, setBeizhu] = React.useState(null);
+    const [beizhuFK, setBeizhuFK] = React.useState(null);
+    const [clde, setClde] = React.useState(null);
+    const [jxde, setJxde] = React.useState(null);
+    const [open, setOpen] = React.useState(false);
+    const [dopen, setDopen] = React.useState(false);
+
+    const [dopen2, setDopen2] = React.useState(false);
+
+    const [dingeclick, setDingeclick] = React.useState(null);
+    const [tihuanClick, setTihuanClick] = React.useState(null);
+    const tihuanRowRef = React.useRef(null);
+
+    const relation = React.useRef({});
+    const columns =[
+    
+      {field: '定额编号', headerName: '定额编号', sortable: false},
+      {field: '名称', headerName: '名称', sortable: false}, 
+      {field: '单位', headerName: '单位', sortable: false},
+      {field: '单价', headerName: '单价', sortable: false}
+    ];
+    const columns2 =[
+    
+      {field: '编号', headerName: '定额编号', sortable: false},
+      {field: '名称', headerName: '名称', width: 200, sortable: false}, 
+      {field: '单位', headerName: '单位', sortable: false},
+      {field: '单价', headerName: '单价', sortable: false}
+    ];
+    let location = useParams();
+
+
+    const [acvalue, setAcvalue] = React.useState('');
+    const [acinputvalue, setAcinputvalue] = React.useState('');
+    const [options, setOptions] = React.useState([]);
+    const [suanshiError, setSuanshiError] = React.useState(false);
+    const [helperText, setHelperText] = React.useState('');
+
+    
+    const traverse = (shu) => {
+       for(let i = 0; i < shu.length; i++) {
+          let id = shu[i]["id"];
+          let children = shu[i]["children"];
+          for (let j = 0; j < children.length; j++) {
+             let id2 = children[j]["id"];
+             relation.current[id2]=id;
+          }
+          traverse(children);
+       }
+    };
+    const setOutlineDes_ = (x) => {
+       setOutlineDes(x);
+       relation.current = {};
+       traverse(x);
+      
+    };
+    const handleChangeZhuanye = (event) => {
+           //console.log(event.target.value);
+           Service.generateDingeshu(event.target.value).then(x=>{
+               setOutlineDes_(x);
+           });
+           setZhuanye(event.target.value);
+    };
+
+    const handleChangeZhuanye2 = (event) => {
+      //console.log(event.target.value);
+      
+      setZhuanye2(event.target.value);
+};
+
+    const handleChange = (event, newValue) => {
+      setValue(newValue);
+      setRgde(null);
+      setJxde(null);
+      setClde(null);
+    };
+
+
+
+    const findparent = (id) => {
+        let result = [];
+        while(id) {
+           result.push(id);
+           id = relation.current[id];
+        }
+        return result;
+    };
+
+    const loadingCallback = () => {
+      setOpen(true); 
+      Service.save().then(x=>{
+        setOpen(false);
+      });
+    };
+
+    const suanshiCallback = () => {
+      setDopen2(true);
+    };
+
+    const loadingCallback_djcs = () => {
+      setOpen(true); 
+      Service.save_djcs().then(x=>{
+        setOpen(false);
+      });
+    };
+
+    const qufeiCallback = (id, data) => {
+      setOpen(true); 
+      Service.applyFL(id, data).then(x=>{
+        Service.clearCache();
+        Service.setQufei(data);
+        setOpen(false);
+      });
+    };
+
+    const tihuanCallback = (row, col) => {
+        setDopen(true);
+        tihuanRowRef.current = row;
+    };
+
+
+    const tiaojiaCallback = (bh, bm, mingcheng, danwei, jiage) => {
+      setOpen(true); 
+      Service.tiaojia(location['id'], bh, bm, mingcheng, danwei, jiage).then(x=>{
+        
+        setOpen(false);
+      });
+    };
+
+    const zjcsCallback = (biao_id,bh, row) => {
+      setOpen(true); 
+      Service.updateZjcs(biao_id, bh, row).then(x=>{
+        
+        setOpen(false);
+      });
+    };
+
+
+    const handleClose = () => {
+      setDopen(false);
+    };
+
+
+    const handleSuanshi = () => {
+      //console.log(acinputvalue);
+      if (/^[A-Z0-9\.\-\[\]\+\*\(\)盐常镇泰补扬南通苏新市附录]+$/.test(acinputvalue)) {
+        //console.log();
+        
+        Service.generateSingleDingeXilie(zhuanye2, acinputvalue).then(x=>{
+          let res = JSON.parse(x);
+          let id = res['reverse'];
+          if (id && id != "None") {
+            setSuanshiError(false);
+            setHelperText('');
+            setDopen2(false);
+            res["date"] = Date.now().toString();
+            setDingeclick(JSON.stringify(res));
+          } else {
+            setSuanshiError(true);
+            setHelperText('无效输入');
+            console.log("error");
+          }
+
+        });
+      } else {
+        setSuanshiError(true);
+        setHelperText('无效输入');
+        console.log("error");
+      }
+    };
+
+    const handleClose2 = () => {
+      setDopen2(false);
+    };
+  
+
+    const clickCallback = (qdbm, debh) => {
+      console.log('####################################zylb#####################'.concat(zylb.toString()));
+       //console.log(debh);
+       setExpandedQd(false);
+       setExpandedDe(true);//1 jianzhu 2 zhuangshi 3 anzhuang 4 shizheng 5 yuanlin 6 guidao 7 xiushantujian 8 xiushananzhuang 9 xiushanjiagu  
+       if (qdbm.startsWith("01")) {
+        let suggestion = 10;
+        if (zylb == "7") {
+          suggestion = 50;
+        }  
+        setZhuanye(suggestion);
+          Service.generateSingleDingeXilie(suggestion, debh).then(x=>{
+              //console.log(x);
+              let res = JSON.parse(x);
+              console.log(res);
+              setZhuanye(res["actual_zhuanye"]);
+              let id = res['reverse'];
+              if (id && id != "None") {
+                    setRgde(res["rgde"]);
+                    setJxde(res["jxde"]);
+                    setClde(res["clde"]);
+                    console.log(res["rgde"]);
+                    console.log(res["jxde"]);
+                    console.log(res["clde"]);
+                    setBeizhu(res["bz_selected"]);
+                    setBeizhuFK(res["bz_selected2"]);
+                    Service.generateDingeshu(res["actual_zhuanye"]).then(x=>{
+                        setOutlineDes_(x);
+                        setSelectedItems(id);
+                        setExpandedItems(findparent(id));
+                           Service.generateDingeXilie(res["actual_zhuanye"], id).then(x=>{
+                                let y = JSON.parse(x);
+                                //console.log(y);
+                                let result = [];
+                                let keys = Object.keys(y["DW"])
+                                for(let i = 0; i < keys.length; i++) {
+                                    let key = keys[i];
+                                    let entry = {
+                                      "id": y["DEBH"][key],
+                                      "定额编号":  y["DEBH"][key], 
+                                      "名称":  y["GCLMC"][key],
+                                      "单位":  y["DW"][key],
+                                      "单价":  y["GCLSJDJ"][key]
+                                    };
+                                    result.push(entry);
+                                }
+                                setDeXilie(result);
+                           });
+                    });
+              } else {
+              
+                    setRgde(null);
+                    setJxde(null);
+                    setClde(null);
+                    setBeizhu(res["bz_selected"]);
+              }
+           });
+       
+       } else if (qdbm.startsWith("03")) {//安装
+        let suggestion = 30;
+        if (zylb == "8") {
+          suggestion = 60;
+        }   
+        setZhuanye(suggestion);
+         Service.generateSingleDingeXilie(suggestion, debh).then(x=>{
+          //console.log(x);
+          let res = JSON.parse(x);
+          console.log(res);
+          setZhuanye(res["actual_zhuanye"]);
+          let id = res['reverse'];
+          if (id && id != "None") {
+                setRgde(res["rgde"]);
+                setJxde(res["jxde"]);
+                setClde(res["clde"]);
+                console.log(res["rgde"]);
+                console.log(res["jxde"]);
+                console.log(res["clde"]);
+                setBeizhu(res["bz_selected"]);
+                Service.generateDingeshu(res["actual_zhuanye"]).then(x=>{
+                    setOutlineDes_(x);
+                    setSelectedItems(id);
+                    setExpandedItems(findparent(id));
+                       Service.generateDingeXilie(res["actual_zhuanye"], id).then(x=>{
+                            let y = JSON.parse(x);
+                            //console.log(y);
+                            let result = [];
+                            let keys = Object.keys(y["DW"])
+                            for(let i = 0; i < keys.length; i++) {
+                                let key = keys[i];
+                                let entry = {
+                                  "id": y["DEBH"][key],
+                                  "定额编号":  y["DEBH"][key], 
+                                  "名称":  y["GCLMC"][key],
+                                  "单位":  y["DW"][key],
+                                  "单价":  y["GCLSJDJ"][key]
+                                };
+                                result.push(entry);
+                            }
+                            setDeXilie(result);
+                       });
+                });
+          } else {
+          
+                setRgde(null);
+                setJxde(null);
+                setClde(null);
+                setBeizhu(res["bz_selected"]);
+          }
+       });
+       } else if (qdbm.startsWith("04")) {////市政
+         setZhuanye(20);
+         Service.generateSingleDingeXilie(20, debh).then(x=>{
+          //console.log(x);
+          let res = JSON.parse(x);
+          console.log(res);
+          setZhuanye(res["actual_zhuanye"]);
+          let id = res['reverse'];
+          if (id && id != "None") {
+                setRgde(res["rgde"]);
+                setJxde(res["jxde"]);
+                setClde(res["clde"]);
+                console.log(res["rgde"]);
+                console.log(res["jxde"]);
+                console.log(res["clde"]);
+                setBeizhu(res["bz_selected"]);
+                Service.generateDingeshu(res["actual_zhuanye"]).then(x=>{
+                    setOutlineDes_(x);
+                    setSelectedItems(id);
+                    setExpandedItems(findparent(id));
+                       Service.generateDingeXilie(res["actual_zhuanye"], id).then(x=>{
+                            let y = JSON.parse(x);
+                            //console.log(y);
+                            let result = [];
+                            let keys = Object.keys(y["DW"])
+                            for(let i = 0; i < keys.length; i++) {
+                                let key = keys[i];
+                                let entry = {
+                                  "id": y["DEBH"][key],
+                                  "定额编号":  y["DEBH"][key], 
+                                  "名称":  y["GCLMC"][key],
+                                  "单位":  y["DW"][key],
+                                  "单价":  y["GCLSJDJ"][key]
+                                };
+                                result.push(entry);
+                            }
+                            setDeXilie(result);
+                       });
+                });
+          } else {
+          
+                setRgde(null);
+                setJxde(null);
+                setClde(null);
+                setBeizhu(res["bz_selected"]);
+          }
+       });
+       }
+       else if (qdbm.startsWith("05")) {//园林
+        setZhuanye(40);
+        Service.generateSingleDingeXilie(40, debh).then(x=>{
+         //console.log(x);
+         let res = JSON.parse(x);
+         console.log(res);
+         setZhuanye(res["actual_zhuanye"]);
+         let id = res['reverse'];
+         if (id && id != "None") {
+               setRgde(res["rgde"]);
+               setJxde(res["jxde"]);
+               setClde(res["clde"]);
+               console.log(res["rgde"]);
+               console.log(res["jxde"]);
+               console.log(res["clde"]);
+               setBeizhu(res["bz_selected"]);
+               Service.generateDingeshu(res["actual_zhuanye"]).then(x=>{
+                   setOutlineDes_(x);
+                   setSelectedItems(id);
+                   setExpandedItems(findparent(id));
+                      Service.generateDingeXilie(res["actual_zhuanye"], id).then(x=>{
+                           let y = JSON.parse(x);
+                           //console.log(y);
+                           let result = [];
+                           let keys = Object.keys(y["DW"])
+                           for(let i = 0; i < keys.length; i++) {
+                               let key = keys[i];
+                               let entry = {
+                                 "id": y["DEBH"][key],
+                                 "定额编号":  y["DEBH"][key], 
+                                 "名称":  y["GCLMC"][key],
+                                 "单位":  y["DW"][key],
+                                 "单价":  y["GCLSJDJ"][key]
+                               };
+                               result.push(entry);
+                           }
+                           setDeXilie(result);
+                      });
+               });
+         } else {
+         
+               setRgde(null);
+               setJxde(null);
+               setClde(null);
+               setBeizhu(res["bz_selected"]);
+         }
+      });
+       } else {
+        console.log('####################################zylb#####################'.concat(zylb.toString()));
+       }
+    };
+
+
+    const handleEvent = (A) => {
+      let state = {
+        'time': Date.now(),
+        'newBianhao': A.row['编号'],
+        'newName': A.row['名称'],
+        'newJia': A.row['单价'],
+        'old' : tihuanRowRef.current
+      };
+      setTihuanClick(JSON.stringify(state));
+      setDopen(false);
+      
+    };
+
+
+     const handleChangeAccord = (panel) => (event, newExpanded) => {
+          if (panel == 'qingdan') {
+             setExpandedQd(newExpanded);
+          }
+          else if (panel == 'peibi'){
+             setExpandedPb(newExpanded);
+          } else {
+             setExpandedDe(newExpanded);
+          }
+       };
+    const handleItemSelectionTogglePbs = (itemId, event) => {
+      
+        console.log(itemId);
+        if (["0", "3", "4", "6", "7", "8", "9", "11", "12", "13", "15", "16", "18", "19", "20", "21"].includes(itemId['id'])) {
+            Service.generatePeibiXilie(itemId['id']).then(x=>{
+                let y = JSON.parse(x);
+                console.log(y);
+               
+                let result = [];
+                let keys = Object.keys(y["PBBH"])
+                for(let i = 0; i < keys.length; i++) {
+                    let key = keys[i];
+                    let entry = {
+                      "id": y["id"][key],
+                      "编号":  y["PBBH"][key], 
+                      "名称":  y["PBMC"][key],
+                      "单位":  y["DW"][key],
+                      "单价":  y["PBDJ"][key]
+                    };
+                    result.push(entry);
+                    //setPbXilie(result);
+                }
+                setPbXilie(result);
+            });
+        }
+      
+    }
+
+    const handleDingEEvent = (row) => {
+      
+      Service.generateSingleDingeXilie(zhuanye, row.id).then(x=>{
+       
+        let res = JSON.parse(x);
+        console.log(res);
+        res["date"] = Date.now().toString();
+        setDingeclick(JSON.stringify(res));
+      });
+      //
+    };
+
+    const handleItemSelectionToggleDes = (event, itemId, isSelected) => {
+      if (isSelected) {
+        //console.log(itemId);
+        setSelectedItems(itemId);
+        setExpandedItems(findparent(itemId));
+           Service.generateDingeXilie(zhuanye, itemId).then(x=>{
+                let y = JSON.parse(x);
+                //console.log(y);
+                let result = [];
+                let keys = Object.keys(y["DW"])
+                for(let i = 0; i < keys.length; i++) {
+                    let key = keys[i];
+                    let entry = {
+                      "id": y["DEBH"][key],
+                      "定额编号":  y["DEBH"][key], 
+                      "名称":  y["GCLMC"][key],
+                      "单位":  y["DW"][key],
+                      "单价":  y["GCLSJDJ"][key]
+                    };
+                    result.push(entry);
+                }
+                setDeXilie(result);
+           });
+      }
+    }
+
+    const handleItemSelectionToggle = (event, itemId, isSelected) => {
+      if (isSelected) {
+        //console.log(itemId);
+        let pos = itemId.indexOf("Zylb");
+        let Zylb = itemId.substring(pos+4, pos+5);
+        setZylb(Zylb);
+        //console.log("Zylb=".concat(Zylb));
+        if (itemId.includes("bao jia hui zong")) {
+          let regex = /[0-9]*/; 
+          let id = itemId.match(regex)[0];     
+          Service.generateBaojiahuizong2(location["id"], id).then(x=>{
+                  setBjhzData(x);
+                  setNest(true);
+                  setQingdan(false);
+                  setCuoshi(false);
+                  setQufei(false);
+                  setRcjhz(false);
+                  setGfsj(false);
+                  setBjhz(true);
+                  setTbxx(false);
+                  setQtxm(false);
+                  setZlje(false);
+                  setZygczgj(false);
+                  setJrg(false);
+                  setZcbfwf(false);
+                  setFbrgycl(false);
+                  //setColumnHeaders(["序号", "名称", "金额", "暂估价", "类别"]);
+                });
+        }
+        else if (itemId.includes("gui fei shui jin")) {
+          let regex = /[0-9]*/; 
+          let id = itemId.match(regex)[0];     
+          Service.generateGuifeishuijin2(location["id"], id).then(x=>{
+                  setGfsjData(x);
+                  setNest(true);
+                  setQingdan(false);
+                  setCuoshi(false);
+                  setQufei(false);
+                  setRcjhz(false);
+                  setGfsj(true);
+                  setBjhz(false);
+                  setTbxx(false);
+                  setQtxm(false);
+                  setZlje(false);
+                  setZygczgj(false);
+                  setJrg(false);
+                  setZcbfwf(false);
+                  setFbrgycl(false);
+                  //setColumnHeaders(["序号", "名称", "取费基数", "计算基础","费率", "金额", "类别"]);
+                });
+
+        }
+        else if (itemId.includes("qing dan xiang mu")) {
+          let regex = /[0-9]*/; 
+          let id = itemId.match(regex)[0];     
+          Service.generateQingdanxiangmu2(location["id"], id).then(x=>{
+                  setValue("1");
+                  setNest(false);
+                  setQingdan(true);
+                  setCuoshi(false);
+                  setQdbt(x);
+                  setQdbh(id);
+                  setQufei(false);
+                  setRcjhz(false);
+                  setGfsj(false);
+                  setBjhz(false);
+                  setTbxx(false);
+                  setQtxm(false);
+                  setZlje(false);
+                  setZygczgj(false);
+                  setJrg(false);
+                  setZcbfwf(false);
+                  setFbrgycl(false);
+                  //setColumnHeaders(["序号", "名称", "取费基数", "计算基础", "金额", "类别"]);
+                });
+
+        }
+        else if (itemId.includes("cuo shi xiang mu")) {
+          let regex = /[0-9]*/; 
+          let id = itemId.match(regex)[0];     
+          setValue("1");
+          setNest(false);
+          setQingdan(false);
+          setCuoshi(true);
+          setDwgc(id);
+          setQufei(false);
+          setRcjhz(false);
+          setGfsj(false);
+          setBjhz(false);
+          setTbxx(false);
+          setQtxm(false);
+          setZlje(false);
+          setZygczgj(false);
+          setJrg(false);
+          setZcbfwf(false);
+          setFbrgycl(false);
+          //setColumnHeaders(["序号", "名称", "取费基数", "计算基础", "金额", "类别"]);
+
+        }
+        else if (itemId.includes("qi ta xiang mu")) {
+          let regex = /[0-9]*/; 
+          let id = itemId.match(regex)[0];     
+          setValue("1");
+          //setColumnHeaders(["序号", "名称", "取费基数", "计算基础", "金额", "类别"]);
+          Service.generateQitaxiangmu2(location["id"], id).then(x=>{
+                  //setNestDetail(x);
+                  setQtxmData(x);
+                  setNest(true);
+                  setQingdan(false);
+                  setCuoshi(false);
+                  setQufei(false);
+                  setRcjhz(false);
+                  setGfsj(false);
+                  setBjhz(false);
+                  setTbxx(false);
+                  setQtxm(true);
+                  setZlje(false);
+                  setZygczgj(false);
+                  setJrg(false);
+                  setZcbfwf(false);
+                  setFbrgycl(false);
+                 //setColumnHeaders(["序号", "名称", "金额", "项目类别", "备注"]);
+                });
+
+        } else if (itemId.includes("zhuan ye gong cheng zan gu jia")){
+          let regex = /[0-9]*/; 
+          let id = itemId.match(regex)[0];     
+          setValue("1");
+          //setColumnHeaders(["序号", "名称", "取费基数", "计算基础", "金额", "类别"]);
+          Service.generateZygczgj(location["id"], id).then(x=>{
+                  setZygczgjData(x);
+                  setNest(false);
+                  setQingdan(false);
+                  setCuoshi(false);
+                  setQufei(false);
+                  setRcjhz(false);
+                  setGfsj(false);
+                  setBjhz(false);
+                  setTbxx(false);
+                  setQtxm(false);
+                  setZlje(false);
+                  setZygczgj(true);
+                  setJrg(false);
+                  setZcbfwf(false);
+                  setFbrgycl(false);
+                  //setColumnHeaders(["序号", "名称", "金额", "项目类别", "备注"]);
+                });
+        }
+        else if (itemId.includes("zan lie jin e")) {
+          let regex = /[0-9]*/; 
+          let id = itemId.match(regex)[0];     
+          setValue("1");
+          //setColumnHeaders(["序号", "名称", "取费基数", "计算基础", "金额", "类别"]);
+          Service.generateZanliejine2(location["id"], id).then(x=>{
+                  //setDetail(x);
+                  setZljeData(x);
+                  setNest(false);
+                  setQingdan(false);
+                  setCuoshi(false);
+                  setQufei(false);
+                  setRcjhz(false);
+                  setGfsj(false);
+                  setBjhz(false);
+                  setTbxx(false);
+                  setQtxm(false);
+                  setZlje(true);
+                  setZygczgj(false);
+                  setJrg(false);
+                  setZcbfwf(false);
+                  setFbrgycl(false);
+                });
+
+        }
+        else if (itemId.includes("ji ri gong")) {
+          let regex = /[0-9]*/; 
+          let id = itemId.match(regex)[0];     
+          setValue("1");
+          //setColumnHeaders(["序号", "名称", "取费基数", "计算基础", "金额", "类别"]);
+          Service.generateJirigong2(location["id"], id).then(x=>{
+                  setJrgData(x);
+                  setNest(false);
+                  setQingdan(false);
+                  setCuoshi(false);
+                  setQufei(false);
+                  setRcjhz(false);
+                  setGfsj(false);
+                  setBjhz(false);
+                  setTbxx(false);
+                  setQtxm(false);
+                  setZlje(false);
+                  setZygczgj(false);
+                  setJrg(true);
+                  setZcbfwf(false);
+                  setFbrgycl(false);
+                });
+
+        }
+        else if (itemId.includes("zong cheng bao fu wu fei")) {
+          let regex = /[0-9]*/; 
+          let id = itemId.match(regex)[0];     
+          setValue("1");
+          //setColumnHeaders(["序号", "名称", "取费基数", "计算基础", "金额", "类别"]);
+          Service.generateZongchengbaofuwufei2(location["id"], id).then(x=>{
+                  setZcbfwfData(x);
+                  setNest(false);
+                  setQingdan(false);
+                  setCuoshi(false);
+                  setQufei(false);
+                  setRcjhz(false);
+                  setGfsj(false);
+                  setBjhz(false);
+                  setTbxx(false);
+                  setQtxm(false);
+                  setZlje(false);
+                  setZygczgj(false);
+                  setJrg(false);
+                  setZcbfwf(true);
+                  setFbrgycl(false);
+                });
+
+        }
+        else if (itemId.includes("fa bao ren gong ying cai liao")) {
+          let regex = /[0-9]*/; 
+          let id = itemId.match(regex)[0];     
+          setValue("1");
+          //setColumnHeaders(["序号", "名称", "取费基数", "计算基础", "金额", "类别"]);
+          Service.generateFabaorengongyingcailiao2(location["id"], id).then(x=>{
+                  setFbrgyclData(x);
+                  setNest(false);
+                  setQingdan(false);
+                  setCuoshi(false);
+                  setQufei(false);
+                  setRcjhz(false);
+                  setGfsj(false);
+                  setBjhz(false);
+                  setTbxx(false);
+                  setQtxm(false);
+                  setZlje(false);
+                  setZygczgj(false);
+                  setJrg(false);
+                  setZcbfwf(false);
+                  setFbrgycl(true);
+                });
+
+        }
+        else if (itemId.includes("ren cai ji hui zong")) {
+          let regex = /[0-9]*/; 
+          let id = itemId.match(regex)[0];     
+          setValue("1");
+          //setColumnHeaders(["序号", "名称", "取费基数", "计算基础", "金额", "类别"]);
+          //Service.generateRencaijihuizong2(location["id"], id).then(x=>{
+                  //setDetail(x);
+                  setRcjhz(true);
+                  setNest(false);
+                  setQingdan(false);
+                  setCuoshi(false);
+                  setQufei(false);
+                  setGfsj(false);
+                  setBjhz(false);
+                  setTbxx(false);
+                  setQtxm(false);
+                  setZlje(false);
+                  setZygczgj(false);
+                  setJrg(false);
+                  setZcbfwf(false);
+                  setFbrgycl(false);
+                  setQdbh(id);
+                //}
+                //)
+                ;
+
+        }
+        else if (itemId.includes("TouBiaoXx")) {
+            Service.generateDetail2(location["id"]).then(x=>{
+            setQingdan(false);
+            setCuoshi(false);
+            setTbxxData(x);
+            setNest(false);
+            setQufei(false);
+            setRcjhz(false);
+            setGfsj(false);
+            setBjhz(false);
+            setTbxx(true);
+            setQtxm(false);
+            setZlje(false);
+            setZygczgj(false);
+            setJrg(false);
+            setZcbfwf(false);
+            setFbrgycl(false);
+        });
+
+        }
+      }
+    };
+    React.useEffect(
+      () => {
+        console.log(location);
+        Service.generateQufei(location["id"]).then(x=>{
+
+          Service.setQufei(x);
+          });
+        Service.generateOutline2(location["id"]).then(x=>{
+          let y = x.map(z=>{
+            z['key'] = z['id'];
+            z['title'] = z['label'];
+            z['value'] = z['id'];
+            return z;
+          });
+          let y1 = y.map(
+            z=> {
+              if (z.hasOwnProperty('children')) {
+                z['children'] = z['children'].map(a=>{
+                  a['key'] = a['id'];
+                  a['title'] = a['label'];
+                  a['value'] = a['id'];
+                  return a;
+                });
+              }
+              return z;
+            }
+          );
+          let y2 = y1.map(z=>{
+            if (z.hasOwnProperty('children')) {
+              let child = z['children'];
+              for (let i = 0; i < child.length; i++) {
+                let children = child[i];
+                if (children.hasOwnProperty('children')) {
+                  children['children'] = children['children'].map(a=>{
+                    a['key'] = a['id'];
+                    a['title'] = a['label'];
+                    a['value'] = a['id'];
+                    return a;
+                  })
+                }
+              }
+
+            }
+            return z;
+          });
+        setOutline(y2);
+        });
+        Service.generateDetail2(location['id']).then(x=>{
+
+        setTbxxData(x);
+        setTbxx(true);
+        });
+           Service.generateDingeshu(10).then(x=>{
+               setOutlineDes_(x);
+           });
+      }, [location]
+    );
+    React.useEffect(
+      () => {
+        Service.generatePeibishu(zhuanye).then(x=>{
+            setPeibishu(x);
+        });
+      }, [zhuanye]
+    );
+
+    /**  <MenuItem value={10}>土建</MenuItem>
+                     <MenuItem value={20}>市政</MenuItem>
+                     <MenuItem value={30}>安装</MenuItem>
+                     <MenuItem value={40}>园林</MenuItem>
+                     <MenuItem value={50}>修缮(土建)</MenuItem>
+                     <MenuItem value={60}>修缮(安装)</MenuItem> */
+
+    const throttled = React.useRef(throttle((zhuanye2, newValue) => {
+      if (zhuanye2 == 10) {
+        Service.searchDe('土建', newValue).then(x=>{setOptions(x)});
+      }
+      if (zhuanye2 == 20) {
+        Service.searchDe('市政', newValue).then(x=>{setOptions(x)});
+      }
+      if (zhuanye2 == 30) {
+        Service.searchDe('安装', newValue).then(x=>{setOptions(x)});
+      }
+      if (zhuanye2 == 40) {
+        Service.searchDe('园林', newValue).then(x=>{setOptions(x)});
+      }
+      if (zhuanye2 == 50) {
+        Service.searchDe('修缮(土建)', newValue).then(x=>{setOptions(x)});
+      }
+      if (zhuanye2 == 60) {
+        Service.searchDe('修缮(安装)', newValue).then(x=>{setOptions(x)});
+      }
+
+      
+    }, 1000));
+    React.useEffect(
+      () => {
+        throttled.current(zhuanye2, acinputvalue);
+      }, [acinputvalue]
+    );
+
+
+    const onSelect = (selectedKeys, info) => {
+      if (!selectedKeys.hasOwnProperty("children")) {
+      console.log(selectedKeys);
+      if (selectedKeys['id'].includes('Zylb')) {
+      handleItemSelectionToggle(null, selectedKeys['id'], true);
+      } else if (selectedKeys['id'].includes('TouBiaoXx')){
+        console.log(selectedKeys);
+        handleItemSelectionToggle(null, "Zylb1TouBiaoXx", true);
+      }
+    }
+    };
+    const onSelectDes = (selectedKeys, info) => {
+      
+      console.log(selectedKeys);
+      
+      handleItemSelectionToggleDes(null, selectedKeys['id'], true);
+      
+    };
+
+
+    function CustomToolbar() {
+      return (
+        <Box
+          sx={{
+            p: 0.5,
+            pb: 0,
+          }}
+        >
+          <GridToolbarQuickFilter />
+        </Box>
+      );
+    }
+
+
+    return (
+
+        <Box sx={{ flexGrow: 1  }}>
+          <Grid container spacing={2}>
+            <Grid item size={3}>
+            <Box sx={{ width: '25vw'}}>
+
+
+
+                <Accordion expanded={expandedQd} disableGutters
+                     onChange={handleChangeAccord('qingdan')}>
+                   <AccordionSummary 
+                     expandIcon={<ExpandMoreIcon />}
+                     aria-controls="panel1-content"
+                     id="panel1-header"
+                   >
+                     <Typography  component="span">清单</Typography>
+                   </AccordionSummary>
+                   <AccordionDetails>
+                     <Tree_2 height="90vh" 
+                     onSelect={onSelect}
+                     
+                     
+
+                     data={outline}/>
+                   </AccordionDetails>
+                 </Accordion>
+                <Accordion expanded={expandedDe} disableGutters
+                      onChange={handleChangeAccord('dinge')}>
+                   <AccordionSummary
+                     expandIcon={<ExpandMoreIcon />}
+                     aria-controls="panel1-content"
+                     id="panel1-header"
+                   >
+                     <Typography component="span">定额</Typography>
+                   </AccordionSummary>
+                   <AccordionDetails>
+                     <FormControl  size="small">
+                     <InputLabel id="demo-multiple-name-label">专业</InputLabel>
+                     <Select
+                       labelId="demo-multiple-name-label"
+                       id="demo-multiple-name"
+                       value={zhuanye}
+                       onChange={handleChangeZhuanye}
+                       label="专业" 
+                     >
+                     <MenuItem value={10}>土建</MenuItem>
+                     <MenuItem value={20}>市政</MenuItem>
+                     <MenuItem value={30}>安装</MenuItem>
+                     <MenuItem value={40}>园林</MenuItem>
+                     <MenuItem value={50}>修缮(土建)</MenuItem>
+                     <MenuItem value={60}>修缮(安装)</MenuItem>
+                     </Select>
+                   </FormControl> 
+                   <Stack spacing={1}>
+                    <Tree_2 height="calc(100vh - 560px)" 
+                     onSelect={onSelectDes}
+                     value={selectedItems}
+                     expandItemValues={expandedItems}
+                     data={outlineDes}/>
+                  <div style={{ height: 350 }}>
+
+                    <DataGrid
+                    sx={{
+                      '& .MuiDataGrid-cell': {
+                        fontSize: '0.8rem', // Adjust font size for cells
+                      },
+                    /*  '& .MuiDataGrid-columnHeaders': {
+                        fontSize: '1rem', // Adjust font size for column headers
+                      },*/
+                    }}
+                       getRowHeight={() => 'auto'}
+                      rows={deXilie}
+                      columns={columns}
+                      hideFooter={true}
+                      disableColumnMenu
+                      onRowDoubleClick={handleDingEEvent}
+                      localeText={zhCN.components.MuiDataGrid.defaultProps.localeText}
+                    />
+                   </div>
+                   </Stack>
+                   </AccordionDetails>
+                 </Accordion>
+
+                 <Button variant="outlined" fullWidth onClick={()=> {
+                  setQufei(true);
+                  setQingdan(false);
+                  setCuoshi(false);
+                  setRcjhz(false);
+                  setGfsj(false);
+                  setBjhz(false);
+                  setTbxx(false);
+                  setQtxm(false);
+                  setZlje(false);
+                  setZygczgj(false);
+                  setJrg(false);
+                  setZcbfwf(false);
+                  setFbrgycl(false);
+                 }}>费率</Button>
+
+            
+
+            </Box>
+
+            </Grid>
+            <Grid item size={9}>
+              {!nest && !qingdan && !cuoshi && !qufei && rcjhz && !gfsj && !bjhz && !tbxx && !qtxm && !zlje && !zygczgj && !jrg && !zcbfwf && !fbrgycl && <Box sx={{ width: '70vw'}}><Rcjhz 
+              id={location['id']} 
+              bh={qdbh}
+              tiaojiaCallback={tiaojiaCallback}
+              /></Box>}
+
+               {!nest && !qingdan && !cuoshi && !qufei && !rcjhz && !gfsj && !bjhz && !tbxx && !qtxm && zlje && !zygczgj && !jrg && !zcbfwf && !fbrgycl && <Zlje 
+              data={zljeData} 
+              />}
+
+            {!nest && !qingdan && !cuoshi && !qufei && !rcjhz && !gfsj && !bjhz && !tbxx && !qtxm && !zlje && !zygczgj && !jrg && !zcbfwf && fbrgycl && <Fbrgycl
+              data={fbrgyclData} 
+              />}
+
+              {!nest && !qingdan && !cuoshi && !qufei && !rcjhz && !gfsj && !bjhz && !tbxx && !qtxm && !zlje && !zygczgj && !jrg && zcbfwf && !fbrgycl && <Zcbfwf
+              data={zcbfwfData} 
+              />}
+
+              {!nest && !qingdan && !cuoshi && !qufei && !rcjhz && !gfsj && !bjhz && !tbxx && !qtxm && !zlje && !zygczgj && jrg && !zcbfwf && !fbrgycl && <Jrg 
+              data={jrgData} 
+              />}
+              
+              {!nest && !qingdan && !cuoshi && !qufei && !rcjhz && !gfsj && !bjhz && !tbxx && !qtxm && !zlje && zygczgj && !jrg && !zcbfwf && !fbrgycl && <Zygczgj
+              data={zygczgjData} 
+              />}
+
+              {!nest && !qingdan && !cuoshi && !qufei && !rcjhz && !gfsj && !bjhz && tbxx && !qtxm && !zlje && !zygczgj && !jrg && !zcbfwf && !fbrgycl && <Tbxx 
+              data={tbxxData} 
+              
+              />}
+
+              {nest && !qingdan && !cuoshi && !qufei && !rcjhz && gfsj && !bjhz && !tbxx && !qtxm && !zlje && !zygczgj && !jrg && !zcbfwf && !fbrgycl && <Gfsj 
+                   data={gfsjData}
+              
+              />}
+
+              {nest && !qingdan && !cuoshi && !qufei && !rcjhz && !gfsj && !bjhz && !tbxx && qtxm && !zlje && !zygczgj && !jrg && !zcbfwf && !fbrgycl && <Qtxm 
+                   data={qtxmData}
+              
+              />}
+
+
+               {nest && !qingdan && !cuoshi && !qufei && !rcjhz && !gfsj && bjhz && !tbxx && !qtxm && !zlje && !zygczgj && !jrg && !zcbfwf && !fbrgycl && <Bjhz 
+                   data={bjhzData}
+              
+               />}
+             
+            
+            
+            {!qingdan && !cuoshi && qufei && !rcjhz && !gfsj && !bjhz && !tbxx && !qtxm && !zlje && !zygczgj && !jrg && !zcbfwf && !fbrgycl && <Qufei id={location['id']} qufeiCallback={qufeiCallback}
+                  />}
+
+            {!nest && qingdan && !cuoshi && !qufei && !rcjhz && !gfsj && !bjhz  && !tbxx && !qtxm && !zlje && !zygczgj && !jrg && !zcbfwf && !fbrgycl &&  <Box sx={{ width: '70vw'}}><TabContext value={value}>
+                   <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
+                      <TabList scrollButtons='auto' 
+                              variant="scrollable"
+                              sx={{minHeight: '24px'}}
+                      onChange={handleChange} aria-label="lab API tabs example">
+                        {qdbt.map((x, index)=> <Tab sx={{p: 0, minHeight: '24px'}} label={x} value={(index+1).toString()} />)}
+                      </TabList>
+                   </Box>
+                   {qdbt.map((x, index)=><TabPanel sx={{p: 1}} value={(index+1).toString()}>
+                             <Qingdan3
+                                name={location["id"]}
+                                bh={qdbh}
+                                bt={x}
+                                rgde={rgde}
+                                jxde={jxde}
+                                clde={clde}
+                                beizhu={beizhu}
+                                beizhuFK={beizhuFK}
+                                clickCallback={clickCallback}
+                                loadingCallback={loadingCallback}
+                                dingeclick={dingeclick}
+                                tihuanCallback={tihuanCallback}
+                                tihuanClick={tihuanClick}
+                                suanshiCallback={suanshiCallback}
+                             />                     
+                     </TabPanel>
+                      )}
+                </TabContext></Box>}
+            {!nest && !qingdan && cuoshi && !qufei && !rcjhz && !gfsj && !bjhz && !tbxx && !qtxm && !zlje && !zygczgj && !jrg && !zcbfwf && !fbrgycl &&  <Box sx={{ width: '70vw'}}><TabContext value={value}>
+                   <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
+                      <TabList scrollButtons='auto' 
+                              variant="scrollable"
+                              sx={{minHeight: '24px'}}
+                      onChange={handleChange} aria-label="lab API tabs example">
+                        <Tab sx={{p: 0, minHeight: '24px'}} label="总价措施" value="1" />
+                        <Tab sx={{p: 0, minHeight: '24px'}} label="单价措施" value="2" />
+                      </TabList>
+                   </Box>
+                   <TabPanel sx={{p: 1}} value="1">
+                     <Zjcs2 name={location["id"]} bh={dwgc} zjcsCallback={zjcsCallback}/>
+                   </TabPanel>
+                   <TabPanel sx={{p: 1}} value="2">
+                     <Djcs3
+                         name={location["id"]} 
+                         bh={dwgc}
+                         rgde={rgde}
+                         jxde={jxde}
+                         clde={clde}
+                         beizhu={beizhu}
+                         clickCallback={clickCallback}
+                         loadingCallback={loadingCallback_djcs}
+                         dingeclick={dingeclick}
+                         beizhuFK={beizhuFK}
+
+
+                     />
+                   </TabPanel>
+                      
+                </TabContext>
+                </Box>
+                }
+
+
+            </Grid>
+
+          </Grid>
+
+          <Backdrop
+              sx={(theme) => ({ color: '#fff', zIndex: theme.zIndex.drawer + 1 })}
+              open={open}
+          >
+                <CircularProgress color="inherit" />
+         </Backdrop>
+         <Dialog
+           onClose={handleClose}
+           aria-labelledby="customized-dialog-title"
+           open={dopen}
+           fullWidth={true}
+           maxWidth="md"
+          >
+            <DialogTitle sx={{ m: 0, p: 2 }} id="customized-dialog-title">
+             替换
+            </DialogTitle>
+            <IconButton
+             aria-label="close"
+             onClick={handleClose}
+             sx={(theme) => ({
+               position: 'absolute',
+               right: 8,
+               top: 8,
+               color: theme.palette.grey[500],
+             })}
+            >
+             <CloseIcon />
+            </IconButton>
+            <DialogContent dividers>
+            <Stack  direction="row" spacing={2}>
+               <Box sx={{ maxHeight: "350px", minWidth: "300px", maxWidth: "300px"}}>
+               <Tree_2  
+                      onSelect={handleItemSelectionTogglePbs}
+                      defaultValue={null}
+
+                     
+                     data={peibishu}/>
+                     </Box>
+                     
+               
+              
+               <div style={{ height: 350 }}>
+
+                    <DataGrid disableColumnMenu
+                      sx={{
+                        '& .MuiDataGrid-cell': {
+                          fontSize: '0.8rem', // Adjust font size for cells
+                        }}}
+                       getRowHeight={() => 'auto'}
+                      rows={pbXilie}
+                      onRowDoubleClick={handleEvent}
+                      columns={columns2}
+                      hideFooter={false}
+                      disableColumnFilter
+                      disableColumnSelector
+                      disableDensitySelector
+                      slots={{ toolbar: CustomToolbar}}
+                      
+                      localeText={zhCN.components.MuiDataGrid.defaultProps.localeText}
+                     />
+                    </div>
+              
+             
+              
+            </Stack>
+          
+          
+           </DialogContent>
+         </Dialog>
+         <Dialog
+           onClose={handleClose2}
+           aria-labelledby="customized-dialog-title"
+           open={dopen2}
+           fullWidth={true}
+           maxWidth="md"
+          >
+            <DialogTitle sx={{ m: 0, p: 2 }} id="customized-dialog-title">
+             定额(算式)
+            </DialogTitle>
+            <IconButton
+             aria-label="close"
+             onClick={handleClose2}
+             sx={(theme) => ({
+               position: 'absolute',
+               right: 8,
+               top: 8,
+               color: theme.palette.grey[500],
+             })}
+            >
+             <CloseIcon />
+            </IconButton>
+            <DialogContent dividers>
+            <Stack direction='row' spacing={2}>
+            <FormControl  size="small">
+                     <InputLabel id="demo-multiple-name-label">专业</InputLabel>
+                     <Select
+                       labelId="demo-multiple-name-label"
+                       id="demo-multiple-name"
+                       value={zhuanye2}
+                       onChange={handleChangeZhuanye2}
+                       label="专业" 
+                     >
+                     <MenuItem value={10}>土建</MenuItem>
+                     <MenuItem value={20}>市政</MenuItem>
+                     <MenuItem value={30}>安装</MenuItem>
+                     <MenuItem value={40}>园林</MenuItem>
+                     <MenuItem value={50}>修缮(土建)</MenuItem>
+                     <MenuItem value={60}>修缮(安装)</MenuItem>
+                     </Select>
+              </FormControl> 
+              <Autocomplete sx={{ width: 300 }} size="small" disableClearable
+                id="free-solo-demo"
+                freeSolo
+                filterOptions={(x) => x}
+                options={options}
+                value={acvalue}
+                inputValue={acinputvalue}
+                onChange={(event, newValue) => {
+                  //setOptions(newValue ? [newValue, ...options] : options);
+                  setAcvalue(newValue);
+                }}
+                getOptionDisabled={()=>true}
+                onInputChange={(event, newInputValue) => {
+                  setAcinputvalue(newInputValue);
+                }}
+                renderInput={(params) => <TextField {...params} error={suanshiError}  helperText={helperText}/>}
+               />
+
+                <Button variant="outlined" size="small" onClick={handleSuanshi}>确定</Button>   
+              </Stack>
+          
+           </DialogContent>
+         </Dialog>
+            
+        </Box>
+    );
+  }

+ 71 - 0
src/Bjhz.js

@@ -0,0 +1,71 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+//registerPlugin(NestedRows);
+import Service from './Service';
+
+import Button from '@mui/material/Button';
+
+import {copy} from './utils';
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+export default function Bjhz({data}) {
+    const myRef = React.useRef();
+    const myTable = React.useRef(null);
+
+
+
+    React.useEffect(() => {
+      myTable.current = new Tabulator(myRef.current, {
+           index: "key",
+           height: 600,
+         data: data, //link data to table
+         reactiveData: false, //enable data reactivity
+         dataTreeStartExpanded:true,
+         dataTree: true,
+         selectableRows:1, //make rows selectable
+         editTriggerEvent:"dblclick", //trigger edit on double click
+         dataTreeStartExpanded:function(row, level){
+             //console.log(row);
+             //console.log(level);
+             return true; //expand rows where the "driver" data field is true;
+         },
+         columns: [ //Define Table Columns 序号", "名称", "取费基数", "计算基础","费率", "金额", "类别
+                      {title:"序号", field:"序号", width:80, headerSort:false,}, //never hide this column
+                      {title:"名称", field:"名称", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                      {title:"金额", field:"金额", width:100,   formatter:"money", },
+                      {title:"暂估价", field:"暂估价", width:100,   formatter:"textarea"},
+                      {title:"类别", field:"类别", width:100,   formatter:"textarea"},
+                    
+              ]
+       }); 
+       
+       myTable.current.on("cellDblClick", function(e, cell){
+           //e - the click event object
+           //cell - cell component
+           console.log(cell);
+       });
+  
+       //myTable.current.on("rowSelected", handleSelect);
+       
+  
+       
+  
+  
+      
+     
+    }, [data]);
+    return (
+      <div ref={myRef}> 
+      </div>
+
+
+
+    );
+}

+ 900 - 0
src/Djcs3.js

@@ -0,0 +1,900 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import Table from 'rsuite/Table';
+import 'rsuite/Table/styles/index.css';
+import Checkbox from 'rsuite/Checkbox';
+import 'rsuite/Checkbox/styles/index.css';
+import { CustomProvider } from 'rsuite';
+import zhCN from 'rsuite/locales/zh_CN';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+import Service from './Service';
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+import {extractFuzhu, match_target} from './utils';
+import Button from '@mui/material/Button';
+import {shanchu_djcs, undo_djcs, redo_djcs, danxiangdinge_djcs, updateDercj_djcs, changguidinge_djcs, handleBeizhu_djcs, huan, updateShuliang_djcs} from './editor';
+import {copy} from './utils';
+
+const {Column, HeaderCell, Cell} = Table;
+
+
+function number_equal(a, b) {
+     if (Number(a) - Number(b) < 0.0001 && Number(a) - Number(b) > -0.0001) {
+          return true;
+     }
+     return false;
+}
+export default function Djcs3({name, bh, rgde, jxde, clde, beizhu, beizhuFK, clickCallback, loadingCallback, dingeclick}) {
+     const lastClickRef = React.useRef(null);
+
+    
+     var editCheck = function(cell){
+          //cell - the cell component for the editable cell
+      
+          //get row data
+          //console.log(cell);
+          if(cell._cell.row.data['序号']) return false;
+          return true;
+      }
+
+      var editCheckRcj = function(cell){
+          //cell - the cell component for the editable cell
+      
+          //get row data
+          //console.log(cell);
+          if(isQdrcj.current) return false;
+          return true;
+      }
+
+
+
+      var sparklineFormatter = function(cell, formatterParams, onRendered){
+          for (let i = 0; i < highlight.current.length; i++) {
+               let entry = highlight.current[i];
+               if (entry.row + 1 == cell._cell.row.position && entry.col + 1 == cell._cell.column.getPosition()) {
+                    cell.getElement().style.fontWeight = 'bold';
+                    cell.getElement().style.color = 'green';
+                    cell.getElement().style.background = '#d7f1e1';
+               }
+              }
+              return Number(cell.getValue()).toFixed(2).toString(); 
+          };
+
+
+     function handleSelect(row){
+          //e - the click event object
+          //cell - cell component
+          console.log('rowSelected');
+          selectedRowKeysTable.current = [row._row['data']['key']];
+          let bt = "Djcs" ;
+          
+          if (row._row.data['序号'] != null && row._row.data['序号'].length >0) {
+               selectedRowKeysTableParent.current = row._row['data']['key'];
+
+               setFuzhu([]);
+               Service.generateQingdanrcj(name, bh,bt,row._row.data['清单编码']).then(x=>{
+                    let y =[];
+                    for (let i = 1; i < x.length; i++) {
+                         y.push({
+                              'ID' : x[i][0],
+                              '人材机编码' : x[i][1],
+                              '名称' : x[i][2],
+                              '规格型号': x[i][3],
+                              '单位' : x[i][4],
+                              '单价' : x[i][5],
+                              '产地' : x[i][6],
+                              '供应厂商' : x[i][7],
+                              '人材机类别' : x[i][8],
+                              '甲供标志': x[i][9],
+                              '含量' : x[i][10],
+                              '合价' : x[i][11],
+                              '暂估价标志' : x[i][12],
+                              '主要材料标志' : x[i][13],
+                              '主材标志' : x[i][14],
+                              '设备标志' : x[i][15] 
+
+                         });
+                    }
+                    setRcjhl(y);
+                    if (rcjTable.current) {
+                         rcjTable.current.replaceData(y);
+                    }
+
+                    isQdrcj.current=true;
+                    highlight.current = [];
+               });
+               Service.generateQingdanTuijian(name, bh,bt,row._row.data['清单编码']).then(x=>{
+                    setTuijian(x);
+                    if (tuijianTable.current) tuijianTable.current.replaceData(x);
+               });
+          } else {
+               
+               let row_parent = row._row;
+               while(row_parent.modules.dataTree.parent) {
+                   row_parent = row_parent.modules.dataTree.parent;
+               }
+               debmRef.current = row._row['data']['清单编码'];
+               selectedRowKeysTableParent.current = row_parent['data']['key'];
+
+
+                             clickCallback(row_parent['data']['清单编码'], row._row['data']['清单编码']);
+                             Service.generateDingercj(name, bh,bt,row_parent['data']['清单编码'], row._row['data']['清单编码']).then(x=>{
+                              let y =[];
+                              for (let i = 1; i < x[0].length; i++) {
+                                   y.push({
+                                        'ID' : x[0][i][0],
+                                        '人材机编码' : x[0][i][1],
+                                        '名称' : x[0][i][2],
+                                        '规格型号': x[0][i][3],
+                                        '单位' : x[0][i][4],
+                                        '单价' : x[0][i][5],
+                                        '产地' : x[0][i][6],
+                                        '供应厂商' : x[0][i][7],
+                                        '人材机类别' : x[0][i][8],
+                                        '甲供标志': x[0][i][9],
+                                        '含量' : x[0][i][10],
+                                        '合价' : x[0][i][11],
+                                        '暂估价标志' : x[0][i][12],
+                                        '主要材料标志' : x[0][i][13],
+                                        '主材标志' : x[0][i][14],
+                                        '设备标志' : x[0][i][15] 
+          
+                                   });
+                              }
+                              setRcjhl(y);
+                              if (rcjTable.current) {
+                                   rcjTable.current.replaceData(y);
+                              }
+                               isQdrcj.current = false;
+                               setFuzhuEnable(x[1]);
+                               let toHighlight = [];
+                               for(let i = 0; i < y.length; i++) {
+                                   let entry = y[i];
+                                   let bianhao = entry['人材机编码'];
+                                   let rcjlb = entry['人材机类别'];
+                                   if (Number(rcjlb) == 1 &&  rgdeRef.current  ) {
+                                      for (let j = 0;j < rgdeRef.current.length; j++) {
+                                         if (rgdeRef.current[j]["CLBH"] == bianhao) {
+                                              let danjia = Number(entry['单价']);
+                                              if (!number_equal(danjia , rgdeRef.current[j]["YSJG"])) {
+                                                   console.log(`[${i},5]danjia bu yizhi`);
+                                                   toHighlight.push({row: i, col: 5, });
+                                              }
+                                              let hanliang = Number(entry['含量']);
+                                              if (!number_equal(hanliang , rgdeRef.current[j]["gr"])) {
+                                                   console.log(`[${i}, 10]hanliang bu yizhi`);
+                                                   toHighlight.push({row: i, col: 10, });
+                                              }
+                                         }
+                                      }
+
+                                   }   
+                                   if (Number(rcjlb) == 3 && jxdeRef.current  ) {
+                                      for (let j = 0; j < jxdeRef.current.length; j++) {
+                                         if (jxdeRef.current[j]["jxbh"] == bianhao) {
+                                               let danjia = Number(entry['单价']);
+                                               if (!number_equal(danjia , jxdeRef.current[j]["tbdj"])) {
+                                                    console.log(`[${i},5]danjia bu yizhi`);
+                                                    toHighlight.push({row: i, col: 5, });
+                                               }
+                                               let hanliang = Number(entry['含量']);
+                                               if (!number_equal(hanliang , jxdeRef.current[j]["sl"])) {
+                                                    console.log(`[${i}, 10]hanliang bu yizhi`);
+                                                    toHighlight.push({row: i, col: 10, });
+                                               }
+                                         }
+                                      }
+
+                                   }   
+                                   if (Number(rcjlb) == 2 && cldeRef.current  ) {
+                                      for (let j = 0; j < cldeRef.current.length; j++) {
+                                         if (cldeRef.current[j]["CLBH"] == bianhao) {
+                                               let danjia = Number(entry['单价']);
+                                               if (!number_equal(danjia , cldeRef.current[j]["YSJG"])) {
+                                                    console.log(`[${i},5]danjia bu yizhi`);
+                                                    toHighlight.push({row: i, col: 5, });
+                                               }
+                                               let hanliang = Number(entry['含量']);
+                                               if (!number_equal(hanliang , cldeRef.current[j]["SL"])) {
+                                                    console.log(`[${i}, 10]hanliang bu yizhi`);
+                                                    toHighlight.push({row: i, col: 10, });
+                                               }
+                                         }
+                                      }
+
+                                   }   
+                               }
+                               highlight.current = toHighlight;
+                             });
+          }
+     }
+     
+  
+
+       
+    const [detail, setDetail] = React.useState([
+                    
+    ]);
+    const myRef = React.useRef(null);
+    const myTable = React.useRef(null);
+    const tuijianRef = React.useRef(null);
+    const tuijianTable = React.useRef(null);
+    const rcj2Ref = React.useRef(null);
+    const rcj2Table = React.useRef(null);
+    const rcjRef = React.useRef(null);
+    const rcjTable = React.useRef(null);
+    const [value, setValue] = React.useState("1");
+    const [rcjhl, setRcjhl] = React.useState([]);
+    const [rcjhl2, setRcjhl2] = React.useState([]);
+    const [fuzhu, setFuzhu] = React.useState([]);
+    const [tuijian, setTuijian] = React.useState([]);
+    const beizhuFKRef = React.useRef(null);
+
+    const [fuzhuEnable, setFuzhuEnable] = React.useState(false);
+
+   const [selectedRowKeys, setSelectedRowKeys] = React.useState([]);
+   const onSelectChange = (newSelectedRowKeys) => {
+     
+     const [newData, newHl] = handleBeizhu_djcs(beizhuFKRef.current, selectedRowKeysTable.current[0], newSelectedRowKeys, fuzhu);
+                                  if (newData) {
+                                     myTable.current.updateData(newData.filter(x=>x['key'] == selectedRowKeysTableParent.current));
+                                     let y =[];
+                                     for (let i = 1; i < newHl.length; i++) {
+                                         y.push({
+                                          'ID' : newHl[i][0],
+                                          '人材机编码' : newHl[i][1],
+                                          '名称' : newHl[i][2],
+                                          '规格型号': newHl[i][3],
+                                          '单位' : newHl[i][4],
+                                          '单价' : newHl[i][5],
+                                          '产地' : newHl[i][6],
+                                          '供应厂商' : newHl[i][7],
+                                          '人材机类别' : newHl[i][8],
+                                          '甲供标志': newHl[i][9],
+                                          '含量' : newHl[i][10],
+                                          '合价' : newHl[i][11],
+                                          '暂估价标志' : newHl[i][12],
+                                          '主要材料标志' : newHl[i][13],
+                                          '主材标志' : newHl[i][14],
+                                          '设备标志' : newHl[i][15] 
+
+                                      });
+                                     }
+                                     setRcjhl(y);
+                                     if (rcjTable.current) {
+                                        rcjTable.current.replaceData(y);
+                                     }
+
+                                  }
+   };
+   const rowSelection = {
+     selectedRowKeys,
+     onChange: onSelectChange,
+     getCheckboxProps: (record) => {
+          return {
+               disabled: !fuzhuEnable
+          };
+     }
+   };
+    const highlight = React.useRef([]);
+
+    
+    const rgdeRef = React.useRef(null);
+    const jxdeRef = React.useRef(null);
+    const cldeRef = React.useRef(null);
+    const isQdrcj = React.useRef(false);
+    const debmRef = React.useRef(null);
+    const selectedRowKeysTable = React.useRef([]);
+    const selectedRowKeysTableParent = React.useRef(null);
+    const [checked, setChecked] = React.useState(false);
+    const [indeterminate, setIndeterminate] = React.useState(false);
+    const [checkedKeys, setCheckedKeys] = React.useState([]);
+    const setCheckedKeys_ = (keys) => {
+     setCheckedKeys(keys);
+     if (keys.length == fuzhu.length) {
+          setChecked(true);
+          setIndeterminate(false);
+     } else if (keys.length == 0) {
+          setChecked(false);
+          setIndeterminate(false);
+     } else {
+          setIndeterminate(true);
+          setChecked(false);
+     }
+     onSelectChange(keys);
+    };
+    const setCheckedKeys_2 = (keys) => {
+     setCheckedKeys(keys);
+     if (keys.length == fuzhu.length) {
+          setChecked(true);
+          setIndeterminate(false);
+     } else if (keys.length == 0) {
+          setChecked(false);
+          setIndeterminate(false);
+     } else {
+          setIndeterminate(true);
+          setChecked(false);
+     }
+     //onSelectChange(keys);
+    };
+    const handleCheckAll = (value, checked) => {
+     const keys = checked? fuzhu.map(item => item.id) : [];
+     setCheckedKeys_(keys);
+
+    }
+    const handleCheck = (value, checked) => {
+     const keys = checked? [...checkedKeys, value] : checkedKeys.filter(item => item != value);
+     setCheckedKeys_(keys);
+
+    }
+
+    const CheckCell = ({rowData, onChange, checkedKeys, dataKey, disabled, ...props}) => {
+      return <Cell {...props} style={{ padding: 0}}>
+          <div style={{lineHeight: '40px'}}>
+             <Checkbox value = {rowData[dataKey]}
+             inline
+             disabled={disabled}
+             onChange={onChange}
+             checked={checkedKeys.some(item => item === rowData[dataKey])}
+             ></Checkbox>
+          </div>
+      </Cell>
+    };
+
+    React.useEffect(() => {
+     myTable.current = new Tabulator(myRef.current, {
+          index: "key",
+          height: 380,
+        data: detail, //link data to table
+        reactiveData: false, //enable data reactivity
+        dataTreeStartExpanded:true,
+        dataTree: true,
+        selectableRows:1, //make rows selectable
+        editTriggerEvent:"dblclick", //trigger edit on double click
+        dataTreeStartExpanded:function(row, level){
+            //console.log(row);
+            //console.log(level);
+            return true; //expand rows where the "driver" data field is true;
+        },
+        columns: [ //Define Table Columns
+                     {title:"序号", field:"序号", width:80, headerSort:false, frozen: true}, //never hide this column
+                     {title:"清单编码", field:"清单编码", width:120,headerSort:false, frozen: true, formatter:"textarea" },
+                     {title:"名称", field:"名称", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                     {title:"项目特征", field:"项目特征", width:150 , headerSort:false, formatter:"textarea"},
+                     {title:"计算规则", field:"计算规则", width:150, headerSort:false, formatter:"textarea"},
+                     {title:"单位", field:"单位", width:100, headerSort:false},
+                     {title:"数量", field:"数量", width:100, headerSort:false, editor: "input", editable: editCheck },
+                     {title:"综合单价", field:"综合单价", width:100, headerSort:false, formatter:"money"},
+                     {title:"合价", field:"合价", width:100, headerSort:false, formatter:"money"},
+                     {title:"人工费", field:"人工费", width:100, headerSort:false, formatter:"money"},
+                     {title:"主材费", field:"主材费", width:100, headerSort:false, formatter:"money"},
+                     {title:"设备费", field:"设备费", width:100, headerSort:false, formatter:"money"},
+                     {title:"辅材费", field:"辅材费", width:100, headerSort:false, formatter:"money"},
+                     {title:"材料费", field:"材料费", width:100, headerSort:false, formatter:"money"},
+                     {title:"机械费", field:"机械费", width:100, headerSort:false, formatter:"money"},
+                     {title:"管理费", field:"管理费", width:100, headerSort:false, formatter:"money"},
+                     {title:"利润", field:"利润", width:100, headerSort:false, formatter:"money"},
+                     {title:"暂估价", field:"暂估价", width:100, headerSort:false, formatter:"money"},
+                     {title:"综合人工工日", field:"综合人工工日", width:100, headerSort:false},
+             ]
+      }); 
+      
+      myTable.current.on("cellDblClick", function(e, cell){
+          //e - the click event object
+          //cell - cell component
+          console.log(cell);
+      });
+
+      myTable.current.on("rowSelected", handleSelect);
+      
+
+      myTable.current.on("cellEdited", function(cell){
+          //console.log("edited");
+          //console.log();
+          let key = cell._cell.row.data['key'];
+          myTable.current.deselectRow();
+          let [success, data] = updateShuliang_djcs(cell._cell.row.data['数量'], selectedRowKeysTable.current[0]);
+          if (success) {
+                           myTable.current.updateData(data.filter(x=>x['key'] == selectedRowKeysTableParent.current)).then(function() {
+                              let getRow = myTable.current.getRows(); //get array of currently selected row components.
+                              let component = null;
+                              for(let i = 0; i < getRow.length; i++) {
+                                   let entry = getRow[i]._row.modules.dataTree.children;
+                                   for(let j = 0; j < entry.length; j++) {
+                                        let child = entry[j];
+                                        if(child.data['key'] == key) {
+                                             //console.log(child);
+                                             component = child.component;
+                                             break;
+                                        }
+                                        
+                                   }
+
+                              }
+                              component.select();
+                              handleSelect(component);
+                              //handleSelect(getRow[0]);
+                           });                            
+                                                       
+          }
+      });
+
+
+      myTable.current.on("tableBuilt", () => {
+          Service.generateDjcs(name, bh).then(x=>{
+               myTable.current.replaceData(x);
+               });
+        });
+
+        
+    
+   }, [bh]);
+
+
+   React.useEffect(
+     () => {
+          beizhuFKRef.current = beizhuFK;
+     }, [beizhuFK]
+   );
+ 
+    React.useEffect(
+        () => {
+            console.log(beizhu);
+            let result = [];
+            if (beizhu != null) { 
+                let keys = Object.keys(beizhu["BZBH"]);
+                for(let i = 0; i < keys.length; i++) {
+                    let key = keys[i];
+                    result.push({'id': i+1, 'key': i+1,  '序号': i+1, '编号': beizhu["BZBH"][key], '说明': beizhu["SM"][key]});//序号很重要
+                }
+                setFuzhu(result);
+                let newSelect = extractFuzhu(debmRef.current);
+                setCheckedKeys_2(newSelect);
+                //setSelectedRowKeys(newSelect);
+                //setSelectedRowKeys([1]);
+                
+            }
+        }, [beizhu]
+      );
+
+      React.useEffect(
+          () => {
+               if (tuijianRef.current != null ) {
+               tuijianTable.current = new Tabulator(tuijianRef.current, {
+                    index: "key",
+                    height: 200,
+                  data: tuijian, //link data to table
+                  reactiveData: false, //enable data reactivity
+                  dataTreeStartExpanded:false,
+                  dataTree: false,
+                  selectableRows:1, //make rows selectable
+                  
+                  
+                  columns: [ //Define Table Columns
+                               {title:"ID", field:"ID", width:80, headerSort:false, }, //never hide this column
+                               {title:"定额编号", field:"定额编号", width:120,headerSort:false,  formatter:"textarea" },
+                               {title:"工程量名称", field:"工程量名称", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                               {title:"工作内容", field:"工作内容", width:150 , headerSort:false, formatter:"textarea"},
+                             
+                       ]
+               });
+               tuijianTable.current.on("tableBuilt", () => {
+                    
+                    tuijianTable.current.replaceData(tuijian);
+                         
+                  });
+               }
+               if (rcj2Ref.current != null ) {
+                    rcj2Table.current = new Tabulator(rcj2Ref.current, {
+                         index: "key",
+                         height: 200,
+                       data: rcjhl2, //link data to table
+                       reactiveData: false, //enable data reactivity
+                       dataTreeStartExpanded:false,
+                       dataTree: false,
+                       selectableRows:1, //make rows selectable
+                       
+                       
+                       columns: [ //Define Table Columns
+                                    {title:"人材机编码", field:"人材机编码", width:80, headerSort:false, }, //never hide this column
+                                    {title:"名称", field:"名称", width:120,headerSort:false,  formatter:"textarea" },
+                                    {title:"单位", field:"单位", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                                    {title:"单价", field:"单价", width:150 , headerSort:false, formatter:"money"},
+                                    {title:"合价", field:"合价", width:150 , headerSort:false, formatter:"money"},
+                                    {title:"含量", field:"含量", width:150 , headerSort:false, formatter:"textarea"},
+                                  
+                            ]
+                    });
+                    rcj2Table.current.on("tableBuilt", () => {
+                         
+                         rcj2Table.current.replaceData(rcjhl2);
+                              
+                       });
+                    }
+
+               if (rcjRef.current != null ) {
+                         rcjTable.current = new Tabulator(rcjRef.current, {
+                              index: "key",
+                              height: 200,
+                            data: rcjhl, //link data to table
+                            reactiveData: false, //enable data reactivity
+                            dataTreeStartExpanded:false,
+                            dataTree: false,
+                            selectableRows:1, //make rows selectable
+                            editTriggerEvent:"dblclick",
+                            
+                            columns: [ //Define Table Columns
+                                         {title:"ID", field:"ID", width:80, headerSort:false, },
+                                         {title:"人材机编码", field:"人材机编码", width:80, headerSort:false, }, //never hide this column
+                                         {title:"名称", field:"名称", width:120,headerSort:false,  formatter:"textarea", editor: "input", editable: editCheckRcj },
+                                         {title:"规格型号", field:"规格型号", width:80, headerSort:false, editor: "input", editable: editCheckRcj },
+                                         {title:"单位", field:"单位", width:80, headerSort:false, formatter:"textarea"}, //hide this column first
+                                         {title:"单价", field:"单价", width:80 , headerSort:false, formatter: sparklineFormatter, editor: "input", editable: editCheckRcj },
+                                         {title:"产地", field:"产地", width:80, headerSort:false, },
+                                         {title:"供应厂商", field:"供应厂商", width:80, headerSort:false, },
+                                         {title:"人材机类别", field:"人材机类别", width:80, headerSort:false, },
+                                         {title:"甲供标志", field:"甲供标志", width:80 , headerSort:false, formatter:"textarea"},
+                                         {title:"含量", field:"含量", width:80 , headerSort:false, formatter:"money", formatterParams:{precision:4}, editor: "input", editable: editCheckRcj },
+                                         {title:"合价", field:"合价", width:80 , headerSort:false, formatter:"money"},
+                                         {title:"暂估价标志", field:"暂估价标志", width:80 , headerSort:false, formatter:"textarea"},
+                                         {title:"主要材料标志", field:"主要材料标志", width:100 , headerSort:false, formatter:"textarea"},
+                                         {title:"主材标志", field:"主材标志", width:80 , headerSort:false, formatter:"textarea"},
+                                         {title:"设备标志", field:"设备标志", width:80 , headerSort:false, formatter:"textarea"},
+                                       
+                                 ]
+                         });
+                         rcjTable.current.on("tableBuilt", () => {
+                              
+                              rcjTable.current.replaceData(rcjhl);
+                                   
+                            });
+                         rcjTable.current.on("cellEdited", function(cell){
+                              let data =  copy(cell._cell.table.getData());
+                              for(let i = 0; i < data.length; i++) {
+                                   data[i]['合价'] = Number(data[i]['单价']) * Number(data[i]['含量']);
+                              }
+                              setRcjhl(data);
+                              if (rcjTable.current) {
+                                   rcjTable.current.replaceData(data);
+                              }
+                              let data2 = [['ID', '人材机编码', '名称', '规格型号', '单位', '单价', '产地', '供应厂商', '人材机类别', '甲供标志', '含量', '合价', '暂估价标志', '主要材料标志', '主材标志', '设备标志']]
+                              for (let i = 0; i < data.length; i++) {
+                                   data2.push([data[i]['ID'], data[i]['人材机编码'], data[i]['名称'], data[i]['规格型号'], data[i]['单位'], 
+                                   data[i]['单价'], data[i]['产地'], data[i]['供应厂商'], data[i]['人材机类别'], 
+                                   data[i]['甲供标志'], data[i]['含量'], data[i]['合价'], data[i]['暂估价标志'], data[i]['主要材料标志'], data[i]['主材标志'], data[i]['设备标志']]);
+                              }
+     
+                              let newData = updateDercj_djcs(selectedRowKeysTable.current[0], data2);
+                              myTable.current.updateData(newData.filter(x=>x['key'] == selectedRowKeysTableParent.current)).then(function() {
+                              let getRow = myTable.current.getRows(); //get array of currently selected row components.
+                              let component = null;
+                              for(let i = 0; i < getRow.length; i++) {
+                                     let entry = getRow[i]._row.modules.dataTree.children;
+                                     for(let j = 0; j < entry.length; j++) {
+                                           let child = entry[j];
+                                           if(child.data['key'] == selectedRowKeysTable.current[0]) {
+                                                //console.log(child);
+                                               component = child.component;
+                                                break;
+                                            }
+                         
+                                      }
+
+                              }
+               
+                                handleSelect(component);
+                              });
+                         });
+                         }
+          }, [value]
+        );
+
+
+
+      React.useEffect(
+          () => {
+               myTable.current.deselectRow();
+               //console.log(dingeclick);
+               if (selectedRowKeysTable.current.length > 0 ) {
+                    const [success, data, key] = changguidinge_djcs(JSON.parse(dingeclick), selectedRowKeysTable.current[0]);
+                    if (success) {
+                         myTable.current.updateData(data.filter(x=>x['key'] == selectedRowKeysTableParent.current)).then(function(){
+                              let getRow = myTable.current.getRows(); //get array of currently selected row components.
+                              let component = null;
+                              for(let i = 0; i < getRow.length; i++) {
+                                   let entry = getRow[i]._row.modules.dataTree.children;
+                                   for(let j = 0; j < entry.length; j++) {
+                                        let child = entry[j];
+                                        if(child.data['key'] == key) {
+                                             //console.log(child);
+                                             component = child.component;
+                                             break;
+                                        }
+                                        
+                                   }
+
+                              }
+                              
+                              component.select();
+                              handleSelect(component);
+
+                                   
+                               
+                          });
+                    }
+               }
+               
+          }, [dingeclick]//常规添加定额
+      );
+
+    React.useEffect(
+        () => {
+          console.log("rgde changed");
+          console.log(rgde);
+          rgdeRef.current = rgde;
+          jxdeRef.current = jxde;
+          cldeRef.current = clde;
+          if (isQdrcj.current) {
+             highlight.current = [];
+          } else {
+          let toHighlight = [];
+          for(let i = 0; i < rcjhl.length; i++) {
+              let entry = rcjhl[i];
+              let bianhao = entry['人材机编码'];
+              let rcjlb = entry['人材机类别'];
+              if (Number(rcjlb) == Number(1) && rgde) {
+                  for (let j = 0; j < rgde.length; j++) {
+                      if (rgde[j]["CLBH"] == bianhao) {
+                          let danjia = Number(entry['单价']);
+                          if (!number_equal(danjia , rgde[j]["YSJG"])) {
+                               console.log(`[${i},5]danjia bu yizhi`);
+                               toHighlight.push({row: i, col: 5});
+                          }
+                          let hanliang = Number(entry['含量']);
+                          if (!number_equal(hanliang , rgde[j]["gr"])) {
+                               console.log(`[${i}, 10]hanliang bu yizhi`);
+                               toHighlight.push({row: i, col: 10});
+                          }
+
+                      }              
+                  }
+
+              }   
+              if (Number(rcjlb) == Number(3) && jxde ) {
+                   for (let j = 0; j < jxde.length; j++) {
+                      if (jxde[j]["jxbh"] == bianhao) {
+                         let danjia = Number(entry['单价']);
+                         if (!number_equal(danjia , jxde[j]["tbdj"])) {
+                              console.log(`[${i},5]danjia bu yizhi`);
+                              toHighlight.push({row: i, col: 5, });
+                         }
+                         let hanliang = Number(entry['含量']);
+                         if (!number_equal(hanliang , jxde[j]["sl"])) {
+                              console.log(`[${i}, 10]hanliang bu yizhi`);
+                              toHighlight.push({row: i, col: 10, });
+                         }
+                      }
+                   }
+
+              }   
+              if (Number(rcjlb) == Number(2) && clde ) {
+                   for (let j = 0; j < clde.length; j++) {
+                      if (clde[j]["CLBH"] == bianhao) {
+                         let danjia = Number(entry['单价']);
+                         if (!number_equal(danjia , clde[j]["YSJG"])) {
+                              console.log(`[${i},5]danjia bu yizhi`);
+                              toHighlight.push({row: i, col: 5, });
+                         }
+                         let hanliang = Number(entry['含量']);
+                         if (!number_equal(hanliang ,clde[j]["SL"])) {
+                              console.log(`[${i}, 10]hanliang bu yizhi`);
+                              toHighlight.push({row: i, col: 10, });
+                         }
+                      }
+                   }
+
+              }   
+          }
+          console.log(toHighlight);
+          highlight.current = toHighlight;
+          }
+
+
+          let bzrcjhl = [] 
+          if (rgde)
+          for (let i = 0; i  < rgde.length; i++) {
+               bzrcjhl.push({'人材机编码': rgde[i]["CLBH"], '名称': rgde[i]["CLMC"], '单位': rgde[i]["JLDW"], '单价': rgde[i]["YSJG"], '合价': rgde[i]["gf"], '含量': rgde[i]["gr"]});
+          }
+          
+          if (clde)
+          for (let i = 0; i  < clde.length; i++) {
+               bzrcjhl.push({'人材机编码': clde[i]["CLBH"], '名称': clde[i]["CLMC"], '单位': clde[i]["JLDW"], '单价': clde[i]["YSJG"], '合价': clde[i]["HJ"], '含量': clde[i]["SL"]});
+          }
+          if (jxde)
+          for (let i = 0; i  < jxde.length; i++) {
+               bzrcjhl.push({'人材机编码': jxde[i]["jxbh"], '名称': jxde[i]["jxmc"], '单位': jxde[i]["DW"], '单价': jxde[i]["tbdj"], '合价': jxde[i]["hj"], '含量': jxde[i]["sl"]});
+          }
+          setRcjhl2(bzrcjhl);
+          if (rcj2Table.current) {
+               rcj2Table.current.replaceData(bzrcjhl);
+          }
+        }, [rgde, jxde, clde]
+      );
+
+      const handleChange = (event, newValue) => {
+        setValue(newValue);
+      };
+
+
+    return (
+
+               <Stack spacing={1}>
+                         <Stack direction='row' spacing={2}>
+                   <Button variant="outlined" size="small" onClick={() => {
+                      if (selectedRowKeysTable.current.length > 0) {
+                         const [success, data] = danxiangdinge_djcs(selectedRowKeysTable.current[0]);
+                         if(success) {
+                            myTable.current.updateData(data.filter(x=>x['key'] == selectedRowKeysTableParent.current)).then(function(){
+                              selectedRowKeysTable.current = [];
+                              selectedRowKeysTableParent.current = null;
+                                   setRcjhl([]);
+                                   if (rcjTable.current) {
+                                        rcjTable.current.replaceData([]);
+                                   }
+                                   setFuzhu([]);
+                                   isQdrcj.current = true;
+                                   highlight.current = [];
+                            });
+                            //console.log(data);
+                         }
+                      }
+                 
+                      
+                      }}
+                   >单项定额</Button>
+                      <Button variant="outlined" size="small" onClick={() => {
+                      if (selectedRowKeysTable.current.length > 0) {
+                          let newData = shanchu_djcs(selectedRowKeysTable.current[0]);
+                          myTable.current.updateData(newData.filter(x=>x['key'] == selectedRowKeysTableParent.current)).then(function(){
+                              if (newData.filter(x=>x['key'] == selectedRowKeysTable.current[0]).length == 0) {
+                                   selectedRowKeysTable.current = [];
+                                   selectedRowKeysTableParent.current = [];
+                                   setRcjhl([]);
+                                   if (rcjTable.current) {
+                                        rcjTable.current.replaceData([]);
+                                   }
+                                   setFuzhu([]);
+                                   isQdrcj.current = true;
+                                   highlight.current = [];
+                               }
+                          });
+                          
+                          
+                          
+                      }
+                      
+                 
+                      
+                      }}
+                   >删除</Button>
+                   <Button variant="outlined" size="small" onClick={() => {
+                      let newData = undo_djcs();
+                      myTable.current.updateData(newData).then(function(){
+                         
+                            selectedRowKeysTable.current = [];
+                            selectedRowKeysTableParent.current = null;
+                            setRcjhl([]);
+                            if (rcjTable.current) {
+                              rcjTable.current.replaceData([]);
+                            }
+                            setFuzhu([]);
+                            isQdrcj.current = true;
+                            highlight.current = [];
+                            
+                        
+                      });
+                     
+                      
+                      }}
+                   >撤销</Button>
+                   <Button variant="outlined" size="small" onClick={() => {
+                      let newData = redo_djcs();
+                      myTable.current.updateData(newData).then(function(){
+                         selectedRowKeysTable.current = [];
+                         selectedRowKeysTableParent.current = null;
+
+                            setRcjhl([]);
+                            if (rcjTable.current) {
+                              rcjTable.current.replaceData([]);
+                            }
+                            setFuzhu([]);
+                            isQdrcj.current = true;
+                            highlight.current = [];
+                      });
+                      
+                      
+                      
+                      }}
+                   >重做</Button>
+                   <Button variant="outlined" size="small" onClick={() => {
+                            console.log("save to cloud");
+                            loadingCallback();
+                      
+                      }}
+                   >保存</Button>
+
+                  
+                   </Stack>
+                 <div ref={myRef}> 
+                  </div>
+                   <Box >
+                   
+                   <TabContext value={value}>
+                       <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
+                         <TabList onChange={handleChange} aria-label="lab API tabs example"  sx={{minHeight: '24px'}}   >
+                           <Tab sx={{p: 0, minHeight: '24px'}} label="人材机含量" value="1" />
+                           <Tab sx={{p: 0, minHeight: '24px'}} label="标准定额人材机含量" value="2" />
+                           <Tab sx={{p: 0, minHeight: '24px'}} label="定额附注" value="3" />
+                           <Tab sx={{p: 0, minHeight: '24px'}} label="组价推荐" value="4" />
+                         </TabList>
+                       </Box>
+                       <TabPanel value="1">
+                       <div ref={rcjRef}></div>
+                       </TabPanel>
+                       <TabPanel value="2">
+                       <div ref={rcj2Ref}></div>
+
+                       </TabPanel>
+                       <TabPanel value="3">
+                       <Box sx={{maxHeight: `200px`, minHeight: `200px`, height: `200px`}}>
+                         <CustomProvider locale={zhCN}>
+                        <Table rowHeight={rowData=>{
+                         return 40;
+                        }}
+                        height={200} data = {fuzhu} id="fuzhu">
+                         <Column width={80} align="center">
+                              <HeaderCell style={{padding: 0}}>
+                                   <div style={{lineHeight: '40px'}}>
+                                        <Checkbox inline checked={checked} indeterminate={indeterminate} onChange={handleCheckAll} disabled={!fuzhuEnable}
+                                        ></Checkbox>
+                                   </div>
+                              </HeaderCell>
+                              <CheckCell dataKey="id" checkedKeys={checkedKeys} onChange={handleCheck} disabled={!fuzhuEnable}></CheckCell>
+                         </Column>
+                         <Column width={80} align="center">
+                              <HeaderCell>序号</HeaderCell>
+                              <Cell dataKey="序号"></Cell>
+                         </Column>
+                         <Column width={120} align="center">
+                              <HeaderCell>编号</HeaderCell>
+                              <Cell dataKey="编号"></Cell>
+                         </Column>
+                         <Column fullText width={650} align="center">
+                              <HeaderCell>说明</HeaderCell>
+                              <Cell dataKey="说明"></Cell>
+                         </Column>
+                        </Table>
+                        </CustomProvider>
+                       </Box>
+                      
+
+                       </TabPanel>
+
+                       <TabPanel value="4">
+                          <div ref={tuijianRef}></div>
+
+                       </TabPanel>
+                     </TabContext>
+                  </Box>
+
+                  </Stack>
+
+
+
+    );
+}

+ 72 - 0
src/Editable.js

@@ -0,0 +1,72 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+//registerPlugin(NestedRows);
+import Service from './Service';
+import {useLocation} from "react-router";
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import Typography from '@mui/material/Typography';
+import InputLabel from '@mui/material/InputLabel';
+import MenuItem from '@mui/material/MenuItem';
+import FormControl from '@mui/material/FormControl';
+import Select from '@mui/material/Select';
+import Accordion from '@mui/material/Accordion';
+import AccordionActions from '@mui/material/AccordionActions';
+import AccordionSummary from '@mui/material/AccordionSummary';
+import AccordionDetails from '@mui/material/AccordionDetails';
+import Stack from '@mui/material/Stack';
+
+import Button from '@mui/material/Button';
+import TextField from '@mui/material/TextField';
+
+
+
+
+  export default function Editable({ initialText,  onChange }) {
+    const [isEditing, setIsEditing] = React.useState(false);
+    const [textValue, setTextValue] = React.useState(initialText);
+    
+    React.useEffect(
+      () => {
+        setTextValue(initialText);
+      }, [initialText]
+    );
+    return (
+
+        <Box>
+        {isEditing ? (
+            <TextField id="outlined-basic" value={textValue} size="small"
+            autoFocus
+             variant="outlined"
+             onChange={(event) => {
+              setTextValue(event.target.value);
+              }} 
+            onKeyDown={(e)=> {
+              if (e.key == "Enter") {
+                
+                setIsEditing(false);
+                onChange(textValue);
+                
+
+              }
+            }}
+            onBlur={()=> {
+              setIsEditing(false);
+              onChange(textValue);
+            }}
+            />
+          ) : (
+            <Button disableRipple variant="text" color="#000000"
+               onDoubleClick={()=>{
+                setIsEditing(true);
+               }}
+            >{textValue}</Button>
+          )}
+        </Box>
+    
+    );
+  }

+ 78 - 0
src/EditableSelect.js

@@ -0,0 +1,78 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+//registerPlugin(NestedRows);
+import Service from './Service';
+import {useLocation} from "react-router";
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import Typography from '@mui/material/Typography';
+import InputLabel from '@mui/material/InputLabel';
+import MenuItem from '@mui/material/MenuItem';
+import FormControl from '@mui/material/FormControl';
+import Select from '@mui/material/Select';
+import Accordion from '@mui/material/Accordion';
+import AccordionActions from '@mui/material/AccordionActions';
+import AccordionSummary from '@mui/material/AccordionSummary';
+import AccordionDetails from '@mui/material/AccordionDetails';
+import Stack from '@mui/material/Stack';
+
+import Button from '@mui/material/Button';
+import TextField from '@mui/material/TextField';
+
+
+
+
+  export default function EditableSelect({ initialText,  onChange }) {
+    const [isEditing, setIsEditing] = React.useState(false);
+    const [textValue, setTextValue] = React.useState(initialText);
+    const handleChange = (event) => {
+      setTextValue(event.target.value);
+      setIsEditing(false);
+      onChange(event.target.value);
+    };
+    React.useEffect(
+      () => {
+        setTextValue(initialText);
+        setIsEditing(false);
+        
+      }, [initialText]
+    );
+    return (
+
+        <Box>
+        {isEditing ? (
+            <FormControl sx={{ m: 1, minWidth: 100 }} size="small">
+            <InputLabel id="demo-select-small-label">工程类别</InputLabel>
+            <Select
+              labelId="demo-select-small-label"
+              id="demo-select-small"
+              value={textValue}
+              label="工程类别"
+              onChange={handleChange}
+              onBlur={()=>{
+                setIsEditing(false);
+              }}
+            >
+              <MenuItem value="">
+                <em></em>
+              </MenuItem>
+              <MenuItem value={"一类工程"}>一类工程</MenuItem>
+              <MenuItem value={"二类工程"}>二类工程</MenuItem>
+              <MenuItem value={"三类工程"}>三类工程</MenuItem>
+            </Select>
+          </FormControl>
+          ) : (
+            <Button disableRipple variant="text" color="#000000"
+               onDoubleClick={()=>{
+                setIsEditing(true);
+               }}
+            >{textValue}</Button>
+          )}
+        </Box>
+    
+    );
+  }

+ 95 - 0
src/EditableSelectGC.js

@@ -0,0 +1,95 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+//registerPlugin(NestedRows);
+import Service from './Service';
+import {useLocation} from "react-router";
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import Typography from '@mui/material/Typography';
+import InputLabel from '@mui/material/InputLabel';
+import MenuItem from '@mui/material/MenuItem';
+import FormControl from '@mui/material/FormControl';
+import Select from '@mui/material/Select';
+import Accordion from '@mui/material/Accordion';
+import AccordionActions from '@mui/material/AccordionActions';
+import AccordionSummary from '@mui/material/AccordionSummary';
+import AccordionDetails from '@mui/material/AccordionDetails';
+import Stack from '@mui/material/Stack';
+
+import Button from '@mui/material/Button';
+import TextField from '@mui/material/TextField';
+
+import ListSubheader from '@mui/material/ListSubheader';
+
+
+
+  export default function EditableSelectGC({ initialText,  onChange }) {
+    const [isEditing, setIsEditing] = React.useState(false);
+    const [textValue, setTextValue] = React.useState(initialText);
+    const handleChange = (event) => {
+      setTextValue(event.target.value);
+      setIsEditing(false);
+      onChange(event.target.value);
+    };
+    React.useEffect(
+      () => {
+        setTextValue(initialText);
+        setIsEditing(false);
+        
+      }, [initialText]
+    );
+    return (
+
+        <Box>
+        {isEditing ? (
+            <FormControl sx={{ m: 1, minWidth: 100 }} size="small">
+            <InputLabel id="demo-select-small-label">工程类型</InputLabel>
+            <Select
+              labelId="demo-select-small-label"
+              id="demo-select-small"
+              value={textValue}
+              label="工程类型"
+              onChange={handleChange}
+              onBlur={()=>{
+                setIsEditing(false);
+              }}
+            >
+              <MenuItem value="">
+                <em></em>
+              </MenuItem>
+              <ListSubheader>建筑工程</ListSubheader>
+              <MenuItem value={"建筑工程"}>建筑工程</MenuItem>
+              <MenuItem value={"单独预制构件制作"}>单独预制构件制作</MenuItem>
+              <MenuItem value={"打预制桩、单独构件吊装"}>打预制桩、单独构件吊装</MenuItem>
+              <MenuItem value={"单独预制构件制作"}>单独预制构件制作</MenuItem>
+              <MenuItem value={"制作兼打桩"}>制作兼打桩</MenuItem>
+              <MenuItem value={"大型土石方工程"}>大型土石方工程</MenuItem>
+              <ListSubheader>单独装饰工程</ListSubheader>
+              <MenuItem value={"单独装饰工程"}>单独装饰工程</MenuItem>
+              <ListSubheader>安装工程</ListSubheader>
+              <MenuItem value={"安装工程"}>安装工程</MenuItem>
+              <ListSubheader>市政工程</ListSubheader>
+              <MenuItem value={"通用项目、道路、排水工程"}>通用项目、道路、排水工程</MenuItem>
+              <MenuItem value={"桥梁、水工构筑物"}>桥梁、水工构筑物</MenuItem>
+              <MenuItem value={"给水、燃气与集中供热"}>给水、燃气与集中供热</MenuItem>
+              <MenuItem value={"路灯及交通设施工程"}>路灯及交通设施工程</MenuItem>
+              <MenuItem value={"(市)大型土石方工程"}>(市)大型土石方工程</MenuItem>
+              
+
+            </Select>
+          </FormControl>
+          ) : (
+            <Button disableRipple variant="text" color="#000000"
+               onDoubleClick={()=>{
+                setIsEditing(true);
+               }}
+            >{textValue}</Button>
+          )}
+        </Box>
+    
+    );
+  }

+ 81 - 0
src/Fbrgycl.js

@@ -0,0 +1,81 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+//registerPlugin(NestedRows);
+import Service from './Service';
+import EditableSelect from './EditableSelect';
+import EditableSelectGC from './EditableSelectGC';
+import Editable from './Editable';
+import Button from '@mui/material/Button';
+
+import {copy} from './utils';
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+export default function Fbrgycl({data}) {
+    const myRef = React.useRef();
+    const myTable = React.useRef(null);
+
+
+
+    React.useEffect(() => {
+      myTable.current = new Tabulator(myRef.current, {
+           index: "key",
+           height: 600,
+         data: data, //link data to table
+         reactiveData: false, //enable data reactivity
+         dataTreeStartExpanded:true,
+         dataTree: true,
+         selectableRows:1, //make rows selectable
+         editTriggerEvent:"dblclick", //trigger edit on double click
+         dataTreeStartExpanded:function(row, level){
+             //console.log(row);
+             //console.log(level);
+             return true; //expand rows where the "driver" data field is true;
+         },
+         columns: [ //Define Table Columns 序号", "名称", "取费基数", "计算基础","费率", "金额", "类别
+                      {title:"序号", field:"序号", width:80, headerSort:false,}, //never hide this column
+                      {title:"ID", field:"ID", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                      {title:"材料编号", field:"材料编号", width:100,   formatter:"textarea", },
+                      {title:"名称", field:"名称", width:100,   formatter:"textarea"},
+                      {title:"规格型号", field:"规格型号", width:100,   formatter:"textarea"},
+                      {title:"单位", field:"单位", width:100,   formatter:"textarea"},
+                      {title:"数量", field:"数量", width:100,   formatter:"textarea"},
+                      {title:"单价", field:"单价", width:100,   formatter:"money"},
+                      {title:"合价", field:"合价", width:100,   formatter:"money"},
+                      {title:"交货方式", field:"交货方式", width:100,   formatter:"textarea"},
+                      {title:"送达地点", field:"送达地点", width:100,   formatter:"textarea"},
+                      {title:"备注", field:"备注", width:100,   formatter:"textarea"},
+
+                    
+              ]
+       }); 
+       
+       myTable.current.on("cellDblClick", function(e, cell){
+           //e - the click event object
+           //cell - cell component
+           console.log(cell);
+       });
+  
+       //myTable.current.on("rowSelected", handleSelect);
+       
+  
+       
+  
+  
+      
+     
+    }, [data]);
+    return (
+      <div ref={myRef}> 
+      </div>
+
+
+
+    );
+}

+ 73 - 0
src/Gfsj.js

@@ -0,0 +1,73 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+//registerPlugin(NestedRows);
+import Service from './Service';
+
+import Button from '@mui/material/Button';
+
+import {copy} from './utils';
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+export default function Gfsj({data}) {
+    const myRef = React.useRef();
+    const myTable = React.useRef(null);
+
+
+
+    React.useEffect(() => {
+      myTable.current = new Tabulator(myRef.current, {
+           index: "key",
+           height: 600,
+         data: data, //link data to table
+         reactiveData: false, //enable data reactivity
+         dataTreeStartExpanded:true,
+         dataTree: true,
+         selectableRows:1, //make rows selectable
+         editTriggerEvent:"dblclick", //trigger edit on double click
+         dataTreeStartExpanded:function(row, level){
+             //console.log(row);
+             //console.log(level);
+             return true; //expand rows where the "driver" data field is true;
+         },
+         columns: [ //Define Table Columns 序号", "名称", "取费基数", "计算基础","费率", "金额", "类别
+                      {title:"序号", field:"序号", width:80, headerSort:false,}, //never hide this column
+                      {title:"名称", field:"名称", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                      {title:"取费基数", field:"取费基数", width:100 , headerSort:false, formatter:"money"},
+                      {title:"计算基础", field:"计算基础", width:350, headerSort:false, formatter: "textarea"},
+                      {title:"费率", field:"费率", width:100, headerSort:true, sorter:"number", formatter:"textarea", },
+                      {title:"金额", field:"金额", width:100, headerSort:true, sorter:"number", formatter:"money", },
+                      {title:"类别", field:"类别", width:100, headerSort:true, sorter:"number", formatter:"textarea"},
+                    
+              ]
+       }); 
+       
+       myTable.current.on("cellDblClick", function(e, cell){
+           //e - the click event object
+           //cell - cell component
+           console.log(cell);
+       });
+  
+       //myTable.current.on("rowSelected", handleSelect);
+       
+  
+       
+  
+  
+      
+     
+    }, [data]);
+    return (
+      <div ref={myRef}> 
+      </div>
+
+
+
+    );
+}

+ 377 - 0
src/Home2.js

@@ -0,0 +1,377 @@
+import * as React from 'react';
+
+import Service from './Service';
+import {useNavigate, useLocation} from "react-router";
+//registerAllModules();
+import { DataGrid, GridActionsCellItem, zhCN} from '@mui/x-data-grid';
+import Box from '@mui/material/Box';
+import MuiAppBar from '@mui/material/AppBar';
+import { styled, useTheme } from '@mui/material/styles';
+import Toolbar from '@mui/material/Toolbar';
+import Typography from '@mui/material/Typography';
+import CssBaseline from '@mui/material/CssBaseline';
+import AccountCircle from '@mui/icons-material/AccountCircle';
+import Fab from '@mui/material/Fab';
+import Tooltip from '@mui/material/Tooltip';
+import DeleteIcon from '@mui/icons-material/Delete';
+import Button from '@mui/material/Button';
+import Dialog from '@mui/material/Dialog';
+import Drawer from '@mui/material/Drawer';
+import Divider from '@mui/material/Divider';
+import IconButton from '@mui/material/IconButton';
+import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
+import ChevronRightIcon from '@mui/icons-material/ChevronRight';
+import MenuIcon from '@mui/icons-material/Menu';
+import AddIcon from '@mui/icons-material/Add';
+import DialogTitle from '@mui/material/DialogTitle';
+import DialogActions from '@mui/material/DialogActions';
+import CircularProgress from '@mui/material/CircularProgress';
+import Backdrop from '@mui/material/Backdrop';
+
+export default function Home2() {
+  const drawerWidth = 240;
+  const theme = useTheme();
+
+  const deleteItem = React.useCallback(
+    (id) => () => {
+
+      itemRef.current = id;
+      /*
+      console.log(id);
+      Service.deleteFiles(id).then(x=> {
+        Service.generateFiles2().then(x=>{
+          setDetail(x.map(y=>{return {'id': y[0], 'ID': y[0], '名称': y[1], '创建时间': y[2], '操作': y[0]};}));
+        });
+      });*/
+      setDopen(true);
+    },
+    [],
+  );
+
+
+
+  function RenderDate(props) {
+    const { hasFocus, value } = props;
+    const buttonElement = React.useRef(null);
+    const rippleRef = React.useRef(null);
+  
+    React.useLayoutEffect(() => {
+      if (hasFocus) {
+        const input = buttonElement.current.querySelector('input');
+        input?.focus();
+      } else if (rippleRef.current) {
+        // Only available in @mui/material v5.4.1 or later
+        rippleRef.current.stop({});
+      }
+    }, [hasFocus]);
+  
+    return (
+      <strong>
+        
+        <Button
+          ref={buttonElement}
+          touchRippleRef={rippleRef}
+          variant="contained"
+          size="small"
+          style={{ marginLeft: 4 }}
+          
+          
+          onClick={(event) => {
+            console.log(value);
+            event.stopPropagation();
+            setBopen(true);
+            Service.download(value)
+                .then(blob => {
+                // Create a temporary URL for the Blob
+                const url = URL.createObjectURL(blob);
+    
+                // Create a link and set its href to the temporary URL
+                const link = document.createElement('a');
+                link.href = url;
+    
+                 // Set the link attributes for downloading
+                link.setAttribute('download', value.concat('.xml'));
+    
+                 // Programmatically click the link to initiate the download
+                link.click();
+    
+                 // Clean up the temporary URL
+                URL.revokeObjectURL(url);
+                setBopen(false);
+             })
+             .catch(error => console.error(error));
+          }}
+        >
+          导出文件
+        </Button>
+      </strong>
+    );
+  }
+  
+ 
+  const columns = React.useMemo(
+    () => [
+      { field: 'ID', headerName: 'ID', width: 250 },
+      { field: '名称', headerName: '名称', width: 400 },
+      { field: '创建时间', headerName: '创建时间', width: 200 },
+      { field: '操作', headerName: '操作', width: 100 , sortable: false, renderCell: RenderDate},
+      {
+        field: 'actions',
+        type: 'actions',
+        width: 80,
+        getActions: (params) => [
+          <GridActionsCellItem
+            icon={<DeleteIcon />}
+            label="删除"
+            onClick={deleteItem(params.id)}
+          />,
+       
+      
+        ],
+      },
+    ],
+    [deleteItem],
+  );
+  const Style = {
+    position: "absolute",
+    bottom: 128,
+    right: 64,
+  };
+  const VisuallyHiddenInput = styled('input')({
+    display: 'none',
+    accept: ".13jz, .13jt, .jszf"
+    });
+
+    const hotRef = React.useRef(null);
+    const itemRef = React.useRef(null);
+    const navigate = useNavigate();
+    let location = useLocation();
+    const [detail, setDetail] = React.useState([]);
+    const [open, setOpen] = React.useState(false);
+    const [dopen, setDopen] = React.useState(false);
+    const [bopen, setBopen] = React.useState(false);
+    const [selectedFiles, setSelectedFiles] = React.useState([]);
+
+    const handleFileChange = (event) => {
+         setSelectedFiles(event.target.files);
+         console.log(event.target.files);
+         const fd = new FormData();
+         fd.append('file', event.target.files[0]);
+         Service.uploadFile(fd).then(x=>{
+            console.log("uploaded");
+            Service.generateFiles2().then(x=>{
+              setDetail(x.map(y=>{return {'id': y[0], 'ID': y[0], '名称': y[1], '创建时间': y[2], '操作': y[0]};}));
+            });
+
+         });
+
+
+    };
+
+    React.useEffect(
+      () => {
+         Service.generateFiles2().then(x=>{
+           setDetail(x.map(y=>{return {'id': y[0], 'ID': y[0], '名称': y[1], '创建时间': y[2], '操作': y[0]};}));
+         });
+      }, []
+    );
+
+
+    const handleRowClick = (params) => {
+      //setMessage(`Movie "${params.row.title}" clicked`);
+      navigate('/editor/qingdan/'.concat(params.row.id));
+    };
+
+    const AppBar = styled(MuiAppBar, {
+      shouldForwardProp: (prop) => prop !== 'open',
+    })(({ theme }) => ({
+      transition: theme.transitions.create(['margin', 'width'], {
+        easing: theme.transitions.easing.sharp,
+        duration: theme.transitions.duration.leavingScreen,
+      }),
+      variants: [
+        {
+          props: ({ open }) => open,
+          style: {
+            width: `calc(100% - ${drawerWidth}px)`,
+            marginLeft: `${drawerWidth}px`,
+            transition: theme.transitions.create(['margin', 'width'], {
+              easing: theme.transitions.easing.easeOut,
+              duration: theme.transitions.duration.enteringScreen,
+            }),
+          },
+        },
+      ],
+    }));
+
+    const Main = styled('main', { shouldForwardProp: (prop) => prop !== 'open' })(
+      ({ theme }) => ({
+        flexGrow: 1,
+        padding: theme.spacing(3),
+        transition: theme.transitions.create('margin', {
+          easing: theme.transitions.easing.sharp,
+          duration: theme.transitions.duration.leavingScreen,
+        }),
+        marginLeft: `-${drawerWidth}px`,
+        variants: [
+          {
+            props: ({ open }) => open,
+            style: {
+              transition: theme.transitions.create('margin', {
+                easing: theme.transitions.easing.easeOut,
+                duration: theme.transitions.duration.enteringScreen,
+              }),
+              marginLeft: 0,
+            },
+          },
+        ],
+      }),
+    );
+
+    const DrawerHeader = styled('div')(({ theme }) => ({
+      display: 'flex',
+      alignItems: 'center',
+      padding: theme.spacing(0, 1),
+      // necessary for content to be below app bar
+      ...theme.mixins.toolbar,
+      justifyContent: 'flex-end',
+    }));
+
+    const handleDrawerClose = () => {
+      setOpen(false);
+    };
+
+
+  const handleDrawerOpen = () => {
+    setOpen(true);
+  };
+
+  const handleClose = () => {
+    setDopen(false);
+  };
+  const handleCloseB = () => {
+    setBopen(false);
+  };
+
+  const handleDelete = () => {
+    Service.deleteFiles(itemRef.current).then(x=> {
+      Service.generateFiles2().then(x=>{
+        setDetail(x.map(y=>{return {'id': y[0], 'ID': y[0], '名称': y[1], '创建时间': y[2], '操作': y[0]};}));
+      });
+    });
+    setDopen(false);
+  };
+
+
+    return (
+      <Box sx={{ display: 'flex' }}>
+       
+        <CssBaseline />
+        <AppBar position="fixed" open={open}>
+        <Toolbar>
+        
+          <IconButton
+            color="inherit"
+            aria-label="open drawer"
+            onClick={handleDrawerOpen}
+            edge="start"
+            sx={[
+              {
+                mr: 2,
+              },
+              open && { display: 'none' },
+            ]}
+          >
+            <MenuIcon />
+          </IconButton>
+          <Typography variant="h6" noWrap component="div">
+            工作台
+          </Typography>
+          <Box sx={{ flexGrow: 1 }} />
+          <Box sx={{ display: { xs: 'none', md: 'flex' } }}>
+           
+            <IconButton
+              size="large"
+              edge="end"
+              aria-label="account of current user"
+              
+              aria-haspopup="true"
+              
+              color="inherit"
+            >
+              <AccountCircle />
+            </IconButton>
+          </Box>
+          </Toolbar>
+        </AppBar>
+        <Drawer
+        sx={{
+          width: drawerWidth,
+          flexShrink: 0,
+          '& .MuiDrawer-paper': {
+            width: drawerWidth,
+            boxSizing: 'border-box',
+          },
+        }}
+        variant="persistent"
+        anchor="left"
+        open={open}
+      >
+         <DrawerHeader>
+          <IconButton onClick={handleDrawerClose}>
+            {theme.direction === 'ltr' ? <ChevronLeftIcon /> : <ChevronRightIcon />}
+          </IconButton>
+        </DrawerHeader>
+        <Divider />
+
+      </Drawer>
+      <Main open={open}>
+      <DrawerHeader />
+
+      <div style={{ height: `calc(100vh - 150px)`, width: '100%' }}>
+      <DataGrid onRowClick={handleRowClick}
+      rows={detail} columns={columns}
+      disableColumnMenu={true}
+      localeText={zhCN.components.MuiDataGrid.defaultProps.localeText}
+      />
+
+        <Tooltip title="导入">
+       <Fab color="primary" aria-label="add" sx={Style} component="label">
+        <AddIcon />
+        <VisuallyHiddenInput
+             type="file"
+             accept=".13jz, .13jt, .jszf"
+             onChange={handleFileChange}
+          />
+      </Fab>
+      </Tooltip>
+    </div>
+   
+    </Main>
+    <Dialog
+        open={dopen}
+        onClose={handleClose}
+        aria-labelledby="alert-dialog-title"
+        aria-describedby="alert-dialog-description"
+      >
+        <DialogTitle id="alert-dialog-title">
+          {"删除该项目?"}
+        </DialogTitle>
+        
+        <DialogActions>
+          <Button onClick={handleClose}>取消</Button>
+          <Button onClick={handleDelete} autoFocus>
+            确定
+          </Button>
+        </DialogActions>
+      </Dialog>
+      <Backdrop
+        sx={(theme) => ({ color: '#fff', zIndex: theme.zIndex.drawer + 1 })}
+        open={bopen}
+        
+      >
+        <CircularProgress color="inherit" />
+      </Backdrop>
+    </Box>
+    );
+  }

+ 72 - 0
src/Jrg.js

@@ -0,0 +1,72 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+//registerPlugin(NestedRows);
+import Service from './Service';
+import EditableSelect from './EditableSelect';
+import EditableSelectGC from './EditableSelectGC';
+import Editable from './Editable';
+import Button from '@mui/material/Button';
+
+import {copy} from './utils';
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+export default function Jrg({data}) {
+    const myRef = React.useRef();
+    const myTable = React.useRef(null);
+
+
+
+    React.useEffect(() => {
+      myTable.current = new Tabulator(myRef.current, {
+           index: "key",
+           height: 600,
+         data: data, //link data to table
+         reactiveData: false, //enable data reactivity
+         dataTreeStartExpanded:true,
+         dataTree: true,
+         selectableRows:1, //make rows selectable
+         editTriggerEvent:"dblclick", //trigger edit on double click
+         dataTreeStartExpanded:function(row, level){
+             //console.log(row);
+             //console.log(level);
+             return true; //expand rows where the "driver" data field is true;
+         },
+         columns: [ //Define Table Columns 序号", "名称", "取费基数", "计算基础","费率", "金额", "类别
+                      {title:"序号", field:"序号", width:80, headerSort:false,}, //never hide this column
+                      {title:"名称", field:"名称", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                      {title:"金额", field:"金额", width:100,   formatter:"money", },
+                      {title:"类别", field:"类别", width:100,   formatter:"textarea"},
+                    
+              ]
+       }); 
+       
+       myTable.current.on("cellDblClick", function(e, cell){
+           //e - the click event object
+           //cell - cell component
+           console.log(cell);
+       });
+  
+       //myTable.current.on("rowSelected", handleSelect);
+       
+  
+       
+  
+  
+      
+     
+    }, [data]);
+    return (
+      <div ref={myRef}> 
+      </div>
+
+
+
+    );
+}

+ 1438 - 0
src/Qingdan3.js

@@ -0,0 +1,1438 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Table, ConfigProvider } from "antd";
+import { Grid } from '@mui/material';
+import Tooltip from '@mui/material/Tooltip';
+import AddIcon from '@mui/icons-material/Add';
+import SaveIcon from '@mui/icons-material/Save';
+import CancelIcon from '@mui/icons-material/Close';
+import EditIcon from '@mui/icons-material/Edit';
+import DeleteIcon from '@mui/icons-material/DeleteOutlined';
+
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+import Service from './Service';
+import Button from '@mui/material/Button';
+import ButtonGroup from '@mui/material/ButtonGroup';
+import {extractFuzhu} from './utils';
+import {shanchu, undo, redo, danxiangdinge, updateDercj, changguidinge, handleBeizhu, huan, updateShuliang, handleYuban, updateDeMingcheng, handleRcjbc} from './editor';
+import Backdrop from '@mui/material/Backdrop';
+import CircularProgress from '@mui/material/CircularProgress';
+import { DataGrid, GridRowModes, GridActionsCellItem, GridRowEditStopReasons, zhCN as zhCN_MUI, GridToolbarContainer } from '@mui/x-data-grid';
+import Dialog from '@mui/material/Dialog';
+import DialogTitle from '@mui/material/DialogTitle';
+import DialogContent from '@mui/material/DialogContent';
+import IconButton from '@mui/material/IconButton';
+import Typography from '@mui/material/Typography';
+import {
+
+     SettingFilled,
+
+   } from '@ant-design/icons';
+import { v4 as uuidv4 } from 'uuid';
+
+import zhCN from 'antd/locale/zh_CN';
+import {copy} from './utils';
+
+
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+
+
+/**
+ * 
+本条规定了工程量清单编码的表示方式:十二位阿拉伯数字及其设置规定。
+各位数字的含义是:一、二位为专业工程代码(01—房屋建筑与装饰工程;02—仿古建筑工程;
+03—通用安装工程;04—市政工程;05—园林绿化工程;06—矿山工程;07—构筑物工程;08—城市
+轨道交通工程;09—爆破工程。以后进入国标的专业工程代码以此类推);三、四位为附录分类顺序码;
+五、六位为分部工程顺序码;七、八、九位为分项工程项目名称顺序码;十至十二位为清单项目名称
+顺序码。
+ */
+
+
+
+
+
+
+
+
+export default function Qingdan3({name, bh, bt, rgde, jxde, clde, beizhu/*后台传回来的附注信息,要整理后才能成为展示用的行*/ , beizhuFK, clickCallback, loadingCallback, dingeclick, tihuanCallback, tihuanClick, suanshiCallback}) {
+    
+     const myTable = React.useRef(null);
+     const myRef = React.useRef(null);
+     const [valueTab, setValueTab] = React.useState("1");
+     const handleChange = (event, newValue) => {
+          setValueTab(newValue);
+        };
+     const [rcjhl, setRcjhl] = React.useState([]);
+     const [rcjhl2, setRcjhl2] = React.useState([]);
+     const [fuzhu, setFuzhu] = React.useState([]);//展示用的附注行
+     const [yuban, setYuban] = React.useState([{'key': '0', '说明': '无'}, {'key': '1', '说明': '湿拌砂浆'}, {'key': '2', '说明': '散装干拌(混)砂浆'}, {'key': '3', '说明': '袋装干拌(混)砂浆'}]);
+     const [tuijian, setTuijian] = React.useState([]);
+     const [fuzhuEnable, setFuzhuEnable] = React.useState(false);
+     const [yubanEnable, setYubanEnable] = React.useState(false);
+     const hotRcjRef = React.useRef(null);
+     const hotTuijianRef = React.useRef(null);
+     const highlight = React.useRef([]);
+     const debmRef = React.useRef(null);
+     const lastClickRef = React.useRef(null);
+     const tuijianRef = React.useRef(null);
+     const tuijianTable = React.useRef(null);
+     const rcj2Ref = React.useRef(null);
+     const rcj2Table = React.useRef(null);
+     const rcjRef = React.useRef(null);
+     const rcjTable = React.useRef(null);
+     const [detail, setDetail] = React.useState([
+                    
+     ]);
+
+     const selectedRowKeysTable = React.useRef([]);
+     const selectedRowKeysTableParent = React.useRef(null);
+     const beizhuFKRef = React.useRef(null);
+
+
+     const rgdeRef = React.useRef(null);
+     const jxdeRef = React.useRef(null);
+     const cldeRef = React.useRef(null);
+     const isQdrcj = React.useRef(false);
+     const [selectedRowKeys, setSelectedRowKeys] = React.useState([]);
+     const [selectedRowKeys2, setSelectedRowKeys2] = React.useState([]);
+     const onSelectChange = (newSelectedRowKeys) => {
+          console.log('selectedRowKeys changed: ', newSelectedRowKeys);
+          setSelectedRowKeys(newSelectedRowKeys);
+          const [newData, newHl] = handleBeizhu(beizhuFKRef.current, selectedRowKeysTable.current[0], newSelectedRowKeys, fuzhu);
+                                       if (newData) {
+                                          myTable.current.updateData(newData.filter(x=>x['key'] == selectedRowKeysTableParent.current));
+                                          let y =[];
+                                          for (let i = 1; i < newHl.length; i++) {
+                                            y.push({
+                                          'ID' : newHl[i][0],
+                                          '人材机编码' : newHl[i][1],
+                                          '名称' : newHl[i][2],
+                                          '规格型号': newHl[i][3],
+                                          '单位' : newHl[i][4],
+                                          '单价' : newHl[i][5],
+                                          '产地' : newHl[i][6],
+                                          '供应厂商' : newHl[i][7],
+                                          '人材机类别' : newHl[i][8],
+                                          '甲供标志': newHl[i][9],
+                                          '含量' : newHl[i][10],
+                                          '合价' : newHl[i][11],
+                                          '暂估价标志' : newHl[i][12],
+                                          '主要材料标志' : newHl[i][13],
+                                          '主材标志' : newHl[i][14],
+                                          '设备标志' : newHl[i][15] 
+
+                                          });
+                                        }
+                                         setRcjhl(y);
+                                         if (rcjTable.current) {
+                                            rcjTable.current.replaceData(y);
+                                         }
+     
+                                       }
+        };
+
+
+        const onSelectChange2 = (newSelectedRowKeys) => {
+          
+          setSelectedRowKeys2(newSelectedRowKeys);
+          const [newData, newHl]  = handleYuban(selectedRowKeysTable.current[0], newSelectedRowKeys);
+          if (newData) {
+               myTable.current.updateData(newData.filter(x=>x['key'] == selectedRowKeysTableParent.current));
+               let y =[];
+               for (let i = 1; i < newHl.length; i++) {
+                 y.push({
+               'ID' : newHl[i][0],
+               '人材机编码' : newHl[i][1],
+               '名称' : newHl[i][2],
+               '规格型号': newHl[i][3],
+               '单位' : newHl[i][4],
+               '单价' : newHl[i][5],
+               '产地' : newHl[i][6],
+               '供应厂商' : newHl[i][7],
+               '人材机类别' : newHl[i][8],
+               '甲供标志': newHl[i][9],
+               '含量' : newHl[i][10],
+               '合价' : newHl[i][11],
+               '暂估价标志' : newHl[i][12],
+               '主要材料标志' : newHl[i][13],
+               '主材标志' : newHl[i][14],
+               '设备标志' : newHl[i][15] 
+
+               });
+             }
+              setRcjhl(y);
+              if (rcjTable.current) {
+                 rcjTable.current.replaceData(y);
+              }
+
+            }
+        
+        };
+
+
+     /**fuzhu select */
+     const rowSelection = {
+          selectedRowKeys,
+          onChange: onSelectChange,
+          getCheckboxProps: (record) => {
+               return {
+                    disabled: !fuzhuEnable
+               };
+          }
+     };
+
+     const rowSelection2 = {
+          type: 'radio',
+          selectedRowKeys: selectedRowKeys2,
+          selections: [Table.SELECTION_NONE],
+          onChange: onSelectChange2,
+          getCheckboxProps: (record) => {
+               return {
+                    disabled: !yubanEnable
+               };
+          }
+     };
+
+
+     var editCheck = function(cell){
+          //cell - the cell component for the editable cell
+      
+          //get row data
+          //console.log(cell);
+          if(cell._cell.row.data['序号']) return false;
+          return true;
+      }
+
+      var editCheckRcj = function(cell){
+          //cell - the cell component for the editable cell
+      
+          //get row data
+          //console.log(cell);
+          if(isQdrcj.current) return false;
+          if (cell._cell.row.getData()['人材机编码'] == '410000F') {
+               return false;
+          }
+          return true;
+      }
+
+
+      var sparklineFormatter = function(cell, formatterParams, onRendered){
+          for (let i = 0; i < highlight.current.length; i++) {
+               let entry = highlight.current[i];
+               if (entry.row + 1 == cell._cell.row.position && entry.col + 1 == cell._cell.column.getPosition()) {
+                    cell.getElement().style.fontWeight = 'bold';
+                    cell.getElement().style.color = 'green';
+                    cell.getElement().style.background = '#d7f1e1';
+               }
+              }
+              return Number(cell.getValue()).toFixed(2).toString(); 
+          };
+
+      function handleSelect(row){
+          selectedRowKeysTable.current = [row._row['data']['key']];
+          if (row._row.data['序号'] != null && row._row.data['序号'].length >0) {
+               selectedRowKeysTableParent.current = row._row['data']['key'];
+
+               setFuzhu([]);
+               setRcjrows([]);
+               setYubanEnable(false);
+               setSelectedRowKeys2([]);
+               setShowToolbar(false);
+               Service.generateQingdanrcj(name, bh,bt,row._row.data['清单编码']).then(x=>{
+                
+                
+                    let y =[];
+                    for (let i = 1; i < x.length; i++) {
+                         y.push({
+                              'ID' : x[i][0],
+                              '人材机编码' : x[i][1],
+                              '名称' : x[i][2],
+                              '规格型号': x[i][3],
+                              '单位' : x[i][4],
+                              '单价' : x[i][5],
+                              '产地' : x[i][6],
+                              '供应厂商' : x[i][7],
+                              '人材机类别' : x[i][8],
+                              '甲供标志': x[i][9],
+                              '含量' : x[i][10],
+                              '合价' : x[i][11],
+                              '暂估价标志' : x[i][12],
+                              '主要材料标志' : x[i][13],
+                              '主材标志' : x[i][14],
+                              '设备标志' : x[i][15] 
+
+                         });
+                    }
+                    setRcjhl(y);
+                    if (rcjTable.current) {
+                         rcjTable.current.replaceData(y);
+                    }
+                
+                  isQdrcj.current = true;
+                  highlight.current = [];
+               });
+               Service.generateQingdanTuijian(name, bh,bt,row._row.data['清单编码']).then(x=>{
+                setTuijian(x);
+                if (tuijianTable.current) tuijianTable.current.replaceData(x);
+                
+             });
+          }else{
+               setTuijian([]);
+               
+               
+               if (tuijianTable.current) tuijianTable.current.replaceData([]);
+              let row_parent = row._row;
+              while(row_parent.modules.dataTree.parent) {
+                   row_parent = row_parent.modules.dataTree.parent;
+              }
+              
+
+               //console.log(name, bh,bt,qdbm, selected[1]);
+               debmRef.current = row._row['data']['清单编码'];
+               selectedRowKeysTableParent.current = row_parent['data']['key'];
+               let qdbm = row_parent['data']['清单编码'];
+               let debm = row._row['data']['清单编码'];
+               console.log('debm=');
+               console.log(debm);
+               let danwei = row._row['data']['单位'];
+
+               clickCallback(qdbm, debm);
+               Service.generateDingercj(name, bh,bt,qdbm, debm, danwei).then(x=>{
+                 console.log(x);
+                 let y =[];
+                              for (let i = 1; i < x[0].length; i++) {
+                                   y.push({
+                                        'ID' : x[0][i][0],
+                                        '人材机编码' : x[0][i][1],
+                                        '名称' : x[0][i][2],
+                                        '规格型号': x[0][i][3],
+                                        '单位' : x[0][i][4],
+                                        '单价' : x[0][i][5],
+                                        '产地' : x[0][i][6],
+                                        '供应厂商' : x[0][i][7],
+                                        '人材机类别' : x[0][i][8],
+                                        '甲供标志': x[0][i][9],
+                                        '含量' : x[0][i][10],
+                                        '合价' : x[0][i][11],
+                                        '暂估价标志' : x[0][i][12],
+                                        '主要材料标志' : x[0][i][13],
+                                        '主材标志' : x[0][i][14],
+                                        '设备标志' : x[0][i][15] 
+          
+                                   });
+                              }
+                              setRcjhl(y);
+                              if (rcjTable.current) {
+                                   rcjTable.current.replaceData(y);
+                              }
+                 setShowToolbar(true);
+                 setFuzhuEnable(x[1]);
+                 setYubanEnable(x[1]);
+                 setSelectedRowKeys2(x[2]);
+                 setRcjrows(x[3]);
+                 //hotRcjRef.current?.hotInstance?.loadData(x);
+                 isQdrcj.current = false;
+                 let toHighlight = [];
+                 for(let i = 0; i < y.length; i++) {
+                     let entry = y[i];
+                     let bianhao = entry['人材机编码'];
+                     let rcjlb = entry['人材机类别'];
+                     let hit = false;
+                     if (Number(rcjlb) == 1 &&  rgdeRef.current  ) {
+                        for (let j = 0;j < rgdeRef.current.length; j++) {
+                           if (rgdeRef.current[j]["CLBH"] == bianhao) {
+                               if(rgdeRef.current[j]["CLMC"] == entry['名称'])hit = true;
+                                let danjia = Number(entry['单价']);
+                                if (danjia != rgdeRef.current[j]["YSJG"]) {
+                                     //console.log(`[${i},5]danjia bu yizhi`);
+                                     toHighlight.push({row: i, col: 5, renderer: "customStylesRenderer"});
+                                }
+                                let hanliang = Number(entry['含量']);
+                                if (hanliang != rgdeRef.current[j]["gr"]) {
+                                     //console.log(`[${i}, 10]hanliang bu yizhi`);
+                                     toHighlight.push({row: i, col: 10, renderer: "customStylesRenderer"});
+                                }
+                           }
+                        }
+
+                     }   
+                     if (Number(rcjlb) == 3 && jxdeRef.current  ) {
+                        for (let j = 0; j < jxdeRef.current.length; j++) {
+                           if (jxdeRef.current[j]["jxbh"] == bianhao) {
+                               if(jxdeRef.current[j]["jxmc"] == entry['名称'])hit = true;
+                                 let danjia = Number(entry['单价']);
+                                 if (danjia != jxdeRef.current[j]["tbdj"]) {
+                                      //console.log(`[${i},5]danjia bu yizhi`);
+                                      toHighlight.push({row: i, col: 5, renderer: "customStylesRenderer"});
+                                 }
+                                 let hanliang = Number(entry['含量']);
+                                 if (hanliang != jxdeRef.current[j]["sl"]) {
+                                      //console.log(`[${i}, 10]hanliang bu yizhi`);
+                                      toHighlight.push({row: i, col: 10, renderer: "customStylesRenderer"});
+                                 }
+                           }
+                        }
+
+                     }   
+                     if (Number(rcjlb) == 2 && cldeRef.current  ) {
+                        for (let j = 0; j < cldeRef.current.length; j++) {
+                           if (cldeRef.current[j]["CLBH"] == bianhao) {
+                               if(cldeRef.current[j]["CLMC"] == entry['名称'])hit = true;
+                                 let danjia = Number(entry['单价']);
+                                 if (danjia != cldeRef.current[j]["YSJG"]) {
+                                      //console.log(`[${i},5]danjia bu yizhi`);
+                                      toHighlight.push({row: i, col: 5, renderer: "customStylesRenderer"});
+                                 }
+                                 let hanliang = Number(entry['含量']);
+                                 if (hanliang != cldeRef.current[j]["SL"]) {
+                                      //console.log(`[${i}, 10]hanliang bu yizhi`);
+                                      toHighlight.push({row: i, col: 10, renderer: "customStylesRenderer"});
+                                 }
+                           }
+                        }
+
+                     }
+                     if (!hit) {
+                          toHighlight.push({row: i, col: 1, renderer: "customStylesRenderer"});
+                     }   
+                 }
+                 highlight.current = toHighlight;
+               });
+
+          }
+
+      }
+
+     /**补充人材机 */
+     const [rcjrows, setRcjrows] = React.useState([]);
+     //const [rowModesModel, setRowModesModel] = React.useState({});
+     const [showToolbar, setShowToolbar] = React.useState(false);
+     const rcjcolumns = [
+          {
+               field: 'actions',
+               type: 'actions',
+               headerName: '操作',
+               width: 100,
+               cellClassName: 'actions',
+               getActions: ({ id }) => {
+                
+         
+                
+         
+                 return [
+               
+                   <GridActionsCellItem
+                     icon={<DeleteIcon />}
+                     label="Delete"
+                     onClick={handleDeleteClick(id)}
+                     color="inherit"
+                   />,
+                 ];
+               },
+             },
+          { field: '人材机编码', headerName: '人材机编码', width: 120, editable: false },
+          {
+            field: '名称',
+            headerName: '名称',
+            width: 120,
+            align: 'left',
+            headerAlign: 'left',
+            editable: true,
+          },
+          {
+            field: '规格型号',
+            headerName: '规格型号',
+            width: 100,
+            editable: true,
+          },
+          {
+            field: '单位',
+            headerName: '单位',
+            width: 80,
+            editable: true,
+          },
+          {
+               field: '单价',
+               headerName: '单价',
+               width: 80,
+               editable: true,
+             },
+             {
+               field: '产地',
+               headerName: '产地',
+               width: 80,
+               editable: true,
+             },
+             {
+               field: '供应厂商',
+               headerName: '供应厂商',
+               width: 80,
+               editable: true,
+             },
+          {
+               field: '人材机类别',
+               headerName: '人材机类别',
+               width: 120,
+               editable: true,
+             },
+             {
+               field: '甲供标志',
+               headerName: '甲供标志',
+               width: 80,
+               editable: true,
+             },
+             {
+               field: '含量',
+               headerName: '含量',
+               width: 80,
+               editable: true,
+             },
+            /* {
+               field: '合价',
+               headerName: '合价',
+               width: 80,
+               editable: true,
+             },*/
+             {
+               field: '暂估价标志',
+               headerName: '暂估价标志',
+               width: 100,
+               editable: true,
+             },
+             {
+               field: '主要材料标志',
+               headerName: '主要材料标志',
+               width: 120,
+               editable: true,
+             },
+             {
+               field: '主材标志',
+               headerName: '主材标志',
+               width: 80,
+               editable: true,
+             },
+             {
+               field: '设备标志',
+               headerName: '设备标志',
+               width: 80,
+               editable: true,
+             },
+       
+        ];
+
+    
+      
+        const handleDeleteClick = (id) => () => {
+          setRcjrows(rcjrows.filter((row) => row.id !== id));
+          const [newData, newHl] = handleRcjbc(selectedRowKeysTable.current[0], rcjrows.filter((row) => row.id !== id));
+          if (newData) {
+               myTable.current.updateData(newData.filter(x=>x['key'] == selectedRowKeysTableParent.current));
+               let y =[];
+               for (let i = 1; i < newHl.length; i++) {
+                 y.push({
+               'ID' : newHl[i][0],
+               '人材机编码' : newHl[i][1],
+               '名称' : newHl[i][2],
+               '规格型号': newHl[i][3],
+               '单位' : newHl[i][4],
+               '单价' : newHl[i][5],
+               '产地' : newHl[i][6],
+               '供应厂商' : newHl[i][7],
+               '人材机类别' : newHl[i][8],
+               '甲供标志': newHl[i][9],
+               '含量' : newHl[i][10],
+               '合价' : newHl[i][11],
+               '暂估价标志' : newHl[i][12],
+               '主要材料标志' : newHl[i][13],
+               '主材标志' : newHl[i][14],
+               '设备标志' : newHl[i][15] 
+
+               });
+             }
+              setRcjhl(y);
+              if (rcjTable.current) {
+                 rcjTable.current.replaceData(y);
+              }
+
+            }
+
+        };
+      
+      
+        const processRowUpdate = (newRow) => {
+          const updatedRow = { ...newRow, isNew: false };
+          setRcjrows(rcjrows.map((row) => (row.id === newRow.id ? updatedRow : row)));
+          const [newData, newHl] = handleRcjbc(selectedRowKeysTable.current[0], rcjrows.map((row) => (row.id === newRow.id ? updatedRow : row)));
+          if (newData) {
+               myTable.current.updateData(newData.filter(x=>x['key'] == selectedRowKeysTableParent.current));
+               let y =[];
+               for (let i = 1; i < newHl.length; i++) {
+                 y.push({
+               'ID' : newHl[i][0],
+               '人材机编码' : newHl[i][1],
+               '名称' : newHl[i][2],
+               '规格型号': newHl[i][3],
+               '单位' : newHl[i][4],
+               '单价' : newHl[i][5],
+               '产地' : newHl[i][6],
+               '供应厂商' : newHl[i][7],
+               '人材机类别' : newHl[i][8],
+               '甲供标志': newHl[i][9],
+               '含量' : newHl[i][10],
+               '合价' : newHl[i][11],
+               '暂估价标志' : newHl[i][12],
+               '主要材料标志' : newHl[i][13],
+               '主材标志' : newHl[i][14],
+               '设备标志' : newHl[i][15] 
+
+               });
+             }
+              setRcjhl(y);
+              if (rcjTable.current) {
+                 rcjTable.current.replaceData(y);
+              }
+
+            }
+          return updatedRow;
+        };
+
+        function EditToolbar(props) {
+          const { setRcjrows } = props;
+        
+          const handleClick = () => {
+            const id = uuidv4();
+            let a = [];
+            setRcjrows((oldRows) => {
+               a = [
+                 ...oldRows,
+                 { id, '人材机编码': '410000F', '名称': '', '规格型号': '', '单位': '', '单价':'0','产地': '', '供应厂商': '', '人材机类别':'2',
+                '甲供标志':'', '含量':'1', '暂估价标志':'', '主要材料标志':'true', '主材标志':'true', '设备标志':'' },
+               ];
+               return a;
+             });
+             const [newData, newHl] = handleRcjbc(selectedRowKeysTable.current[0], a);
+             if (newData) {
+               myTable.current.updateData(newData.filter(x=>x['key'] == selectedRowKeysTableParent.current));
+               let y =[];
+               for (let i = 1; i < newHl.length; i++) {
+                 y.push({
+               'ID' : newHl[i][0],
+               '人材机编码' : newHl[i][1],
+               '名称' : newHl[i][2],
+               '规格型号': newHl[i][3],
+               '单位' : newHl[i][4],
+               '单价' : newHl[i][5],
+               '产地' : newHl[i][6],
+               '供应厂商' : newHl[i][7],
+               '人材机类别' : newHl[i][8],
+               '甲供标志': newHl[i][9],
+               '含量' : newHl[i][10],
+               '合价' : newHl[i][11],
+               '暂估价标志' : newHl[i][12],
+               '主要材料标志' : newHl[i][13],
+               '主材标志' : newHl[i][14],
+               '设备标志' : newHl[i][15]
+
+               });
+             }
+             setRcjhl(y);
+              if (rcjTable.current) {
+                 rcjTable.current.replaceData(y);
+              }
+          }
+            
+          };
+        
+          return (
+            <GridToolbarContainer>
+              <Button disabled={!showToolbar}
+              color="primary" startIcon={<AddIcon />} onClick={handleClick}>
+                补充
+              </Button>
+            </GridToolbarContainer>
+          );
+        }
+   
+    
+
+   
+     
+    
+
+
+
+     React.useEffect(() => {
+        
+          myTable.current = new Tabulator(myRef.current, {
+               index: "key",
+               height: 380,
+             data: detail, //link data to table
+             reactiveData: false, //enable data reactivity
+             dataTreeStartExpanded:true,
+             dataTree: true,
+             selectableRows:1, //make rows selectable
+             editTriggerEvent:"dblclick", //trigger edit on double click
+             dataTreeStartExpanded:function(row, level){
+                 //console.log(row);
+                 //console.log(level);
+                 return true; //expand rows where the "driver" data field is true;
+             },
+             columns: [ //Define Table Columns
+                          {title:"序号", field:"序号", width:80, headerSort:false, frozen: true}, //never hide this column
+                          {title:"清单编码", field:"清单编码", width:120,headerSort:false, frozen: true ,formatter:"textarea" },
+                          {title:"名称", field:"名称", width:150, headerSort:false, formatter:"textarea", editor: "input", editable: editCheck}, //hide this column first
+                          {title:"项目特征", field:"项目特征", width:200 , headerSort:false, formatter:"textarea"},
+                          {title:"计算规则", field:"计算规则", width:200, headerSort:false, formatter:"textarea"},
+                          {title:"单位", field:"单位", width:100, headerSort:false},
+                          {title:"数量", field:"数量", width:100, headerSort:false, editor: "input", editable: editCheck },
+                          {title:"综合单价", field:"综合单价", width:100, headerSort:false, formatter:"money"},
+                          {title:"合价", field:"合价", width:100, headerSort:false, formatter:"money"},
+                          {title:"人工费", field:"人工费", width:100, headerSort:false, formatter:"money"},
+                          {title:"主材费", field:"主材费", width:100, headerSort:false, formatter:"money"},
+                          {title:"设备费", field:"设备费", width:100, headerSort:false, formatter:"money"},
+                          {title:"辅材费", field:"辅材费", width:100, headerSort:false, formatter:"money"},
+                          {title:"材料费", field:"材料费", width:100, headerSort:false, formatter:"money"},
+                          {title:"机械费", field:"机械费", width:100, headerSort:false, formatter:"money"},
+                          {title:"管理费", field:"管理费", width:100, headerSort:false, formatter:"money"},
+                          {title:"利润", field:"利润", width:100, headerSort:false, formatter:"money"},
+                          {title:"暂估价", field:"暂估价", width:100, headerSort:false, formatter:"money"},
+                          {title:"综合人工工日", field:"综合人工工日", width:100, headerSort:false},
+                  ]
+           }); 
+           
+           myTable.current.on("cellDblClick", function(e, cell){
+               //e - the click event object
+               //cell - cell component
+               console.log(cell);
+           });
+     
+           myTable.current.on("rowSelected", handleSelect);
+           
+     
+           myTable.current.on("cellEdited", function(cell){
+               //console.log("edited");
+               //console.log();
+               let key = cell._cell.row.data['key'];
+               myTable.current.deselectRow();
+               if(cell._cell.column.field == '名称') {
+                    let newData = updateDeMingcheng(cell._cell.row.data['名称'], selectedRowKeysTable.current[0]);
+                    myTable.current.updateData(newData.filter(x=>x['key'] == selectedRowKeysTableParent.current)).then(function() {
+                         let getRow = myTable.current.getRows(); //get array of currently selected row components.
+                         let component = null;
+                         for(let i = 0; i < getRow.length; i++) {
+                              let entry = getRow[i]._row.modules.dataTree.children;
+                              for(let j = 0; j < entry.length; j++) {
+                                   let child = entry[j];
+                                   if(child.data['key'] == key) {
+                                        //console.log(child);
+                                        component = child.component;
+                                        break;
+                                   }
+                                   
+                              }
+
+                         }
+                         component.select();
+                         handleSelect(component);
+                         //handleSelect(getRow[0]);
+                      });                
+               }
+
+               else{
+
+               
+               
+               let [success, data] = updateShuliang(cell._cell.row.data['数量'], selectedRowKeysTable.current[0]);
+               if (success) {
+                                myTable.current.updateData(data.filter(x=>x['key'] == selectedRowKeysTableParent.current)).then(function() {
+                                   let getRow = myTable.current.getRows(); //get array of currently selected row components.
+                                   let component = null;
+                                   for(let i = 0; i < getRow.length; i++) {
+                                        let entry = getRow[i]._row.modules.dataTree.children;
+                                        for(let j = 0; j < entry.length; j++) {
+                                             let child = entry[j];
+                                             if(child.data['key'] == key) {
+                                                  //console.log(child);
+                                                  component = child.component;
+                                                  break;
+                                             }
+                                             
+                                        }
+     
+                                   }
+                                   component.select();
+                                   handleSelect(component);
+                                   //handleSelect(getRow[0]);
+                                });                            
+                                                            
+               }
+          }
+           });
+     
+     
+           myTable.current.on("tableBuilt", () => {
+               Service.generateQingdanmingxi(name, bh, bt).then(x=>{
+                    myTable.current.replaceData(x);
+                    });
+             });
+         
+        }, [bh, bt]);
+
+
+
+        React.useEffect(
+          () => {
+            //console.log("rgde changed");
+            //console.log(rgde);
+            rgdeRef.current = rgde;
+            jxdeRef.current = jxde;
+            cldeRef.current = clde;
+            if (isQdrcj.current) {
+               highlight.current = [];
+            } else {
+            let toHighlight = [];
+            for(let i = 0; i < rcjhl.length; i++) {
+                let entry = rcjhl[i];
+                let bianhao = entry['人材机编码'];
+                let rcjlb = entry['人材机类别'];
+                let hit = false;
+                if (Number(rcjlb) == Number(1) && rgde) {
+                    for (let j = 0; j < rgde.length; j++) {
+                        if (rgde[j]["CLBH"] == bianhao) {
+                            if(rgde[j]["CLMC"] == entry['名称'])hit = true;
+                            let danjia = Number(entry['单价']);
+                            if (danjia != rgde[j]["YSJG"]) {
+                                 //console.log(`[${i},5]danjia bu yizhi`);
+                                 toHighlight.push({row: i, col: 5, renderer: "customStylesRenderer"});
+                            }
+                            let hanliang = Number(entry['含量']);
+                            if (hanliang != rgde[j]["gr"]) {
+                                 //console.log(`[${i}, 10]hanliang bu yizhi`);
+                                 toHighlight.push({row: i, col: 10, renderer: "customStylesRenderer"});
+                            }
+  
+                        }              
+                    }
+  
+                }   
+                if (Number(rcjlb) == Number(3) && jxde ) {
+                     for (let j = 0; j < jxde.length; j++) {
+                        if (jxde[j]["jxbh"] == bianhao) {
+                           if(jxde[j]["jxmc"] == entry['名称'])hit = true;
+                           let danjia = Number(entry['单价']);
+                           if (danjia != jxde[j]["tbdj"]) {
+                                //console.log(`[${i},5]danjia bu yizhi`);
+                                toHighlight.push({row: i, col: 5, renderer: "customStylesRenderer"});
+                           }
+                           let hanliang = Number(entry['含量']);
+                           if (hanliang != jxde[j]["sl"]) {
+                                //console.log(`[${i}, 10]hanliang bu yizhi`);
+                                toHighlight.push({row: i, col: 10, renderer: "customStylesRenderer"});
+                           }
+                        }
+                     }
+  
+                }   
+                if (Number(rcjlb) == Number(2) && clde ) {
+                     for (let j = 0; j < clde.length; j++) {
+                        if (clde[j]["CLBH"] == bianhao) {
+                           if(clde[j]["CLMC"] == entry['名称'])hit = true;
+                           let danjia = Number(entry['单价']);
+                           if (danjia != clde[j]["YSJG"]) {
+                                //console.log(`[${i},5]danjia bu yizhi`);
+                                toHighlight.push({row: i, col: 5, renderer: "customStylesRenderer"});
+                           }
+                           let hanliang = Number(entry['含量']);
+                           if (hanliang != clde[j]["SL"]) {
+                                //console.log(`[${i}, 10]hanliang bu yizhi`);
+                                toHighlight.push({row: i, col: 10, renderer: "customStylesRenderer"});
+                           }
+                        }
+                     }
+  
+                }
+                if (!hit) {
+                   toHighlight.push({row: i, col: 1, renderer: "customStylesRenderer"});
+                }   
+            }
+            //console.log(toHighlight);
+            highlight.current = toHighlight;
+            }
+            let bzrcjhl = [/*["人材机编码", "名称", "单位", "单价", "合价", "含量"]*/] 
+            if (rgde)
+          for (let i = 0; i  < rgde.length; i++) {
+               bzrcjhl.push({'人材机编码': rgde[i]["CLBH"], '名称': rgde[i]["CLMC"], '单位': rgde[i]["JLDW"], '单价': rgde[i]["YSJG"], '合价': rgde[i]["gf"], '含量': rgde[i]["gr"]});
+          }
+          
+          if (clde)
+          for (let i = 0; i  < clde.length; i++) {
+               bzrcjhl.push({'人材机编码': clde[i]["CLBH"], '名称': clde[i]["CLMC"], '单位': clde[i]["JLDW"], '单价': clde[i]["YSJG"], '合价': clde[i]["HJ"], '含量': clde[i]["SL"]});
+          }
+          if (jxde)
+          for (let i = 0; i  < jxde.length; i++) {
+               bzrcjhl.push({'人材机编码': jxde[i]["jxbh"], '名称': jxde[i]["jxmc"], '单位': jxde[i]["DW"], '单价': jxde[i]["tbdj"], '合价': jxde[i]["hj"], '含量': jxde[i]["sl"]});
+          }
+            setRcjhl2(bzrcjhl);
+          }, [rgde, jxde, clde]
+        );
+
+
+
+        React.useEffect(
+          () => {
+              console.log(beizhu);
+              let result = [];
+              if (beizhu != null) { 
+                  let keys = Object.keys(beizhu["BZBH"]);
+                  for(let i = 0; i < keys.length; i++) {
+                      let key = keys[i];
+                      result.push({'key': i+1, '序号': i+1, '编号': beizhu["BZBH"][key], '说明': beizhu["SM"][key]});//序号很重要
+                  }
+                  setFuzhu(result);
+                  let newSelect = extractFuzhu(debmRef.current);
+                  setSelectedRowKeys(newSelect);
+                  //setSelectedRowKeys([1]);
+                  
+              }
+          }, [beizhu]
+        );
+
+        React.useEffect(
+          () => {
+               beizhuFKRef.current = beizhuFK;
+          }, [beizhuFK]
+      );
+
+  
+
+
+      React.useEffect(
+          () => {
+               
+               myTable.current.deselectRow();
+               //console.log(dingeclick);
+               if (selectedRowKeysTable.current.length > 0 ) {
+                    const [success, data, key] = changguidinge(JSON.parse(dingeclick), selectedRowKeysTable.current[0]);
+                    if (success) {
+                         myTable.current.updateData(data.filter(x=>x['key'] == selectedRowKeysTableParent.current)).then(function(){
+                              let getRow = myTable.current.getRows(); //get array of currently selected row components.
+                              let component = null;
+                              for(let i = 0; i < getRow.length; i++) {
+                                   let entry = getRow[i]._row.modules.dataTree.children;
+                                   for(let j = 0; j < entry.length; j++) {
+                                        let child = entry[j];
+                                        if(child.data['key'] == key) {
+                                             //console.log(child);
+                                             component = child.component;
+                                             break;
+                                        }
+                                        
+                                   }
+
+                              }
+                              
+                              component.select();
+                              handleSelect(component);
+
+                                   
+                               
+                          });
+                    }
+               }
+              
+          }, [dingeclick]//常规添加定额
+      );
+
+
+      React.useEffect(
+          () => {
+               //console.log(dingeclick);
+               if (selectedRowKeysTable.current.length > 0 ) {
+                    const data = huan(JSON.parse(tihuanClick), selectedRowKeysTable.current[0]);
+                    
+                    myTable.current.updateData(data.filter(x=>x['key'] == selectedRowKeysTableParent.current)).then(function(){
+                         let getRow = myTable.current.getRows(); //get array of currently selected row components.
+                         let component = null;
+                         for(let i = 0; i < getRow.length; i++) {
+                              let entry = getRow[i]._row.modules.dataTree.children;
+                              for(let j = 0; j < entry.length; j++) {
+                                   let child = entry[j];
+                                   if(child.data['key'] == selectedRowKeysTable.current[0]) {
+                                        //console.log(child);
+                                        component = child.component;
+                                        break;
+                                   }
+                                   
+                              }
+
+                         }
+                         
+                         
+                         handleSelect(component);
+
+                              
+                          
+                     });
+                         
+
+                        
+                    
+               }
+               
+          }, [tihuanClick]//替换定额人材机
+      );
+
+
+
+      React.useEffect(
+          () => {
+               if (tuijianRef.current != null ) {
+               tuijianTable.current = new Tabulator(tuijianRef.current, {
+                    index: "key",
+                    height: 200,
+                  data: tuijian, //link data to table
+                  reactiveData: false, //enable data reactivity
+                  dataTreeStartExpanded:false,
+                  dataTree: false,
+                  selectableRows:1, //make rows selectable
+                  
+                  
+                  columns: [ //Define Table Columns
+                               {title:"ID", field:"ID", width:80, headerSort:false, }, //never hide this column
+                               {title:"定额编号", field:"定额编号", width:120,headerSort:false,  formatter:"textarea" },
+                               {title:"工程量名称", field:"工程量名称", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                               {title:"工作内容", field:"工作内容", width:150 , headerSort:false, formatter:"textarea"},
+                             
+                       ]
+               });
+               tuijianTable.current.on("tableBuilt", () => {
+                    
+                    tuijianTable.current.replaceData(tuijian);
+                         
+                  });
+               }
+               if (rcj2Ref.current != null ) {
+                    rcj2Table.current = new Tabulator(rcj2Ref.current, {
+                         index: "key",
+                         height: 200,
+                       data: rcjhl2, //link data to table
+                       reactiveData: false, //enable data reactivity
+                       dataTreeStartExpanded:false,
+                       dataTree: false,
+                       selectableRows:1, //make rows selectable
+                       
+                       
+                       columns: [ //Define Table Columns
+                                    {title:"人材机编码", field:"人材机编码", width:100, headerSort:false, }, //never hide this column
+                                    {title:"名称", field:"名称", width:120,headerSort:false,  formatter:"textarea" },
+                                    {title:"单位", field:"单位", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                                    {title:"单价", field:"单价", width:150 , headerSort:false, formatter:"money"},
+                                    {title:"合价", field:"合价", width:150 , headerSort:false, formatter:"money"},
+                                    {title:"含量", field:"含量", width:150 , headerSort:false, formatter:"textarea"},
+                                  
+                            ]
+                    });
+                    rcj2Table.current.on("tableBuilt", () => {
+                         
+                         rcj2Table.current.replaceData(rcjhl2);
+                              
+                       });
+                    }
+
+               if (rcjRef.current != null ) {
+                    
+                         rcjTable.current = new Tabulator(rcjRef.current, {
+                              index: "key",
+                              height: 250,
+                            data: rcjhl, //link data to table
+                            reactiveData: false, //enable data reactivity
+                            dataTreeStartExpanded:false,
+                            dataTree: false,
+                            selectableRows:1, //make rows selectable
+                            editTriggerEvent:"dblclick",
+                            rowFormatter:function(row){
+                              //row - row component
+                              
+                              var data = row.getData();
+                              if (data['人材机编码'] == '410000F') {
+                                   row.getElement().style.backgroundColor = "#ffff00";
+                              }
+                              
+                            
+                          },
+                            
+                            columns: [ //Define Table Columns
+                                         {title:"ID", field:"ID", width:80, headerSort:false, },
+                                         {title:"人材机编码", field:"人材机编码", width:100, headerSort:false, }, //never hide this column
+                                         {title:"名称", field:"名称", width:120,headerSort:false,  formatter:"textarea", editor: "input", editable: editCheckRcj },
+                                         {title:"规格型号", field:"规格型号", width:80, headerSort:false, editor: "input", editable: editCheckRcj },
+                                         {title:"单位", field:"单位", width:80, headerSort:false, formatter:"textarea"}, //hide this column first
+                                         {title:"单价", field:"单价", width:80 , headerSort:false, formatter: sparklineFormatter, editor: "input", editable: editCheckRcj },
+                                         {title:"产地", field:"产地", width:80, headerSort:false, },
+                                         {title:"供应厂商", field:"供应厂商", width:80, headerSort:false, },
+                                         {title:"人材机类别", field:"人材机类别", width:80, headerSort:false, },
+                                         {title:"甲供标志", field:"甲供标志", width:80 , headerSort:false, formatter:"textarea"},
+                                         {title:"含量", field:"含量", width:80 , headerSort:false, formatter:"money", formatterParams:{precision:4}, editor: "input", editable: editCheckRcj },
+                                         {title:"合价", field:"合价", width:80 , headerSort:false, formatter:"money"},
+                                         {title:"暂估价标志", field:"暂估价标志", width:80 , headerSort:false, formatter:"textarea"},
+                                         {title:"主要材料标志", field:"主要材料标志", width:100 , headerSort:false, formatter:"textarea"},
+                                         {title:"主材标志", field:"主材标志", width:80 , headerSort:false, formatter:"textarea"},
+                                         {title:"设备标志", field:"设备标志", width:80 , headerSort:false, formatter:"textarea"},
+                                       
+                                 ]
+                         });
+                         rcjTable.current.on("tableBuilt", () => {
+                              
+                              rcjTable.current.replaceData(rcjhl);
+                                   
+                            });
+                         rcjTable.current.on("cellDblClick", function(e, cell){
+                              //e - the click event object
+                              //cell - cell component
+                              let determine = cell._cell.row.getData()['人材机编码'] != '410000F';
+                              if(cell._cell.column.getPosition() == 2  && !isQdrcj.current && determine) {
+                                  tihuanCallback(cell._cell.row.position, cell._cell.column.getPosition());
+                              }
+                          });
+                         rcjTable.current.on("cellEdited", function(cell){
+                              let data =  copy(cell._cell.table.getData());
+                              for(let i = 0; i < data.length; i++) {
+                                   data[i]['合价'] = Number(data[i]['单价']) * Number(data[i]['含量']);
+                              }
+                              setRcjhl(data);
+                              if (rcjTable.current) {
+                                   rcjTable.current.replaceData(data);
+                              }
+                              let data2 = [['ID', '人材机编码', '名称', '规格型号', '单位', '单价', '产地', '供应厂商', '人材机类别', '甲供标志', '含量', '合价', '暂估价标志', '主要材料标志', '主材标志', '设备标志']]
+                              for (let i = 0; i < data.length; i++) {
+                                   data2.push([data[i]['ID'], data[i]['人材机编码'], data[i]['名称'], data[i]['规格型号'], data[i]['单位'], 
+                                   data[i]['单价'], data[i]['产地'], data[i]['供应厂商'], data[i]['人材机类别'], 
+                                   data[i]['甲供标志'], data[i]['含量'], data[i]['合价'], data[i]['暂估价标志'], data[i]['主要材料标志'], data[i]['主材标志'], data[i]['设备标志']]);
+                              }
+     
+                              let newData = updateDercj(selectedRowKeysTable.current[0], data2);
+                              myTable.current.updateData(newData.filter(x=>x['key'] == selectedRowKeysTableParent.current)).then(function() {
+                              let getRow = myTable.current.getRows(); //get array of currently selected row components.
+                              let component = null;
+                              for(let i = 0; i < getRow.length; i++) {
+                                     let entry = getRow[i]._row.modules.dataTree.children;
+                                     for(let j = 0; j < entry.length; j++) {
+                                           let child = entry[j];
+                                           if(child.data['key'] == selectedRowKeysTable.current[0]) {
+                                                //console.log(child);
+                                               component = child.component;
+                                                break;
+                                            }
+                         
+                                      }
+
+                              }
+               
+                                handleSelect(component);
+                              });
+                         });
+                         
+                         
+                    }
+          }, [valueTab]
+        );
+
+
+
+
+    return (
+        <Stack spacing={2}>
+
+                   <Box>
+                   <Stack direction='row' spacing={2}>
+                   <Button variant="outlined" size="small" onClick={() => {
+                      if (selectedRowKeysTable.current.length > 0) {
+                         let getRow = myTable.current.getRows(); //get array of currently selected row components.
+                         let hit = false;
+                         for(let i = 0; i < getRow.length; i++) {
+                              if (getRow[i]._row.data['key'] == selectedRowKeysTable.current[0]) {
+                                   hit = true;
+                              }
+                         }
+                         if (hit) {
+                              suanshiCallback();
+                         }
+                      }
+                 
+                      
+                      }}
+                   >定额(算式)</Button>
+                   <Button variant="outlined" size="small" onClick={() => {
+                      if (selectedRowKeysTable.current.length > 0) {
+                         const [success, data] = danxiangdinge(selectedRowKeysTable.current[0]);
+                         if(success) {
+                              myTable.current.updateData(data.filter(x=>x['key'] == selectedRowKeysTableParent.current)).then(function(){
+                                   selectedRowKeysTable.current = [];
+                                   selectedRowKeysTableParent.current = null;
+                                        setRcjhl([]);
+                                        if (rcjTable.current) {
+                                             rcjTable.current.replaceData([]);
+                                        }
+                                        setFuzhu([]);
+                                        setRcjrows([]);
+                                        setShowToolbar(false);
+                                        setSelectedRowKeys2([]);
+                                        setYubanEnable(false);
+                                        isQdrcj.current = true;
+                                        highlight.current = [];
+                                 });
+                         }
+                      }
+                 
+                      
+                      }}
+                   >单项定额</Button>
+                      <Button variant="outlined" size="small" onClick={() => {
+                      if (selectedRowKeysTable.current.length > 0) {
+                         let newData = shanchu(selectedRowKeysTable.current[0]);
+                         myTable.current.updateData(newData.filter(x=>x['key'] == selectedRowKeysTableParent.current)).then(function(){
+                             if (newData.filter(x=>x['key'] == selectedRowKeysTable.current[0]).length == 0) {
+                                  selectedRowKeysTable.current = [];
+                                  selectedRowKeysTableParent.current = [];
+                                  setRcjhl([]);
+                                  if (rcjTable.current) {
+                                   rcjTable.current.replaceData([]);
+                                  }
+                                  setFuzhu([]);
+                                  setRcjrows([]);
+                                  setShowToolbar(false);
+                                  setSelectedRowKeys2([]);
+                                  setYubanEnable(false);
+                                  isQdrcj.current = true;
+                                  highlight.current = [];
+                              }
+                         });
+                         
+                         
+                         
+                     }
+                      
+                 
+                      
+                      }}
+                   >删除</Button>
+                   <Button variant="outlined" size="small" onClick={() => {
+                   let newData = undo();
+                   myTable.current.updateData(newData).then(function(){
+                      
+                         selectedRowKeysTable.current = [];
+                         selectedRowKeysTableParent.current = null;
+                         setRcjhl([]);
+                         if (rcjTable.current) {
+                              rcjTable.current.replaceData([]);
+                         }
+                         setFuzhu([]);
+                         setRcjrows([]);
+                         setShowToolbar(false);
+                         setSelectedRowKeys2([]);
+                         setYubanEnable(false);
+                         isQdrcj.current = true;
+                         highlight.current = [];
+                         
+                     
+                   });
+                      
+                      }}
+                   >撤销</Button>
+                   <Button variant="outlined" size="small" onClick={() => {
+                   let newData = redo();
+                   myTable.current.updateData(newData).then(function(){
+                      selectedRowKeysTable.current = [];
+                      selectedRowKeysTableParent.current = null;
+
+                         setRcjhl([]);
+                         if (rcjTable.current) {
+                              rcjTable.current.replaceData([]);
+                         }
+                         setFuzhu([]);
+                         setRcjrows([]);
+                         setShowToolbar(false);
+                         setSelectedRowKeys2([]);
+                         setYubanEnable(false);
+                         isQdrcj.current = true;
+                         highlight.current = [];
+                   });
+                   
+                      
+                      }}
+                   >重做</Button>
+                   <Button variant="outlined" size="small" onClick={() => {
+                            console.log("save to cloud");
+                            loadingCallback();
+                      
+                      }}
+                   >保存</Button>
+
+                  
+                   </Stack>
+                   <div style={{width: "70vw"}}>
+                   <div ref={myRef}> 
+                  </div>
+                  </div>
+                  </Box>
+
+
+
+                   <Box >
+                   
+                   <TabContext value={valueTab}>
+                       <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
+                         <TabList sx={{minHeight: '24px'}} onChange={handleChange} aria-label="lab API tabs example">
+                           <Tab sx={{p: 0, minHeight: '24px'}} label="人材机含量" value="1" />
+                           <Tab sx={{p: 0, minHeight: '24px'}} label="标准定额人材机含量" value="2" />
+                           <Tab sx={{p: 0, minHeight: '24px'}} label="人材机补充" value="3" />
+                           <Tab sx={{p: 0, minHeight: '24px'}} label="定额附注" value="4" />
+                           <Tab sx={{p: 0, minHeight: '24px'}} label="预拌砂浆" value="5" />
+                           <Tab sx={{p: 0, minHeight: '24px'}} label="组价推荐" value="6" />
+                         </TabList>
+                       </Box>
+                       
+                       <TabPanel sx={{p: 1}} value="1">
+                        <div style={{width:"70vw"}}>
+                       <div ref={rcjRef}></div>
+                       </div>
+                       </TabPanel>
+                       <TabPanel sx={{p: 1}} value="2">
+                         
+                       <div ref={rcj2Ref}></div>
+                           
+
+                       </TabPanel>
+                       <TabPanel sx={{p: 1}} value="3">
+                         
+                       <Box
+                       sx={{
+                         height: 200,
+                         width: '100%',
+                         '& .actions': {
+                           color: 'text.secondary',
+                         },
+                         '& .textPrimary': {
+                           color: 'text.primary',
+                         },
+                       }}
+                     >
+                       <DataGrid disableColumnMenu disableColumnSorting
+                         hideFooter={true}
+                         rows={rcjrows}
+                         columns={rcjcolumns}
+                         processRowUpdate={processRowUpdate}
+                         slotProps={{
+                           toolbar: { setRcjrows },
+                         }}
+                         slots={{
+                              toolbar: EditToolbar,
+                            }}
+                         
+                         localeText={zhCN_MUI.components.MuiDataGrid.defaultProps.localeText}
+
+                       />
+                     </Box>
+                             
+  
+                         </TabPanel>
+                       <TabPanel sx={{p: 1}} value="4">
+                       <Box sx={{maxHeight: `190px`}}>
+                       <ConfigProvider
+                          locale={zhCN}
+                          theme={{
+                            components: {
+                              Table: {
+                                 /* here is your component tokens */
+                                 cellPaddingBlock : 8
+                              },
+                            },
+                          }}
+                        >
+
+                          <Table 
+                             scroll={{ x: 'max-content' , y : 190}}
+                             pagination={false}
+                             rowSelection={rowSelection}
+                             columns={
+                              [
+                                   { title: '序号', dataIndex: '序号', width : 80},
+                                   {
+                                        title: '编号',
+                                        dataIndex: '编号',
+                                     
+                                   },
+                                   {
+                                        title: '说明',
+                                        dataIndex: '说明',
+                                     width: 550
+                                    
+                                   },
+                                  
+                                 ]
+                             }
+                           dataSource={fuzhu} />
+
+                        </ConfigProvider>
+                       </Box>
+                          
+
+                       </TabPanel>
+                       <TabPanel sx={{p: 1}} value="5">
+                        <Box sx={{maxHeight: `190px`}}>
+                        <ConfigProvider
+                          locale={zhCN}
+                          theme={{
+                            components: {
+                              Table: {
+                                 /* here is your component tokens */
+                                 cellPaddingBlock : 8
+                              },
+                            },
+                          }}
+                        >
+
+                          <Table 
+                             scroll={{ x: 'max-content' , y : 190}}
+                             pagination={false}
+                             rowSelection={rowSelection2}
+                             columns={
+                              [
+                                 
+                                   {
+                                        title: '说明',
+                                        dataIndex: '说明',
+                                        width: 550
+                                    
+                                   },
+                                  
+                                 ]
+                             }
+                           dataSource={yuban} />
+
+
+                         </ConfigProvider>
+                        </Box>
+                       </TabPanel>
+                       
+                       <TabPanel sx={{p: 1}} value="6">
+                       <div ref={tuijianRef}></div>
+
+                       </TabPanel>
+                     </TabContext>
+                  </Box>
+                  </Stack>
+                  
+
+
+
+
+
+    );
+}

+ 73 - 0
src/Qtxm.js

@@ -0,0 +1,73 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+//registerPlugin(NestedRows);
+import Service from './Service';
+import EditableSelect from './EditableSelect';
+import EditableSelectGC from './EditableSelectGC';
+import Editable from './Editable';
+import Button from '@mui/material/Button';
+
+import {copy} from './utils';
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+export default function Qtxm({data}) {
+    const myRef = React.useRef();
+    const myTable = React.useRef(null);
+
+
+
+    React.useEffect(() => {
+      myTable.current = new Tabulator(myRef.current, {
+           index: "key",
+           height: 600,
+         data: data, //link data to table
+         reactiveData: false, //enable data reactivity
+         dataTreeStartExpanded:true,
+         dataTree: true,
+         selectableRows:1, //make rows selectable
+         editTriggerEvent:"dblclick", //trigger edit on double click
+         dataTreeStartExpanded:function(row, level){
+             //console.log(row);
+             //console.log(level);
+             return true; //expand rows where the "driver" data field is true;
+         },
+         columns: [ //Define Table Columns 序号", "名称", "取费基数", "计算基础","费率", "金额", "类别
+                      {title:"序号", field:"序号", width:80, headerSort:false,}, //never hide this column
+                      {title:"名称", field:"名称", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                      {title:"金额", field:"金额", width:100,   formatter:"money", },
+                      {title:"项目类别", field:"项目类别", width:100,   formatter:"textarea"},
+                      {title:"备注", field:"备注", width:100,   formatter:"textarea"},
+                    
+              ]
+       }); 
+       
+       myTable.current.on("cellDblClick", function(e, cell){
+           //e - the click event object
+           //cell - cell component
+           console.log(cell);
+       });
+  
+       //myTable.current.on("rowSelected", handleSelect);
+       
+  
+       
+  
+  
+      
+     
+    }, [data]);
+    return (
+      <div ref={myRef}> 
+      </div>
+
+
+
+    );
+}

+ 679 - 0
src/Qufei.js

@@ -0,0 +1,679 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+//registerPlugin(NestedRows);
+import Service from './Service';
+import EditableSelect from './EditableSelect';
+import EditableSelectGC from './EditableSelectGC';
+import Editable from './Editable';
+import Button from '@mui/material/Button';
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+import {copy} from './utils';
+
+export default function Qufei({id, qufeiCallback}) {
+    
+  const [detail, setDetail] = React.useState([]);
+
+const hotRef = React.useRef(null);
+const myRef = React.useRef();
+const myTable = React.useRef(null);
+const [expandedRowKeys, setExpandedRowKeys] = React.useState([]);
+const [selectedRowKeys, setSelectedRowKeys] = React.useState([]);
+
+
+
+const apply = () => {
+  let checked = check(myTable.current.getData());
+  if (checked) {
+    let origin = myTable.current.getData();
+    let y = origin.map(z=>{
+      z["children"] = z['_children'];
+      return z;
+    });
+    let t = y.map(z=>{
+      if (z.hasOwnProperty("children")) {
+        let children = z["children"];
+        for (let i = 0; i < children.length; i++) {
+          let child = children[i];
+          if (child.hasOwnProperty("_children")) {
+            child["children"] = child["_children"];
+          }
+        }
+      }
+      return z;
+      });
+    qufeiCallback(id, t);
+  }
+};
+
+const check = (data) => {
+  for(let i = 0; i < data.length; i++) {
+    if (data[i]['管理费(%)'].length == 0) {
+      return false;
+    }
+    if (data[i]['利润(%)'].length == 0) {
+      return false;
+    }
+    if (data[i].hasOwnProperty('_children')) {
+       let checked = check(data[i]['_children']);
+       if (!checked) {
+          return false;
+       }
+       return true;
+    }
+    else {
+      return true;
+    }
+    
+
+  }
+};
+
+
+const rowSelection = {
+  selectedRowKeys,
+  onChange: (selectedRowKeys) => {
+       //console.log(selectedRowKeys);
+       if (selectedRowKeys.length > 0) {
+            setExpandedRowKeys([selectedRowKeys.at(-1)]);
+       } else {
+       setSelectedRowKeys(selectedRowKeys);
+       //handleSelection(selectedRowKeys);
+       }
+  }
+};
+
+const traverse = (data) => {
+  for(let i = 0; i < data.length; i++) {
+    if (data[i]['工程类型'].length > 0 && data[i]['工程类别'].length > 0) {
+        if (data[i]['工程类型'] == '建筑工程') {
+          if (data[i]['工程类别'] == '一类工程') {
+            data[i]['管理费(%)'] = '32';
+            data[i]['利润(%)'] = '12';
+            data[i]['备注'] = '';
+          } else if (data[i]['工程类别'] == '二类工程') {
+            data[i]['管理费(%)'] = '29';
+            data[i]['利润(%)'] = '12';
+            data[i]['备注'] = '';
+          } else {
+            data[i]['管理费(%)'] = '26';
+            data[i]['利润(%)'] = '12';
+            data[i]['备注'] = '';
+          }
+        }
+        if (data[i]['工程类型'] == '单独预制构件制作') {
+          if (data[i]['工程类别'] == '一类工程') {
+            data[i]['管理费(%)'] = '15';
+            data[i]['利润(%)'] = '6';
+            data[i]['备注'] = '';
+          } else if (data[i]['工程类别'] == '二类工程') {
+            data[i]['管理费(%)'] = '13';
+            data[i]['利润(%)'] = '6';
+            data[i]['备注'] = '';
+          } else {
+            data[i]['管理费(%)'] = '11';
+            data[i]['利润(%)'] = '6';
+            data[i]['备注'] = '';
+          }
+        }
+        if (data[i]['工程类型'] == '打预制桩、单独构件吊装') {
+          if (data[i]['工程类别'] == '一类工程') {
+            data[i]['管理费(%)'] = '11';
+            data[i]['利润(%)'] = '5';
+            data[i]['备注'] = '';
+          } else if (data[i]['工程类别'] == '二类工程') {
+            data[i]['管理费(%)'] = '9';
+            data[i]['利润(%)'] = '5';
+            data[i]['备注'] = '';
+          } else {
+            data[i]['管理费(%)'] = '7';
+            data[i]['利润(%)'] = '5';
+            data[i]['备注'] = '';
+          }
+        }
+        if (data[i]['工程类型'] == '制作兼打桩') {
+          if (data[i]['工程类别'] == '一类工程') {
+            data[i]['管理费(%)'] = '17';
+            data[i]['利润(%)'] = '7';
+            data[i]['备注'] = '';
+          } else if (data[i]['工程类别'] == '二类工程') {
+            data[i]['管理费(%)'] = '15';
+            data[i]['利润(%)'] = '7';
+            data[i]['备注'] = '';
+          } else {
+            data[i]['管理费(%)'] = '12';
+            data[i]['利润(%)'] = '7';
+            data[i]['备注'] = '';
+          }
+        }
+        if (data[i]['工程类型'] == '大型土石方工程') {
+          if (data[i]['工程类别'] == '一类工程') {
+            data[i]['管理费(%)'] = '7';
+            data[i]['利润(%)'] = '4';
+            data[i]['备注'] = '';
+          } else if (data[i]['工程类别'] == '二类工程') {
+            data[i]['管理费(%)'] = '7';
+            data[i]['利润(%)'] = '4';
+            data[i]['备注'] = '';
+          } else {
+            data[i]['管理费(%)'] = '7';
+            data[i]['利润(%)'] = '4';
+            data[i]['备注'] = '';
+          }
+        }
+        if (data[i]['工程类型'] == '单独装饰工程') {
+          if (data[i]['工程类别'] == '一类工程') {
+            data[i]['管理费(%)'] = '43';
+            data[i]['利润(%)'] = '15';
+            data[i]['备注'] = '';
+          } else if (data[i]['工程类别'] == '二类工程') {
+            data[i]['管理费(%)'] = '43';
+            data[i]['利润(%)'] = '15';
+            data[i]['备注'] = '';
+          } else {
+            data[i]['管理费(%)'] = '43';
+            data[i]['利润(%)'] = '15';
+            data[i]['备注'] = '';
+          }
+        }
+        if (data[i]['工程类型'] == '安装工程') {
+          if (data[i]['工程类别'] == '一类工程') {
+            data[i]['管理费(%)'] = '48';
+            data[i]['利润(%)'] = '14';
+            data[i]['备注'] = '计算基础:人工费';
+          } else if (data[i]['工程类别'] == '二类工程') {
+            data[i]['管理费(%)'] = '44';
+            data[i]['利润(%)'] = '14';
+            data[i]['备注'] = '计算基础:人工费';
+          } else {
+            data[i]['管理费(%)'] = '40';
+            data[i]['利润(%)'] = '14';
+            data[i]['备注'] = '计算基础:人工费';
+          }
+        }
+        if (data[i]['工程类型'] == '通用项目、道路、排水工程') {
+          if (data[i]['工程类别'] == '一类工程') {
+            data[i]['管理费(%)'] = '26';
+            data[i]['利润(%)'] = '10';
+            data[i]['备注'] = '';
+          } else if (data[i]['工程类别'] == '二类工程') {
+            data[i]['管理费(%)'] = '23';
+            data[i]['利润(%)'] = '10';
+            data[i]['备注'] = '';
+          } else {
+            data[i]['管理费(%)'] = '20';
+            data[i]['利润(%)'] = '10';
+            data[i]['备注'] = '';
+          }
+        }
+        if (data[i]['工程类型'] == '桥梁、水工构筑物') {
+          if (data[i]['工程类别'] == '一类工程') {
+            data[i]['管理费(%)'] = '35';
+            data[i]['利润(%)'] = '10';
+            data[i]['备注'] = '';
+          } else if (data[i]['工程类别'] == '二类工程') {
+            data[i]['管理费(%)'] = '32';
+            data[i]['利润(%)'] = '10';
+            data[i]['备注'] = '';
+          } else {
+            data[i]['管理费(%)'] = '29';
+            data[i]['利润(%)'] = '10';
+            data[i]['备注'] = '';
+          }
+        }
+        if (data[i]['工程类型'] == '给水、燃气与集中供热') {
+          if (data[i]['工程类别'] == '一类工程') {
+            data[i]['管理费(%)'] = '45';
+            data[i]['利润(%)'] = '13';
+            data[i]['备注'] = '计算基础:人工费';
+          } else if (data[i]['工程类别'] == '二类工程') {
+            data[i]['管理费(%)'] = '41';
+            data[i]['利润(%)'] = '13';
+            data[i]['备注'] = '计算基础:人工费';
+          } else {
+            data[i]['管理费(%)'] = '37';
+            data[i]['利润(%)'] = '13';
+            data[i]['备注'] = '计算基础:人工费';
+          }
+        }
+        if (data[i]['工程类型'] == '路灯及交通设施工程') {
+          if (data[i]['工程类别'] == '一类工程') {
+            data[i]['管理费(%)'] = '43';
+            data[i]['利润(%)'] = '13';
+            data[i]['备注'] = '计算基础:人工费';
+          } else if (data[i]['工程类别'] == '二类工程') {
+            data[i]['管理费(%)'] = '43';
+            data[i]['利润(%)'] = '13';
+            data[i]['备注'] = '计算基础:人工费';
+          } else {
+            data[i]['管理费(%)'] = '43';
+            data[i]['利润(%)'] = '13';
+            data[i]['备注'] = '计算基础:人工费';
+          }
+        }
+        if (data[i]['工程类型'] == '(市)大型土石方工程') {
+          if (data[i]['工程类别'] == '一类工程') {
+            data[i]['管理费(%)'] = '7';
+            data[i]['利润(%)'] = '4';
+            data[i]['备注'] = '';
+          } else if (data[i]['工程类别'] == '二类工程') {
+            data[i]['管理费(%)'] = '7';
+            data[i]['利润(%)'] = '4';
+            data[i]['备注'] = '';
+          } else {
+            data[i]['管理费(%)'] = '7';
+            data[i]['利润(%)'] = '4';
+            data[i]['备注'] = '';
+          }
+        }
+
+    }
+    if (data[i].hasOwnProperty("_children")) {
+      traverse(data[i]['_children']);
+    }
+  }
+  return data;
+};
+
+
+
+const handleChangeLR = (value) => {
+  
+    let selected = value.row.getData()['key'];
+    let all = value.row.table.getData();
+    if (all[0]['key'] == selected) {
+      //总选择
+      let newData = copy(all);
+      newData[0]['利润(%)'] = value.value;
+      for(let i = 0; i < newData[0]["_children"].length; i++) {
+        let child = newData[0]['_children'][i];
+        child['利润(%)'] = value.value;
+        for(let j = 0; j < child['_children'].length; j++) {
+          child['_children'][j]['利润(%)'] = value.value;
+        }
+      }
+      myTable.current.replaceData(newData);
+
+    }
+    else if (all[0]["_children"].filter(x=>x['key'] == selected).length > 0) {
+      //某个单项工程
+      let newData = copy(all);
+      for(let i = 0; i < newData[0]["_children"].length; i++) {
+        let child = newData[0]['_children'][i];
+        if (child['key'] == selected) {
+          child['利润(%)'] = value.value;
+          for(let j = 0; j < child['_children'].length; j++) {
+            child['_children'][j]['利润(%)'] = value.value;
+          }
+        }
+        
+      } 
+      myTable.current.replaceData(newData);
+    } else {
+      //具体一行
+      let newData = copy(all);
+      for(let i = 0; i < newData[0]["_children"].length; i++) {
+        let child = newData[0]['_children'][i];
+        
+        for(let j = 0; j < child['_children'].length; j++) {
+          if (child['_children'][j]['key'] == selected) {  
+              child['_children'][j]['利润(%)'] = value.value;
+          }
+        }
+        
+        
+      } 
+      myTable.current.replaceData(newData);
+    }
+
+
+  
+};
+
+
+const handleChangeGLF = (value) => {
+  
+    let selected = value.row.getData()['key'];
+    let all = value.row.table.getData();
+    if (all[0]['key'] == selected) {
+      //总选择
+      let newData = copy(all);
+      newData[0]['管理费(%)'] = value.value;
+      for(let i = 0; i < newData[0]["_children"].length; i++) {
+        let child = newData[0]['_children'][i];
+        child['管理费(%)'] = value.value;
+        for(let j = 0; j < child['_children'].length; j++) {
+          child['_children'][j]['管理费(%)'] = value.value;
+        }
+      }
+      myTable.current.replaceData(newData);
+
+    }
+    else if (all[0]["_children"].filter(x=>x['key'] == selected).length > 0) {
+      //某个单项工程
+      let newData = copy(all);
+      for(let i = 0; i < newData[0]["_children"].length; i++) {
+        let child = newData[0]['_children'][i];
+        if (child['key'] == selected) {
+          child['管理费(%)'] = value.value;
+          for(let j = 0; j < child['_children'].length; j++) {
+            child['_children'][j]['管理费(%)'] = value.value;
+          }
+        }
+        
+      } 
+      myTable.current.replaceData(newData);
+    } else {
+      //具体一行
+      let newData = copy(all);
+      for(let i = 0; i < newData[0]["_children"].length; i++) {
+        let child = newData[0]['_children'][i];
+        
+        for(let j = 0; j < child['_children'].length; j++) {
+          if (child['_children'][j]['key'] == selected) {  
+              child['_children'][j]['管理费(%)'] = value.value;
+          }
+        }
+        
+        
+      } 
+      myTable.current.replaceData(newData);
+    }
+
+
+  
+};
+
+
+const handleChange = (value) => {
+  
+    let selected = value.row.getData()['key'];
+    let all = value.row.table.getData();
+    if (all[0]['key'] == selected) {
+      //总选择
+      let newData = copy(all);
+      newData[0]['工程类别'] = value.value;
+      for(let i = 0; i < newData[0]["_children"].length; i++) {
+        let child = newData[0]['_children'][i];
+        child['工程类别'] = value.value;
+        for(let j = 0; j < child['_children'].length; j++) {
+          child['_children'][j]['工程类别'] = value.value;
+        }
+      }
+      myTable.current.replaceData(traverse(newData));
+
+    }
+    else if (all[0]["_children"].filter(x=>x['key'] == selected).length > 0) {
+      //某个单项工程
+      let newData = copy(all);
+      for(let i = 0; i < newData[0]["_children"].length; i++) {
+        let child = newData[0]['_children'][i];
+        if (child['key'] == selected) {
+          child['工程类别'] = value.value;
+          for(let j = 0; j < child['_children'].length; j++) {
+            child['_children'][j]['工程类别'] = value.value;
+          }
+        }
+        
+      } 
+      myTable.current.replaceData(traverse(newData));
+    } else {
+      //具体一行
+      let newData = copy(all);
+      for(let i = 0; i < newData[0]["_children"].length; i++) {
+        let child = newData[0]['_children'][i];
+        
+        for(let j = 0; j < child['_children'].length; j++) {
+          if (child['_children'][j]['key'] == selected) {  
+              child['_children'][j]['工程类别'] = value.value;
+          }
+        }
+        
+        
+      } 
+      myTable.current.replaceData(traverse(newData));
+    }
+
+
+  
+};
+
+const handleChangeGC = (value) => {
+
+    let selected = value.row.getData()['key'];
+    let all = value.row.table.getData();
+    if (all[0]['key'] == selected) {
+      //总选择
+      let newData = copy(all);
+      newData[0]['工程类型'] = value.value;
+      for(let i = 0; i < newData[0]["_children"].length; i++) {
+        let child = newData[0]['_children'][i];
+        child['工程类型'] = value.value;
+        for(let j = 0; j < child['_children'].length; j++) {
+          child['_children'][j]['工程类型'] = value.value;
+        }
+      }
+      myTable.current.replaceData(traverse(newData));
+
+    }
+    else if (all[0]["_children"].filter(x=>x['key'] == selected).length > 0) {
+      //某个单项工程
+      let newData = copy(all);
+      for(let i = 0; i < newData[0]["_children"].length; i++) {
+        let child = newData[0]['_children'][i];
+        if (child['key'] == selected) {
+          child['工程类型'] = value.value;
+          for(let j = 0; j < child['_children'].length; j++) {
+            child['_children'][j]['工程类型'] = value.value;
+          }
+        }
+        
+      } 
+      myTable.current.replaceData(traverse(newData));
+    } else {
+      //具体一行
+      let newData = copy(all);
+      for(let i = 0; i < newData[0]["_children"].length; i++) {
+        let child = newData[0]['_children'][i];
+        
+        for(let j = 0; j < child['_children'].length; j++) {
+          if (child['_children'][j]['key'] == selected) {  
+              child['_children'][j]['工程类型'] = value.value;
+          }
+        }
+        
+        
+      } 
+      myTable.current.replaceData(traverse(newData));
+    }
+
+
+  
+};
+
+
+React.useEffect(
+  () => {
+    myTable.current = new Tabulator(myRef.current, {
+
+      index: "key",
+      height: 600,
+    data: detail, //link data to table
+    reactiveData: false, //enable data reactivity
+    dataTreeStartExpanded:true,
+    dataTree: true,
+    selectableRows:1, //make rows selectable
+    editTriggerEvent:"dblclick", //trigger edit on double click
+    dataTreeStartExpanded:function(row, level){
+        //console.log(row);
+        //console.log(level);
+        return true; //expand rows where the "driver" data field is true;
+    },
+    columns: [ //Define Table Columns 序号", "名称", "取费基数", "计算基础","费率", "金额", "类别
+                 {title:"名称", field:"名称", width:250, headerSort:false, formatter:"textarea"}, //hide this column first
+                 {title:"工程类型", field:"工程类型", width:100 , headerSort:false, formatter:"textarea", editor: "list", editorParams: {
+                   values: [
+                    { //option group
+                      label:"建筑工程",
+                      options:[ //options in option group
+                          {
+                              label:"建筑工程",
+                              value:"建筑工程",
+                             
+                          },
+                          {
+                              label:"单独预制构件制作",
+                              value:"单独预制构件制作",
+                          },
+                          {
+                            label:"打预制桩、单独构件吊装",
+                            value:"打预制桩、单独构件吊装",
+                          },
+                          {
+                          label:"制作兼打桩",
+                          value:"制作兼打桩",
+                          },
+                          {
+                            label:"大型土石方工程",
+                            value:"大型土石方工程",
+                            },
+                      ]
+                    },
+                    { //option group
+                      label:"单独装饰工程",
+                      options:[ //options in option group
+                          {
+                              label:"单独装饰工程",
+                              value:"单独装饰工程",
+                             
+                          },
+                      ]
+                    },
+                    { //option group
+                      label:"安装工程",
+                      options:[ //options in option group
+                          {
+                              label:"安装工程",
+                              value:"安装工程",
+                             
+                          },
+                      ]
+                    },
+                    { //option group
+                      label:"市政工程",
+                      options:[ //options in option group
+                          {
+                              label:"通用项目、道路、排水工程",
+                              value:"通用项目、道路、排水工程",
+                             
+                          },
+                          {
+                            label:"桥梁、水工构筑物",
+                            value:"桥梁、水工构筑物",
+                           
+                        },
+                        {
+                          label:"给水、燃气与集中供热",
+                          value:"给水、燃气与集中供热",
+                         
+                      },
+                      {
+                        label:"路灯及交通设施工程",
+                        value:"路灯及交通设施工程",
+                       
+                    },
+                    {
+                      label:"(市)大型土石方工程",
+                      value:"(市)大型土石方工程",
+                     
+                  },
+                      ]
+                    },
+                   ]
+                 }},
+                 {title:"工程类别", field:"工程类别", width:100, headerSort:false, formatter: "textarea" , editor: "list", editorParams: {
+                   values: ["一类工程", "二类工程", "三类工程"]
+                 }
+
+                 },
+                 {title:"管理费(%)", field:"管理费(%)", width:100, headerSort:false, formatter:"textarea", editor: "input"},
+                 {title:"利润(%)", field:"利润(%)", width:150, headerSort:false, formatter:"textarea", editor: "input" },
+                 {title:"备注", field:"备注", width:200, headerSort:false, formatter:"textarea"},
+               
+         ]
+
+    });//init table
+
+  
+
+
+
+  myTable.current.on("tableBuilt", () => {
+    Service.generateQufei(id).then(x=>{
+
+      console.log(x);
+      let y = x.map(z=>{
+        z["_children"] = z['children'];
+        return z;
+      });
+      let t = y.map(z=>{
+        if (z.hasOwnProperty("_children")) {
+          let children = z["_children"];
+          for (let i = 0; i < children.length; i++) {
+            let child = children[i];
+            if (child.hasOwnProperty("children")) {
+              child["_children"] = child["children"];
+            }
+          }
+        }
+        return z;
+        });
+         myTable.current.replaceData(t);
+     });
+
+   
+    });
+
+    myTable.current.on("cellEdited", function(cell){
+      console.log(cell._cell);
+      if (cell._cell.column.field == '工程类型') {
+        handleChangeGC(cell._cell);
+      }
+      if (cell._cell.column.field == '工程类别') {
+        handleChange(cell._cell);
+      } 
+      if (cell._cell.column.field == '管理费(%)') {
+        handleChangeGLF(cell._cell);
+      } 
+      if (cell._cell.column.field == '利润(%)') {
+        handleChangeLR(cell._cell);
+      } 
+    });
+  
+     
+  }, [id]
+);
+
+
+    return (
+                 <Box sx={{ width: '70vw'}}>
+                <Button variant="outlined" onClick={apply}>应用</Button>
+                 
+                <div ref={myRef}> 
+                </div>
+
+                 </Box>
+
+                  
+
+
+
+    );
+}

+ 118 - 0
src/Rcjhz.js

@@ -0,0 +1,118 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+//registerPlugin(NestedRows);
+import Service from './Service';
+import EditableSelect from './EditableSelect';
+import EditableSelectGC from './EditableSelectGC';
+import Editable from './Editable';
+import Button from '@mui/material/Button';
+
+import {copy} from './utils';
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+export default function Rcjhz({id, bh, tiaojiaCallback}) {
+  const myTable = React.useRef(null);
+  const myRef = React.useRef(null);
+  const [detail, setDetail] = React.useState([]);
+  var editCheck = function(cell){
+    //cell - the cell component for the editable cell
+
+    //get row data
+    //console.log(cell);
+    if(cell._cell.row.data['序号']) return false;
+    return true;
+  }
+
+  function handleSelect(row){
+
+  }
+
+
+
+  React.useEffect(() => {
+    myTable.current = new Tabulator(myRef.current, {
+         index: "key",
+         height: 600,
+       data: detail, //link data to table
+       reactiveData: false, //enable data reactivity
+       dataTreeStartExpanded:true,
+       dataTree: true,
+       selectableRows:1, //make rows selectable
+       editTriggerEvent:"dblclick", //trigger edit on double click
+       dataTreeStartExpanded:function(row, level){
+           //console.log(row);
+           //console.log(level);
+           return true; //expand rows where the "driver" data field is true;
+       },
+       columns: [ //Define Table Columns
+                    {title:"ID", field:"ID", width:80, headerSort:false,}, //never hide this column
+                    {title:"编码", field:"编码", width:120,headerSort:false,headerFilter:"input" },
+                    {title:"名称", field:"名称", width:150, headerSort:false, formatter:"textarea", headerFilter:"input"}, //hide this column first
+                    {title:"规格型号", field:"规格型号", width:70 , headerSort:false, formatter:"textarea"},
+                    {title:"单位", field:"单位", width:50, headerSort:false},
+                    {title:"数量", field:"数量", width:100, headerSort:true, sorter:"number", formatter:"money", formatterParams:{
+                      precision:4,
+                  } },
+                    {title:"单价", field:"单价", width:100, headerSort:true, sorter:"number", formatter:"money", editor: "input"},
+                    {title:"合价", field:"合价", width:100, headerSort:true, sorter:"number", formatter:"money"},
+                    {title:"产地", field:"产地", width:50, headerSort:false, },
+                    {title:"供应厂商", field:"供应厂商", width:80, headerSort:false, },
+                    {title:"人材机类别", field:"人材机类别", width:120, headerSort:true, sorter: 'string', headerFilter:"input"},
+                    {title:"主要材料标志", field:"主要材料标志", width:100, headerSort:false},
+                    {title:"主材标志", field:"主材标志", width:100, headerSort:false, },
+                    {title:"设备标志", field:"设备标志", width:100, headerSort:false, },
+                    {title:"甲供标志", field:"甲供标志", width:100, headerSort:false, },
+                    {title:"暂估价标志", field:"暂估价标志", width:100, headerSort:false, },
+            ]
+     }); 
+     
+     myTable.current.on("cellDblClick", function(e, cell){
+         //e - the click event object
+         //cell - cell component
+         console.log(cell);
+     });
+
+     myTable.current.on("rowSelected", handleSelect);
+     
+
+     myTable.current.on("cellEdited", function(cell){
+         //console.log("edited");
+         //console.log();
+         let newData = copy(cell._cell.row.data);
+         let newDj = newData['单价'];
+         let sl = newData['数量'];
+         newData['合价'] = Number(newDj) * Number(sl);
+         myTable.current.updateData([newData]);
+         tiaojiaCallback(bh, newData['编码'], newData['名称'], newData['单位'], newDj);
+         
+         
+         
+                          
+                                                      
+         
+     });
+
+
+     myTable.current.on("tableBuilt", () => {
+         Service.generateRencaijihuizong2(id, bh).then(x=>{
+              myTable.current.replaceData(x);
+              });
+       });
+   
+  }, [id, bh]);
+
+    return (
+      <div ref={myRef}> 
+      </div>
+
+
+
+    );
+}

+ 2372 - 0
src/Service.js

@@ -0,0 +1,2372 @@
+import {copy, danxiangdinge_index, danxiangdinge_index_djcs, renameDingE, extractFuzhu, match_target} from './utils';
+import { v4 as uuidv4 } from 'uuid';
+class Service{
+    
+    constructor() {
+        this.footprint = [];
+        this.cache = [];
+        this.memory = [];
+        this.mem_pointer = -1;
+        this.cache_djcs = [];
+        this.memory_djcs = [];
+        this.mem_pointer_djcs = -1;
+        this.qufei = [];
+        this.qufeiEntry = null;
+    }
+    
+    ip() {
+        //return "/api"//return "http://127.0.0.1:8000"
+        return "http://192.168.238.87:1313/api"
+    }
+
+    clearCache() {//set qufei will clear cache
+        this.cache = [];
+        this.footprint= [];
+        this.memory = [];
+        this.mem_pointer = -1;
+        this.cache_djcs = [];
+        this.memory_djcs = [];
+        this.mem_pointer_djcs = -1;
+    }
+
+    setQufei(data) {
+        let result = [];
+        for(let i = 0; i < data[0]['children'].length; i++) {
+            let child = data[0]['children'][i];
+            for(let j = 0; j < child['children'].length; j++) {
+                let grandchild = child['children'][j];
+                //console.log(grandchild);
+                result.push(grandchild);
+            }
+        }
+        this.qufei = result;
+    }
+
+    setQufeiEntry(bh) {
+        this.qufeiEntry = this.qufei.filter(x=>x['key'] == bh)[0];
+
+    }
+
+
+    processDjcsmingxi(mingxi) {
+        this.cache_djcs = copy(mingxi);
+        for(let i = 0; i < this.cache_djcs.length; i++) {
+            let zimu = this.cache_djcs[i];
+            if (!zimu.hasOwnProperty("_children")) {
+                zimu["_children"] = [];
+            }
+            if (!zimu.hasOwnProperty("rcj")) {
+                zimu["rcj"] = [["ID", "人材机编码", "名称", "规格型号", "单位", "单价", "产地", 
+                "供应厂商", "人材机类别", "甲供标志", "含量", "合价", "暂估价标志", "主要材料标志", "主材标志", "设备标志" ]];
+            }
+
+        }
+        for(let i = 0; i < this.cache_djcs.length; i++) {
+            let zimu = this.cache_djcs[i];
+            for(let j = 0; j < zimu["_children"].length; j++) {
+                let de = zimu["_children"][j];
+                if (!de.hasOwnProperty("dercj")) {
+                    de["dercj"] = [["ID", "人材机编码", "名称", "规格型号", "单位", "单价", "产地", 
+                    "供应厂商", "人材机类别", "甲供标志", "含量", "合价", "暂估价标志", "主要材料标志", "主材标志", "设备标志" ]];
+                }
+            }
+        }
+        this.cache_djcs = this.cache_djcs.map(x=>{
+            //x["children"] = x["__children"];
+
+            x["key"] = x["序号"];
+            x["_children"] = x["_children"].map(y=>{
+                if (!y.hasOwnProperty('key')) {
+                    y['key'] = uuidv4();
+                }
+                return y;
+            })
+            return x;
+        });
+        this.memory_djcs = [];
+        this.memory_djcs.push(copy(this.cache_djcs));
+        this.mem_pointer_djcs = 0;
+
+    }
+
+
+
+    processQingdanmingxi(mingxi) {
+        this.cache = copy(mingxi);
+        for(let i = 0; i < this.cache.length; i++) {
+            let zimu = this.cache[i];
+            if (!zimu.hasOwnProperty("__children")) {
+                zimu["__children"] = [];
+            }
+            if (!zimu.hasOwnProperty("rcj")) {
+                zimu["rcj"] = [["ID", "人材机编码", "名称", "规格型号", "单位", "单价", "产地", 
+                "供应厂商", "人材机类别", "甲供标志", "含量", "合价", "暂估价标志", "主要材料标志", "主材标志", "设备标志" ]];
+            }
+
+        }
+        for(let i = 0; i < this.cache.length; i++) {
+            let zimu = this.cache[i];
+            for(let j = 0; j < zimu["__children"].length; j++) {
+                let de = zimu["__children"][j];
+                if (!de.hasOwnProperty("dercj")) {
+                    de["dercj"] = [["ID", "人材机编码", "名称", "规格型号", "单位", "单价", "产地", 
+                    "供应厂商", "人材机类别", "甲供标志", "含量", "合价", "暂估价标志", "主要材料标志", "主材标志", "设备标志" ]];
+                }
+            }
+        }
+        this.cache = this.cache.map(x=>{
+            x["_children"] = x["__children"];
+
+            x["key"] = x["序号"];
+            x["_children"] = x["_children"].map(y=>{
+                if (!y.hasOwnProperty('key')) {
+                    y['key'] = uuidv4();
+                }
+                return y;
+            })
+            return x;
+        });
+        this.memory = [];
+        this.footprint = [];
+        this.memory.push(copy(this.cache));
+        this.mem_pointer = 0;
+
+    }
+    async generateOutline(name) {
+        const response = await fetch(this.ip().concat( "/outline"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body : JSON.stringify({
+                "name": name
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async uploadFile(fd) {
+        const response = await fetch(this.ip().concat( "/upload/"), {
+            method : "POST",
+            body : fd
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async generateQufei(name) {
+        const response = await fetch(this.ip().concat("/qufei/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body : JSON.stringify({
+                "name": name
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateOutline2(name) {
+        const response = await fetch(this.ip().concat( "/outline2"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body : JSON.stringify({
+                "name": name
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateDetail(name) {
+        const response = await fetch(this.ip().concat("/detail"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body : JSON.stringify({
+                "name": name
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async generateDetail2(name) {
+        const response = await fetch(this.ip().concat("/detail2"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body : JSON.stringify({
+                "name": name
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateBaojiahuizong(name, id) {
+        const response = await fetch(this.ip().concat(  "/baojiahuizong/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            }, 
+            body: JSON.stringify({
+                name: name,
+                id : id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateBaojiahuizong2(name, id) {
+        const response = await fetch(this.ip().concat(  "/baojiahuizong2/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            }, 
+            body: JSON.stringify({
+                name: name,
+                id : id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateGuifeishuijin(name, id) {
+        const response = await fetch(this.ip().concat( "/guifeishuijin/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id: id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateGuifeishuijin2(name, id) {
+        const response = await fetch(this.ip().concat( "/guifeishuijin2/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id: id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async generateQitaxiangmu(name, id) {
+        const response = await fetch(this.ip().concat( "/qitaxiangmu/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id : id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async generateQitaxiangmu2(name, id) {
+        const response = await fetch(this.ip().concat( "/qitaxiangmu2/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id : id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async generateZygczgj(name, id) {
+        const response = await fetch(this.ip().concat( "/zygczgj/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id : id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+
+    async generateZongchengbaofuwufei(name, id) {
+        const response = await fetch(this.ip().concat( "/zongchengbaofuwufei/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id: id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async generateZongchengbaofuwufei2(name, id) {
+        const response = await fetch(this.ip().concat( "/zongchengbaofuwufei2/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id: id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateFabaorengongyingcailiao(name, id) {
+        const response = await fetch(this.ip().concat( "/fabaorengongyingcailiao/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id : id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateFabaorengongyingcailiao2(name, id) {
+        const response = await fetch(this.ip().concat( "/fabaorengongyingcailiao2/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id : id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async generateRencaijihuizong(name, id) {
+        const response = await fetch(this.ip().concat( "/rencaijihuizong/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id: id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async generateRencaijihuizong2(name, id) {
+        const response = await fetch(this.ip().concat( "/rencaijihuizong2/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id: id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            let result = [];
+            for (let i = 1; i < data.length; i++) {
+                result.push({
+                    'key': uuidv4(),
+                    'ID' : data[i][0],
+                    '编码' : data[i][1],
+                    '名称': data[i][2],
+                    '规格型号' : data[i][3],
+                    '单位' : data[i][4],
+                    '数量' : data[i][5],
+                    '单价' : data[i][6],
+                    '合价' : data[i][7],
+                    '产地' : data[i][8],
+                    '供应厂商' : data[i][9],
+                    '人材机类别' : data[i][10],
+                    '主要材料标志' : data[i][11],
+                    '主材标志' : data[i][12],
+                    '设备标志' : data[i][13],
+                    '甲供标志' : data[i][14],
+                    '暂估价标志' : data[i][15]
+                });
+            }
+            this.setQufeiEntry(id);
+            return result;
+        }
+    }
+    async generateJirigong(name, id) {
+        const response = await fetch(this.ip().concat("/jirigong/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id: id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+
+    async generateJirigong2(name, id) {
+        const response = await fetch(this.ip().concat("/jirigong2/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id: id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateZanliejine(name, id) {
+        const response = await fetch(this.ip().concat( "/zanliejine/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id: id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async generateZanliejine2(name, id) {
+        const response = await fetch(this.ip().concat( "/zanliejine2/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id: id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateQingdanxiangmu(name, id) {
+        const response = await fetch(this.ip().concat( "/qingdanxiangmu/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id: id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateQingdanxiangmu2(name, id) {
+        const response = await fetch(this.ip().concat( "/qingdanxiangmu2/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                name: name,
+                id: id
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async searchDe(zhuanye, text) {
+        const response = await fetch(this.ip().concat( "/searchde/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify({
+                zhuanye: zhuanye,
+                text: text
+            })
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+   
+
+
+    /////////////////////////////////////qingdan//////////////////////////////////////
+
+    async generateQingdanmingxi(name, bh, bt) {
+        if (this.cache.length == 0 || this.cache[0]["biao_id"] != name || this.cache[0]["Dwgcbh"] != bh ||
+        this.cache[0]["bt"] != bt) {
+        const response = await fetch(this.ip().concat("/qingdanmingxi/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    "bh": bh,
+                    "bt": bt,
+                    "name": name
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            this.processQingdanmingxi(data);
+            this.setQufeiEntry(bh);
+            return copy(this.cache);
+        }
+        } else {
+            return copy(this.cache);
+        }
+    }
+
+
+    async generateQingdanrcj(name, bh, bt, bm) {
+        if (bt == "Djcs") {
+            let qd = this.cache_djcs.filter(x=>x["清单编码"] == bm)[0];
+            return copy(qd["rcj"]);
+        }
+        let qd = this.cache.filter(x=>x["清单编码"] == bm)[0];
+        return copy(qd["rcj"]);
+        
+    }
+    async generateDingercj(name, bh, bt, qdbm, debm, danwei) {
+        console.log('generateDingercj');
+        console.log(debm);
+        if (bt == 'Djcs') {
+            let qd = this.cache_djcs.filter(x=>x["清单编码"] == qdbm)[0];
+            let de = qd["_children"].filter(x=>x["清单编码"]==debm)[0];
+            return [copy(de["dercj"]), de["fuzhuEnable"]];
+        
+        }
+        let qd = this.cache.filter(x=>x["清单编码"] == qdbm)[0];
+        let de = qd["_children"].filter(x=>x["清单编码"]==debm)[0];
+        return [copy(de["dercj"]), de["fuzhuEnable"], de['yuban'], de['rcjbc']];
+        
+        
+          
+          
+        
+    }
+
+
+/////////////////////////////end of qingdan////////////////////////////////////
+
+async generateQingdanTuijian(name, bh, bt, bm) {
+    const response = await fetch(this.ip().concat( "/qingdantuijian/"), {
+        method : "POST",
+        headers: {
+            "Content-type": "application/json"
+        },
+        body: JSON.stringify(
+            {
+                "bh": bh,
+                "bt": bt,
+                "bm": bm,
+                "name": name
+            }
+        )
+    });
+    if (!response.ok) {
+        //const error = await response.json();
+        console.error('error');
+    } else {
+        const data = await response.json();
+        return data;
+    }
+}
+    async generateZjcs(name, bh) {
+        const response = await fetch(this.ip().concat( "/zjcs/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    "bh": bh,
+                    "name": name
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateDjcs(name, bh) {
+        if (this.cache_djcs.length == 0 || this.cache_djcs[0]["biao_id"] != name || this.cache_djcs[0]["Dwgcbh"] != bh) {
+        const response = await fetch(this.ip().concat( "/djcs/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    "bh": bh,
+                    "name": name
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            this.processDjcsmingxi(data);
+            this.setQufeiEntry(bh);
+            return copy(this.cache_djcs);
+        }
+        } else {
+            return copy(this.cache_djcs);
+        }
+    }
+    async generateFiles() {
+        const response = await fetch(this.ip().concat( "/files/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            }
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async generateFiles2() {
+        const response = await fetch(this.ip().concat( "/files2/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            }
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async deleteFiles(id) {
+        const response = await fetch(this.ip().concat( "/deleteFile/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    "name": id,
+                    
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async generatePeibiXilie(id) {
+        const response = await fetch(this.ip().concat( "/pbxl/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    "name": id
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generatePeibishu(zhuanye) {
+        const response = await fetch(this.ip().concat( "/pbs/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    "value": zhuanye
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateDingeshu(value) {
+        const response = await fetch(this.ip().concat( "/des/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    "value": value
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateDingeXilie(value, id) {//定额书的一个栏目的所有具体定额
+        const response = await fetch(this.ip().concat("/dexilie/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    "value": value,
+                    "id": id
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+    async generateSingleDingeXilie(zhuanye, debh) {//清单页面展示用
+        const response = await fetch(this.ip().concat( "/singledexilie/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    "debh": debh,
+                    "zhuanye": zhuanye
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+
+    async save() {
+        const response = await fetch(this.ip().concat( "/save/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    
+                    "name": JSON.stringify(this.cache.filter(x=>this.footprint.includes(x['key'])))
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            this.footprint = [];
+            return data;
+        }
+    }
+
+    async save_djcs() {
+        const response = await fetch(this.ip().concat( "/savedjcs/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    
+                    "name": JSON.stringify(this.cache_djcs)
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async applyFL(id, data) {
+        const response = await fetch(this.ip().concat( "/applyFL/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    "id": id,
+                    "name": JSON.stringify(data)
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            return data;
+        }
+    }
+
+    async download(id) {
+        const response = await fetch(this.ip().concat( "/download/").concat(id.toString()));
+
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.blob();
+            return data;
+        }
+    }
+
+    async tiaojia(biao_id, bh, bm, mingcheng, danwei, jiage) {
+        let glf = "";
+        let lr = "";
+        let bz = 0;//changgui
+        if (this.qufeiEntry['备注'].length == 0) {
+            //changuiqufei
+            glf = this.qufeiEntry['管理费(%)'] ;
+            lr = this.qufeiEntry['利润(%)'];
+        } else {
+            glf = this.qufeiEntry['管理费(%)'] ;
+            lr = this.qufeiEntry['利润(%)'];
+            bz = 1;
+        }
+        const response = await fetch(this.ip().concat( "/tiaojia/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    "biao_id": biao_id,
+                    "bh": bh,
+                    "bm": bm,
+                    "mingcheng": mingcheng,
+                    "danwei" : danwei, 
+                    "jiage": jiage,
+                    "glf" : glf,
+                    "lr" : lr,
+                    "bz" : bz
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            this.clearCache();
+            return data;
+        }
+    }
+
+
+    async updateZjcs(biao_id, bh, row) {
+      
+        const response = await fetch(this.ip().concat( "/updatezjcs/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                    "biao_id": biao_id,
+                    "bh": bh,
+                    'mc': row['名称'].toString(),
+                    'fl': row['费率'].toString()
+                    
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+           
+            return data;
+        }
+    }
+
+    async cankao() { //参考费率
+       
+        const response = await fetch(this.ip().concat( "/cankao/"), {
+            method : "POST",
+            headers: {
+                "Content-type": "application/json"
+            },
+            body: JSON.stringify(
+                {
+                  
+                }
+            )
+        });
+        if (!response.ok) {
+            //const error = await response.json();
+            console.error('error');
+        } else {
+            const data = await response.json();
+            
+            return data;
+        }
+    }
+
+
+
+
+    ///////////////////////////////////editor//////////////////////////////////
+
+
+    summarize_one_djcs(qd) {///根据定额汇总清单
+        let dict = {};
+        for(let i = 0; i < qd["_children"].length; i++) {
+            let de = qd["_children"][i];
+            let desl = Number(de['数量']);
+            let dercj = de['dercj'];
+            for (let j = 1; j < dercj.length; j++) {
+                let hl = copy(dercj[j]);
+                hl[10] = desl * Number(hl[10]);
+                hl[11] = desl * Number(hl[11]);
+                let a = hl[1];//"人材机编码", 
+                let b = a.concat(hl[2]);//"名称", 
+                let c = b.concat(hl[4]);// "单位"
+                if (dict.hasOwnProperty(c)) {
+                    dict[c].push(hl);
+                } else {
+                    dict[c] = [hl];
+                }
+
+            }
+        }
+        let result = [];
+        for(const key in dict) {
+            let list = dict[key];
+            let sum = 0;
+            let danjia = Number(list[0][5]);
+            for (let i =0 ;i < list.length; i++) {
+                sum += Number(list[i][10]);
+            }
+            let entry = [list[0][0], list[0][1], list[0][2], list[0][3], list[0][4], danjia,
+             list[0][6], list[0][7], list[0][8], list[0][9], sum, sum * danjia, list[0][12],
+             list[0][13], list[0][14], list[0][15]
+             ];
+             result.push(entry);
+
+        }
+        let gongri = 0;
+        for(let i = 0; i < result.length; i++) {
+            if (result[i][4] == '工日') {
+                gongri += result[i][10];
+            }
+        }
+        result.sort((a, b) => Number(a[8]) - Number(b[8]));
+        qd['rcj'] = [["ID", "人材机编码", "名称", "规格型号", "单位", "单价", "产地", 
+        "供应厂商", "人材机类别", "甲供标志", "含量", "合价", "暂估价标志", "主要材料标志", "主材标志", "设备标志" ]].concat(result);
+        qd["综合人工工日"] = gongri;
+        qd['综合单价'] = 0;
+        qd['合价'] = 0;
+        qd['人工费'] = 0;
+        qd['主材费'] = 0;
+        qd['设备费'] = 0;
+        qd['辅材费'] = 0;
+        qd['材料费'] = 0;
+        qd['机械费'] = 0;
+        qd['管理费'] = 0;
+        qd['利润'] = 0;
+        for(let i = 0; i < qd["_children"].length; i++) {
+            qd['综合单价'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['综合单价']);
+            qd['合价'] += Number(qd['_children'][i]['合价']);
+            qd['人工费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['人工费']);
+            qd['主材费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['主材费']);
+            qd['设备费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['设备费']);
+            qd['辅材费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['辅材费']);
+            qd['材料费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['材料费']);
+            qd['机械费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['机械费']);
+            qd['管理费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['管理费']);
+            qd['利润'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['利润']);   
+        }
+
+        return qd;
+    }
+
+
+    summarize_one(qd) {///根据定额汇总清单
+        let dict = {};
+        for(let i = 0; i < qd["_children"].length; i++) {
+            let de = qd["_children"][i];
+            let desl = Number(de['数量']);
+            let dercj = de['dercj'];
+            for (let j = 1; j < dercj.length; j++) {
+                let hl = copy(dercj[j]);
+                hl[10] = desl * Number(hl[10]);
+                hl[11] = desl * Number(hl[11]);
+                let a = hl[1];//"人材机编码", 
+                let b = a.concat(hl[2]);//"名称", 
+                let c = b.concat(hl[4]);// "单位"
+                if (dict.hasOwnProperty(c)) {
+                    dict[c].push(hl);
+                } else {
+                    dict[c] = [hl];
+                }
+
+            }
+        }
+        let result = [];
+        for(const key in dict) {
+            let list = dict[key];
+            let sum = 0;
+            let danjia = Number(list[0][5]);
+            for (let i =0 ;i < list.length; i++) {
+                sum += Number(list[i][10]);
+            }
+            let entry = [list[0][0], list[0][1], list[0][2], list[0][3], list[0][4], danjia,
+             list[0][6], list[0][7], list[0][8], list[0][9], sum, sum * danjia, list[0][12],
+             list[0][13], list[0][14], list[0][15]
+             ];
+             result.push(entry);
+
+        }
+        let gongri = 0;
+        for(let i = 0; i < result.length; i++) {
+            if (result[i][4] == '工日') {
+                gongri += result[i][10];
+            }
+        }
+        result.sort((a, b) => Number(a[8]) - Number(b[8]));
+        qd['rcj'] = [["ID", "人材机编码", "名称", "规格型号", "单位", "单价", "产地", 
+        "供应厂商", "人材机类别", "甲供标志", "含量", "合价", "暂估价标志", "主要材料标志", "主材标志", "设备标志" ]].concat(result);
+        qd["综合人工工日"] = gongri;
+        qd['综合单价'] = 0;
+        qd['合价'] = 0;
+        qd['人工费'] = 0;
+        qd['主材费'] = 0;
+        qd['设备费'] = 0;
+        qd['辅材费'] = 0;
+        qd['材料费'] = 0;
+        qd['机械费'] = 0;
+        qd['管理费'] = 0;
+        qd['利润'] = 0;
+        for(let i = 0; i < qd["_children"].length; i++) {
+            qd['综合单价'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['综合单价']);
+            qd['合价'] += Number(qd['_children'][i]['合价']);
+            qd['人工费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['人工费']);
+            qd['主材费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['主材费']);
+            qd['设备费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['设备费']);
+            qd['辅材费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['辅材费']);
+            qd['材料费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['材料费']);
+            qd['机械费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['机械费']);
+            qd['管理费'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['管理费']);
+            qd['利润'] += Number(qd['_children'][i]['数量']) * Number(qd['_children'][i]['利润']);   
+        }
+
+        return qd;
+    }
+    summarize(data) {
+        return data.map(x=>this.summarize_one(x));
+    }
+
+    summarize_djcs(data) {
+        return data.map(x=>this.summarize_one_djcs(x));
+    }
+
+    push_op(newData) {
+        if(this.memory.length == this.mem_pointer + 1) {
+            this.memory.push(copy(newData));
+            this.mem_pointer = this.mem_pointer + 1;
+       } else{
+            this.memory.splice(this.mem_pointer + 1);
+            this.memory.push(copy(newData));
+            this.mem_pointer = this.mem_pointer + 1; 
+    
+       }
+    }
+
+    push_op_djcs(newData) {
+        if(this.memory_djcs.length == this.mem_pointer_djcs + 1) {
+            this.memory_djcs.push(copy(newData));
+            this.mem_pointer_djcs = this.mem_pointer_djcs + 1;
+       } else{
+            this.memory_djcs.splice(this.mem_pointer_djcs + 1);
+            this.memory_djcs.push(copy(newData));
+            this.mem_pointer_djcs = this.mem_pointer_djcs + 1; 
+    
+       }
+    }
+
+    undo() {
+        if (this.mem_pointer > 0) {
+            
+            let newData = this.memory[this.mem_pointer - 1];
+            this.mem_pointer = this.mem_pointer - 1;
+            this.cache = copy(newData);
+            return copy(newData);
+           
+        }
+
+        return copy(this.cache);
+    }
+
+    undo_djcs() {
+        if (this.mem_pointer_djcs > 0) {
+            
+            let newData = this.memory_djcs[this.mem_pointer_djcs - 1];
+            this.mem_pointer_djcs = this.mem_pointer_djcs - 1;
+            this.cache_djcs = copy(newData);
+            return copy(newData);
+           
+        }
+
+        return copy(this.cache_djcs);
+    }
+    
+    redo() {
+        if (this.mem_pointer + 1 != this.memory.length) {
+            let newData = this.memory[this.mem_pointer + 1];
+            this.mem_pointer = this.mem_pointer + 1;
+            this.cache = copy(newData);
+            return copy(newData);
+            }
+
+        return copy(this.cache);
+    }
+
+    redo_djcs() {
+        if (this.mem_pointer_djcs + 1 != this.memory_djcs.length) {
+            let newData = this.memory_djcs[this.mem_pointer_djcs + 1];
+            this.mem_pointer_djcs = this.mem_pointer_djcs + 1;
+            this.cache_djcs = copy(newData);
+            return copy(newData);
+            }
+
+        return copy(this.cache_djcs);
+    }
+
+    shanchu_djcs(key) {
+        if (this.cache_djcs.filter(x=>x['key'] == key).length > 0) {
+            ///qd
+            let newData = this.cache_djcs.map(x=>{
+                if (x["key"] == key) {
+                    let y = copy(x);
+                    
+                    y["_children"] = [];
+                    return y;
+                } else {
+                    return x;
+                }
+            });
+            let summarized = this.summarize_djcs(newData);
+            this.push_op_djcs(summarized);
+             /////////////////
+            this.cache_djcs = copy(summarized);
+            return copy(this.cache_djcs);
+
+        } else {
+            let qd = this.cache_djcs.filter(x=>x["_children"].filter(y=>y['key'] == key).length > 0)[0];
+            let qdbm = qd['清单编码'];
+            let newData = this.cache_djcs.map(x=>{
+                if (x["清单编码"] == qdbm) {
+                    let y = copy(x);
+                    let origin = y["_children"];
+                    let trans = origin.filter(z=>z["key"]!=key);
+                    y["_children"] = trans;
+                    return y;
+                } else {
+                    return x;
+                }
+            });
+            let summarized = this.summarize_djcs(newData);
+            this.push_op_djcs(summarized);
+            /////////////////
+            this.cache_djcs = copy(summarized);
+            return copy(this.cache_djcs);
+        }
+        
+        
+
+
+    }
+    updateFootprint(key) {
+        if (this.footprint.includes(key)) {
+
+        } else {
+            this.footprint.push(key);
+        }
+    }
+
+    shanchu(key) {
+        if (this.cache.filter(x=>x['key'] == key).length > 0) {
+            this.updateFootprint(key);
+            ///qd
+            let newData = this.cache.map(x=>{
+                if (x["key"] == key) {
+                    let y = copy(x);
+                    
+                    y["_children"] = [];
+                    return y;
+                } else {
+                    return x;
+                }
+            });
+            let summarized = this.summarize(newData);
+            this.push_op(summarized);
+             /////////////////
+             this.cache = copy(summarized);
+            return copy(this.cache);
+
+        } else {
+            let qd = this.cache.filter(x=>x["_children"].filter(y=>y['key'] == key).length > 0)[0];
+            this.updateFootprint(qd['key']);
+            let qdbm = qd['清单编码'];
+            let newData = this.cache.map(x=>{
+                if (x["清单编码"] == qdbm) {
+                    let y = copy(x);
+                    let origin = y["_children"];
+                    let trans = origin.filter(z=>z["key"]!=key);
+                    y["_children"] = trans;
+                    return y;
+                } else {
+                    return x;
+                }
+            });
+            let summarized = this.summarize(newData);
+            this.push_op(summarized);
+            /////////////////
+            this.cache = copy(summarized);
+            return copy(this.cache);
+        }
+        
+        
+
+
+    }
+
+
+    updateDercj_djcs_(row, data, xuhao) {///change 一条定额 inplace, 汇总一条定额的rcj, xuhao is for rename
+        console.log("data updated");
+        //处理附注
+        let huan = false;//换
+        let qd = this.cache_djcs.filter(x=>x["_children"].filter(y=>y['key']==row).length > 0)[0];
+        let de = qd["_children"].filter(x=>x['key'] == row)[0];
+        if (de.hasOwnProperty("rcjdg")) {//新数据
+            for (let i = 1; i < de['rcjdg'].length; i++) {
+                de['rcjdg'][i][5] = data[i][5];//更新单价
+                /****ToDo 更新其他字段 */
+                if (de['rcjdg'][i][2] == data[i][2]) {//更新名称
+                    
+                } else {
+                    huan = true;
+                }
+            }
+
+            if (de['fuzhuEnable'] && de.hasOwnProperty('fuzhu')) {//没强行改过含量
+                
+                for(let j = 1; j < de['rcjdg'].length; j++) {
+                    let origin = Number(de['rcjdg'][j][10]);
+                    for(let i = 0; i < de['fuzhu'].length; i++) {
+                        let selected = de['fuzhu'][i];
+                        let target = selected[0];
+                        
+                        
+                        if (match_target(de['rcjdg'][j][1], target)) {
+                            if (selected[2] == '系数') {
+                                origin = origin * Number(selected[3]);
+
+                            } else if (selected[2] == '含量') {
+                                origin = Number(selected[3]);
+                            } else if (selected[2] == '调整') {
+                                origin = origin + Number(selected[3]);
+                            } else {
+                                throw new Error('无法处理的附注'.concat(selected[2]));
+                            }
+                            
+                        }
+                        
+
+                    }
+                    de['dercj'][j][2] = data[j][2];//名称
+                    de['dercj'][j][1] = data[j][1];//编号
+                    de['dercj'][j][5] = de['rcjdg'][j][5];//单价
+                    de['dercj'][j][10] =  origin;
+                    de['dercj'][j][11] = Number(de['dercj'][j][5]) * origin;
+                }
+
+            } else if (de['fuzhuEnable'] && !de.hasOwnProperty('fuzhu')) {
+                for(let j = 1; j < de['rcjdg'].length; j++) {
+                    let origin = Number(de['rcjdg'][j][10]);
+                    
+                    de['dercj'][j][2] = data[j][2];//名称
+                    de['dercj'][j][1] = data[j][1];//编号
+
+                    de['dercj'][j][5] = de['rcjdg'][j][5];
+                    de['dercj'][j][10] =  origin;
+                    de['dercj'][j][11] = Number(de['dercj'][j][5]) * origin;
+                }
+            }
+
+            else {
+                //强行改含量
+                de['dercj'] = copy(data);
+            }
+        
+
+            
+            data = de['dercj'];
+        } else {////单项定额没有底稿,老数据没底搞,无法判断换部换,暂时统一认为不换
+            //强行改含量
+            de['dercj'] = copy(data);
+            data = de['dercj'];
+        }
+        //模拟formula计算每一行的合价
+        for(let i = 1; i < data.length; i++) {
+            data[i][11] = Number(data[i][10]) * Number(data[i][5]);
+        }
+        let sum = 0;
+        let rgf_sum = 0;
+        let jxf_sum = 0;
+        let clf_sum = 0;
+        for(let i = 1; i < data.length; i++) {
+            sum += Number(data[i][11]);//11-> hejia
+            if (Number(data[i][8]) == 1) {
+                rgf_sum += Number(data[i][11]);
+            }
+            if (Number(data[i][8]) == 2) {
+                clf_sum += Number(data[i][11]);
+            }
+            if (Number(data[i][8]) == 3) {
+                jxf_sum += Number(data[i][11]);
+            }
+        }
+        console.log("sum=".concat(sum));
+        
+        let shuliang = Number(qd['数量']);
+        for(let i = 0; i< qd["_children"].length; i++) {
+            if(qd["_children"][i]['key'] == row) {
+                let desl = Number(qd["_children"][i]['数量']);
+                let oldname = qd["_children"][i]['清单编码'];
+                
+                qd["_children"][i]['辅材费'] = clf_sum;
+                qd["_children"][i]['材料费'] = clf_sum;
+                qd["_children"][i]['人工费'] = rgf_sum;
+                qd["_children"][i]['主材费'] = 0;
+                qd["_children"][i]['设备费'] = 0;
+                qd["_children"][i]['机械费'] = jxf_sum;
+                if (oldname.startsWith("D")) {//单项清单
+                    qd["_children"][i]['管理费'] = 0;
+                    qd["_children"][i]['利润'] = 0;
+                } else {
+                    if (this.qufeiEntry['备注'].length == 0) {
+                        //changuiqufei
+                        qd["_children"][i]['管理费'] = (rgf_sum + jxf_sum) * Number(this.qufeiEntry['管理费(%)']) / Number(100);
+                        qd["_children"][i]['利润'] = (rgf_sum + jxf_sum) * Number(this.qufeiEntry['利润(%)']) / Number(100);
+                    } else {
+                        qd["_children"][i]['管理费'] = (rgf_sum) * Number(this.qufeiEntry['管理费(%)']) / Number(100);
+                        qd["_children"][i]['利润'] = (rgf_sum) * Number(this.qufeiEntry['利润(%)']) / Number(100);
+                    }
+                }
+                qd["_children"][i]['综合单价'] = sum + qd["_children"][i]['管理费'] + qd["_children"][i]['利润'];
+                qd["_children"][i]['合价'] = (qd["_children"][i]['综合单价'] * shuliang * desl);
+                
+                
+                
+                qd["_children"][i]["dercj"] = copy(data);
+                qd["_children"][i]['清单编码'] = renameDingE(oldname, xuhao, huan);
+
+            }
+        }
+    }
+
+
+    updateDercj_(row, data, xuhao, yuban, rcjbc) {///change 一条定额 inplace, 汇总一条定额的rcj, xuhao is for rename, yuban is 预拌砂浆
+        console.log("data updated");
+        //处理附注
+        let huan = false;//换
+        let qd = this.cache.filter(x=>x["_children"].filter(y=>y['key']==row).length > 0)[0];
+        let de = qd["_children"].filter(x=>x['key'] == row)[0];
+        if (de.hasOwnProperty("rcjdg")) {//新数据
+            for (let i = 1; i < de['rcjdg'].length; i++) {
+                de['rcjdg'][i][5] = data[i][5];//更新单价,底稿的单价不是很需要同步(在人才机汇总修改价格)
+                /****ToDo 更新其他字段 */
+                if (de['rcjdg'][i][2] == data[i][2]) {//更新名称
+                    
+                } else {
+                    huan = true;
+                }
+            }
+           
+            if (de['fuzhuEnable'] && de.hasOwnProperty('fuzhu')) {//没强行改过含量
+                
+                for(let j = 1; j < de['rcjdg'].length; j++) {
+                    let origin = Number(de['rcjdg'][j][10]);
+                    for(let i = 0; i < de['fuzhu'].length; i++) {
+                        let selected = de['fuzhu'][i];
+                        let target = selected[0];
+                        
+                        
+                        if (match_target(de['rcjdg'][j][1], target)) {
+                            if (selected[2] == '系数') {
+                                origin = origin * Number(selected[3]);
+
+                            } else if (selected[2] == '含量') {
+                                origin = Number(selected[3]);
+                            } else if (selected[2] == '调整') {
+                                origin = origin + Number(selected[3]);
+                            } else {
+                                throw new Error('无法处理的附注'.concat(selected[2]));
+                            }
+                            
+                        }
+                        
+
+                    }
+                    de['dercj'][j][2] = data[j][2];//名称
+                    de['dercj'][j][1] = data[j][1];//编号
+                    de['dercj'][j][5] = de['rcjdg'][j][5];//单价
+                    de['dercj'][j][10] =  origin;
+                    de['dercj'][j][11] = Number(de['dercj'][j][5]) * origin;
+                }
+
+            } else if (de['fuzhuEnable'] && !de.hasOwnProperty('fuzhu')) {
+                for(let j = 1; j < de['rcjdg'].length; j++) {
+                    let origin = Number(de['rcjdg'][j][10]);
+                    
+                    de['dercj'][j][2] = data[j][2];//名称
+                    de['dercj'][j][1] = data[j][1];//编号
+
+                    de['dercj'][j][5] = de['rcjdg'][j][5];
+                    de['dercj'][j][10] =  origin;
+                    de['dercj'][j][11] = Number(de['dercj'][j][5]) * origin;
+                }
+            }
+
+            else {
+                //强行改含量
+                de['dercj'] = copy(data);
+            }
+        
+
+            
+            data = de['dercj'];
+        } else {////单项定额没有底稿,老数据没底搞,无法判断换部换,暂时统一认为不换
+            //强行改含量
+            de['dercj'] = copy(data);
+            data = de['dercj'];
+        }
+        data = data.filter(x=>x[1] != 'S00001' && x[1] != 'JD0001');
+        for (let i = 1; i < data.length; i++) {
+            if (data[i][2].includes('(湿拌砂浆)')) {
+                let index = data[i][2].indexOf("(湿拌砂浆)");
+                data[i][2] = data[i][2].substring(0, index);
+            }
+            if (data[i][2].includes('(干拌(混)砂浆)')) {
+                let index = data[i][2].indexOf("(干拌(混)砂浆)");
+                data[i][2] = data[i][2].substring(0, index);
+            }
+        }
+        de['dercj'] = copy(data);
+
+        if (de.hasOwnProperty("rcjdg") && de['fuzhuEnable'] && yuban.length > 0) {//没强行改过含量
+            if (yuban.includes('1')) {
+                for(let i = 1; i < data.length; i++) {
+                    if (data[i][4]=='工日') {
+                        data[i][10] = Number(data[i][10]) - 0.45;
+                    }
+                    if (data[i][2].includes('搅拌机')) {
+                        data[i][10] = 0;
+                    }
+                    if (data[i][2].includes('砂浆') && !data[i][2].includes('搅拌机')) {
+                        data[i][2] = data[i][2].concat('(湿拌砂浆)')
+                    }
+                }
+
+            } else if (yuban.includes('2')) {
+                let origin = 0;
+                for(let i = 1; i < data.length; i++) {
+                  if (data[i][4]=='工日') {
+                    data[i][10] = Number(data[i][10]) - 0.3;
+                  }
+                  if (data[i][2].includes('搅拌机')) {
+                    data[i][10] = 0;
+                  }
+                  
+                  if (data[i][2].includes('砂浆') && !data[i][2].includes('搅拌机')) {
+                    data[i][2] = data[i][2].concat('(干拌(混)砂浆)');
+                    origin = Number(data[i][10]); 
+                    data[i][10] = origin * 1.75;
+                  }
+                }
+                data.push(['', 'S00001', '水', '', 't', '4.70', '', '', '2', 'false', (origin * 0.29).toString(), '', '','','','']);
+                data.push(['', 'JD0001', '其他机械费(电)', '', '度', '0.65', '', '', '3', 'false', (origin * 2.15).toString(), '', '','','','']);
+
+
+
+
+            } else if (yuban.includes('3')) {
+                let origin = 0;
+                for(let i = 1; i < data.length; i++) {
+                  if (data[i][4]=='工日') {
+                    data[i][10] = Number(data[i][10]) - 0.2;
+                  }
+                 
+                  
+                  if (data[i][2].includes('砂浆') && !data[i][2].includes('搅拌机')) {
+                    data[i][2] = data[i][2].concat('(干拌(混)砂浆)');
+                    origin = Number(data[i][10]); 
+                    data[i][10] = origin * 1.75;
+                  }
+                }
+                data.push(['', 'S00001', '水', '', 't', '4.70', '', '', '2', 'false', (origin * 0.29).toString(), '', '','','','']);
+                
+
+            }
+            de['dercj'] = copy(data);
+        }
+        de['dercj'] = de['dercj'].filter(x=>x[1] != '410000F')
+        for(let i = 0; i < rcjbc.length; i++) {
+            de['dercj'].push(['', rcjbc[i]['人材机编码'], rcjbc[i]['名称'], rcjbc[i]['规格型号'], rcjbc[i]['单位'], rcjbc[i]['单价'], rcjbc[i]['产地'], rcjbc[i]['供应厂商'], rcjbc[i]['人材机类别'], rcjbc[i]['甲供标志'], rcjbc[i]['含量'], '', rcjbc[i]['暂估价标志'],rcjbc[i]['主要材料标志'],rcjbc[i]['主材标志'],rcjbc[i]['设备标志']]);
+        }
+        data = copy(de['dercj']);
+
+        //模拟formula计算每一行的合价
+        for(let i = 1; i < data.length; i++) {
+            data[i][11] = Number(data[i][10]) * Number(data[i][5]);
+        }
+        let sum = 0;
+        let rgf_sum = 0;
+        let jxf_sum = 0;
+        let clf_sum = 0;
+        let zcf_sum = 0;
+        for(let i = 1; i < data.length; i++) {
+            sum += Number(data[i][11]);//11-> hejia
+            if (Number(data[i][8]) == 1) {
+                rgf_sum += Number(data[i][11]);
+            }
+            if (Number(data[i][8]) == 2) {
+                clf_sum += Number(data[i][11]);
+                if (data[i][14] == 'true') {
+                    zcf_sum += Number(data[i][11]);
+                }
+            }
+            if (Number(data[i][8]) == 3) {
+                jxf_sum += Number(data[i][11]);
+            }
+        }
+        console.log("sum=".concat(sum));
+        
+        let shuliang = Number(qd['数量']);
+        for(let i = 0; i< qd["_children"].length; i++) {
+            if(qd["_children"][i]['key'] == row) {
+                let desl = Number(qd["_children"][i]['数量']);
+                let oldname = qd["_children"][i]['清单编码'];
+                
+                qd["_children"][i]['辅材费'] = clf_sum - zcf_sum;
+                qd["_children"][i]['材料费'] = clf_sum;
+                qd["_children"][i]['人工费'] = rgf_sum;
+                qd["_children"][i]['主材费'] = zcf_sum;
+                qd["_children"][i]['设备费'] = 0;
+                qd["_children"][i]['机械费'] = jxf_sum;
+                if (oldname.startsWith("D")) {//单项清单
+                    qd["_children"][i]['管理费'] = 0;
+                    qd["_children"][i]['利润'] = 0;
+                } else {
+                    if (this.qufeiEntry['备注'].length == 0) {
+                        //changuiqufei
+                        qd["_children"][i]['管理费'] = (rgf_sum + jxf_sum) * Number(this.qufeiEntry['管理费(%)']) / Number(100);
+                        qd["_children"][i]['利润'] = (rgf_sum + jxf_sum) * Number(this.qufeiEntry['利润(%)']) / Number(100);
+                    } else {
+                        qd["_children"][i]['管理费'] = (rgf_sum) * Number(this.qufeiEntry['管理费(%)']) / Number(100);
+                        qd["_children"][i]['利润'] = (rgf_sum) * Number(this.qufeiEntry['利润(%)']) / Number(100);
+                    }
+                }
+                qd["_children"][i]['综合单价'] = sum + qd["_children"][i]['管理费'] + qd["_children"][i]['利润'];
+                qd["_children"][i]['合价'] = (qd["_children"][i]['综合单价'] * shuliang * desl);
+                
+                
+                
+                qd["_children"][i]["dercj"] = copy(data);
+                qd["_children"][i]['清单编码'] = renameDingE(oldname, xuhao, huan);
+
+            }
+        }
+    }
+
+    updateDercj(row, data) {
+        //是否手动设置含量
+        let qd = this.cache.filter(x=>x["_children"].filter(y=>y['key']==row).length > 0)[0];
+        let de = qd["_children"].filter(x=>x['key'] == row)[0];
+        this.updateFootprint(qd['key']);
+        let bm = de['清单编码'];
+        let alreadyFuzhu = extractFuzhu(bm);//[xuhao]
+        let origin = de['dercj'];
+        let change = false;
+        for(let i = 1; i < data.length; i++) {
+            let before = origin[i][10];//含量
+            let after = data[i][10];
+            if (Number(before) - Number(after) < 0.0001 && Number(before) - Number(after) > -0.0001) {
+                //no change
+            } else {
+                change = true;
+                break;
+            }
+        }
+        if (change) {
+            de['fuzhuEnable'] = false;
+        }
+
+
+        
+        this.updateDercj_(row, data, alreadyFuzhu, de['yuban'], de['rcjbc']);
+        //let qd = this.cache.filter(x=>x["children"].filter(y=>y['key']==row).length > 0)[0];
+
+        let newData = this.cache.map(x=>{
+            if (x['key'] == qd['key']) {
+                return qd;
+            } else {
+                return x;
+            }
+        });
+        let summarized = this.summarize(newData);
+        this.push_op(summarized);
+        /////////////////
+        this.cache = copy(summarized);
+        return copy(this.cache);
+
+
+    }
+
+
+    updateDercj_djcs(row, data) {
+        //是否手动设置含量
+        let qd = this.cache_djcs.filter(x=>x["_children"].filter(y=>y['key']==row).length > 0)[0];
+        let de = qd["_children"].filter(x=>x['key'] == row)[0];
+        let bm = de['清单编码'];
+        let alreadyFuzhu = extractFuzhu(bm);//[xuhao]
+        let origin = de['dercj'];
+        let change = false;
+        for(let i = 1; i < data.length; i++) {
+            let before = origin[i][10];
+            let after = data[i][10];
+            if (Number(before) - Number(after) < 0.0001 && Number(before) - Number(after) > -0.0001) {
+                //no change
+            } else {
+                change = true;
+                break;
+            }
+        }
+        if (change) {
+            de['fuzhuEnable'] = false;
+        }
+
+
+        
+        this.updateDercj_djcs_(row, data, alreadyFuzhu);
+        //let qd = this.cache.filter(x=>x["children"].filter(y=>y['key']==row).length > 0)[0];
+
+        let newData = this.cache_djcs.map(x=>{
+            if (x['key'] == qd['key']) {
+                return qd;
+            } else {
+                return x;
+            }
+        });
+        let summarized = this.summarize_djcs(newData);
+        this.push_op_djcs(summarized);
+        /////////////////
+        this.cache_djcs = copy(summarized);
+        return copy(this.cache_djcs);
+
+
+    }
+
+
+    updateBeizhu(row, selected, xuhao) {//xuhao is for rename
+        let qd = this.cache.filter(x=>x["_children"].filter(y=>y['key']==row).length > 0)[0];
+        if (!qd) return [null, null];
+        this.updateFootprint(qd['key']);
+        let de = qd["_children"].filter(x=>x['key'] == row)[0];
+        if (de.hasOwnProperty("rcjdg")) {//底稿
+
+        } else {///老数据不能有底稿,附注功能也不使能
+            //de['rcjdg'] = copy(de['dercj']);
+
+        }
+        de['fuzhu'] = copy(selected);
+        this.updateDercj_(row, de['dercj'], xuhao, de['yuban'], de['rcjbc']);
+
+        let newData = this.cache.map(x=>{
+            if (x['key'] == qd['key']) {
+                return qd;
+            } else {
+                return x;
+            }
+        });
+        let summarized = this.summarize(newData);
+        this.push_op(summarized);
+        /////////////////
+        this.cache = copy(summarized);
+        return [copy(this.cache), copy(de['dercj'])];
+
+    }
+
+
+    updateBeizhu_djcs(row, selected, xuhao) {//xuhao is for rename
+        let qd = this.cache_djcs.filter(x=>x["_children"].filter(y=>y['key']==row).length > 0)[0];
+        if (!qd) return [null, null];
+        let de = qd["_children"].filter(x=>x['key'] == row)[0];
+        if (de.hasOwnProperty("rcjdg")) {//底稿
+
+        } else {///老数据不能有底稿,附注功能也不使能
+            //de['rcjdg'] = copy(de['dercj']);
+
+        }
+        de['fuzhu'] = copy(selected);
+        this.updateDercj_djcs_(row, de['dercj'], xuhao);
+
+        let newData = this.cache_djcs.map(x=>{
+            if (x['key'] == qd['key']) {
+                return qd;
+            } else {
+                return x;
+            }
+        });
+        let summarized = this.summarize_djcs(newData);
+        this.push_op_djcs(summarized);
+        /////////////////
+        this.cache_djcs = copy(summarized);
+        return [copy(this.cache_djcs), copy(de['dercj'])];
+
+    }
+
+    huan(old_index, new_bianhao, new_name, new_jia, row) {
+        let qd = this.cache.filter(x=>x["_children"].filter(y=>y['key']==row).length > 0)[0];
+        this.updateFootprint(qd['key']);
+        let de = qd["_children"].filter(x=>x['key'] == row)[0];
+        let rcj = copy(de['dercj']);
+        rcj[old_index][1] = new_bianhao;
+        rcj[old_index][2] = new_name;
+        rcj[old_index][5] = new_jia;
+
+        return this.updateDercj(row, rcj);
+
+
+
+
+
+
+    }
+
+    updateShuliang(value, row) {
+        let qd = this.cache.filter(x=>x["_children"].filter(y=>y['key']==row).length > 0)[0];
+        this.updateFootprint(qd['key']);
+        let de = qd["_children"].filter(x=>x['key'] == row)[0];
+        let origin = de['数量']
+        if (Number(origin) - Number(value) < 0.0001 && Number(origin) - Number(value) > -0.0001) {
+            return [false, null];
+        }
+        console.log("shuliang update");
+        de['数量'] = value;
+        de['合价'] = Number(qd['数量']) * Number(de['综合单价']) * Number(de['数量']);
+        let newData = this.cache.map(x=>{
+            if (x['key'] == qd['key']) {
+                return qd;
+            } else {
+                return x;
+            }
+        });
+        let summarized = this.summarize(newData);
+        this.push_op(summarized);
+        /////////////////
+        this.cache = copy(summarized);
+        return [true, copy(this.cache)];
+
+
+
+
+
+
+    }
+
+
+    updateDeMingcheng(value, row) {
+        let qd = this.cache.filter(x=>x["_children"].filter(y=>y['key']==row).length > 0)[0];
+        this.updateFootprint(qd['key']);
+        let de = qd["_children"].filter(x=>x['key'] == row)[0];
+        de['名称'] = value;
+
+        let newData = this.cache.map(x=>{
+            if (x['key'] == qd['key']) {
+                return qd;
+            } else {
+                return x;
+            }
+        });
+        let summarized = this.summarize(newData);
+        this.push_op(summarized);
+        /////////////////
+        this.cache = copy(summarized);
+        return copy(this.cache);
+
+
+
+
+
+
+    }
+
+
+    updateShuliang_djcs(value, row) {
+        let qd = this.cache_djcs.filter(x=>x["_children"].filter(y=>y['key']==row).length > 0)[0];
+        let de = qd["_children"].filter(x=>x['key'] == row)[0];
+        let origin = de['数量']
+        if (Number(origin) - Number(value) < 0.0001 && Number(origin) - Number(value) > -0.0001) {
+            return [false, null];
+        }
+        console.log("shuliang update");
+        de['数量'] = value;
+        de['合价'] = Number(qd['数量']) * Number(de['综合单价']) * Number(de['数量']);
+        let newData = this.cache_djcs.map(x=>{
+            if (x['key'] == qd['key']) {
+                return qd;
+            } else {
+                return x;
+            }
+        });
+        let summarized = this.summarize_djcs(newData);
+        this.push_op_djcs(summarized);
+        /////////////////
+        this.cache_djcs = copy(summarized);
+        return [true, copy(this.cache_djcs)];
+
+
+
+
+
+
+    }
+
+
+    changguidinge_djcs(dingeclick, row) {
+        if (this.cache_djcs.filter(x=>x['key'] == row).length > 0) {
+            
+                let res =dingeclick;
+                let keys = Object.keys(res['DEBH']);
+                let key = keys[0];
+                //console.log(res);
+                let qd = this.cache_djcs.filter(x=>x['key'] == row)[0];
+                let dercj = [["ID", "人材机编码", "名称", "规格型号", "单位", "单价", "产地", 
+                "供应厂商", "人材机类别", "甲供标志", "含量", "合价", "暂估价标志", "主要材料标志", "主材标志", "设备标志" ]];
+                for(let i = 0; i < res['rgde'].length; i++) {
+                    dercj.push(['', res['rgde'][i]['CLBH'], res['rgde'][i]['CLMC'], '', res['rgde'][i]['JLDW'], 
+                    res['rgde'][i]['YSJG'], '', '', '1', '', res['rgde'][i]['gr'], res['rgde'][i]['gf'],
+                    '', '', '', '' ]);
+                }
+                for(let i = 0; i < res['clde'].length; i++) {
+                    dercj.push(['', res['clde'][i]['CLBH'], res['clde'][i]['CLMC'], '', res['clde'][i]['JLDW'], 
+                    res['clde'][i]['YSJG'], '', '', '2', '', res['clde'][i]['SL'], res['clde'][i]['HJ'],
+                    '', '', '', '' ]);
+                }
+                for(let i = 0; i < res['jxde'].length; i++) {
+                    dercj.push(['', res['jxde'][i]['jxbh'], res['jxde'][i]['jxmc'], '', res['jxde'][i]['DW'], 
+                    res['jxde'][i]['tbdj'], '', '', '3', '', res['jxde'][i]['sl'], res['jxde'][i]['hj'],
+                    '', '', '', '' ]);
+                }
+                let newKey = uuidv4();
+                qd["_children"].push({
+                    '操作': '',
+                    '序号': null,
+                    '清单编码': res['DEBH'][key],
+                    '名称': res['GCLMC'][key],
+                    '项目特征': null,
+                    '计算规则': null,
+                    '单位': res['DW'][key],
+                    '数量': '1',
+                    '综合单价': '0',
+                    '合价': '0',
+                    '人工费': '0',
+                    '主材费': '0',
+                    '设备费': '0',
+                    '辅材费': '0',
+                    '材料费': '0',
+                    '机械费': '0',
+                    '管理费': '0',
+                    '利润': '0',
+                    '暂估价': null,
+                    '综合人工工日': null,
+                    '备注': null,
+                    "dercj": dercj,
+                    'rcjdg': copy(dercj),
+                    'key' :   newKey,
+                    "fuzhuEnable": true
+    
+                    
+                });
+                this.updateDercj_djcs_(newKey, dercj, []);
+                let summarized = this.summarize_djcs(this.cache_djcs);
+                this.push_op_djcs(copy(summarized));
+                /////////////////
+                this.cache_djcs = copy(summarized);
+                //return copy(this.cache);
+            
+
+            return [true, copy(this.cache_djcs), newKey];
+        } else {
+            return [false, null, null];
+        }
+    }
+
+
+
+    changguidinge(dingeclick, row) {
+        if (this.cache.filter(x=>x['key'] == row).length > 0) {
+            this.updateFootprint(row);
+            
+                let res =dingeclick;
+                let keys = Object.keys(res['DEBH']);
+                let key = keys[0];
+                //console.log(res);
+                let qd = this.cache.filter(x=>x['key'] == row)[0];
+                let dercj = [["ID", "人材机编码", "名称", "规格型号", "单位", "单价", "产地", 
+                "供应厂商", "人材机类别", "甲供标志", "含量", "合价", "暂估价标志", "主要材料标志", "主材标志", "设备标志" ]];
+                for(let i = 0; i < res['rgde'].length; i++) {
+                    dercj.push(['', res['rgde'][i]['CLBH'], res['rgde'][i]['CLMC'], '', res['rgde'][i]['JLDW'], 
+                    res['rgde'][i]['YSJG'], '', '', '1', '', res['rgde'][i]['gr'], res['rgde'][i]['gf'],
+                    '', '', '', '' ]);
+                }
+                for(let i = 0; i < res['clde'].length; i++) {
+                    dercj.push(['', res['clde'][i]['CLBH'], res['clde'][i]['CLMC'], '', res['clde'][i]['JLDW'], 
+                    res['clde'][i]['YSJG'], '', '', '2', '', res['clde'][i]['SL'], res['clde'][i]['HJ'],
+                    '', '', '', '' ]);
+                }
+                for(let i = 0; i < res['jxde'].length; i++) {
+                    dercj.push(['', res['jxde'][i]['jxbh'], res['jxde'][i]['jxmc'], '', res['jxde'][i]['DW'], 
+                    res['jxde'][i]['tbdj'], '', '', '3', '', res['jxde'][i]['sl'], res['jxde'][i]['hj'],
+                    '', '', '', '' ]);
+                }
+                let newKey = uuidv4();
+                qd["_children"].push({
+                    '操作': '',
+                    '序号': null,
+                    '清单编码': res['DEBH'][key],
+                    '名称': res['GCLMC'][key],
+                    '项目特征': null,
+                    '计算规则': null,
+                    '单位': res['DW'][key],
+                    '数量': '1',
+                    '综合单价': '0',
+                    '合价': '0',
+                    '人工费': '0',
+                    '主材费': '0',
+                    '设备费': '0',
+                    '辅材费': '0',
+                    '材料费': '0',
+                    '机械费': '0',
+                    '管理费': '0',
+                    '利润': '0',
+                    '暂估价': null,
+                    '综合人工工日': null,
+                    '备注': null,
+                    "dercj": dercj,
+                    'rcjdg': copy(dercj),
+                    'key' :   newKey,
+                    "fuzhuEnable": true,
+                    'yuban': [],
+                    'rcjbc': []
+    
+                    
+                });
+                this.updateDercj_(newKey, dercj, [], [], []);
+                let summarized = this.summarize(this.cache);
+                this.push_op(copy(summarized));
+                /////////////////
+                this.cache = copy(summarized);
+                //return copy(this.cache);
+            
+
+            return [true, copy(this.cache), newKey];
+        } else {
+            return [false, null, null];
+        }
+    }
+
+    danxiangdinge(row) {
+        let bh = danxiangdinge_index(this.cache);
+        
+        if (this.cache.filter(x=>x['key'] == row).length > 0) {
+            this.updateFootprint(row);
+            let selected = this.cache.filter(x=>x['key'] == row)[0];
+            let danwei = selected["单位"];
+            let mingcheng = selected['名称'];
+            let children = selected["_children"];
+            children.push({
+                '操作': '',
+                '序号': null,
+                '清单编码': bh,
+                '名称': mingcheng,
+                '项目特征': null,
+                '计算规则': null,
+                '单位': danwei,
+                '数量': '1',
+                '综合单价': '',
+                '合价': '',
+                '人工费': '0',
+                '主材费': '0',
+                '设备费': '0',
+                '辅材费': '',
+                '材料费': '',
+                '机械费': '0',
+                '管理费': '0',
+                '利润': '0',
+                '暂估价': null,
+                '综合人工工日': null,
+                '备注': null,
+                "dercj": [["ID", "人材机编码", "名称", "规格型号", "单位", "单价", "产地", 
+                "供应厂商", "人材机类别", "甲供标志", "含量", "合价", "暂估价标志", "主要材料标志", "主材标志", "设备标志" ],
+                   ['', bh, mingcheng, '', danwei, '', '', '', '2', '', '1', '', '',  '', '', '' ]
+                      ],
+                'key' :   uuidv4(),
+                "fuzhuEnable": false,
+                'yuban': [],
+                'rcjbc' : []
+
+                
+            });
+            let summarized = this.summarize(this.cache);
+            this.push_op(summarized);
+            this.cache = copy(summarized);
+            
+            return [true, copy(this.cache)];
+        } else {
+            return [false,null];
+        }
+
+    }
+
+    danxiangdinge_djcs(row) {
+        let bh = danxiangdinge_index_djcs(this.cache_djcs);
+        
+        if (this.cache_djcs.filter(x=>x['key'] == row).length > 0) {
+            let selected = this.cache_djcs.filter(x=>x['key'] == row)[0];
+            let danwei = selected["单位"];
+            let mingcheng = selected['名称'];
+            let children = selected["_children"];
+            children.push({
+                
+                '序号': null,
+                '清单编码': bh,
+                '名称': mingcheng,
+                '项目特征': null,
+                '计算规则': null,
+                '单位': danwei,
+                '数量': '1',
+                '综合单价': '',
+                '合价': '',
+                '人工费': '0',
+                '主材费': '0',
+                '设备费': '0',
+                '辅材费': '',
+                '材料费': '',
+                '机械费': '0',
+                '管理费': '0',
+                '利润': '0',
+                '暂估价': null,
+                '综合人工工日': null,
+                '备注': null,
+                "dercj": [["ID", "人材机编码", "名称", "规格型号", "单位", "单价", "产地", 
+                "供应厂商", "人材机类别", "甲供标志", "含量", "合价", "暂估价标志", "主要材料标志", "主材标志", "设备标志" ],
+                   ['', bh, mingcheng, '', danwei, '', '', '', '2', '', '1', '', '',  '', '', '' ]
+                      ],
+                'key' :   uuidv4(),
+                "fuzhuEnable": false
+
+                
+            });
+            let summarized = this.summarize_djcs(this.cache_djcs);
+            this.push_op_djcs(summarized);
+            this.cache_djcs = copy(summarized);
+            
+            return [true, copy(this.cache_djcs)];
+        } else {
+            return [false,null];
+        }
+
+    }
+
+    handleYuban(row, selected) {
+        let qd = this.cache.filter(x=>x["_children"].filter(y=>y['key']==row).length > 0)[0];
+        if (!qd) return [null, null];
+        this.updateFootprint(qd['key']);
+        let de = qd["_children"].filter(x=>x['key'] == row)[0];
+        let bm = de['清单编码'];
+        let alreadyFuzhu = extractFuzhu(bm);//[xuhao]
+        if (de.hasOwnProperty("rcjdg")) {//底稿
+
+        } else {///老数据不能有底稿,附注功能也不使能,预拌也不能使
+            //de['rcjdg'] = copy(de['dercj']);
+
+        }
+        de['yuban'] = copy(selected);
+        this.updateDercj_(row, de['dercj'], alreadyFuzhu, selected, de['rcjbc']);
+
+        let newData = this.cache.map(x=>{
+            if (x['key'] == qd['key']) {
+                return qd;
+            } else {
+                return x;
+            }
+        });
+        let summarized = this.summarize(newData);
+        this.push_op(summarized);
+        /////////////////
+        this.cache = copy(summarized);
+        return [copy(this.cache), copy(de['dercj'])];
+    }
+
+    handleRcjbc(row, rcjbc) {
+        let qd = this.cache.filter(x=>x["_children"].filter(y=>y['key']==row).length > 0)[0];
+        if (!qd) return [null, null];
+        this.updateFootprint(qd['key']);
+        let de = qd["_children"].filter(x=>x['key'] == row)[0];
+        let bm = de['清单编码'];
+        let alreadyFuzhu = extractFuzhu(bm);//[xuhao]
+        if (de.hasOwnProperty("rcjdg")) {//底稿
+    
+        } else {///老数据不能有底稿,附注功能也不使能,预拌也不能使
+            //de['rcjdg'] = copy(de['dercj']);
+    
+        }
+        de['rcjbc'] = copy(rcjbc);
+        this.updateDercj_(row, de['dercj'], alreadyFuzhu, de['yuban'], rcjbc);
+    
+        let newData = this.cache.map(x=>{
+            if (x['key'] == qd['key']) {
+                return qd;
+            } else {
+                return x;
+            }
+        });
+        let summarized = this.summarize(newData);
+        this.push_op(summarized);
+        /////////////////
+        this.cache = copy(summarized);
+        return [copy(this.cache), copy(de['dercj'])];
+    }
+
+    
+}
+
+
+
+
+
+
+
+export default new Service();

+ 1 - 0
src/Tabulator.css

@@ -0,0 +1 @@
+.tabulator{background-color:#E8E9EB;}

+ 71 - 0
src/Tbxx.js

@@ -0,0 +1,71 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+//registerPlugin(NestedRows);
+import Service from './Service';
+
+import Button from '@mui/material/Button';
+
+import {copy} from './utils';
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+export default function Tbxx({data}) {
+    const myRef = React.useRef();
+    const myTable = React.useRef(null);
+
+
+
+    React.useEffect(() => {
+      myTable.current = new Tabulator(myRef.current, {
+           index: "key",
+           height: 600,
+         data: data, //link data to table
+         reactiveData: false, //enable data reactivity
+         dataTreeStartExpanded:true,
+         dataTree: true,
+         selectableRows:1, //make rows selectable
+         editTriggerEvent:"dblclick", //trigger edit on double click
+         dataTreeStartExpanded:function(row, level){
+             //console.log(row);
+             //console.log(level);
+             return true; //expand rows where the "driver" data field is true;
+         },
+         columns: [ //Define Table Columns 序号", "名称", "取费基数", "计算基础","费率", "金额", "类别
+                      {title:"名称", field:"名称", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                      {title:"金额", field:"金额", width:150, headerSort:false, formatter:"money", },
+                      {title:"暂估价", field:"暂估价", width:100, headerSort:false,  formatter:"money"},
+                      {title:"安全文明施工费", field:"安全文明施工费", width:150, headerSort:false,  formatter:"money"},
+                      {title:"规费", field:"规费", width:150, headerSort:false,  formatter:"money"},
+                    
+              ]
+       }); 
+       
+       myTable.current.on("cellDblClick", function(e, cell){
+           //e - the click event object
+           //cell - cell component
+           console.log(cell);
+       });
+  
+       //myTable.current.on("rowSelected", handleSelect);
+       
+  
+       
+  
+  
+      
+     
+    }, [data]);
+    return (
+      <div ref={myRef}> 
+      </div>
+
+
+
+    );
+}

+ 50 - 0
src/Test.js

@@ -0,0 +1,50 @@
+import * as React from 'react';
+import {Tree} from 'rsuite';
+import 'rsuite/Tree/styles/index.css';
+
+export default function Test() {
+  const MUI_X_PRODUCTS = [
+    {
+      value: 'grid',
+      label: 'Data Grid',
+      children: [
+        { value: 'grid-community', label: '@mui/x-data-grid' },
+        { value: 'grid-pro', label: '@mui/x-data-grid-pro' },
+        { value: 'grid-premium', label: '@mui/x-data-grid-premium' },
+      ],
+    },
+    {
+      value: 'pickers',
+      label: 'Date and Time Pickers',
+      children: [
+        { value: 'pickers-community', label: '@mui/x-date-pickers' },
+        { value: 'pickers-pro', label: '@mui/x-date-pickers-pro' },
+      ],
+    },
+    {
+      value: 'charts',
+      label: 'Charts',
+      children: [
+        { value: 'charts-community', label: '@mui/x-charts' },
+        { value: 'charts-pro', label: '@mui/charts-pro' },
+      ],
+    },
+    {
+      value: 'tree-view',
+      label: 'Tree View',
+      children: [
+        { value: 'tree-view-community', label: '@mui/x-tree-view' },
+        { value: 'tree-view-pro', label: '@mui/x-tree-view-pro' },
+      ],
+    },
+  ];
+   
+    return (
+      <Tree data ={ MUI_X_PRODUCTS} height="20vh">
+
+      </Tree>
+
+
+
+    );
+}

+ 75 - 0
src/Zcbfwf.js

@@ -0,0 +1,75 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+//registerPlugin(NestedRows);
+import Service from './Service';
+import EditableSelect from './EditableSelect';
+import EditableSelectGC from './EditableSelectGC';
+import Editable from './Editable';
+import Button from '@mui/material/Button';
+
+import {copy} from './utils';
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+export default function Zcbfwf({data}) {
+    const myRef = React.useRef();
+    const myTable = React.useRef(null);
+
+
+
+    React.useEffect(() => {
+      myTable.current = new Tabulator(myRef.current, {
+           index: "key",
+           height: 600,
+         data: data, //link data to table
+         reactiveData: false, //enable data reactivity
+         dataTreeStartExpanded:true,
+         dataTree: true,
+         selectableRows:1, //make rows selectable
+         editTriggerEvent:"dblclick", //trigger edit on double click
+         dataTreeStartExpanded:function(row, level){
+             //console.log(row);
+             //console.log(level);
+             return true; //expand rows where the "driver" data field is true;
+         },
+         columns: [ //Define Table Columns 序号", "名称", "取费基数", "计算基础","费率", "金额", "类别
+                      {title:"序号", field:"序号", width:80, headerSort:false,}, //never hide this column
+                      {title:"名称", field:"名称", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                      {title:"项目价值", field:"项目价值", width:100,   formatter:"money", },
+                      {title:"服务内容", field:"服务内容", width:100,   formatter:"textarea"},
+                      {title:"计算基础", field:"计算基础", width:100,   formatter:"textarea"},
+                      {title:"费率", field:"费率", width:100,   formatter:"money"},
+                      {title:"金额", field:"金额", width:100,   formatter:"money"},
+                    
+              ]
+       }); 
+       
+       myTable.current.on("cellDblClick", function(e, cell){
+           //e - the click event object
+           //cell - cell component
+           console.log(cell);
+       });
+  
+       //myTable.current.on("rowSelected", handleSelect);
+       
+  
+       
+  
+  
+      
+     
+    }, [data]);
+    return (
+      <div ref={myRef}> 
+      </div>
+
+
+
+    );
+}

+ 288 - 0
src/Zjcs2.js

@@ -0,0 +1,288 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import Tabs from '@mui/material/Tabs';
+import FormControl from '@mui/material/FormControl';
+import InputLabel from '@mui/material/InputLabel';
+import Select from '@mui/material/Select';
+import MenuItem from '@mui/material/MenuItem';
+import { v4 as uuidv4 } from 'uuid';
+import {copy} from './utils';
+
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+import Service from './Service';
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+
+export default function Zjcs2({name, bh, zjcsCallback}) {
+    const [detail, setDetail] = React.useState([
+
+                    {
+                    "序号" : null, "清单编码": null, "名称" : null, "计算基数" : null,
+                     "计算基础" : null, "费率" : null, "金额" : null, "项目类别" : null}
+    ]);
+    const [cankao, setCankao] = React.useState([
+
+    ]);
+    const myRef = React.useRef(null);
+    const myTable = React.useRef(null);
+    const cankaoRef = React.useRef(null);
+    const cankaoTable = React.useRef(null);
+    const hotRef = React.useRef(null);
+    const allRef = React.useRef([]);
+
+    const [value, setValue] = React.useState(10);
+    const [valueTab, setValueTab] = React.useState("1");
+    React.useEffect(
+        () => {
+
+
+
+          myTable.current = new Tabulator(myRef.current, {
+            index: "key",
+            height: 380,
+          data: detail, //link data to table
+          reactiveData: false, //enable data reactivity
+          dataTreeStartExpanded:true,
+          dataTree: true,
+          selectableRows:1, //make rows selectable
+          editTriggerEvent:"dblclick", //trigger edit on double click
+          dataTreeStartExpanded:function(row, level){
+              //console.log(row);
+              //console.log(level);
+              return true; //expand rows where the "driver" data field is true;
+          },
+          columns: [ //Define Table Columns
+                       {title:"序号", field:"序号", width:40, headerSort:false, frozen: true}, //never hide this column
+                       {title:"清单编码", field:"清单编码", width:120,headerSort:false, frozen: true, formatter:"textarea" },
+                       {title:"名称", field:"名称", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                       {title:"计算基数", field:"计算基数", width:150 , headerSort:false, formatter:"money"},
+                       {title:"计算基础", field:"计算基础", width:250, headerSort:false, formatter:"textarea"},
+                       {title:"费率", field:"费率", width:60 , headerSort:false, formatter:"money", editor:"input", editable:editCheck},
+                       {title:"金额", field:"金额", width:150, headerSort:false, formatter:"money"},
+                       {title:"项目类别", field:"项目类别", width:80 , headerSort:false, formatter:"textarea"},
+                       
+
+               ]
+        }); 
+        
+        myTable.current.on("cellDblClick", function(e, cell){
+            //e - the click event object
+            //cell - cell component
+            console.log(cell);
+        });
+  
+        myTable.current.on("cellEdited", function(cell){
+          //cell - cell component
+          console.log(cell);
+          let newData = copy(cell._cell.row.data);
+          newData['金额'] = Number(newData['计算基数']) * Number(newData['费率']) / Number(100);
+          myTable.current.updateData([newData]);
+          zjcsCallback(name, bh, newData);
+        });
+        
+  
+        
+
+
+          Service.generateZjcs(name, bh).then(x=>{
+            let addedkey = x.map(y=>{
+              y['key'] = uuidv4();
+              if (y.hasOwnProperty('_children')) {
+              y['_children'] = y['_children'].map(z=>{
+                z['key'] = uuidv4();
+                return z;
+              });
+            }
+              return y;
+            });
+            myTable.current.replaceData(addedkey);
+          });
+        }, [bh]
+      );
+
+      React.useEffect(
+        () => {
+
+          cankaoTable.current = new Tabulator(cankaoRef.current, {
+            index: "key",
+            height: 200,
+          data: cankao, //link data to table
+          reactiveData: false, //enable data reactivity
+          
+          dataTree: false,
+          selectableRows:1, //make rows selectable
+          
+         
+          columns: [ //Define Table Columns
+                       {title:"工程类型", field:"工程类型", width:200, headerSort:false, headerFilter:"input", formatter:"textarea"}, //never hide this column
+                       {title:"名称", field:"名称", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                       {title:"计算基础", field:"计算基础", width:250, headerSort:false, formatter:"textarea"},
+                       {title:"参考费率", field:"参考费率", width:100 , headerSort:false, formatter:"money"},
+                       {title:"地区", field:"地区", width:50, headerSort:false, formatter:"textarea"},
+                       {title:"备注", field:"备注", width:280 , headerSort:false, formatter:"textarea"},
+                       
+
+               ]
+        }); 
+          Service.cankao().then(x=>{
+            allRef.current = x;
+            filterData(value);
+            
+          });
+        }, []
+      );
+
+      const filterData = (value) => {
+        if (value == 10) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('安全文明施工措施费'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 20) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('扬尘污染防治增加费'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 30) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('按质论价'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 40) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('非夜间施工照明'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 50) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('冬雨季施工'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 60) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('已完工程及设备保护'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 70) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('临时设施'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 80) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('赶工措施'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 90) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('住宅分户验收'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 100) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('夜间施工'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 110) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('建筑工人实名制费用'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 120) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('苏安码管理增加费'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 130) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('特殊施工降效'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 140) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('交通组织维护'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 150) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('协管费'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 160) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('垂直运输'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 170) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('二次搬运'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 180) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('智慧工地费用'));
+          cankaoTable.current.replaceData(newData);
+        } else if (value == 190) {
+          let newData = allRef.current.filter(y=>y['名称'].includes('外脚手架钢板网使用增加费'));
+          cankaoTable.current.replaceData(newData);
+        }
+        
+      };
+
+      const handleChange = (event) => {
+        setValue(event.target.value);
+        filterData(event.target.value);
+
+      };
+
+      var editCheck = function(cell){
+        //cell - the cell component for the editable cell
+    
+        //get row data
+        let row = cell._cell.row;
+        while(row.modules.dataTree.parent) {
+          row = row.modules.dataTree.parent;
+        }
+        if (row.data['名称'] == '现场安全文明施工') return false;
+    
+        return true; // only allow the name cell to be edited if the age is over 18
+    }
+
+
+
+
+
+
+    return (
+      <Stack spacing={1}>
+      
+        <div ref={myRef}> 
+        </div>
+        <Box >
+                   
+          <TabContext value={valueTab}>
+          <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
+                         <TabList sx={{minHeight: '24px'}}  aria-label="lab API tabs example">
+                           <Tab sx={{p: 0, minHeight: '24px'}} label="参考费率" value="1" />
+                         </TabList>
+           </Box>
+           <TabPanel sx={{p: 1}} value="1">
+           <Stack direction="row" spacing={1}>
+        <FormControl sx={{width: 200}}>
+         <InputLabel id="demo-simple-select-label">措施分类</InputLabel>
+         <Select
+           labelId="demo-simple-select-label"
+           id="demo-simple-select"
+            value={value}
+            label="措施分类"
+            onChange={handleChange}
+          >
+            <MenuItem value={10}>安全文明施工措施费</MenuItem>
+            <MenuItem value={20}>扬尘污染防治增加费</MenuItem>
+            <MenuItem value={30}>按质论价</MenuItem>
+            <MenuItem value={40}>非夜间施工照明</MenuItem>
+            <MenuItem value={50}>冬雨季施工</MenuItem>
+            <MenuItem value={60}>已完工程及设备保护</MenuItem>
+            <MenuItem value={70}>临时设施</MenuItem>
+            <MenuItem value={80}>赶工措施</MenuItem>
+            <MenuItem value={90}>住宅分户验收</MenuItem>
+            <MenuItem value={100}>夜间施工</MenuItem>
+            <MenuItem value={110}>建筑工人实名制费用</MenuItem>
+            <MenuItem value={120}>苏安码管理增加费</MenuItem>
+            <MenuItem value={130}>特殊施工降效</MenuItem>
+            <MenuItem value={140}>交通组织维护</MenuItem>
+            <MenuItem value={150}>协管费</MenuItem>
+            <MenuItem value={160}>垂直运输</MenuItem>
+            <MenuItem value={170}>二次搬运</MenuItem>
+            <MenuItem value={180}>智慧工地费用</MenuItem>
+            <MenuItem value={190}>外脚手架钢板网使用增加费</MenuItem>
+
+            </Select>
+          </FormControl>
+            <div ref={cankaoRef}> 
+            </div>
+        </Stack>
+       </TabPanel>
+     </TabContext>
+     </Box>
+
+    
+     
+    </Stack>
+
+
+
+
+    );
+}

+ 73 - 0
src/Zlje.js

@@ -0,0 +1,73 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+//registerPlugin(NestedRows);
+import Service from './Service';
+import EditableSelect from './EditableSelect';
+import EditableSelectGC from './EditableSelectGC';
+import Editable from './Editable';
+import Button from '@mui/material/Button';
+
+import {copy} from './utils';
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+export default function Zlje({data}) {
+    const myRef = React.useRef();
+    const myTable = React.useRef(null);
+
+
+
+    React.useEffect(() => {
+      myTable.current = new Tabulator(myRef.current, {
+           index: "key",
+           height: 600,
+         data: data, //link data to table
+         reactiveData: false, //enable data reactivity
+         dataTreeStartExpanded:true,
+         dataTree: true,
+         selectableRows:1, //make rows selectable
+         editTriggerEvent:"dblclick", //trigger edit on double click
+         dataTreeStartExpanded:function(row, level){
+             //console.log(row);
+             //console.log(level);
+             return true; //expand rows where the "driver" data field is true;
+         },
+         columns: [ //Define Table Columns 序号", "名称", "取费基数", "计算基础","费率", "金额", "类别
+                      {title:"序号", field:"序号", width:80, headerSort:false,}, //never hide this column
+                      {title:"名称", field:"名称", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                      {title:"单位", field:"单位", width:100, },
+                      {title:"暂定金额", field:"暂定金额", width:100,   formatter:"money"},
+                      {title:"备注", field:"备注", width:100,   formatter:"textarea"},
+                    
+              ]
+       }); 
+       
+       myTable.current.on("cellDblClick", function(e, cell){
+           //e - the click event object
+           //cell - cell component
+           console.log(cell);
+       });
+  
+       //myTable.current.on("rowSelected", handleSelect);
+       
+  
+       
+  
+  
+      
+     
+    }, [data]);
+    return (
+      <div ref={myRef}> 
+      </div>
+
+
+
+    );
+}

+ 73 - 0
src/Zygczgj.js

@@ -0,0 +1,73 @@
+import * as React from 'react';
+import Box from "@mui/material/Box";
+import { Grid } from '@mui/material';
+import Tab from "@mui/material/Tab";
+import TabContext from "@mui/lab/TabContext";
+import TabList from "@mui/lab/TabList";
+import TabPanel from "@mui/lab/TabPanel";
+import Stack from "@mui/material/Stack";
+//registerPlugin(NestedRows);
+import Service from './Service';
+import EditableSelect from './EditableSelect';
+import EditableSelectGC from './EditableSelectGC';
+import Editable from './Editable';
+import Button from '@mui/material/Button';
+
+import {copy} from './utils';
+import {TabulatorFull as Tabulator} from "tabulator-tables"; //import Tabulator library
+import "tabulator-tables/dist/css/tabulator.min.css"; //import Tabulator stylesheet
+import './Tabulator.css';
+export default function Zygczgj({data}) {
+    const myRef = React.useRef();
+    const myTable = React.useRef(null);
+
+
+
+    React.useEffect(() => {
+      myTable.current = new Tabulator(myRef.current, {
+           index: "key",
+           height: 600,
+         data: data, //link data to table
+         reactiveData: false, //enable data reactivity
+         dataTreeStartExpanded:true,
+         dataTree: true,
+         selectableRows:1, //make rows selectable
+         editTriggerEvent:"dblclick", //trigger edit on double click
+         dataTreeStartExpanded:function(row, level){
+             //console.log(row);
+             //console.log(level);
+             return true; //expand rows where the "driver" data field is true;
+         },
+         columns: [ //Define Table Columns 序号", "名称", "取费基数", "计算基础","费率", "金额", "类别
+                      {title:"序号", field:"序号", width:80, headerSort:false,}, //never hide this column
+                      {title:"名称", field:"名称", width:150, headerSort:false, formatter:"textarea"}, //hide this column first
+                      {title:"工程内容", field:"工程内容", width:100,   formatter:"textarea", },
+                      {title:"金额", field:"金额", width:100,   formatter:"money"},
+                      {title:"备注", field:"备注", width:100,   formatter:"textarea"},
+                    
+              ]
+       }); 
+       
+       myTable.current.on("cellDblClick", function(e, cell){
+           //e - the click event object
+           //cell - cell component
+           console.log(cell);
+       });
+  
+       //myTable.current.on("rowSelected", handleSelect);
+       
+  
+       
+  
+  
+      
+     
+    }, [data]);
+    return (
+      <div ref={myRef}> 
+      </div>
+
+
+
+    );
+}

+ 178 - 0
src/editor.js

@@ -0,0 +1,178 @@
+
+import {danxiangdinge_index} from './utils';
+import Service from './Service';
+
+function copy(input) {
+    return JSON.parse(JSON.stringify(input));
+}
+
+
+export const undo = () => {
+    let newData = Service.undo();
+    return newData;
+};
+
+export const undo_djcs = () => {
+    let newData = Service.undo_djcs();
+    return newData;
+};
+
+
+
+export const redo = () => {
+    let newData = Service.redo();
+    return newData;
+};
+
+export const redo_djcs = () => {
+    let newData = Service.redo_djcs();
+    return newData;
+};
+
+export const shanchu = ( selectedRow) => {
+   
+    
+    
+    let newData = Service.shanchu(selectedRow);
+    
+    return newData;
+  };
+
+  export const shanchu_djcs = ( selectedRow) => {
+   
+    
+    
+    let newData = Service.shanchu_djcs(selectedRow);
+    
+    return newData;
+  };
+
+
+
+
+
+
+
+export const danxiangdinge = (selectedRow) => {
+    return Service.danxiangdinge(selectedRow);
+};
+
+export const danxiangdinge_djcs = (selectedRow) => {
+    return Service.danxiangdinge_djcs(selectedRow);
+};
+
+export const updateDercj = (row, data) => {
+    return Service.updateDercj(row, data);
+
+};
+
+export const updateDercj_djcs = (row, data) => {
+    return Service.updateDercj_djcs(row, data);
+
+};
+
+
+export const huan = (replaceState, row) => {
+    return Service.huan(replaceState['old'],replaceState['newBianhao'],replaceState['newName'], replaceState['newJia'], row);
+
+};
+
+export const updateShuliang = (data, row) => {
+    return Service.updateShuliang(data, row);
+
+};
+
+export const updateDeMingcheng = (data, row) => {
+    return Service.updateDeMingcheng(data, row);
+
+};
+
+export const updateShuliang_djcs = (data, row) => {
+    return Service.updateShuliang_djcs(data, row);
+
+};
+
+export const changguidinge = (dingeclick, selectedRow) => {
+    return Service.changguidinge(dingeclick, selectedRow);
+
+};
+
+
+
+export const changguidinge_djcs = (dingeclick, selectedRow) => {
+    return Service.changguidinge_djcs(dingeclick, selectedRow);
+
+};
+
+export const handleYuban = (derow, select ) => {
+    return Service.handleYuban(derow, select);
+
+};
+
+export const handleRcjbc = (derow, rcjbc ) => {
+    return Service.handleRcjbc(derow, rcjbc);
+
+};
+
+export const handleBeizhu = (beizhuFK, derow, fuzhuSelect, fuzhu ) => {
+    console.log(beizhuFK);
+    let bianma = [];
+    let xuhao = [];
+    let fuzhuSelect_ = Array.from(fuzhuSelect);
+    let keys = beizhuFK['BZBH'];
+    for(let j = 0; j < fuzhuSelect_.length; j++) {
+        let entry = fuzhuSelect_[j];
+        for(let i = 0; i < fuzhu.length; i++) {
+            if (fuzhu[i]['key'] == entry) {
+                bianma.push(fuzhu[i]['编号']);
+                xuhao.push(fuzhu[i]['序号']);
+            }
+        }
+    }
+    let result = [];
+    for(let i = 0; i < bianma.length; i++) {
+        let bh = bianma[i];
+        for(let j = 0; j < Object.keys(keys).length; j++) {
+            let BZBH_ = Object.keys(keys)[j];
+            let BZBH = keys[BZBH_];
+            if (BZBH == bh) {
+                result.push([beizhuFK['BH'][BZBH_], beizhuFK['MC'][BZBH_], beizhuFK['LB'][BZBH_], beizhuFK['SL'][BZBH_], beizhuFK['DW'][BZBH_]]);
+            }
+        }
+    }
+    console.log(result);
+    return Service.updateBeizhu(derow, result, xuhao);
+};
+
+export const handleBeizhu_djcs = (beizhuFK, derow, fuzhuSelect, fuzhu ) => {
+    console.log(beizhuFK);
+    let bianma = [];
+    let xuhao = [];
+    let fuzhuSelect_ = Array.from(fuzhuSelect);
+    let keys = beizhuFK['BZBH'];
+    for(let j = 0; j < fuzhuSelect_.length; j++) {
+        let entry = fuzhuSelect_[j];
+        for(let i = 0; i < fuzhu.length; i++) {
+            if (fuzhu[i]['key'] == entry) {
+                bianma.push(fuzhu[i]['编号']);
+                xuhao.push(fuzhu[i]['序号']);
+            }
+        }
+    }
+    let result = [];
+    for(let i = 0; i < bianma.length; i++) {
+        let bh = bianma[i];
+        for(let j = 0; j < Object.keys(keys).length; j++) {
+            let BZBH_ = Object.keys(keys)[j];
+            let BZBH = keys[BZBH_];
+            if (BZBH == bh) {
+                result.push([beizhuFK['BH'][BZBH_], beizhuFK['MC'][BZBH_], beizhuFK['LB'][BZBH_], beizhuFK['SL'][BZBH_], beizhuFK['DW'][BZBH_]]);
+            }
+        }
+    }
+    console.log(result);
+    return Service.updateBeizhu_djcs(derow, result, xuhao);
+};
+
+
+

+ 19 - 9
src/index.js

@@ -1,15 +1,25 @@
-import React from 'react';
-import ReactDOM from 'react-dom/client';
+import React, {Suspense} from 'react';
+import ReactDOM from 'react-dom';
 import './index.css';
-import App from './App';
+import Test from './Test';
 import reportWebVitals from './reportWebVitals';
+import {createBrowserRouter, RouterProvider, Route, Link} from "react-router-dom";
+const Home2 = React.lazy(() => import('./Home2'));
+const App2 = React.lazy(() => import('./App2'));
+
+const router = createBrowserRouter([
+   {path: "/editor/qingdan/:id",
+     element: (<Suspense fallback={<div></div>}><App2></App2></Suspense>)
+   },
+   {path: "/editor/index.html",
+   element: (<Suspense fallback={<div></div>}><Home2></Home2></Suspense>)
+ },
+ {path: "/editor/test.html",
+   element: (<Suspense fallback={<div></div>}><Test></Test></Suspense>)
+ },
+]);
+const root = ReactDOM.render(<RouterProvider router={router}/>, document.getElementById('root'));
 
-const root = ReactDOM.createRoot(document.getElementById('root'));
-root.render(
-  <React.StrictMode>
-    <App />
-  </React.StrictMode>
-);
 
 // If you want to start measuring performance in your app, pass a function
 // to log results (for example: reportWebVitals(console.log))

+ 126 - 0
src/utils.js

@@ -0,0 +1,126 @@
+export const danxiangdinge_index = (data) => {
+    let max = 0;
+    for(let i = 0;  i< data.length; i++) {
+        if (data[i].hasOwnProperty("_children")) {
+            let child = data[i]["_children"];
+            for (let j = 0; j < child.length; j++) {
+                let de = child[j];
+                if (de["清单编码"].startsWith("D")) {
+                    let number = de["清单编码"].substring(1);
+                    let n = Number(number);
+                    if (n > max) {
+                        max = n;
+                    }
+                }
+            }
+        }
+    }
+        let result =  (max + 1).toString();
+        result = result.padStart(5, '0');
+        return "D".concat(result);
+
+    
+  };
+
+  export const danxiangdinge_index_djcs = (data) => {
+    let max = 0;
+    for(let i = 0;  i< data.length; i++) {
+        if (data[i].hasOwnProperty("_children")) {
+            let child = data[i]["_children"];
+            for (let j = 0; j < child.length; j++) {
+                let de = child[j];
+                if (de["清单编码"].startsWith("D")) {
+                    let number = de["清单编码"].substring(1);
+                    let n = Number(number);
+                    if (n > max) {
+                        max = n;
+                    }
+                }
+            }
+        }
+    }
+        let result =  (max + 1).toString();
+        result = result.padStart(5, '0');
+        return "D".concat(result);
+
+    
+  };
+
+
+export const copy = (input) => {
+    return JSON.parse(JSON.stringify(input));
+};
+
+
+export const renameDingE = (oldname, xuhao, huan) => {
+    let index = oldname.indexOf('附注', 0);
+    let raw = oldname;
+    if (index == -1) {
+
+    } else {
+        raw = oldname.substring(0, index);
+    }
+    for(let i = 0; i < xuhao.length; i++) {
+        raw = raw.concat("附注");
+        raw = raw.concat(xuhao[i].toString());
+    }
+    if (huan && raw.indexOf('换') == -1) {
+        raw = raw.concat('换');
+    }
+    
+    return raw;
+};
+
+export const extractFuzhu = (debm) => {
+    if (debm) {
+        let start = 0;
+        let result = [];
+        while(start < debm.length) {
+            let index = debm.indexOf('附注', start);
+            if (index == -1) break;
+            let i = index + 2;
+            for(i = index+2; i < debm.length; i++) {
+                if (debm[i] >= '0' && debm[i] <= '9') {
+
+                } else {
+                    break;
+                }
+            }
+            let find = debm.substring(index+2, i);
+            result.push(Number(find));
+            start = i;
+
+
+        }
+        return result;
+    } else {
+        return [];
+    }
+};
+
+export const match_target = (input ,target) => {
+    if (target == '000001') {//普世的人工费
+        if(input.startsWith("0001")) {
+            return true;
+        } else {
+            return false;
+        }
+    } else if (target == 'J00000') {//普世机械费
+        if (input.startsWith('99')) {
+            return true;
+        } else {
+            return false;
+        }
+    } else if (target == '100000') {//全部材料
+        if (input.startsWith('99')) {
+            return false;
+        } else if (input.startsWith("0001")) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+    return input == target;
+};
+
+

Vissa filer visades inte eftersom för många filer har ändrats