Browse Source

管网科技

xjj 2 năm trước cách đây
mục cha
commit
7189e50163

+ 1 - 0
package.json

@@ -7,6 +7,7 @@
     "precommit": "npm run lint"
   },
   "dependencies": {
+    "@ahooksjs/use-request": "^2.8.15",
     "@ant-design/icons": "^5.0.1",
     "@jiaminghi/data-view-react": "^1.2.4",
     "antd": "4",

+ 131 - 0
src/components/Pine/InfoBox.js

@@ -0,0 +1,131 @@
+import React from "react";
+import { Spin } from "antd";
+import { AreaChartOutlined } from "@ant-design/icons";
+// import { UnityAction } from "@/utils/utils";
+import useRequest from "@ahooksjs/use-request";
+import styled from "styled-components";
+import { getDeviceRealData } from "../../services";
+
+export const ItemType = {
+  text: 0,
+  progressBar: 1,
+  pump: 2,
+};
+
+const InfoBox = (props) => {
+  const { dataPump, title, position } = props;
+  const clickChart = (item) => {
+    // UnityAction.emit("clickChart", item);
+  };
+  const { data, loading } = useRequest(getDeviceRealData, {
+    defaultParams: [dataPump],
+    initialData: dataPump,
+    formatResult({ data }) {
+      let list = [];
+      dataPump.forEach((item) => {
+        let realItem = data.find((rItem) => rItem.itemname == item.deviceItems);
+        list.push({
+          ...item,
+          value: realItem.val,
+        });
+      });
+      return list;
+    },
+  });
+
+  return (
+    <InfoMain style={{ ...position, position: "fixed", zIndex: 99999999 }}>
+      <div className="top">{title}</div>
+      {data?.map((item) => {
+        if (item?.type == ItemType.progressBar) {
+          return (
+            <div className="item" key={item.name}>
+              <div className="item-name">{item.name}</div>
+              <div className="item-value">
+                <div className="Progress">
+                  <div className="Bar" style={{ width: item.value }} />
+                </div>
+              </div>
+            </div>
+          );
+        } else {
+          return (
+            <div className="item" key={item.name}>
+              <div className="item-name">{item.name}</div>
+              <div className="item-value">
+                <Spin spinning={loading}>{item?.value}</Spin>
+                <AreaChartOutlined
+                  style={{ color: "#fff", fontSize: 18 }}
+                  onClick={() => clickChart(item)}
+                />
+              </div>
+            </div>
+          );
+        }
+      })}
+    </InfoMain>
+  );
+};
+
+const InfoMain = styled.div`
+  position: absolute;
+  top: -30%;
+  left: 100%;
+  width: 240px;
+  padding-bottom: 10px;
+  border-bottom-width: 6px;
+  border-top-width: 6px;
+  border-color: #017899;
+  border-style: solid;
+  color: #fff;
+  background: rgba(8, 41, 75, 0.7);
+
+  .top {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 4px 10px;
+    border-bottom: 1px solid #046681;
+  }
+
+  .item {
+    border-bottom: 1px solid #046681;
+    display: flex;
+    font-size: 14px;
+  }
+
+  .item-name {
+    width: 47%;
+    color: #02a7f0;
+    padding: 8px 10px;
+  }
+
+  .item-value {
+    flex: 1;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    /* width: 50%; */
+    color: #02a7f0;
+    padding: 8px 10px;
+  }
+
+  .item-name {
+    border-right: 1px solid #046681;
+  }
+
+  .Progress {
+    width: 100%;
+    height: 12px;
+    border-radius: 6px;
+    background-color: gray;
+  }
+
+  .Bar {
+    height: 100%;
+    border-radius: 6px;
+    background-color: yellow;
+  }
+`;
+
+export default InfoBox;

+ 457 - 0
src/components/Pine/PineMap.js

@@ -0,0 +1,457 @@
+import React, { PureComponent } from "react";
+import { Map, MapvglView, MapvglLayer } from "react-bmapgl";
+
+import { styleJson } from "../centerPage/charts/BMapConfig";
+import Point from "./Point";
+import Legend from "../Map/Legend";
+import InfoBox from "./InfoBox";
+
+// 浊度,余氯和 PH 值
+const data = [
+  {
+    name: "监测点1",
+    position: { lng: 120.76320738823746, lat: 31.741432990607994 },
+    data: [
+      {
+        name: "浊度",
+        value: "",
+        deviceId: "1436022785",
+        deviceItems: "Skid_1_1st_Stage_DP",
+        deviceName: "RO1一段压差",
+        project_id: 46,
+      },
+      {
+        name: "余氯",
+        value: "",
+        deviceId: "1436022785",
+        deviceItems: "Skid_1_2nd_Stage_DP",
+        deviceName: "RO1二段压差",
+        project_id: 46,
+      },
+      {
+        name: "PH",
+        value: "",
+        deviceId: "1436022785",
+        deviceItems: "Skid_2_2nd_Stage_DP",
+        deviceName: "RO2二段压差",
+        project_id: 46,
+      },
+    ],
+    value: 0,
+  },
+
+  {
+    name: "监测点2",
+    position: { lng: 120.63814859657909, lat: 31.78603808271634 },
+    data: [
+      {
+        name: "浊度",
+        value: "11",
+        deviceId: "1436022785",
+        deviceItems: "Skid_1_1st_Stage_DP",
+        deviceName: "RO1一段压差",
+        project_id: 46,
+      },
+    ],
+    value: 50,
+  },
+  {
+    name: "监测点3",
+    position: { lng: 120.67528441284294, lat: 31.776567069187767 },
+    data: [
+      {
+        name: "浊度",
+        value: "11",
+        deviceId: "1436022785",
+        deviceItems: "Skid_1_1st_Stage_DP",
+        deviceName: "RO1一段压差",
+        project_id: 46,
+      },
+    ],
+    value: 20,
+  },
+  {
+    name: "监测点4",
+    position: { lng: 120.61788229509295, lat: 31.792679949152973 },
+    data: [
+      {
+        name: "浊度",
+        value: "11",
+        deviceId: "1436022785",
+        deviceItems: "Skid_1_1st_Stage_DP",
+        deviceName: "RO1一段压差",
+        project_id: 46,
+      },
+    ],
+    value: 90,
+  },
+  {
+    name: "监测点5",
+    position: { lng: 120.64299239870044, lat: 31.771555311429843 },
+    data: [
+      {
+        name: "浊度",
+        value: "11",
+        deviceId: "1436022785",
+        deviceItems: "Skid_1_1st_Stage_DP",
+        deviceName: "RO1一段压差",
+        project_id: 46,
+      },
+    ],
+    value: 80,
+  },
+  {
+    name: "监测点6",
+    position: { lng: 120.67377745218297, lat: 31.787739083321107 },
+    data: [
+      {
+        name: "浊度",
+        value: "11",
+        deviceId: "1436022785",
+        deviceItems: "Skid_1_1st_Stage_DP",
+        deviceName: "RO1一段压差",
+        project_id: 46,
+      },
+    ],
+    value: 60,
+  },
+];
+
+const pipeData = [
+  {
+    geometry: {
+      type: "LineString",
+      coordinates: [
+        [120.76320738823746, 31.741432990607994],
+        [120.67528441284294, 31.776567069187767],
+      ],
+    },
+    properties: {
+      start: "监测点1",
+      end: "监测点3",
+    },
+  },
+  {
+    geometry: {
+      type: "LineString",
+      coordinates: [
+        [120.67528441284294, 31.776567069187767],
+        [120.63814859657909, 31.78603808271634],
+      ],
+    },
+    properties: {
+      start: "监测点3",
+      end: "监测点2",
+    },
+  },
+  {
+    geometry: {
+      type: "LineString",
+      coordinates: [
+        [120.63814859657909, 31.78603808271634],
+        [120.61788229509295, 31.792679949152973],
+      ],
+    },
+    properties: {
+      start: "监测点2",
+      end: "监测点4",
+    },
+  },
+  {
+    geometry: {
+      type: "LineString",
+      coordinates: [
+        [120.63804095653205, 31.786635735178557],
+        [120.63265895417499, 31.799277469243197],
+        [120.63874061683849, 31.800472597396833],
+      ],
+    },
+  },
+  {
+    geometry: {
+      type: "LineString",
+      coordinates: [
+        [120.63814859657909, 31.78603808271634],
+        [120.64299239870044, 31.771555311429843],
+      ],
+    },
+    properties: {
+      start: "监测点2",
+      end: "监测点5",
+    },
+  },
+  {
+    geometry: {
+      type: "LineString",
+      coordinates: [
+        [120.67528441284294, 31.776567069187767],
+        [120.67377745218297, 31.787739083321107],
+      ],
+    },
+    properties: {
+      start: "监测点3",
+      end: "监测点6",
+    },
+  },
+  {
+    geometry: {
+      type: "LineString",
+      coordinates: [
+        [120.67523059281936, 31.775785436942982],
+        [120.67458475253653, 31.761944843898444],
+      ],
+    },
+  },
+  {
+    geometry: {
+      type: "LineString",
+      coordinates: [
+        [120.63954791719192, 31.781624528379645],
+        [120.61979596854141, 31.780567082731945],
+      ],
+    },
+  },
+  {
+    geometry: {
+      type: "LineString",
+      coordinates: [
+        [120.64310003874758, 31.771509330731554],
+        [120.63201311389199, 31.77242894031243],
+        [120.62786897207705, 31.77311864144008],
+      ],
+    },
+  },
+];
+
+class BMap extends PureComponent {
+  constructor(props) {
+    super(props);
+    this.state = {
+      position: {},
+      active: 1,
+      visible: false,
+      currentData: {},
+      pipe: [],
+      pointData: [...data],
+      layer: getLayer(pipeData, data),
+    };
+  }
+  lineLayer = null;
+
+  componentDidMount() {}
+
+  onClickLine(e, index) {
+    console.log(e, index);
+    e.cancelBubble = true;
+    this.setState({
+      active: index,
+      visible: true,
+      position: { top: e.pixel.y + "px", left: e.pixel.x + "px" },
+      currentData: {
+        name: `管道${index}`,
+        data: [
+          {
+            name: "浊度",
+            value: "11",
+            deviceId: "1436022785",
+            deviceItems: "Skid_1_1st_Stage_DP",
+            deviceName: "RO1一段压差",
+            project_id: 46,
+          },
+          {
+            name: "余氯",
+            value: "11",
+            deviceId: "1436022785",
+            deviceItems: "Skid_1_2nd_Stage_DP",
+            deviceName: "RO1二段压差",
+            project_id: 46,
+          },
+          {
+            name: "PH",
+            value: "1",
+            deviceId: "1436022785",
+            deviceItems: "Skid_2_2nd_Stage_DP",
+            deviceName: "RO2二段压差",
+            project_id: 46,
+          },
+        ],
+      },
+    });
+  }
+
+  showInfo(e, item) {
+    const { currentData } = this.state;
+    e.stopPropagation();
+    if (currentData == item) {
+      this.setState({
+        visible: false,
+      });
+    } else {
+      this.setState({
+        visible: true,
+        currentData: item,
+        position: { top: e.pageY - 20 + "px", left: e.pageX + 20 + "px" },
+      });
+    }
+  }
+
+  setPipe() {
+    const { pipe } = this.state;
+    this.setState({
+      edit: 1,
+      pipe: [
+        ...pipe,
+        {
+          geometry: {
+            type: "LineString",
+            coordinates: [],
+          },
+        },
+      ],
+    });
+  }
+  setPoint() {}
+
+  save() {
+    const { pipe } = this.state;
+    console.log(JSON.stringify(pipe));
+  }
+
+  mapOnClick(e) {
+    const { edit, pipe } = this.state;
+    if (edit == 1) {
+      var current = pipe[pipe.length - 1];
+      const { lat, lng } = e.latlng;
+      current.geometry.coordinates.push([lng, lat]);
+
+      this.setState({
+        pipe: [...pipe],
+        visible: false,
+      });
+    } else {
+      this.setState({
+        visible: false,
+      });
+    }
+  }
+
+  render() {
+    const { visible, position, currentData, active, layer, pointData } =
+      this.state;
+
+    return (
+      <div
+        style={{
+          position: "absolute",
+          left: 0,
+          top: 0,
+          height: "100vh",
+          width: "100vw",
+          zIndex: 0,
+        }}
+      >
+        <Map
+          style={{
+            width: "100%",
+            height: "100%",
+          }}
+          center={new window.BMapGL.Point(120.60315172059, 31.7329254736496)}
+          minZoom={12}
+          zoom={11}
+          mapStyleV2={{
+            styleJson,
+          }}
+          enableScrollWheelZoom
+          onClick={(e) => this.mapOnClick(e)}
+        >
+          {pointData.map((item, index) => (
+            <Point
+              key={`${item}_${index}`}
+              title={item.value}
+              position={item.position}
+              data={item.data}
+              onClick={(e) => this.showInfo(e, item)}
+            />
+          ))}
+          <MapvglView>
+            {layer.map((item) => (
+              <MapvglLayer
+                type="LineRainbowLayer"
+                data={[item]}
+                options={{
+                  color: item.color,
+                  style: "road", // road, arrow, normal
+                  width: 4,
+                }}
+              />
+            ))}
+          </MapvglView>
+        </Map>
+        {visible && (
+          <InfoBox
+            position={position}
+            title={currentData.name}
+            dataPump={currentData.data}
+          />
+        )}
+        <Legend
+          list={[
+            { type: 1, name: "COD" },
+            { type: 2, name: "PH" },
+          ]}
+          active={active}
+          onClick={(active) => this.setState({ active: active })}
+        />
+      </div>
+    );
+  }
+}
+
+function getLayer(pipeData, pointData) {
+  var pointMap = new window.Map();
+
+  pointData.forEach((point) => {
+    pointMap.set(point.name, point);
+  });
+  pipeData.forEach((pipe) => {
+    let start = pointMap.get(pipe.properties?.start),
+      end = pointMap.get(pipe.properties?.end);
+
+    if (start) {
+      // 根据监测点数据设置渐变色
+      pipe.color = [
+        getGradientColor(start.value),
+        getGradientColor(end?.value || start.value),
+      ];
+    } else {
+      // 默认蓝色
+      pipe.color = ["#0000ff", "#0000ff"];
+    }
+  });
+  return pipeData;
+}
+function getGradientColor(percent) {
+  var startColor = [0, 0, 255]; // 蓝色 渐变开始的颜色
+  var maxEndColor = [255, 0, 0]; // 红色  渐变最大结束的颜色
+
+  var r = Math.round(
+    startColor[0] + (maxEndColor[0] - startColor[0]) * (percent / 100)
+  );
+  var g = Math.round(
+    startColor[1] + (maxEndColor[1] - startColor[1]) * (percent / 100)
+  );
+  var b = Math.round(
+    startColor[2] + (maxEndColor[2] - startColor[2]) * (percent / 100)
+  );
+
+  var endColor =
+    "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
+  return endColor;
+}
+
+function componentToHex(c) {
+  var hex = c.toString(16);
+  return hex.length === 1 ? "0" + hex : hex;
+}
+
+export default BMap;

+ 61 - 0
src/components/Pine/Point.js

@@ -0,0 +1,61 @@
+import React, { PureComponent } from "react";
+import { CustomOverlay } from "react-bmapgl";
+import styled from "styled-components";
+import img1 from "../../assets/icon1.jpg";
+
+class Project extends PureComponent {
+  constructor(props) {
+    super(props);
+    this.state = { visible: false };
+  }
+
+  toggleInfo() {
+    if (!this.props.data) return;
+    this.setState({
+      visible: !this.state.visible,
+    });
+  }
+  render() {
+    const { position, title, onClick } = this.props;
+    return (
+      <CustomOverlay position={position}>
+        <Box>
+          <div className="text">{title}</div>
+          <div onClick={(e) => onClick(e)} className={`icon iconWater`}></div>
+        </Box>
+      </CustomOverlay>
+    );
+  }
+}
+
+const Box = styled.div`
+  position: relative;
+  text-align: center;
+
+  .text {
+    padding: 4px 10px;
+    white-space: nowrap;
+    background-color: rgba(8, 41, 75, 0.7);
+    color: #fff;
+    position: absolute;
+    bottom: 120%;
+    left: 50%;
+    transform: translateX(-50%);
+    max-width: 100px;
+  }
+
+  .icon {
+    width: 30px;
+    height: 30px;
+    margin: auto;
+    background-size: 100% 100%;
+    background-position: center;
+    background-repeat: no-repeat;
+  }
+
+  .iconWater {
+    background-image: url(${img1});
+  }
+`;
+
+export default Project;

+ 19 - 0
src/components/Pine/indexCenter.js

@@ -0,0 +1,19 @@
+// 污水
+import React, { PureComponent } from "react";
+import { CenterPage } from "../PineNet/style";
+import PineMap from "./PineMap";
+
+class index extends PureComponent {
+  constructor(props) {
+    super(props);
+  }
+  render() {
+    return (
+      <CenterPage>
+        <PineMap />
+      </CenterPage>
+    );
+  }
+}
+
+export default index;

+ 2 - 0
src/router.jsx

@@ -8,6 +8,7 @@ import WaterSupply from "./routes/WaterSupply";
 import { Iconstyle } from "./assets/icon/iconfont";
 import { Globalstyle } from "./style/global.js";
 import FloodControl from "./routes/FloodControl";
+import Pine from "./routes/Pine";
 
 function RouterConfig({ history }) {
   const route = () => {
@@ -24,6 +25,7 @@ function RouterConfig({ history }) {
           <Route path="/water-supply" exact component={WaterSupply} />
           <Route path="/sewage" exact component={Sewage} />
           <Route path="/pine-net" exact component={PineNet} />
+          <Route path="/pine" exact component={Pine} />
           <Route path="/pump-station" exact component={PumpStation} />
           <Route path="/flood-control" exact component={FloodControl} />
         </Switch>

+ 33 - 0
src/routes/Pine.jsx

@@ -0,0 +1,33 @@
+// 污水
+import React, { Component } from "react";
+import { connect } from "dva";
+import { IndexPageStyle, IndexPageContent } from "./style";
+import TopPage from "../components/topPage";
+import PineNetLeft from "../components/PineNet/indexLeft";
+import PineNetRight from "../components/PineNet/indexRight";
+import Nav from "../components/Nav";
+
+
+import PineCenter from "../components/Pine/indexCenter";
+
+class Pine extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {};
+  }
+  render() {
+    return (
+      <IndexPageStyle>
+        <TopPage />
+        <IndexPageContent>
+          <PineNetLeft />
+          <PineCenter className="center-page" />
+          <PineNetRight />
+        </IndexPageContent>
+        <Nav />
+      </IndexPageStyle>
+    );
+  }
+}
+
+export default connect()(Pine);

+ 7 - 0
src/services/index.js

@@ -2329,3 +2329,10 @@ export const getRightPageData = async () => {
     },
   };
 };
+
+export async function getDeviceRealData(params) {
+  return request(`/jinke-cloud/device/current-data`, {
+    method: "POST",
+    body: params,
+  });
+}

+ 18 - 0
yarn.lock

@@ -2,6 +2,14 @@
 # yarn lockfile v1
 
 
+"@ahooksjs/use-request@^2.8.15":
+  version "2.8.15"
+  resolved "https://registry.npmmirror.com/@ahooksjs/use-request/-/use-request-2.8.15.tgz#daa32a8395ba75e8deb9f4fde4e221a4a8f525db"
+  integrity sha512-xhVaM4fyIiAMdVFuuU5i3CFUdFa/IblF+fvITVMFaUEO3w/V5tVCAF6WIA3T03n1/RPuzRkA7Ao1PFtSGtGelw==
+  dependencies:
+    lodash.debounce "^4.0.8"
+    lodash.throttle "^4.1.1"
+
 "@ampproject/remapping@^2.2.0":
   version "2.2.0"
   resolved "https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"
@@ -8711,6 +8719,11 @@ lodash.camelcase@^4.3.0:
   resolved "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
   integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
 
+lodash.debounce@^4.0.8:
+  version "4.0.8"
+  resolved "https://registry.npmmirror.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
+  integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
+
 lodash.defaults@^4.2.0:
   version "4.2.0"
   resolved "https://registry.npmmirror.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
@@ -8761,6 +8774,11 @@ lodash.templatesettings@^4.0.0:
   dependencies:
     lodash._reinterpolate "^3.0.0"
 
+lodash.throttle@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.npmmirror.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
+  integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==
+
 lodash.uniq@^4.5.0:
   version "4.5.0"
   resolved "https://registry.npmmirror.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"