소스 검색

项目代码

zhaojijng 2 년 전
부모
커밋
915342762e
89개의 변경된 파일7407개의 추가작업 그리고 0개의 파일을 삭제
  1. 2 0
      .env.development
  2. 2 0
      .env.production
  3. 2 0
      .env.zhijiang
  4. 24 0
      .gitignore
  5. 3 0
      .vscode/extensions.json
  6. 13 0
      index.html
  7. 3419 0
      package-lock.json
  8. 36 0
      package.json
  9. 1 0
      public/vite.svg
  10. 38 0
      src/App.vue
  11. 182 0
      src/api/index.ts
  12. BIN
      src/assets/font/Persagy Bold.otf
  13. BIN
      src/assets/font/Persagy Bold.woff
  14. BIN
      src/assets/font/Persagy Bold.woff2
  15. BIN
      src/assets/font/Persagy Regular.otf
  16. BIN
      src/assets/font/Persagy Regular.woff
  17. BIN
      src/assets/font/Persagy Regular.woff2
  18. BIN
      src/assets/font/PersagyBold.ttf
  19. BIN
      src/assets/font/PersagyBold2.ttf
  20. BIN
      src/assets/font/PersagyRegular.ttf
  21. BIN
      src/assets/font/PersagyRegular2.ttf
  22. BIN
      src/assets/image/horImg/bluegreen.png
  23. BIN
      src/assets/image/horImg/bluelight.png
  24. 7 0
      src/assets/image/horImg/changeHor.svg
  25. 7 0
      src/assets/image/horImg/changeVer.svg
  26. BIN
      src/assets/image/horImg/floor_co2.png
  27. BIN
      src/assets/image/horImg/floor_co2_ver.png
  28. BIN
      src/assets/image/horImg/floor_jiaquan.png
  29. BIN
      src/assets/image/horImg/floor_jiaquan_ver.png
  30. BIN
      src/assets/image/horImg/floor_pm25.png
  31. BIN
      src/assets/image/horImg/floor_pm25_ver.png
  32. BIN
      src/assets/image/horImg/floor_shidu.png
  33. BIN
      src/assets/image/horImg/floor_shidu_ver.png
  34. BIN
      src/assets/image/horImg/floor_wendu.png
  35. BIN
      src/assets/image/horImg/floor_wendu_ver.png
  36. BIN
      src/assets/image/horImg/greenlight.png
  37. BIN
      src/assets/image/horImg/hor_big_bg.png
  38. BIN
      src/assets/image/horImg/lastAllLight.png
  39. 3 0
      src/assets/image/horImg/lastGold.svg
  40. 3 0
      src/assets/image/horImg/lastGray.svg
  41. BIN
      src/assets/image/horImg/lastco2.png
  42. BIN
      src/assets/image/horImg/lasthumidity.png
  43. BIN
      src/assets/image/horImg/lastmethanal.png
  44. BIN
      src/assets/image/horImg/lastpm25.png
  45. BIN
      src/assets/image/horImg/lasttemp.png
  46. 95 0
      src/assets/image/horImg/persagyLogo.svg
  47. BIN
      src/assets/image/horImg/redlight.png
  48. BIN
      src/assets/image/horImg/redyellow.png
  49. BIN
      src/assets/image/horImg/saveCarbon.png
  50. BIN
      src/assets/image/horImg/saveCo2.png
  51. BIN
      src/assets/image/horImg/saveEnergy.mov
  52. BIN
      src/assets/image/horImg/saveLight.png
  53. BIN
      src/assets/image/horImg/saveTree.png
  54. BIN
      src/assets/image/horImg/twoLight.png
  55. BIN
      src/assets/image/horImg/xxx.gif
  56. BIN
      src/assets/image/horImg/yellowgreen.png
  57. BIN
      src/assets/image/horImg/yellowlight.png
  58. BIN
      src/assets/image/horImg/zhijianglogo.png
  59. 1 0
      src/assets/vue.svg
  60. 715 0
      src/components/HorFloorSpace.vue
  61. 168 0
      src/components/LastAllEnergy.vue
  62. 227 0
      src/components/LastMonthData.vue
  63. 159 0
      src/components/LastSaveEnergy.vue
  64. 35 0
      src/components/MyButton.vue
  65. 209 0
      src/components/NowData.vue
  66. 268 0
      src/components/TemChart.vue
  67. 170 0
      src/components/airSwitchHor.vue
  68. 98 0
      src/components/airSwitchVer.vue
  69. 274 0
      src/components/lastEnergyChart.vue
  70. 155 0
      src/components/pageHead.vue
  71. 11 0
      src/main.ts
  72. 50 0
      src/router/index.ts
  73. 54 0
      src/store/useProjectStore.ts
  74. 63 0
      src/style.scss
  75. 8 0
      src/types/service/index.ts
  76. 69 0
      src/utils/dapingImage.ts
  77. 212 0
      src/utils/publicMethod.ts
  78. 93 0
      src/utils/request.ts
  79. 12 0
      src/utils/tcookies.ts
  80. 24 0
      src/utils/useAirSwitch.ts
  81. 11 0
      src/utils/useCouter.ts
  82. 19 0
      src/utils/useLocalStorage.ts
  83. 218 0
      src/views/horiScreen/index.vue
  84. 23 0
      src/views/login/index.vue
  85. 138 0
      src/views/verScreen/index.vue
  86. 7 0
      src/vite-env.d.ts
  87. 23 0
      tsconfig.json
  88. 9 0
      tsconfig.node.json
  89. 47 0
      vite.config.ts

+ 2 - 0
.env.development

@@ -0,0 +1,2 @@
+VITE_BASE_API='/sgdaping'
+VITE_TARGET_HOST='https://duoduoenv.sagacloud.cn/'

+ 2 - 0
.env.production

@@ -0,0 +1,2 @@
+VITE_BASE_API='/sgdaping'
+VITE_TARGET_HOST='https://duoduoenv.sagacloud.cn/'

+ 2 - 0
.env.zhijiang

@@ -0,0 +1,2 @@
+VITE_BASE_API='/sgdaping'
+VITE_TARGET_HOST='https://duoduoenv.sagacloud.cn/'

+ 24 - 0
.gitignore

@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

+ 3 - 0
.vscode/extensions.json

@@ -0,0 +1,3 @@
+{
+  "recommendations": ["Vue.volar"]
+}

+ 13 - 0
index.html

@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>daping</title>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.ts"></script>
+  </body>
+</html>

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 3419 - 0
package-lock.json


+ 36 - 0
package.json

@@ -0,0 +1,36 @@
+{
+  "name": "vite-project",
+  "private": true,
+  "version": "0.0.0",
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "dev:zhijiang": "vite serve --mode zhijiang",
+    "build": "vite build",
+    "preview": "vite preview"
+  },
+  "dependencies": {
+    "@antv/data-set": "^0.11.8",
+    "@antv/g2": "^4.2.7",
+    "axios": "^0.27.2",
+    "dotenv": "^16.0.2",
+    "element-plus": "^2.2.15",
+    "js-cookie": "^3.0.1",
+    "moment": "^2.29.4",
+    "pinia": "^2.0.21",
+    "vue": "^3.2.37"
+  },
+  "devDependencies": {
+    "@types/js-cookie": "^3.0.2",
+    "@types/node": "^18.7.14",
+    "@vitejs/plugin-vue": "^3.0.3",
+    "node-sass": "^7.0.1",
+    "path": "^0.12.7",
+    "sass": "^1.54.6",
+    "sass-loader": "^13.0.2",
+    "typescript": "^4.6.4",
+    "vite": "^3.0.7",
+    "vue-router": "^4.1.5",
+    "vue-tsc": "^0.39.5"
+  }
+}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 0
public/vite.svg


+ 38 - 0
src/App.vue

@@ -0,0 +1,38 @@
+<script lang="ts">
+import { ref, defineComponent, reactive, toRefs, watch, onMounted } from "vue";
+import useProjectStore from "@/store/useProjectStore";
+
+export default defineComponent({
+    setup() {
+        const projectStore = useProjectStore();
+        onMounted(() => {
+            //这两个请求不能写在这里 router.beforeEach 发生在后面,其中有 改变projectId的方法
+            // projectStore.setWeather();
+            // projectStore.setProjectObj();
+        });
+
+        watch(projectStore.$state, (nstate, ostate) => {
+            //console.log(nstate.projectId, ostate.projectId);
+           // debugger;
+        });
+    },
+});
+</script>
+
+<template>
+    <router-view></router-view>
+</template>
+
+<style scoped lang="scss">
+
+#app {
+    font-family: Avenir, Helvetica, Arial, sans-serif;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+  
+    // background: #f3fdff;
+    //   text-align: center;
+    //   color: #2c3e50;
+    //   margin-top: 60px;
+}
+</style>

+ 182 - 0
src/api/index.ts

@@ -0,0 +1,182 @@
+import request from "@/utils/request";
+import { seasonTypeParam, mapParam } from "@/types/service/index";
+import useProjectStore from "@/store/useProjectStore";
+import moment from "moment";
+export const getWeather = () => {
+    const projectStore = useProjectStore();
+    //debugger;
+    return request({
+        url:
+            "/duoduo-service/object-service/weather/getCurrent?projectId=" +
+            projectStore.projectId,
+        method: "GET",
+        headers: {
+            "Content-Type": "application/json",
+        },
+    });
+};
+
+export const getProjectObj = () => {
+    const projectStore = useProjectStore();
+
+    return request({
+        url: "/duoduo-service/object-service/object/project/query",
+        method: "POST",
+        headers: {
+            "Content-Type": "application/json",
+        },
+        data: {
+            criteria: {
+                id: projectStore.projectId,
+            },
+        },
+    });
+};
+//实时数据
+export const queryEnvCurrent = () => {
+    const projectStore = useProjectStore();
+    return request({
+        url:
+            "/duoduo-service/setup-service/environment/queryEnvCurrent?projectId=" +
+            projectStore.projectId,
+        method: "GET",
+        headers: {
+            "Content-Type": "application/json",
+        },
+    });
+};
+//上月数据
+export const queryEnvHistory = () => {
+    const projectStore = useProjectStore();
+    return request({
+        url:
+            "/duoduo-service/setup-service/environment/queryEnvHistory?projectId=" +
+            projectStore.projectId,
+        method: "GET",
+        headers: {
+            "Content-Type": "application/json",
+        },
+    });
+};
+//空调状态
+export const queryConditionerStatus = () => {
+    const projectStore = useProjectStore();
+    return request({
+        url:
+            "/duoduo-service/setup-service/environment/queryConditionerStatus?projectId=" +
+            projectStore.projectId,
+        method: "GET",
+        headers: {
+            "Content-Type": "application/json",
+        },
+    });
+};
+
+//实时温度
+export const queryIndoorTempList = () => {
+    const projectStore = useProjectStore();
+    return request({
+        url:
+            "/duoduo-service/setup-service/environment/queryIndoorTempList?projectId=" +
+            projectStore.projectId,
+        method: "GET",
+        headers: {
+            "Content-Type": "application/json",
+        },
+    });
+};
+
+//查询建筑
+export const queryBuilding = () => {
+    const projectStore = useProjectStore();
+    return request({
+        url: "/duoduo-service/object-service/object/building/query",
+        method: "POST",
+        headers: {
+            "Content-Type": "application/json",
+        },
+        data: {
+            criteria: {
+                projectId: projectStore.projectId,
+            },
+        },
+    });
+};
+
+//查询楼
+export const queryFs = (data: any) => {
+    const projectStore = useProjectStore();
+    return request({
+        url: "/duoduo-service/object-service/object/floor/queryFs",
+        method: "POST",
+        headers: {
+            "Content-Type": "application/json",
+        },
+        data: data,
+    });
+};
+
+//查询楼参数
+export const queryParam = (
+    endStr: string,
+    startStr: string,
+    param: string,
+    data: any
+) => {
+    const projectStore = useProjectStore();
+    return request({
+        url: `/duoduo-service/object-service/object/floor/queryParam?endTime=${endStr}&startTime=${startStr}&param=${param}`,
+        method: "POST",
+        headers: {
+            "Content-Type": "application/json",
+        },
+        data: data,
+    });
+};
+
+// 上月所有能耗数据
+export const queryLastEnergy = () => {
+    const projectStore = useProjectStore();
+    var monthTime = moment().subtract(1, "month");
+    var monthTimeStr = monthTime.format("YYYYMM");
+
+    return request({
+        url: "/duoduo-service/review-service/sceneValue/query",
+        method: "POST",
+        headers: {
+            "Content-Type": "application/json",
+        },
+        data: {
+            criteria: {
+                projectId: projectStore.projectId,
+                yyyymm: monthTimeStr,
+            },
+        },
+    });
+};
+
+//上月每日能耗
+export const queryLastDayEnergy = () => {
+    const projectStore = useProjectStore();
+    var start = moment()
+        .subtract(1, "months")
+        .startOf("month")
+        .format("YYYYMMDD");
+    var end = moment().subtract(1, "months").endOf("month").format("YYYYMMDD");
+    return request({
+        url: "/duoduo-service/review-service/energy/week/day/query",
+        method: "POST",
+        headers: {
+            "Content-Type": "application/json",
+        },
+        data: {
+            criteria: {
+                projectId: projectStore.projectId,
+                date: {
+                    $gte: start,
+                    $lte: end,
+                },
+            },
+        },
+    });
+};

BIN
src/assets/font/Persagy Bold.otf


BIN
src/assets/font/Persagy Bold.woff


BIN
src/assets/font/Persagy Bold.woff2


BIN
src/assets/font/Persagy Regular.otf


BIN
src/assets/font/Persagy Regular.woff


BIN
src/assets/font/Persagy Regular.woff2


BIN
src/assets/font/PersagyBold.ttf


BIN
src/assets/font/PersagyBold2.ttf


BIN
src/assets/font/PersagyRegular.ttf


BIN
src/assets/font/PersagyRegular2.ttf


BIN
src/assets/image/horImg/bluegreen.png


BIN
src/assets/image/horImg/bluelight.png


+ 7 - 0
src/assets/image/horImg/changeHor.svg

@@ -0,0 +1,7 @@
+<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="2.625" y="4.375" width="13.125" height="20.125" rx="1.75" stroke="#575271" stroke-width="1.6"/>
+<rect x="7" y="20.125" width="4.375" height="1.6" rx="0.8" fill="#575271"/>
+<path d="M18.375 14H23.625C24.5915 14 25.375 14.7835 25.375 15.75V22.75C25.375 23.7165 24.5915 24.5 23.625 24.5H18.375" stroke="#575271" stroke-width="1.6" stroke-linecap="round"/>
+<path d="M23.625 10.625C23.625 8.20875 21.6662 6.25 19.25 6.25" stroke="#575271" stroke-width="1.6" stroke-linecap="round"/>
+<path d="M23.2277 12.2474C23.3123 12.3207 23.4377 12.3207 23.5223 12.2474L25.8416 10.2388C25.9991 10.1025 25.9027 9.84375 25.6943 9.84375H21.0557C20.8473 9.84375 20.7509 10.1025 20.9084 10.2388L23.2277 12.2474Z" fill="#575271"/>
+</svg>

+ 7 - 0
src/assets/image/horImg/changeVer.svg

@@ -0,0 +1,7 @@
+<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="2.625" y="4.375" width="13.125" height="20.125" rx="1.75" stroke="#575271" stroke-width="1.6"/>
+<rect x="7" y="20.125" width="4.375" height="1.6" rx="0.8" fill="#575271"/>
+<path d="M18.375 14H23.625C24.5915 14 25.375 14.7835 25.375 15.75V22.75C25.375 23.7165 24.5915 24.5 23.625 24.5H18.375" stroke="#575271" stroke-width="1.6" stroke-linecap="round"/>
+<path d="M24.625 10.625C24.625 8.20875 22.6662 6.25 20.25 6.25" stroke="#575271" stroke-width="1.6" stroke-linecap="round"/>
+<path d="M18.1276 6.2277C18.0543 6.31225 18.0543 6.43775 18.1276 6.5223L20.1362 8.84163C20.2725 8.99911 20.5312 8.90266 20.5312 8.69434L20.5312 4.05566C20.5312 3.84734 20.2725 3.75089 20.1362 3.90837L18.1276 6.2277Z" fill="#575271"/>
+</svg>

BIN
src/assets/image/horImg/floor_co2.png


BIN
src/assets/image/horImg/floor_co2_ver.png


BIN
src/assets/image/horImg/floor_jiaquan.png


BIN
src/assets/image/horImg/floor_jiaquan_ver.png


BIN
src/assets/image/horImg/floor_pm25.png


BIN
src/assets/image/horImg/floor_pm25_ver.png


BIN
src/assets/image/horImg/floor_shidu.png


BIN
src/assets/image/horImg/floor_shidu_ver.png


BIN
src/assets/image/horImg/floor_wendu.png


BIN
src/assets/image/horImg/floor_wendu_ver.png


BIN
src/assets/image/horImg/greenlight.png


BIN
src/assets/image/horImg/hor_big_bg.png


BIN
src/assets/image/horImg/lastAllLight.png


+ 3 - 0
src/assets/image/horImg/lastGold.svg

@@ -0,0 +1,3 @@
+<svg width="6" height="15" viewBox="0 0 6 15" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="2" height="15" fill="#FFDCAF"/>
+</svg>

+ 3 - 0
src/assets/image/horImg/lastGray.svg

@@ -0,0 +1,3 @@
+<svg width="6" height="15" viewBox="0 0 6 15" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="2" height="15" fill="#70768B"/>
+</svg>

BIN
src/assets/image/horImg/lastco2.png


BIN
src/assets/image/horImg/lasthumidity.png


BIN
src/assets/image/horImg/lastmethanal.png


BIN
src/assets/image/horImg/lastpm25.png


BIN
src/assets/image/horImg/lasttemp.png


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 95 - 0
src/assets/image/horImg/persagyLogo.svg


BIN
src/assets/image/horImg/redlight.png


BIN
src/assets/image/horImg/redyellow.png


BIN
src/assets/image/horImg/saveCarbon.png


BIN
src/assets/image/horImg/saveCo2.png


BIN
src/assets/image/horImg/saveEnergy.mov


BIN
src/assets/image/horImg/saveLight.png


BIN
src/assets/image/horImg/saveTree.png


BIN
src/assets/image/horImg/twoLight.png


BIN
src/assets/image/horImg/xxx.gif


BIN
src/assets/image/horImg/yellowgreen.png


BIN
src/assets/image/horImg/yellowlight.png


BIN
src/assets/image/horImg/zhijianglogo.png


+ 1 - 0
src/assets/vue.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

+ 715 - 0
src/components/HorFloorSpace.vue

@@ -0,0 +1,715 @@
+<template>
+    <div
+        class="floorSpace"
+        :class="[screenType === 'hor' ? 'horiFloorClass ' : 'verFloorClass ']"
+    >
+        <div class="buildName" v-show="allBuild.length">
+            {{ nowBuildName }}
+        </div>
+        <div class="leftChange" v-if="screenType == 'hor'">
+            <div class="allIndicator">
+                <div
+                    class="showItem"
+                    v-bind:style="{
+                        top: selIndicator.index * 16 + '%',
+                    }"
+                >
+                    <div class="title">{{ selIndicator.name }}</div>
+                    <div class="textCont">
+                        <span class="value"
+                            >{{ totalAvgValues }}{{ selIndicator.unit }}</span
+                        ><br /><span class="name"
+                            >平均{{ selIndicator.name }}</span
+                        >
+                    </div>
+                    <div class="other">
+                        <img class="img" :src="selIndicator.img" />
+                    </div>
+                </div>
+                <div
+                    class="eachItem"
+                    v-for="(item, index) in allIndicator"
+                    @click="clickIndicator(index)"
+                    v-bind:class="{ select: item.id == selIndicator.id }"
+                >
+                    <div class="title">{{ item.name }}</div>
+                    <!-- <div class="textCont" v-show="item.id == selIndicator.id">
+                        <span class="value"
+                            >{{ totalAvgValues }}{{ selIndicator.unit }}</span
+                        ><br /><span class="name"
+                            >平均{{ selIndicator.name }}</span
+                        >
+                    </div>
+                    <img
+                        v-show="item.id == selIndicator.id"
+                        class="img"
+                        :src="selIndicator.img"
+                    /> -->
+                </div>
+            </div>
+        </div>
+        <div class="topChange" v-if="screenType == 'ver'">
+            <div class="allIndicator">
+                <div
+                    class="eachItem"
+                    v-for="(item, index) in allIndicator"
+                    @click="clickIndicator(index)"
+                    v-bind:class="{ select: item.id == selIndicator.id }"
+                >
+                    <span>{{ item.name }}</span>
+                    <!-- <img
+                        class="bar"
+                        src="@/assets/image/horImg/lastAllLight.png"
+                    /> -->
+                </div>
+            </div>
+            <div class="imageDiv">
+                <img :src="selIndicator.verimg" />
+            </div>
+            <div class="textCont">
+                平均<span>{{ selIndicator.name }}</span
+                ><span class="value">{{ totalAvgValues }}</span
+                ><span>
+                    {{ selIndicator.unit }}
+                </span>
+            </div>
+        </div>
+        <div class="floorWrap" id="floorWrap">
+            <div
+                class="floor-item"
+                v-for="(item, index) in showFloors"
+                :key="index"
+                v-bind:style="{ height: item.floorHeight + 'px' }"
+            >
+                <div class="floor-num">
+                    <span>{{ item.localName }}</span>
+                </div>
+                <div class="floor-space">
+                    <div
+                        class="space-box"
+                        v-for="(childItem, id) in item.dataSpaces"
+                        :key="id"
+                        v-bind:style="{
+                            width: item.spacewidth + '%',
+                            height: item.spaceheight + '%',
+                        }"
+                    >
+                        <div
+                            class="space-name"
+                            v-bind:style="{
+                                backgroundColor: selectColor(
+                                    childItem.avgValues,
+                                    selIndicatorId,
+                                    true
+                                ),
+                            }"
+                        >
+                            {{ childItem.localName }}
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+<script lang="ts">
+import { ref, defineComponent, reactive, toRefs, onMounted } from "vue";
+import { queryBuilding, queryFs, queryParam } from "@/api/index";
+import useProjectStore from "@/store/useProjectStore";
+import { dapingImage } from "@/utils/dapingImage";
+import moment from "moment";
+import { selectColor } from "@/utils/publicMethod";
+
+export default defineComponent({
+    props: {
+        screenType: {
+            type: String,
+        },
+        showPing: {
+            type: Number,
+        },
+    },
+    setup(props, contx) {
+
+        const {
+            floor_co2,
+            floor_jiaquan,
+            floor_pm25,
+            floor_shidu,
+            floor_wendu,
+            floor_co2_ver,
+            floor_jiaquan_ver,
+            floor_pm25_ver,
+            floor_shidu_ver,
+            floor_wendu_ver,
+        } = dapingImage;
+        const projectStore = useProjectStore();
+        const allData = reactive({
+            selectColor: selectColor,
+            selIndicator: {},
+            selIndicatorId: "", //为了颜色用
+            //              温度
+            nowIndicatorIndex: null, //现在选中的指标 index
+            allIndicator: [
+                {
+                    id: "temp",
+                    index: 0,
+                    code: "Tdb",
+                    name: "温度",
+                    img: dapingImage.floor_wendu,
+                    verimg: dapingImage.floor_wendu_ver,
+                    unit: "℃",
+                    fixed: 1,
+                },
+                {
+                    id: "humidity",
+                    index: 1,
+                    code: "RH",
+                    name: "湿度",
+                    img: dapingImage.floor_shidu,
+                    verimg: dapingImage.floor_shidu_ver,
+                    unit: "%",
+                    fixed: 0,
+                },
+                {
+                    id: "co2",
+                    index: 2,
+                    code: "CO2",
+                    name: "CO₂",
+                    img: dapingImage.floor_co2,
+                    verimg: dapingImage.floor_co2_ver,
+                    unit: "ppm",
+                    fixed: 0,
+                },
+                {
+                    id: "methanal",
+                    index: 3,
+                    code: "HCHO",
+                    name: "甲醛",
+                    img: dapingImage.floor_jiaquan,
+                    verimg: dapingImage.floor_jiaquan_ver,
+                    unit: "mg/m³",
+                    fixed: 2,
+                },
+                {
+                    id: "pm25",
+                    index: 4,
+                    code: "PM2d5",
+                    name: "PM2.5",
+                    img: dapingImage.floor_pm25,
+                    verimg: dapingImage.floor_pm25_ver,
+                    unit: "ug/m³",
+                    fixed: 0,
+                },
+            ],
+            allBuild: [],
+            nowBuildName: "",
+            nowBuildPage: 1, //目前是第几个建筑
+
+            allFloor: [],
+            firstPageParams: [],
+            secondPageParams: [],
+            nowPage: 1, //当前哪一屏幕
+            pageNum: 0,
+            showFloors: [],
+            totalAvgValues: null,
+            hqueryBuild() {
+                queryBuilding()
+                    .then((res) => {
+                        var data = (res.data || {}).content || [];
+                        //debugger;
+                        if (projectStore.projectId == "Pj3301100002") {
+                            var filterdata = data.filter((item) => {
+                                return item.localName == "1#楼";
+                            });
+                            allData.allBuild = filterdata;
+                        } else {
+                            allData.allBuild = data;
+                        }
+
+                        allData.nowBuildPage = 1;
+
+                        allData.fqueryFs();
+                    })
+                    .catch((res) => {
+                        // loading.close();
+                    });
+            },
+            fqueryFs() {
+                //var loading = this.$loading({ fullscreen: true });
+                //debugger;
+                var buildId = (allData.allBuild[allData.nowBuildPage - 1] || {})
+                    .id; //当前的建筑id
+                if (!buildId) {
+                    return;
+                }
+
+                queryFs({
+                    criteria: {
+                        projectId: projectStore.projectId,
+                        buildingId: buildId,
+                    },
+                    size: 14, //最多14层
+                    page: 1,
+                    orders: [
+                        {
+                            column: "floorSequenceId",
+                            asc: true,
+                        },
+                    ],
+                })
+                    .then((res) => {
+                        // loading.close();
+                        var allFloor = res.data.content || [];
+                        allFloor = allFloor.filter(function (item) {
+                            return item.spaceNum > 0;
+                        });
+
+                        //如果该建筑的所有楼层 没有空间 则请求下一个建筑
+                        if (allFloor.length == 0) {
+                            //换下一栋楼
+                            allData.nowBuildPage = allData.nowBuildPage + 1;
+                            if (
+                                allData.nowBuildPage > allData.allBuild.length
+                            ) {
+                                contx.emit("donetowpage"); // 所有建筑切换完毕
+                                return;
+                            }
+                            allData.fqueryFs();
+                            return;
+                        }
+                        allData.nowBuildName =
+                            allData.allBuild[
+                                allData.nowBuildPage - 1
+                            ].localName;
+
+                        allData.allFloor = allFloor;
+                        var allFloorNum = allFloor.length;
+                        //如果超过7层 就显示两屏幕 第一屏 firstPageNum
+                        //如果超过7层 就显示两屏幕 第二屏 secondPageNum
+                        var firstPageNum, secondPageNum;
+                        if (allFloorNum <= 7) {
+                            firstPageNum = allFloorNum;
+                            secondPageNum = 0;
+                            allData.pageNum = 1;
+                        } else {
+                            firstPageNum = Math.ceil(allFloorNum / 2);
+                            secondPageNum = Math.floor(allFloorNum / 2);
+                            allData.pageNum = 2;
+                        }
+
+                        var firstMaxSpace = allData.floorHandle(firstPageNum); //第一屏 一层最多空间
+                        var sendMaxSpace = allData.floorHandle(secondPageNum);
+                        var firstPageFloors = allFloor.slice(0, firstPageNum); //第一屏 所有楼层
+                        var secondPageFloors = allFloor.slice(firstPageNum); //第二屏 所有楼层
+                        //第一屏的参数 第二屏的参数
+                        allData.firstPageParams = firstPageFloors.map(
+                            (item) => {
+                                var obj = {};
+                                obj.id = item.id;
+                                obj.projectId = projectStore.projectId;
+                                obj.spaceNum = firstMaxSpace; //最多空间数
+                                return obj;
+                            }
+                        );
+
+                        allData.secondPageParams = secondPageFloors.map(
+                            (item) => {
+                                var obj = {};
+                                obj.id = item.id;
+                                obj.projectId = projectStore.projectId;
+                                obj.spaceNum = sendMaxSpace;
+                                return obj;
+                            }
+                        );
+
+                        allData.nowIndicatorIndex = 0;
+                        //debugger;
+                        allData.getTimeFloorParam();
+                    })
+                    .catch(function (res) {
+                        // loading.close();
+                    });
+            },
+            getTimeFloorParam() {
+                //第一屏的参数 第二屏的参数
+                var floorparam =
+                    allData.nowPage == 1
+                        ? allData.firstPageParams
+                        : allData.secondPageParams;
+
+                allData.fqueryParam(floorparam).then(() => {
+                    var timeoutsign = setTimeout(() => {
+                        //debugger;
+                        allData.nowIndicatorIndex =
+                            allData.nowIndicatorIndex + 1; //湿度等指标的轮询变化
+                        if (allData.nowIndicatorIndex == 5) {
+                            if (allData.pageNum == allData.nowPage) {
+                                //如果指标轮询结束 通知切换
+
+                                allData.nowPage = 1;
+                                if (
+                                    allData.nowBuildPage ==
+                                    allData.allBuild.length
+                                ) {
+                                    contx.emit("donetowpage"); //todo
+                                    clearTimeout(timeoutsign);
+                                } else {
+                                    //换下一个建筑
+                                    allData.nowBuildPage =
+                                        allData.nowBuildPage + 1;
+                                    allData.fqueryFs();
+                                }
+                                return;
+                            }
+                            //如果是两页 并且nowPage是第一页
+                            if (allData.pageNum == 2 && allData.nowPage == 1) {
+                                allData.nowPage = 2;
+                                allData.nowIndicatorIndex = 0;
+                            }
+                        }
+                        allData.getTimeFloorParam();
+                    }, 2000);
+                });
+            },
+            fqueryParam(floorparam) {
+                var endTime = moment();
+                var startTime = moment().subtract(30, "minutes");
+                var startStr = startTime.format("YYYYMMDDHHmmss");
+                var endStr = endTime.format("YYYYMMDDHHmmss");
+                var newv = allData.nowIndicatorIndex;
+                //debugger;
+                allData.selIndicator = allData.allIndicator[newv];
+                var param = allData.selIndicator.code;
+
+                return queryParam(endStr, startStr, param, floorparam).then(
+                    (res) => {
+                        //loading.close();
+
+                        //debugger;
+                        var showFloors = res.data.data.floors || [];
+                        allData.totalAvgValues =
+                            res.data.data.avgValues || null;
+                        allData.totalAvgValues &&
+                            (allData.totalAvgValues =
+                                allData.totalAvgValues.toFixed(
+                                    allData.selIndicator.fixed
+                                ));
+                        var wrapHeight =
+                            document.getElementById("floorWrap") &&
+                            document.getElementById("floorWrap").offsetHeight;
+                        showFloors.forEach((ele) => {
+                            var filterFloorarr = allData.allFloor.filter(
+                                (item) => {
+                                    return item.id == ele.id;
+                                }
+                            );
+                            var filterFloor = filterFloorarr[0] || {};
+                            ele.name = filterFloor.name;
+                            ele.localId = filterFloor.localId;
+                            ele.localName = filterFloor.localName;
+                            var dataSpacesNum = (ele.dataSpaces || []).length;
+                            var floorParam = allData.spaceHandle(dataSpacesNum); //一行的个数
+
+                            ele.spacewidth = 100 / floorParam.lineNum;
+                            ele.spaceheight = 100 / floorParam.floorline; //每一行的高度
+                            ele.floorHeight = wrapHeight / showFloors.length; //每一层的高度
+                        });
+                        allData.showFloors = showFloors;
+                        allData.selIndicatorId = allData.selIndicator.id;
+                    }
+                );
+            },
+            spaceHandle(spaceNum) {
+                //返回一层 的每一行 几个房间
+                var lineNum = spaceNum; //一行的房间数
+                var floorline = Math.ceil(spaceNum / 14); //20-30 3排 30-40个 4排 所以一排10个
+                lineNum = Math.ceil(spaceNum / floorline);
+                return { lineNum, floorline };
+                //debugger;
+            },
+            floorHandle(floorNum) {
+                //返回一层 最多多少房间
+                var maxFloorSpace = 28; //一层 最多显示房间数
+                // switch (floorNum) {
+                //     case 1:
+                //         maxFloorSpace = 160;
+                //         break;
+                //     case 2:
+                //         maxFloorSpace = 80;
+                //         break;
+                //     case 3:
+                //         maxFloorSpace = 50;
+                //         break;
+                //     case 4:
+                //         maxFloorSpace = 30;
+                //         break;
+                //     case 5:
+                //     case 6:
+                //     case 7:
+                //         maxFloorSpace = 20;
+                //         break;
+                // }
+                return maxFloorSpace;
+            },
+        });
+
+        onMounted(() => {
+            allData.nowPage = 1;
+            allData.hqueryBuild();
+        });
+        return { ...toRefs(allData) };
+    },
+});
+</script>
+
+<style lang="scss" scoped>
+.floorSpace {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    position: relative;
+    border-radius: 16px;
+    .buildName {
+        position: absolute;
+        top: -40px;
+        left: -40px;
+        background: linear-gradient(
+            90deg,
+            rgba(131, 195, 255, 0.16) 0%,
+            rgba(131, 195, 255, 0) 100%
+        );
+        height: 46px;
+        line-height: 46px;
+        font-size: 20px;
+        //min-width: 145px;
+        padding: 0 20px;
+        color: #f7ecdb;
+        box-sizing: border-box;
+    }
+}
+
+.topChange {
+    height: 220px;
+    width: 100%;
+    margin: 0 auto;
+    background: #ffffff;
+    position: relative;
+    background: rgba(149, 162, 194, 0.1);
+    backdrop-filter: blur(20px);
+    border-radius: 20px;
+
+    .allIndicator {
+        position: relative;
+        padding-top: 36px;
+        padding-bottom: 36px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        .eachItem {
+            cursor: pointer;
+            font-size: 28px;
+            font-weight: 600;
+            color: #9b98ad;
+            margin-right: 40px;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            width: 90px;
+
+            .bar {
+                width: 80px;
+            }
+            &.select {
+                color: #f7e6cd;
+                background-image: url("@/assets/image/horImg/lastAllLight.png");
+                background-repeat: no-repeat;
+                background-position: center bottom;
+                background-size: 100%;
+                padding-bottom: 5px;
+                // .bar {
+                //     // background: #46ccf6;
+                // }
+            }
+        }
+    }
+    .imageDiv {
+        height: 32px;
+        margin: 0 32px;
+        text-align: center;
+        img {
+            height: 100%;
+        }
+    }
+    .textCont {
+        color: #f7e6cd;
+        font-size: 20px;
+        font-weight: 600;
+        text-align: center;
+        padding-top: 16px;
+        .value {
+            margin-left: 4px;
+        }
+    }
+}
+
+.leftChange {
+    height: 100%;
+    width: 154px;
+    box-sizing: border-box;
+    padding: 65px 0 20px;
+    margin: 0 auto;
+    position: relative;
+    //min-height: 730px;
+
+    .allIndicator {
+        // padding-top: 65px;
+        //padding-bottom: 20px;
+        // display: flex;
+        // align-items: center;
+        // justify-content: center;
+        position: relative;
+        height: 100%;
+        .showItem {
+            transition: all 400ms linear;
+            // height: 342px;
+            height: 36%;
+            box-sizing: border-box;
+            padding-top: 20px;
+            position: absolute;
+            top: 0;
+            left: 16px;
+            width: 120px;
+            // display: flex;
+            // flex-direction: column;
+            background-color: rgba(100, 108, 130, 0.2);
+            backdrop-filter: blur(10px);
+            background-image: url("@/assets/image/horImg/twoLight.png");
+            background-repeat: no-repeat;
+            background-position: center top;
+            background-size: 100%;
+            border-radius: 10px;
+            text-align: center;
+            .other {
+                height: 62%;
+                padding: 10px 0;
+                box-sizing: border-box;
+                .img {
+                    height: 100%;
+                    padding: 0;
+                    margin: 0;
+                }
+            }
+            .title {
+                color: #f7ecdb;
+                font-size: 24px;
+                font-size: 1.3vw;
+                height: 18%;
+            }
+            .textCont {
+                color: #f7ecdb;
+                font-size: 20px;
+                font-size: 1.1vw;
+                line-height: 1;
+                height: 20%;
+                .value {
+                    font-weight: 600;
+                }
+                .name {
+                    font-size: 14px;
+                }
+            }
+        }
+        .eachItem {
+            cursor: pointer;
+            //margin-bottom: 56px;
+            padding-top: 20px;
+            // height: 90px;
+            height: 16%;
+            box-sizing: border-box;
+            text-align: center;
+            font-family: PingFang SC;
+            .title {
+                color: #9b98ad;
+                font-size: 24px;
+                font-weight: 600;
+            }
+            &.select {
+                // height: 350px;
+                height: 36%;
+            }
+        }
+        .eachItem:last-child {
+            margin-bottom: 0;
+        }
+    }
+}
+
+.floorWrap {
+    flex: 1;
+    margin: 0 auto;
+    // background: #ffffff;
+    border-top-right-radius: 16px;
+    border-bottom-right-radius: 16px;
+
+    box-sizing: border-box;
+    .floor-item {
+        display: flex;
+        padding: 18px 20px 18px 0;
+        box-sizing: border-box;
+        // background: linear-gradient(
+        //     186deg,
+        //     rgba(50, 129, 246, 0.1) 6.16%,
+        //     rgba(50, 129, 246, 0) 81.03%
+        // );
+    }
+
+    .floor-num {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        font-family: Persagy;
+        font-size: 36px;
+        font-weight: 700;
+        line-height: 43px;
+        color: #f7ecdb;
+        width: 90px;
+        flex-shrink: 0;
+    }
+    .floor-space {
+        display: flex;
+        flex: 1;
+        flex-wrap: wrap;
+        .space-box {
+            padding: 4px;
+            box-sizing: border-box;
+            .space-name {
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                //height: 86px;
+                height: 100%;
+                min-width: 20px;
+                border-radius: 8px;
+                color: #f7ecdb;
+
+                background: rgba(34, 139, 81, 0.76);
+                text-align: center;
+                padding: 0 8px;
+                box-sizing: border-box;
+            }
+        }
+    }
+}
+.verFloorClass {
+    height: auto;
+    display: block;
+    .floorWrap {
+        padding-top: 14px;
+        height: 700px;
+    }
+    .buildName {
+        top: -55px;
+    }
+}
+</style>

+ 168 - 0
src/components/LastAllEnergy.vue

@@ -0,0 +1,168 @@
+<template>
+    <div
+        class="lastMonth"
+        :class="[screenType === 'hor' ? 'horizontalClass ' : 'verAllClass ']"
+    >
+        <div class="subhead-title">
+            <span>上月总能耗</span>
+        </div>
+        <div class="saveEnergy">
+            <span>节能{{ lastAllComputed.energyCompare }}%</span>
+        </div>
+        <div class="energySave">
+            <div class="textDiv">
+                <span>中海能耗</span
+                ><span>{{ lastAllComputed.energySaving }}kWh</span>
+            </div>
+            <div
+                class="saveBack"
+                :style="{ width: lastAllComputed.energyCompare + '%' }"
+            ></div>
+        </div>
+        <div class="energyTotal">
+            <div class="textDiv">
+                <span>基准能耗</span
+                ><span>{{ lastAllComputed.energyTotal }}kWh</span>
+            </div>
+            <div class="totalBack" :style="{ width: widthBase }"></div>
+        </div>
+    </div>
+</template>
+<script lang="ts">
+import {
+    ref,
+    defineComponent,
+    reactive,
+    toRefs,
+    onMounted,
+    computed,
+} from "vue";
+import { queryLastEnergy } from "@/api/index";
+import useProjectStore from "@/store/useProjectStore";
+import { storeToRefs, mapState } from "pinia";
+
+//import { lastGold, lastGray } from "@/utils/dapingImage";
+
+export default defineComponent({
+    props: {
+        screenType: {
+            type: String,
+        },
+    },
+    setup(props, contx) {
+        //   console.log("props", props, contx);
+        const projectStore = useProjectStore();
+        ///  const { lastAllEnergy22 } = storeToRefs(projectStore);
+        const allData = reactive({
+            widthBase: "0%",
+        });
+        const lastAllComputed = computed(() => {
+            const lastAllEnergy = projectStore.lastAllEnergy;
+
+            var lastObj = {
+                energySaving: lastAllEnergy.energySaving
+                    ? lastAllEnergy.energySaving.toFixed(1)
+                    : lastAllEnergy.energySaving,
+                energyTotal: lastAllEnergy.energyTotal
+                    ? lastAllEnergy.energyTotal.toFixed(1)
+                    : lastAllEnergy.energyTotal,
+                energyCompare: lastAllEnergy.energyCompare
+                    ? (lastAllEnergy.energyCompare * 100).toFixed(1)
+                    : lastAllEnergy.energyCompare,
+            };
+            return lastObj;
+        });
+        projectStore.$subscribe((mutation, state) => {
+            //debugger;
+            allData.widthBase = "100%";
+        });
+        onMounted(() => {
+            projectStore.setLastAllEnergy();
+        });
+        return { ...toRefs(allData), lastAllComputed, projectStore };
+    },
+    computed: {
+        // ...mapState(useProjectStore, {
+        //     lastAllEnergy2: (store) => {
+        //         debugger;
+        //         return store.lastAllEnergy.energyCompare
+        //             ? (store.lastAllEnergy.energyCompare * 100).toFixed(1)
+        //             : store.lastAllEnergy.energyCompare;
+        //     },
+        // }),
+        // lastAllEnergy2() {
+        //     debugger;
+        //     if (this.projectStore) {
+        //         return this.projectStore.lastAllEnergy.energyCompare
+        //             ? (
+        //                   this.projectStore.lastAllEnergy.energyCompare * 100
+        //               ).toFixed(1)
+        //             : this.projectStore.lastAllEnergy.energyCompare;
+        //     } else {
+        //         return 122;
+        //     }
+        // },
+    },
+});
+</script>
+
+<style scoped lang="scss">
+.lastMonth {
+    height: 100%;
+    background: rgba(100, 108, 130, 0.06);
+    backdrop-filter: blur(20px);
+    border-radius: 20px;
+    .saveEnergy {
+        color: #f7e6cd;
+        font-size: 46px;
+        height: calc(100% - 195px);
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        span {
+            background-image: url("@/assets/image/horImg/lastAllLight.png");
+            background-repeat: no-repeat;
+            background-position: center bottom;
+            background-size: 100%;
+            padding-bottom: 5px;
+        }
+    }
+    .energySave {
+        color: #e0c29b;
+        font-size: 20px;
+        padding-bottom: 32px;
+        height: 85px;
+        box-sizing: border-box;
+    }
+    .energyTotal {
+        color: #cbcdda;
+        font-size: 20px;
+        height: 50px;
+        box-sizing: border-box;
+    }
+    .textDiv {
+        display: flex;
+        justify-content: space-between;
+        padding-bottom: 8px;
+    }
+    .saveBack {
+        height: 15px;
+        background-image: url("@/assets/image/horImg/lastGold.svg");
+        transition: width 3s linear;
+        width: 0;
+    }
+    .totalBack {
+        height: 15px;
+        background-image: url("@/assets/image/horImg/lastGray.svg");
+        transition: width 2s linear;
+        width: 0;
+    }
+}
+.verAllClass {
+    height: 420px;
+    padding: 0 36px;
+    background: rgba(149, 162, 194, 0.1);
+    backdrop-filter: blur(40px);
+    border-radius: 20px;
+}
+</style>

+ 227 - 0
src/components/LastMonthData.vue

@@ -0,0 +1,227 @@
+<template>
+    <div
+        class="lastMonth"
+        :class="[screenType === 'hor' ? 'horiLastMonth' : 'verticalLastMonth']"
+    >
+        <div class="subhead-title"><span>上月数据</span></div>
+        <div class="itemWrap">
+            <div class="item" v-for="(item, index) in lastDataArr" :key="index">
+                <div class="item-left">
+                    <img :src="item.img" />
+                </div>
+                <div class="item-right">
+                    <div class="item-value">
+                        <span>{{ item.value }}</span
+                        ><span>{{ item.unit }}</span>
+                    </div>
+                    <div class="item-content">
+                        <div class="item-content-right">
+                            <div class="max">
+                                <span>{{ item.maxName }}</span>
+                                <span>{{ item.max }}</span>
+                                <span>{{ item.unit }}</span>
+                            </div>
+                            <div class="min">
+                                <span>{{ item.minName }}</span>
+                                <span>{{ item.min }}</span>
+                                <span>{{ item.unit }}</span>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+<script lang="ts">
+import { ref, defineComponent, reactive, toRefs, onMounted } from "vue";
+import { queryEnvHistory } from "@/api/index";
+import { dapingImage } from "@/utils/dapingImage";
+
+export default defineComponent({
+    props: {
+        screenType: {
+            type: String,
+        },
+    },
+    setup(props, contx) {
+       
+        const { lastco2, lasthumidity, lastmethanal, lastpm25, lasttemp } =
+            dapingImage;
+        const allData = reactive({
+            lastDataArr: [],
+        });
+        onMounted(() => {
+            queryEnvHistory()
+                .then((res) => {
+                    var lastMonthData = res.data.data || [];
+                    var lastMonthInit = [
+                        {
+                            id: "temp",
+                            name: "温度",
+                            code: "Tdb",
+                            unit: "℃",
+                            maxName: "最高温",
+                            minName: "最低温",
+                            img: lasttemp,
+                            fixed: 1,
+                        },
+                        {
+                            id: "humidity",
+                            name: "湿度",
+                            code: "RH",
+                            unit: "%",
+                            maxName: "最大值",
+                            max: 50,
+                            minName: "最小值",
+                            min: 20,
+                            img: lasthumidity,
+                            fixed: 0,
+                        },
+                        {
+                            id: "co2",
+                            name: "CO2",
+                            code: "CO2",
+                            value: 2600,
+                            unit: "ppm",
+                            maxName: "最大值",
+                            max: 2600,
+                            minName: "最小值",
+                            min: 300,
+                            img: lastco2,
+                            fixed: 0,
+                        },
+                        {
+                            id: "methanal",
+                            name: "甲醛",
+                            code: "HCHO",
+                            value: 0.03,
+                            unit: "mg/m³",
+                            maxName: "最大值",
+                            max: 0.01,
+                            minName: "最小值",
+                            min: 0.07,
+                            img: lastmethanal,
+                            fixed: 2,
+                        },
+                        {
+                            id: "pm25",
+                            name: "PM2.5",
+                            code: "PM2d5",
+                            value: 120,
+                            unit: "ug/m³",
+                            maxColor: "#C4E34F",
+                            minColor: "#7ed874",
+                            maxName: "最大值",
+                            max: 340,
+                            minName: "最小值",
+                            min: 20,
+                            img: lastpm25,
+                            fixed: 0,
+                        },
+                    ];
+                    lastMonthInit.forEach((item) => {
+                        var filterRes = lastMonthData.filter((ele) => {
+                            return ele.code == item.code;
+                        });
+                        var filterObj = filterRes[0] || {};
+                        item.value = filterObj.avgData
+                            ? Number(filterObj.avgData.toFixed(item.fixed))
+                            : filterObj.avgData;
+                        item.max = filterObj.maxData
+                            ? Number(filterObj.maxData.toFixed(item.fixed))
+                            : filterObj.maxData;
+                        item.min = filterObj.minData
+                            ? Number(filterObj.minData.toFixed(item.fixed))
+                            : filterObj.minData;
+                    });
+                    // debugger;
+                    allData.lastDataArr = lastMonthInit;
+                })
+                .catch((err) => {});
+        });
+        return { ...toRefs(allData) };
+    },
+});
+</script>
+
+<style scoped lang="scss">
+.lastMonth {
+    .item {
+        padding-top: 60px;
+        display: flex;
+        align-items: center;
+
+        .item-left {
+            width: 86px;
+            height: 86px;
+            margin-right: 20px;
+            background: rgba(100, 108, 130, 0.3);
+            backdrop-filter: blur(10px);
+            border-radius: 12px;
+            img {
+                width: 86px;
+            }
+        }
+        .item-value {
+            font-family: Persagy;
+            font-weight: 700;
+            font-size: 24px;
+            line-height: 30px;
+            color: #f7e6cd;
+        }
+        .item-content {
+            display: flex;
+            align-items: center;
+            padding-top: 8px;
+            font-weight: 500;
+            font-size: 14px;
+        }
+        .item-content-right {
+            font-size: 14px;
+            font-weight: 400;
+            line-height: 20px;
+            color: #f7e6cd;
+            white-space: nowrap;
+
+            .min {
+                padding-top: 8px;
+            }
+        }
+    }
+}
+.horiLastMonth {
+    height: 100%;
+    padding-left: 35px;
+    .item {
+        padding-top: 0;
+    }
+    .itemWrap {
+        height: calc(100% - 30px);
+        display: flex;
+        flex-direction: column;
+        justify-content: space-evenly;
+    }
+}
+.verticalLastMonth {
+    height: 400px;
+    padding: 0 36px;
+    background: rgba(149, 162, 194, 0.1);
+    backdrop-filter: blur(40px);
+    border-radius: 20px;
+    .itemWrap {
+        display: flex;
+        flex-direction: row;
+        flex-wrap: wrap;
+        //  justify-content:space-around;
+        .item {
+            width: 33.33%;
+            // justify-content: center;
+            .item-content-right {
+                font-size: 14px;
+                white-space: nowrap;
+            }
+        }
+    }
+}
+</style>

+ 159 - 0
src/components/LastSaveEnergy.vue

@@ -0,0 +1,159 @@
+<template>
+    <div
+        class="lastMonth"
+        :class="[screenType === 'hor' ? 'horizontalClass ' : 'verAllClass ']"
+    >
+        <div class="subhead-title">
+            <span>上月节约能耗</span>
+        </div>
+        <div class="saveCont">
+            <div class="co2Wrap sco2">
+                减排<span class="value">{{ lastAllEnergyRes.cdmCo2 }}Kg</span
+                >CO2
+            </div>
+            <div class="co2Wrap scarbon">
+                减排<span class="value">{{ lastAllEnergyRes.cdmC }}Kg</span>碳
+            </div>
+            <div class="co2Wrap stree">
+                为国家种<span class="value">{{ lastAllEnergyRes.cdmTree }}</span
+                >棵树
+            </div>
+            <div class="electWrap">
+                <div>节约电</div>
+                <div class="value">{{ lastAllEnergyRes.energySaving }}度</div>
+            </div>
+            <video class="svideo" autoplay loop muted>
+                <source src="@/assets/image/horImg/saveEnergy.mov" />
+            </video>
+        </div>
+    </div>
+</template>
+<script lang="ts">
+import {
+    ref,
+    defineComponent,
+    reactive,
+    toRefs,
+    onMounted,
+    computed,
+} from "vue";
+import { queryLastEnergy } from "@/api/index";
+import useProjectStore from "@/store/useProjectStore";
+import { storeToRefs, mapState } from "pinia";
+
+//import { lastGold, lastGray } from "@/utils/dapingImage";
+
+export default defineComponent({
+    props: {
+        screenType: {
+            type: String,
+        },
+    },
+    setup(props, contx) {
+        const projectStore = useProjectStore();
+        const { lastAllEnergy } = storeToRefs(projectStore);
+
+        const allData = reactive({
+            lastAllEnergyRes: {},
+        });
+
+        projectStore.$subscribe((mutation, state) => {
+            
+            const lastAllEnergy = state.lastAllEnergy || {};
+            allData.lastAllEnergyRes = {
+                cdmCo2: lastAllEnergy.cdmCo2
+                    ? lastAllEnergy.cdmCo2.toFixed(2)
+                    : lastAllEnergy.cdmCo2,
+                cdmTree: lastAllEnergy.cdmTree
+                    ? lastAllEnergy.cdmTree.toFixed(2)
+                    : lastAllEnergy.cdmTree,
+                cdmC: lastAllEnergy.cdmC
+                    ? lastAllEnergy.cdmC.toFixed(2)
+                    : lastAllEnergy.cdmC,
+                energySaving: lastAllEnergy.energySaving
+                    ? lastAllEnergy.energySaving.toFixed(2)
+                    : lastAllEnergy.energySaving,
+            };
+        });
+        onMounted(() => {
+            //projectStore.setLastAllEnergy();
+        });
+        return { ...toRefs(allData), lastAllEnergy };
+    },
+    computed: {},
+});
+</script>
+
+<style scoped lang="scss">
+.lastMonth {
+    height: 100%;
+    background: rgba(100, 108, 130, 0.06);
+    backdrop-filter: blur(20px);
+    border-radius: 20px;
+    .saveCont {
+        height: calc(100% - 60px);
+        padding-top: 10px;
+        box-sizing: border-box;
+        // display: flex;
+        // justify-content: center;
+        // align-items: center;
+        color: #f7e6cd;
+        position: relative;
+        .svideo {
+            width: 100%;
+        }
+        .co2Wrap {
+            position: absolute;
+            // font-size: 22px;
+            font-size: 1.2vw;
+            .value {
+                padding: 0 8px;
+                font-size: 24px;
+                font-size: 1.4vw;
+            }
+            .co2Img {
+                width: 58px;
+            }
+        }
+        .sco2 {
+            top: 26%;
+            left: 0%;
+        }
+        .scarbon {
+            top: 3%;
+            right: 10%;
+        }
+        .stree {
+            top: 62%;
+            right: 0%;
+        }
+        .electWrap {
+            position: absolute;
+            top: 20%;
+            left: 32%;
+            width:200px;
+            font-size: 30px;
+            font-size: 1.4vw;
+            // line-height: 45px;
+            text-align: center;
+            color: #f7e6cd;
+            .value {
+                margin-top: 5px;
+                font-weight: 700;
+                font-size: 46px;
+                font-size: 2vw;
+                // line-height: 58px;
+                text-shadow: 0px 0px 8px rgba(255, 255, 255, 0.4);
+            }
+        }
+    }
+}
+.verAllClass {
+    height: 600px;
+    padding: 0 36px;
+    background: rgba(149, 162, 194, 0.1);
+    backdrop-filter: blur(40px);
+    border-radius: 20px;
+    margin: 22px 0;
+}
+</style>

+ 35 - 0
src/components/MyButton.vue

@@ -0,0 +1,35 @@
+<template>
+    <div
+        v-if="navigateItem == 'home'"
+        :style="{ color: color }"
+        @click="clickButton()"
+    >
+        button按钮
+    </div>
+    <div v-else>非button按钮</div>
+</template>
+<script lang="ts">
+import { ref, defineComponent, reactive, toRefs } from "vue";
+export default defineComponent({
+    props: {
+        navigateItem: {
+            type: String,
+        },
+        color: {
+            type: String,
+        },
+    },
+    setup(props, contx) {
+     
+
+        const allData = reactive({
+            clickButton: () => {
+                contx.emit("changeColor", "22");
+            },
+        });
+        return { ...toRefs(allData) };
+    },
+});
+</script>
+
+<style scoped lang="scss"></style>

+ 209 - 0
src/components/NowData.vue

@@ -0,0 +1,209 @@
+<template>
+    <div
+        class="NowData"
+        :class="[screenType === 'hor' ? 'horizontalClass' : 'verticalNowData']"
+    >
+        <div class="head-title">
+            <span>实时数据</span>
+            <span class="subhead-title">主动式空调,会呼吸的写字楼</span>
+        </div>
+
+        <div class="contain">
+            <div class="item" v-for="(item, index) in realDataArr" :key="index">
+                <div
+                    class="item_content"
+                    :style="{
+                        backgroundImage:
+                            'url(' + selectColor(item.value, item.id) + ')',
+                    }"
+                >
+                    <div class="content_value">
+                        <span>{{ item.value }}</span
+                        ><span>{{ item.unit }}</span>
+                    </div>
+                    <div class="content_name">
+                        <span>{{ item.name }}</span>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+<script lang="ts">
+import { ref, defineComponent, reactive, toRefs, onMounted } from "vue";
+import { queryEnvCurrent } from "@/api/index";
+import { selectColor } from "@/utils/publicMethod";
+export default defineComponent({
+    props: {
+        screenType: {
+            type: String,
+        },
+    },
+    setup(props, contx) {
+     
+        const allData = reactive({
+            realDataArr: [],
+            selectColor: selectColor,
+        });
+
+        onMounted(() => {
+            queryEnvCurrent()
+                .then((res) => {
+                    let realTimeData = res.data.data || [];
+                    let realInit = [
+                        {
+                            id: "temp",
+                            code: "Tdb",
+                            name: "温度",
+                            //value: 24.5,
+                            unit: "℃",
+                            level: "low",
+                            fixed: 1,
+                        },
+                        {
+                            id: "humidity",
+                            name: "湿度",
+                            code: "RH",
+                            // value: 33,
+                            unit: "%",
+                            level: "middle",
+                            fixed: 0,
+                        },
+                        {
+                            id: "co2",
+                            name: "CO₂",
+                            code: "CO2",
+                            unit: "ppm",
+                            level: "low",
+                            fixed: 0,
+                        },
+                        {
+                            id: "methanal",
+                            code: "HCHO",
+                            name: "甲醛",
+                            unit: "mg/m³",
+                            level: "low",
+                            fixed: 2,
+                        },
+                        {
+                            id: "pm25",
+                            code: "PM2d5",
+                            name: "PM2.5",
+                            unit: "ug/m³",
+                            level: "low",
+                            fixed: 0,
+                        },
+                    ];
+                    realInit.forEach((item) => {
+                        var filterRes = realTimeData.filter((ele) => {
+                            return ele.code == item.code;
+                        });
+                        var value = (filterRes[0] || {}).data;
+                        item.value = value
+                            ? Number(value.toFixed(item.fixed))
+                            : value;
+                    });
+                    allData.realDataArr = realInit;
+                })
+                .catch((err) => {});
+        });
+        return { ...toRefs(allData) };
+    },
+});
+</script>
+
+<style scoped lang="scss">
+.horizontalClass {
+    height: 50%;
+}
+
+.NowData {
+    .title-right-icon {
+        display: inline-block;
+        padding: 0;
+        width: 12px;
+        height: 12px;
+        margin-right: 8px;
+        border-radius: 50%;
+        background: rgba(126, 216, 116, 1);
+    }
+
+    .contain {
+        height: calc(100% - 60px);
+        display: flex;
+    }
+    .item {
+        width: calc(100% / 5);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        .item_content {
+            // height: 100%;
+            background-size: auto 240px;
+            background-position: center -36px;
+            background-repeat: no-repeat;
+            padding-bottom: 30px;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            text-align: center;
+
+            .content_value {
+                font-family: Persagy;
+                font-size: 52px;
+                font-weight: 700;
+                background: linear-gradient(180deg, #fff5df 0%, #ead0b1 100%);
+                -webkit-background-clip: text;
+                -webkit-text-fill-color: transparent;
+                background-clip: text;
+                text-fill-color: transparent;
+                text-shadow: 0px 0px 8px rgba(255, 255, 255, 0.4);
+                line-height: 64px;
+            }
+            .content_name {
+                margin-top: 8px;
+                font-family: PingFang SC;
+                font-size: 32px;
+                font-weight: 400;
+                line-height: 46px;
+                color: #f7e6cd;
+            }
+        }
+    }
+    .content_level {
+        margin-top: 8px;
+        margin-right: 8px;
+        box-sizing: border-box;
+        width: 16px;
+        height: 16px;
+        border-radius: 50%;
+        background: rgba(126, 216, 116, 1);
+        &.middle {
+            background: rgba(239, 214, 46, 1);
+        }
+    }
+    .normal-explain {
+        display: flex;
+        align-items: center;
+        font-size: 14px;
+    }
+}
+.verticalNowData {
+    height: 380px;
+    .item {
+        .item_content {
+            .content_value {
+                font-size: 46px;
+            }
+            .content_name {
+                margin-top: 12px;
+                font-size: 28px;
+            }
+            .content_level {
+                margin-top: 12px;
+            }
+        }
+    }
+}
+</style>

+ 268 - 0
src/components/TemChart.vue

@@ -0,0 +1,268 @@
+<template>
+    <div
+        class="temChart"
+        :class="[screenType === 'hor' ? 'horiCompClass' : 'verCompClass ']"
+    >
+        <div class="subhead-title" v-show="screenType === 'ver'">
+            <span>实时温度</span>
+        </div>
+        <div id="tempChartBox" class="tempChartBox" ref="tempChartRef"></div>
+    </div>
+</template>
+<script lang="ts">
+import {
+    ref,
+    defineComponent,
+    reactive,
+    toRefs,
+    onMounted,
+    nextTick,
+} from "vue";
+import { queryIndoorTempList } from "@/api";
+import { Chart, registerShape } from "@antv/g2";
+import moment from "moment";
+
+export default defineComponent({
+    props: {
+        screenType: {
+            type: String,
+        },
+    },
+    setup(props, contx) {
+        //console.log("props", props, contx);
+        const { screenType } = props;
+        const allData = reactive({});
+        const tempChartRef = ref();
+        const cInitChart = (cdata) => {
+            registerShape("point", "breath-point", {
+                draw(cfg, container) {
+                    const data = cfg.data;
+                    const point = { x: cfg.x, y: cfg.y };
+                    const group = container.addGroup();
+                    if (
+                        data.time === cdata[cdata.length - 1].time &&
+                        data.temp === cdata[cdata.length - 1].temp
+                    ) {
+                        const decorator1 = group.addShape("circle", {
+                            attrs: {
+                                x: point.x,
+                                y: point.y,
+                                r: 8,
+                                fill: "#F2E2CC",
+                                // opacity: 0.8,
+                            },
+                        });
+                        // decorator1.animate(
+                        //     {
+                        //         r: 20,
+                        //         opacity: 0,
+                        //     },
+                        //     {
+                        //         duration: 1800,
+                        //         easing: "easeLinear",
+                        //         repeat: true,
+                        //     }
+                        // );
+                        group.addShape("circle", {
+                            attrs: {
+                                x: point.x,
+                                y: point.y,
+                                r: 4,
+                                fill: "#ffffff",
+                                filter: "blur(2px)",
+                                opacity: 0.5,
+                            },
+                        });
+                        // group.addShape("circle", {
+                        //     attrs: {
+                        //         x: point.x,
+                        //         y: point.y,
+                        //         r: 1.5,
+                        //         fill: "#1890ff",
+                        //     },
+                        // });
+                    }
+
+                    return group;
+                },
+            });
+
+            var chartWidth =
+                (tempChartRef.value && tempChartRef.value.offsetWidth) || 0;
+            var chartHeight =
+                (tempChartRef.value && tempChartRef.value.offsetHeight) || 0;
+            // if (this.tempChart) {
+            //     this.tempChart.clear();
+            //     var chart = this.tempChart;
+            // } else {
+            var chart = new Chart({
+                container: "tempChartBox",
+                autoFit: true,
+                // width: chartWidth,
+                // height: chartHeight,
+                padding: [50, 50, 46, 60],
+            });
+            // }
+
+            chart.data(cdata);
+
+            chart.scale("time", {
+                //range: [0, 1],
+                //tickCount: 2,
+                //tickInterval
+                // type: 'timeCat'
+            });
+            chart.scale("temp", {
+                //range: [0, 1],
+                tickCount: 5,
+                minTickInterval: 2,
+                //ticks:[20,24,28,32]
+            });
+            chart.axis("time", {
+                label: {
+                    style: {
+                        fill: "#E0C29B",
+                        fontSize: 12,
+                    },
+                },
+                tickLine: null,
+            });
+            chart.axis("temp", {
+                tickLine: null,
+                grid: {
+                    line: {
+                        style: {
+                            lineWidth: 1, // 设置线的宽度
+                            stroke: "rgba(224,194,155,0.2)", // 设置线的颜色
+                            lineDash: [3, 3], // 设置虚线样式
+                        },
+                    },
+                },
+                label: {
+                    style: {
+                        fill: "#E0C29B",
+                        fontSize: 12,
+                    },
+                    // formatter: function formatter(text) {
+                    //     return text;
+                    // }
+                },
+            });
+            chart.legend(false);
+
+            chart
+                .line()
+                .position("time*temp")
+                .color("#F2E3CD")
+                .shape("smooth")
+                .tooltip(false)
+                .style({
+                    lineWidth: 3,
+                });
+
+            chart
+                .area()
+                .position("time*temp")
+                .color("l(90) 0:#F2E3CD 1:#CFAE88")
+                .tooltip(false)
+                .shape("smooth");
+
+            chart.point().position("time*temp").shape("breath-point");
+
+            var lastpoint = cdata[cdata.length - 1];
+            var nowtime = moment();
+            var timestr = nowtime.format("YYYY.MM.DD");
+            const tooltipHtml = `<div style='line-height:22px;color:#321D0A;background: linear-gradient(105.46deg, #F2E3CD 8.6%, #D9B991 62.71%);padding:10px 12px;border-radius:5px;'>
+                <div style='font-size:12px;font-weight:600;'><span style='margin-right:5px'>${timestr}</span>${
+                lastpoint && lastpoint.time
+            }</div>
+                <div style='font-size:16px;font-weight:600;'>室内温度:${
+                    lastpoint &&
+                    lastpoint.temp &&
+                    Number(lastpoint.temp).toFixed(1)
+                }℃</div></div>`;
+            chart.annotation().html({
+                position: lastpoint,
+                html: tooltipHtml,
+                alignX: "right",
+                alignY: "bottom",
+                offsetX: 60,
+                offsetY: -20,
+            });
+
+            chart.annotation().text({
+                // position: ['min', 'max'], // 文本的起始位置,值为原始数据值,支持 callback
+                position: function (xScale, yScale) {
+                    //console.log("position", xScale, yScale);
+                    return ["0%", "0%"];
+                },
+                content: "温度/℃", // 显示的文本内容
+                style: {
+                    fill: "#E0C29B", // 文本颜色
+                    fontSize: "12", // 文本大小
+                    // fontWeight: 'bold' // 文本粗细
+                    // rotate: Math.PI / 4 // 文本旋转,以弧度为单位
+                }, // 文本的图形样式属性
+                offsetX: -40, // x 方向的偏移量
+                offsetY: -24, // y 方向偏移量
+            });
+
+            chart.render();
+            return chart;
+        };
+        onMounted(() => {
+            queryIndoorTempList()
+                .then((res) => {
+                    var cdata = res.data.data || [];
+                    cdata.forEach((element) => {
+                        var timestr = element.time || "";
+                        var hour = timestr.substr(8, 2);
+                        var minute = timestr.substr(10, 2);
+                        element.time = hour + ":" + minute;
+                        element.temp =
+                            element && element.temp
+                                ? Number(element.temp).toFixed(1)
+                                : element.temp;
+                    });
+
+                    // debugger;
+                    nextTick(() => {
+                        cInitChart(cdata);
+                    });
+                })
+                .catch((err) => {});
+        });
+        return { ...toRefs(allData), tempChartRef };
+    },
+});
+</script>
+
+<style scoped lang="scss">
+.temChart {
+    .tempChartBox {
+        width: 100%;
+        height: 100%;
+
+        box-sizing: border-box;
+        // height: 330px;
+    }
+}
+.horiCompClass {
+    height: 100%;
+    box-sizing: border-box;
+    padding: 50px 20px 20px;
+}
+.verCompClass {
+    margin: 22px 0;
+    height: 410px;
+    background: rgba(149, 162, 194, 0.1);
+    backdrop-filter: blur(40px);
+    border-radius: 20px;
+    padding: 0 36px;
+    .tempChartBox {
+        height: calc(100% - 60px);
+        padding-top: 30px;
+        box-sizing: border-box;
+    }
+}
+</style>

+ 170 - 0
src/components/airSwitchHor.vue

@@ -0,0 +1,170 @@
+<template>
+    <div class="airSwitch">
+        <div class="air-cont">
+            <div class="container" id="container"></div>
+        </div>
+        <div class="air-title">
+            <span> {{ airStatus ? "空调已开启" : "空调已关闭" }}</span>
+        </div>
+    </div>
+</template>
+<script lang="ts">
+import { ref, defineComponent, reactive, toRefs, onMounted, watch } from "vue";
+import useAirSwitch from "@/utils/useAirSwitch";
+import { Chart } from "@antv/g2";
+
+export default defineComponent({
+    props: {
+        navigateItem: {
+            type: String,
+        },
+        color: {
+            type: String,
+        },
+    },
+    setup(props, contx) {
+      
+        const { airValue, airStatus } = useAirSwitch();
+        const allData = reactive({
+            airStatus: airStatus,
+        });
+        watch(airValue, (newValue, oldValue) => {
+            initChart();
+        });
+
+        const initChart = () => {
+            var avalue = airValue.value || 0;
+            const data = [
+                { type: "开启", value: avalue },
+                { type: "关闭", value: 100 - avalue },
+            ];
+            const chart = new Chart({
+                container: "container",
+                autoFit: true,
+            });
+            chart.data(data);
+            chart.legend(false);
+            chart.tooltip(false);
+
+            chart.coordinate("theta", {
+                radius: 0.9,
+                innerRadius: 0.8,
+            });
+            const interval = chart
+                .interval()
+                .adjust("stack")
+                .position("value")
+                .color("type", ["l(90) 0:#BFA17E 1:#E0D1BB", "#3C3F52"])
+                .style({
+                    opacity: 1,
+                    lineCap: "round",
+                });
+
+            chart.annotation().text({
+                position: ["50%", "50%"],
+                content: data[0].value + "%",
+                style: {
+                    fontSize: 40,
+                    fill: "#F8EDDA",
+                    fontWeight: 700,
+                    textAlign: "center",
+                },
+                offsetY: -10,
+            });
+            chart.annotation().text({
+                position: ["50%", "50%"],
+                content: "空调开启率",
+                style: {
+                    fontSize: 16,
+                    fill: "#F8EDDA",
+                    fontWeight: 400,
+                    textAlign: "center",
+                },
+                offsetY: 26,
+            });
+            chart.render();
+
+            interval.elements[0].setState("active", true); //将第一个数据设置成 选中状态
+        };
+        onMounted(() => {
+            // initChart();
+        });
+        // onMounted(() => {
+        //     const data = [
+        //         { type: "1-3秒", value: 0.06 },
+        //         { type: "2-3秒", value: 0.2 },
+        //     ];
+
+        //     const chart = new Chart({
+        //         container: "container",
+        //         autoFit: true,
+        //         height: 500,
+        //         theme: "dark",
+        //     });
+        //     chart.data(data);
+
+        //     chart.axis(false);
+        //     chart.tooltip({
+        //         showMarkers: false,
+        //     });
+        //     chart.coordinate("theta", { innerRadius: 0.8, radius: 0.95 });
+        //     chart.legend(false);
+        //     const { colors10, subColor } = chart.getTheme();
+
+        //     chart
+        //         .interval({
+        //             background: { style: { fill: subColor, fillOpacity: 1 } },
+        //         })
+        //         .position("type*value")
+        //         .color("type", (val) => {
+        //             if (val === "10-30分" || val === "30+分") {
+        //                 return "green";
+        //             }
+        //             return colors10[0];
+        //         })
+        //         .style({
+        //             lineCap: "round",
+        //         });
+
+        //     chart.interaction("element-active");
+        //     chart.annotation().html({
+        //         position: ["50%", "50%"],
+        //         html: () => {
+        //             return `<div style="transform:translate(-50%,-50%)">sssss</div>`;
+        //         },
+        //     });
+        //     chart.render();
+
+        // });
+        return { ...toRefs(allData) };
+    },
+});
+</script>
+<style scoped lang="scss">
+.airSwitch {
+    height: 100%;
+    .container {
+        height: 200px;
+    }
+    .air-cont {
+        .air-rate {
+            font-size: 16px;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            color: #f7e6cd;
+            .air-rate-value {
+                color: #f7e6cd;
+                font-size: 42px;
+                font-weight: 700;
+            }
+        }
+    }
+    .air-title {
+        font-size: 24px;
+        line-height: 34px;
+        text-align: center;
+        color: #f7e6cd;
+    }
+}
+</style>

+ 98 - 0
src/components/airSwitchVer.vue

@@ -0,0 +1,98 @@
+<template>
+    <div class="airSwitch verticalClass">
+        <div class="subhead-title">
+            <span> {{ airStatus ? "空调已开启" : "空调已关闭" }}</span>
+        </div>
+        <div class="air-cont">
+            <div class="air-left">
+                <div class="bar-box">
+                    <div
+                        class="bar"
+                        v-bind:style="{ width: airValue + '%' }"
+                    ></div>
+                </div>
+                <div class="air-rate">
+                    <span>空调开启率</span>
+                    <span class="air-rate-value">{{ airValue }}%</span>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+<script lang="ts">
+import { ref, defineComponent, reactive, toRefs } from "vue";
+import useAirSwitch from "@/utils/useAirSwitch";
+export default defineComponent({
+    props: {
+        navigateItem: {
+            type: String,
+        },
+        color: {
+            type: String,
+        },
+    },
+    setup(props, contx) {
+        //console.log("props", props, contx);
+        const { airValue, airStatus } = useAirSwitch();
+        const allData = reactive({
+            airValue: airValue,
+            airStatus: airStatus,
+        });
+        return { ...toRefs(allData) };
+    },
+});
+</script>
+<style scoped lang="scss">
+.airSwitch {
+    background: rgba(149, 162, 194, 0.1);
+    backdrop-filter: blur(40px);
+    border-radius: 20px;
+    height: 226px;
+
+    &.verticalClass {
+        padding: 0 36px;
+        box-sizing: border-box;
+    }
+    .air-cont {
+        padding-top: 35px;
+        .air-left {
+            display: flex;
+            // justify-content: center;
+            flex-direction: column;
+            padding-top: 20px;
+            .bar-box {
+                width: 93%;
+                height: 10px;
+                background: #3c3f52;
+                border-radius: 6px;
+                .bar {
+                    width: 80%;
+                    height: 10px;
+                    background: linear-gradient(
+                        249.29deg,
+                        #fffbec 13.72%,
+                        #efdec6 36.81%,
+                        #cfae88 85.57%
+                    );
+                    border-radius: 8px;
+                }
+            }
+            .air-rate {
+                font-size: 20px;
+                display: flex;
+                height: 40px;
+                align-items: center;
+                margin-top: 14px;
+                color: #f7e6cd;
+                .air-rate-value {
+                    color: #f7e6cd;
+                    font-size: 32px;
+                    //line-height: 39px;
+                    padding-left: 8px;
+                    font-weight: 700;
+                }
+            }
+        }
+    }
+}
+</style>

+ 274 - 0
src/components/lastEnergyChart.vue

@@ -0,0 +1,274 @@
+<template>
+    <div
+        class="lastChart"
+        :class="[screenType === 'hor' ? 'horizontalClass' : 'verticalTemChart']"
+    >
+        <div class="subhead-title">
+            <span>上月每日能耗(kWh)</span>
+        </div>
+        <div id="lastChartBox" class="lastChartBox" ref="lastChartBox"></div>
+    </div>
+</template>
+<script lang="ts">
+import { ref, defineComponent, reactive, toRefs, onMounted } from "vue";
+import moment from "moment";
+import { queryLastDayEnergy } from "@/api/index";
+import { Chart, registerShape } from "@antv/g2";
+import DataSet from "@antv/data-set";
+
+// 自定义 shape, 支持图片形式的气泡
+registerShape("interval", "borderRadius", {
+    draw: function draw(cfg, container) {
+        var points = cfg.points;
+        var path = [];
+        path.push(["M", points[0].x, points[0].y]);
+        path.push(["L", points[1].x, points[1].y]);
+        path.push(["L", points[2].x, points[2].y]);
+        path.push(["L", points[3].x, points[3].y]);
+        path.push("Z");
+        path = this.parsePath(path); // 将 0 - 1 转化为画布坐标
+        return container.addShape("rect", {
+            attrs: {
+                x: path[1][1], // 矩形起始点为左上角
+                y: path[1][2],
+                width: path[2][1] - path[1][1],
+                height: path[0][2] - path[1][2],
+                fill: cfg.color,
+                radius: (path[2][1] - path[1][1]) / 2,
+            },
+        });
+    },
+});
+
+export default defineComponent({
+    props: {
+        screenType: {
+            type: String,
+        },
+    },
+    setup(props, contx) {
+        //debugger;
+        const lastChartBox = ref();
+        const allData = reactive({
+            lastChart: null,
+            ds: null,
+            getLastDayEnergy() {
+                queryLastDayEnergy().then((res) => {
+                    var resdata = res.data.content || [];
+                    //debugger;
+                    resdata.forEach(function (item) {
+                        var dateStr = item.date;
+                        item.Date =
+                            dateStr.substr(0, 4) +
+                            "-" +
+                            dateStr.substr(4, 2) +
+                            "-" +
+                            dateStr.substr(6, 2);
+                        item.value = Number(
+                            (
+                                (item.energyAcTerminal || 0) +
+                                (item.energyCooling || 0) +
+                                (item.energyHeating || 0) +
+                                (item.energyLight || 0) +
+                                (item.energyOthers || 0)
+                            ).toFixed(0)
+                        );
+                    });
+                    allData.lastChart = allData.cInitChart(resdata);
+                    console.log("contx,contx", contx, contx.emit);
+                    allData.setChartInterval();
+                });
+            },
+            setChartInterval() {
+                if (props.screenType == "ver") {
+                    //只有竖屏才轮播
+                    //上个月
+                    var start = moment().subtract(1, "months").date(1);
+                    var end = moment().subtract(1, "months").date(12);
+                    var end2 = moment().subtract(1, "months");
+                    var intervalInt = setInterval(() => {
+                        start.add(1, "days");
+                        end.add(1, "days");
+
+                        allData.ds.setState(
+                            "laststart",
+                            start.format("YYYY-MM-DD")
+                        );
+                        allData.ds.setState(
+                            "lastend",
+                            end.format("YYYY-MM-DD")
+                        );
+
+                        allData.ds.on("statechange", (name, value) => {
+                            const rows = allData.ds.views.bar.rows;
+                            allData.lastChart.changeData(rows);
+                            // allData.lastChart.render(true);
+                            // console.log(
+                            //     "end--22",
+                            //     ds.views,
+                            //     ds.views.bar.rows,
+                            //     rows
+                            // );
+                        });
+
+                        if (
+                            end.format("YYYY-MM-DD") ==
+                            end2.endOf("month").format("YYYY-MM-DD")
+                        ) {
+                            clearInterval(intervalInt);
+                            contx.emit("donethreepage");
+                        }
+                    }, 1500);
+                }
+            },
+            cInitChart(cdata) {
+                if (props.screenType == "hor") {
+                    var end =
+                        cdata[cdata.length - 1] && cdata[cdata.length - 1].Date;
+                } else {
+                    var end = cdata[11] && cdata[11].Date;
+                }
+                let ds = new DataSet({
+                    state: {
+                        laststart: cdata[0] && cdata[0].Date,
+                        lastend: end,
+                    },
+                });
+                // var dv = new DataSet.DataView(ds, {
+                //     watchingStates: [],
+                // });
+                var dv = ds.createView("bar", {
+                    watchingStates: ["laststart", "lastend"],
+                });
+                dv.source(cdata).transform({
+                    type: "filter",
+                    callback: function callback(obj) {
+                        var date = obj.Date;
+                        return (
+                            date <= ds.state.lastend &&
+                            date >= ds.state.laststart
+                        );
+                    },
+                });
+
+                //console.log("dv.row", dv.rows, dv.transforms);
+                var width =
+                    document.getElementsByTagName("body")[0].offsetWidth - 80;
+                console.log("lastChartBox", lastChartBox.value);
+                var chart =
+                    lastChartBox.value &&
+                    new Chart({
+                        container: "lastChartBox",
+                        autoFit: true,
+                        // width: width,
+                        // height: props.screenType === "hor" ? 274 : 330,
+                        padding: [20, 20, 36, 20],
+                    });
+                if (!chart) return chart;
+                chart.data(dv.rows); //这个赋值是升级后的 方式
+                chart.tooltip(false);
+                chart.scale("Date", {
+                    //range: [0, 1],
+                    tickCount: 12,
+                    //tickInterval:0,
+                    type: "timeCat",
+                    mask: "MM-DD",
+                });
+                chart.scale("value", {
+                    //range: [0, 1],
+                    tickCount: 5,
+                    type: "linear",
+                    //max: 1500,//这个不能小于实际值 不然显示不出来
+                    //tickInterval
+                    // type: 'timeCat'
+                });
+                chart.axis("Date", {
+                    line: {
+                        style: {
+                            lineWidth: 1, // 设置线的宽度
+                            stroke: "rgba(224,194,155,0.6)", // 设置线的颜色
+                            lineDash: [3, 3], // 设置虚线样式
+                        },
+                    },
+                    label: {
+                        style: {
+                            fill: "#E0C29B",
+                            fontSize: 12,
+                        },
+                    },
+                    tickLine: null,
+                });
+                chart.axis("value", {
+                    line: null,
+                    grid: {
+                        line: {
+                            style: {
+                                lineWidth: 1, // 设置线的宽度
+                                stroke: "rgba(224,194,155,0.5)", // 设置线的颜色
+                                lineDash: [3, 3], // 设置虚线样式
+                            },
+                        },
+                    },
+                    tickline: null,
+                    label: null,
+                });
+
+                chart.legend(false);
+
+                chart
+                    .interval()
+                    .position("Date*value")
+                    .color("l(90) 0:#BFA17E 1:#E0D1BB")
+                    .shape("borderRadius")
+                    .adjust({ type: "stack" })
+                    .size(12)
+                    .label("value", {
+                        offset: 10,
+                        style: {
+                            fill: "#E0C29B",
+                            fontSize: 12,
+                        },
+                    });
+
+                chart.render();
+                allData.ds = ds;
+
+                return chart;
+            },
+        });
+        onMounted(() => {
+            allData.getLastDayEnergy();
+        });
+        return { ...toRefs(allData), lastChartBox };
+    },
+});
+</script>
+
+<style scoped lang="scss">
+.lastChart {
+    height: 100%;
+    .head-title {
+        justify-content: space-between;
+        padding: 0 32px;
+        .rightVal {
+            color: #39354e;
+            font-size: 14px;
+            font-weight: normal;
+        }
+    }
+    .lastChartBox {
+        padding-top: 36px;
+        box-sizing: border-box;
+        height: calc(100% - 60px);
+    }
+}
+.horizontalClass {
+}
+.verticalTemChart {
+    height: 450px;
+    padding: 0 36px;
+    background: rgba(149, 162, 194, 0.1);
+    backdrop-filter: blur(40px);
+    border-radius: 20px;
+}
+</style>

+ 155 - 0
src/components/pageHead.vue

@@ -0,0 +1,155 @@
+<template>
+    <div class="horHead horSty">
+        <div class="horHead-content">
+            <div>
+                <div class="firtitle">{{ projectObj.localName }}</div>
+                <div class="sectitle">懂空间,更懂办公</div>
+            </div>
+            <!-- <img :src="title" v-else /> -->
+        </div>
+        <div class="horHead-left">
+            <img :src="logo" alt="" style="height: 60px" />
+        </div>
+        <div class="horHead-right">
+            <div class="right-item">
+                <span class="item-time">{{ nowStr }}</span>
+            </div>
+            <div class="right-item">{{ weatherCont.text }}</div>
+            <div class="right-item" @click="changeScreen">
+                <img
+                    class="firstImg"
+                    alt=""
+                    :src="nowScreen == 'vertical' ? changeHor : changeVer"
+                />
+            </div>
+            <div class="right-item" style="display: none">退出</div>
+        </div>
+    </div>
+</template>
+<script lang="ts">
+import { ref, defineComponent, reactive, toRefs, onMounted } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import moment from "moment";
+import { storeToRefs } from "pinia";
+import useProjectStore from "@/store/useProjectStore";
+import { dapingImage } from "@/utils/dapingImage";
+
+export default defineComponent({
+    props: {
+        navigateItem: {
+            type: String,
+        },
+    },
+    setup(props, contx) {
+       
+        const { persagyLogo, zhijiangLogo, changeHor, changeVer } = dapingImage;
+
+        const route: any = useRoute();
+        const router = useRouter();
+        const projectStore = useProjectStore();
+
+        const { weatherCont, projectObj, projectId } =
+            storeToRefs(projectStore);
+
+      
+        const allData = reactive({
+            // logo: new URL(
+            //     "../assets/image/horImg/zhijianglogo.png",
+            //     import.meta.url
+            // ).href,
+            logo: projectId == "Pj3301100002" ? zhijiangLogo : persagyLogo,
+            changeHor: changeHor,
+            changeVer: changeVer,
+            nowScreen:
+                route.path.indexOf("horiScreen") > -1
+                    ? "horizontal"
+                    : "vertical",
+            nowStr: moment().format("YYYY.MM.DD HH:mm"),
+            setNowInterval() {
+                setInterval(() => {
+                    allData.nowstr = moment().format("YYYY.MM.DD HH:mm");
+                }, 5000);
+            },
+            changeScreen() {
+                if (allData.nowScreen == "vertical") {
+                    allData.nowScreen = "horizontal";
+                    router.push({ path: "/horiScreen" });
+                } else {
+                    allData.nowScreen = "vertical";
+                    router.push({ path: "/verScreen" });
+                }
+            },
+        });
+
+        onMounted(() => {
+            allData.setNowInterval();
+        });
+        return { ...toRefs(allData), weatherCont, projectObj };
+    },
+});
+</script>
+
+<style scoped lang="scss">
+.horHead {
+    // display: flex;
+    // justify-content: space-between;
+    // align-items: center;
+    position: relative;
+    &.horSty {
+        height: 74px;
+    }
+    .horHead-content {
+        width: 100%;
+        height: 100%;
+        color: #efdec6;
+        text-align: center;
+        .firtitle {
+            font-weight: 700;
+            font-size: 38px;
+            font-family: Alibaba PuHuiTi;
+        }
+        .sectitle {
+            font-weight: 500;
+            font-size: 16px;
+            letter-spacing: 8px;
+        }
+    }
+    .horHead-left {
+        position: absolute;
+        top: 0;
+        left: 0;
+    }
+    .horHead-right {
+        position: absolute;
+        top: 0;
+        right: 0;
+        display: flex;
+        // justify-content: space-between;
+        height: 46px;
+        // width: 396px;
+        .right-item {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            cursor: pointer;
+            // padding: 12px 16px;
+            font-size: 16px;
+            color: #efdec6;
+            font-weight: 400;
+            line-height: 22px;
+            margin-left: 18px;
+            // background: #ffffff99;
+            // border: 2px solid #ffffffcc;
+            box-sizing: border-box;
+            // border-radius: 8px;
+            .firstImg {
+                margin-right: 6px;
+            }
+            .item-time {
+                font-family: Persagy;
+                font-weight: 400;
+            }
+        }
+    }
+}
+</style>

+ 11 - 0
src/main.ts

@@ -0,0 +1,11 @@
+import { createApp } from "vue";
+import "./style.scss";
+import App from "./App.vue";
+import router from "./router";
+import "element-plus/dist/index.css";
+import ElementPlus from "element-plus";
+import { createPinia } from "pinia";
+
+
+
+createApp(App).use(router).use(createPinia()).use(ElementPlus).mount("#app");

+ 50 - 0
src/router/index.ts

@@ -0,0 +1,50 @@
+import {
+    createRouter,
+    createWebHistory,
+    createWebHashHistory,
+} from "vue-router";
+
+const history = createWebHistory("/sgdaping/");
+const routes = [
+    {
+        path: "/",
+        redirect: "/horiScreen",
+    },
+    {
+        path: "/horiScreen",
+        name: "horiScreen",
+        component: () => import("@/views/horiScreen/index.vue"),
+    },
+    {
+        path: "/verScreen",
+        name: "verScreen",
+        component: () => import("@/views/verScreen/index.vue"),
+    },
+    {
+        path: "/login",
+        name: "login",
+        component: () => import("@/views/login/index.vue"),
+    },
+];
+const router = createRouter({
+    history,
+    routes,
+});
+
+import useProjectStore from "@/store/useProjectStore";
+router.beforeEach(async (to, from, next) => {
+    // canUserAccess() 返回 `true` 或 `false`
+
+    //debugger;
+    var projectId = to.query.projectId || "";
+    const projectStore = useProjectStore();
+    projectId && projectStore.setProjectId(projectId);
+
+    await projectStore.setWeather();
+    await projectStore.setProjectObj();
+    next();
+    // if (to.path.indexOf("login") == -1) {
+    //     return { name: "login" };
+    // }
+});
+export default router;

+ 54 - 0
src/store/useProjectStore.ts

@@ -0,0 +1,54 @@
+import { defineStore } from "pinia";
+import { getWeather, getProjectObj, queryLastEnergy } from "@/api/index";
+
+interface projectStoreState {
+    weatherCont: any;
+    projectId: string;
+    projectObj: any;
+    lastAllEnergy: any;
+}
+
+const useProjectStore = defineStore({
+    id: "project",
+    state: (): projectStoreState => {
+        return {
+            weatherCont: {}, //天气
+            projectId: "Pj1101080259", // "Pj3301100002",
+            projectObj: {},
+            lastAllEnergy: {},
+        };
+    },
+    getters: {
+        floorIdAfter() {},
+    },
+    actions: {
+        setProjectId(param: any) {
+            //console.log("this", this);
+            //debugger;
+            this.projectId = param;
+        },
+        async setProjectObj() {
+            try {
+                var res = await getProjectObj();
+                var project = res.data.content[0] || {};
+                this.projectObj = project;
+            } catch (err) {}
+        },
+        async setWeather() {
+            try {
+                var res = await getWeather();
+                var weatherRes = res.data.content || {};
+                this.weatherCont = weatherRes;
+            } catch (err) {}
+        },
+        async setLastAllEnergy() {
+            try {
+                var res = await queryLastEnergy();
+
+                var resdata = (res.data.content || [])[0] || {};
+                this.lastAllEnergy = resdata;
+            } catch (err) {}
+        },
+    },
+});
+export default useProjectStore;

+ 63 - 0
src/style.scss

@@ -0,0 +1,63 @@
+:root {
+    font-size: 14px;
+    font-weight: 400;
+
+    color-scheme: light dark;
+
+    font-synthesis: none;
+    text-rendering: optimizeLegibility;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+    -webkit-text-size-adjust: 100%;
+}
+
+@font-face {
+    font-family: "PersagyBold";
+    src: url("@/assets/font/PersagyBold2.ttf");
+}
+
+@font-face {
+    font-family: "Persagy";
+    src: url("@/assets/font/PersagyRegular2.ttf");
+}
+html {
+    height: 100%;
+    margin: 0;
+    padding: 0;
+}
+body {
+    overflow-x: hidden;
+    margin: 0;
+    padding: 0;
+    height: 100%;
+}
+#app {
+    height: 100%;
+}
+.horizontalClass {
+    padding: 0px 28px 28px;
+    box-sizing: border-box;
+    border-radius: 20px;
+    // background: #ffffff;
+    font-size: 20px;
+}
+.head-title {
+    height: 56px;
+    font-weight: 700;
+    font-size: 40px;
+    line-height: 56px;
+    color: #f7e6cd;
+}
+
+.subhead-title {
+    font-weight: 400;
+    font-size: 25px;
+    padding-top: 36px;
+    line-height: 1;
+    height: 60px;
+    box-sizing: border-box;
+    color: #f7e6cd;
+}
+.verticalClass {
+    box-sizing: border-box;
+}

+ 8 - 0
src/types/service/index.ts

@@ -0,0 +1,8 @@
+export interface seasonTypeParam {
+    projectId: string;
+    date: string;
+}
+
+export interface mapParam {
+    floorId: string;
+}

+ 69 - 0
src/utils/dapingImage.ts

@@ -0,0 +1,69 @@
+import persagyLogo from "@/assets/image/horImg/persagyLogo.svg";
+import zhijiangLogo from "@/assets/image/horImg/zhijianglogo.png";
+
+import changeVer from "@/assets/image/horImg/changeVer.svg";
+import changeHor from "@/assets/image/horImg/changeHor.svg";
+
+import yellowlight from "@/assets/image/horImg/yellowlight.png";
+import redlight from "@/assets/image/horImg/redlight.png";
+import greenlight from "@/assets/image/horImg/greenlight.png";
+import bluegreen from "@/assets/image/horImg/bluegreen.png";
+import yellowgreen from "@/assets/image/horImg/yellowgreen.png";
+import redyellow from "@/assets/image/horImg/redyellow.png";
+import bluelight from "@/assets/image/horImg/bluelight.png";
+
+import lastco2 from "@/assets/image/horImg/lastco2.png";
+import lasthumidity from "@/assets/image/horImg/lasthumidity.png";
+import lastmethanal from "@/assets/image/horImg/lastmethanal.png";
+import lastpm25 from "@/assets/image/horImg/lastpm25.png";
+import lasttemp from "@/assets/image/horImg/lasttemp.png";
+
+import floor_co2 from "@/assets/image/horImg/floor_co2.png";
+import floor_jiaquan from "@/assets/image/horImg/floor_jiaquan.png";
+import floor_pm25 from "@/assets/image/horImg/floor_pm25.png";
+import floor_shidu from "@/assets/image/horImg/floor_shidu.png";
+import floor_wendu from "@/assets/image/horImg/floor_wendu.png";
+
+import floor_co2_ver from "@/assets/image/horImg/floor_co2_ver.png";
+import floor_jiaquan_ver from "@/assets/image/horImg/floor_jiaquan_ver.png";
+import floor_pm25_ver from "@/assets/image/horImg/floor_pm25_ver.png";
+import floor_shidu_ver from "@/assets/image/horImg/floor_shidu_ver.png";
+import floor_wendu_ver from "@/assets/image/horImg/floor_wendu_ver.png";
+
+import lastGold from "@/assets/image/horImg/lastGold.svg";
+import lastGray from "@/assets/image/horImg/lastGray.svg";
+export const dapingImage = {
+    persagyLogo: persagyLogo,
+    zhijiangLogo: zhijiangLogo,
+    changeVer: changeVer,
+    changeHor: changeHor,
+
+    yellowlight: yellowlight,
+    redlight: redlight,
+    greenlight: greenlight,
+    bluegreen: bluegreen,
+    yellowgreen: yellowgreen,
+    redyellow: redyellow,
+    bluelight: bluelight,
+
+    lastco2: lastco2,
+    lasthumidity: lasthumidity,
+    lastmethanal: lastmethanal,
+    lastpm25: lastpm25,
+    lasttemp: lasttemp,
+
+    floor_co2: floor_co2,
+    floor_jiaquan: floor_jiaquan,
+    floor_pm25: floor_pm25,
+    floor_shidu: floor_shidu,
+    floor_wendu: floor_wendu,
+
+    floor_co2_ver: floor_co2_ver,
+    floor_jiaquan_ver: floor_jiaquan_ver,
+    floor_pm25_ver: floor_pm25_ver,
+    floor_shidu_ver: floor_shidu_ver,
+    floor_wendu_ver: floor_wendu_ver,
+
+    lastGold: lastGold,
+    lastGray: lastGray,
+};

+ 212 - 0
src/utils/publicMethod.ts

@@ -0,0 +1,212 @@
+import { dapingImage } from "@/utils/dapingImage";
+import { ref } from "vue";
+
+var selectColor = function (value: any, typestr: string, floor: any) {
+    if (value === null || value === undefined) return null;
+    const {
+        yellowlight,
+        redlight,
+        greenlight,
+        bluegreen,
+        yellowgreen,
+        redyellow,
+        bluelight,
+    } = dapingImage;
+
+    var colorArr: { [key: string]: Array<any> } = {
+        temp: [
+            {
+                min: Number.NEGATIVE_INFINITY,
+                max: 20,
+                image: bluelight,
+                color: "#52A0FF",
+                fcolor: "rgba(0, 95, 163, 0.76)",
+            },
+            {
+                min: 20,
+                max: 22,
+                image: bluegreen,
+                color: "#40DDCE",
+                fcolor: "rgba(0, 160, 163, 0.76)",
+            },
+            {
+                min: 22,
+                max: 27,
+                image: greenlight,
+                color: "#7ED874",
+                fcolor: "rgba(34, 139, 81, 0.76)",
+            },
+            {
+                min: 27,
+                max: 28,
+                image: yellowgreen,
+                color: "#C4E34F",
+                fcolor: "rgba(133, 148, 0, 0.76)",
+            },
+            {
+                min: 28,
+                max: 30,
+                image: redyellow,
+                color: "#EE9F2B",
+                fcolor: "rgba(173, 107, 0, 0.8)",
+            },
+            {
+                min: 30,
+                max: Number.POSITIVE_INFINITY,
+                image: redlight,
+                color: "#F5483D",
+                fcolor: "rgba(154, 40, 40, 0.8)",
+            },
+        ],
+        humidity: [
+            {
+                min: 0,
+                max: 30,
+                image: redlight,
+                color: "#F5483D",
+                fcolor: "rgba(173, 107, 0, 0.8)",
+            },
+            {
+                min: 30,
+                max: 35,
+                image: redyellow,
+                color: "#EE9F2B",
+                fcolor: "rgba(133, 148, 0, 0.76)",
+            },
+            {
+                min: 35,
+                max: 65,
+                image: greenlight,
+                color: "#7ED874",
+                fcolor: "rgba(34, 139, 81, 0.76)",
+            },
+            {
+                min: 65,
+                max: 95,
+                image: bluegreen,
+                color: "#40DDCE",
+                fcolor: "rgba(0, 160, 163, 0.76)",
+            },
+            {
+                min: 95,
+                max: Number.POSITIVE_INFINITY,
+                image: bluelight,
+                color: "#52A0FF",
+                fcolor: "rgba(0, 95, 163, 0.76)",
+            },
+        ],
+        co2: [
+            {
+                min: 0,
+                max: 800,
+                image: greenlight,
+                color: "#7ED874",
+                fcolor: "rgba(34, 139, 81, 0.76)",
+            },
+            {
+                min: 800,
+                max: 1000,
+                image: yellowgreen,
+                color: "#C4E34F",
+                fcolor: "rgba(133, 148, 0, 0.76)",
+            },
+            {
+                min: 1000,
+                max: 2500,
+                image: redyellow,
+                color: "#EE9F2B",
+                fcolor: "rgba(173, 107, 0, 0.8)",
+            },
+            {
+                min: 2500,
+                max: Number.POSITIVE_INFINITY,
+                image: redlight,
+                color: "#F5483D",
+                fcolor: "rgba(154, 40, 40, 0.8)",
+            },
+        ],
+        methanal: [
+            {
+                min: 0,
+                max: 0.08,
+                image: greenlight,
+                color: "#7ED874",
+                fcolor: "rgba(34, 139, 81, 0.76)",
+            },
+            {
+                min: 0.08,
+                max: 0.1,
+                image: yellowgreen,
+                color: "#C4E34F",
+                fcolor: "rgba(133, 148, 0, 0.76)",
+            },
+            {
+                min: 0.1,
+                max: 0.2,
+                image: redyellow,
+                color: "#EE9F2B",
+                fcolor: "rgba(173, 107, 0, 0.8)",
+            },
+            {
+                min: 0.2,
+                max: Number.POSITIVE_INFINITY,
+                image: redlight,
+                color: "#F5483D",
+                fcolor: "rgba(154, 40, 40, 0.8)",
+            },
+        ],
+        pm25: [
+            {
+                min: 0,
+                max: 35,
+                image: greenlight,
+                color: "#7ED874",
+                fcolor: "rgba(34, 139, 81, 0.76)",
+            },
+            {
+                min: 35,
+                max: 75,
+                image: yellowgreen,
+                color: "#C4E34F",
+                fcolor: "rgba(133, 148, 0, 0.76)",
+            },
+            {
+                min: 75,
+                max: 150,
+                image: yellowlight,
+                color: "#EFD62E",
+                fcolor: "rgba(156, 137, 0, 0.76)",
+            },
+            {
+                min: 150,
+                max: 250,
+                image: redyellow,
+                color: "#EE9F2B",
+                fcolor: "rgba(173, 107, 0, 0.8)",
+            },
+            {
+                min: 250,
+                max: Number.POSITIVE_INFINITY,
+                image: redlight,
+                color: "#F5483D",
+                fcolor: "rgba(154, 40, 40, 0.8)",
+            },
+        ],
+    };
+
+    var nowColorArr = colorArr[typestr];
+    var colorImage = null;
+    nowColorArr.forEach((ele: any) => {
+        if (value > ele.min && value < ele.max) {
+            colorImage = floor ? ele.fcolor : ele.image;
+        }
+    });
+
+    return colorImage;
+};
+
+var operateNum = function (num: any) {
+    return num.toFixed(1);
+};
+
+export { selectColor };

+ 93 - 0
src/utils/request.ts

@@ -0,0 +1,93 @@
+import axios from "axios";
+import { getToken } from "@/utils/tcookies";
+//import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
+
+// console.log(
+//     "import.meta.env.VITE_BASE_API ",
+//     import.meta.env.VITE_BASE_API,
+//     import.meta.env.BASE_URL
+// );
+
+const service = axios.create({
+    baseURL: import.meta.env.VITE_BASE_API,
+    timeout: 99999,
+});
+
+service.interceptors.request.use(
+    (config: any) => {
+        // debugger;
+        var token = getToken();
+        if (token) {
+            config.headers["asr-token"] = token;
+        }
+        return config;
+    },
+    (error) => {
+        return Promise.reject(error);
+    }
+);
+service.interceptors.response.use(
+    (response) => {
+        //  debugger;
+        if (response.status == 200) {
+            return response;
+        } else {
+            return Promise.reject(response);
+        }
+    },
+    (error) => {
+        return Promise.reject(error);
+    }
+);
+export default service;
+
+// // http request 拦截器
+// service.interceptors.request.use(
+//     (config: any) => {
+//         // 全局添加 token
+//         if (getToken()) {
+//             config.headers["asr-token"] = getToken();
+//         }
+//         return config;
+//     },
+//     (error) => {
+//         console.error(error);
+//         return Promise.reject(error);
+//     }
+// );
+// // http response 拦截器
+// service.interceptors.response.use(
+//     (response) => {
+//         if (response.data.code === 9) {
+//             // Router.replace('/rejectUser');
+//             return;
+//         }
+//         return response.data;
+//     },
+//     (error) => {
+//         if (
+//             error.response &&
+//             error.response.status &&
+//             error.response.status === 403
+//         ) {
+//             //   logout().then(() => {
+//             //     // removeToken()
+//             //   });
+//         }
+//         // 网络超时
+//         if (error.message && error.message.includes("timeout")) {
+//             console.error("请求超时");
+//             return error.message;
+//         }
+//         if (
+//             error.response &&
+//             error.response.status &&
+//             error.response.status === 500
+//         ) {
+//             // 没有权限
+//             console.error("接口异常");
+//             return error;
+//         }
+//         return error;
+//     }
+// );

+ 12 - 0
src/utils/tcookies.ts

@@ -0,0 +1,12 @@
+import Cookies from "js-cookie";
+const TokenKey = "au-token";
+
+export const getToken = () => {
+    return Cookies.get(TokenKey);
+};
+export const setToken = (token: string) => {
+    Cookies.set(TokenKey, token);
+};
+export const delToken = () => {
+    return Cookies.remove(TokenKey);
+};

+ 24 - 0
src/utils/useAirSwitch.ts

@@ -0,0 +1,24 @@
+import { ref, computed, onMounted } from "vue";
+import { queryConditionerStatus } from "@/api/index";
+
+export default function () {
+    const airValue = ref();
+    const airStatus = ref();
+    onMounted(() => {
+        queryConditionerStatus()
+            .then((res) => {
+                var airCondition = res.data.data || {};
+
+                var openRate = airCondition.openRate || 0;
+                airValue.value = openRate
+                    ? Number((openRate * 100).toFixed(0))
+                    : openRate;
+
+                airStatus.value = openRate ? true : false;
+
+                // debugger;
+            })
+            .catch((err) => {});
+    });
+    return { airValue, airStatus };
+}

+ 11 - 0
src/utils/useCouter.ts

@@ -0,0 +1,11 @@
+import { ref, computed } from "vue";
+export default function () {
+    const counter = ref(0);
+    const doubleCounter = computed(() => {
+        return counter.value * 2;
+      
+    });
+    const increment = () => counter.value++;
+    const decrement = () => counter.value--;
+    return { counter, doubleCounter, increment, decrement };
+}

+ 19 - 0
src/utils/useLocalStorage.ts

@@ -0,0 +1,19 @@
+import { ref, watch } from "vue";
+
+export default function (key: string, value: any) {
+    const localdata = ref<any>();
+
+    var storageValue = window.localStorage.getItem(key);
+    storageValue && (localdata.value = JSON.parse(storageValue)); //初始值
+
+    if (value) {
+        window.localStorage.setItem(key, JSON.stringify(value));
+    }
+
+    watch(localdata, (newvalue, oldvalue) => {
+        //debugger;
+        // console.log("newvalue", newvalue);
+        window.localStorage.setItem(key, JSON.stringify(newvalue));
+    });
+    return localdata;
+}

+ 218 - 0
src/views/horiScreen/index.vue

@@ -0,0 +1,218 @@
+<template>
+    <div class="horizontalScreen">
+        <div class="bg">
+            <img
+                src="@/assets/image/horImg/hor_big_bg.png"
+                style="display: none"
+            />
+        </div>
+        <div class="container">
+            <div class="hor-head">
+                <pageHead />
+            </div>
+            <div
+                class="hor-content firstScreen flexBetween"
+                v-if="nowPage == 1"
+            >
+                <div class="content-left">
+                    <NowData screenType="hor" />
+                    <div class="content-left-cont horizontalClass flexBetween">
+                        <div class="bottom-left">
+                            <airSwitchHor></airSwitchHor>
+                            <!-- <airSwitchVer></airSwitchVer> -->
+                        </div>
+                        <div class="bottom-right">
+                            <TemChart screenType="hor"></TemChart>
+                        </div>
+                    </div>
+                </div>
+                <div class="content-right">
+                    <LastMonthData screenType="hor"></LastMonthData>
+                </div>
+            </div>
+            <div class="hor-content" v-if="nowPage == 2">
+                <HorFloorSpace
+                    screenType="hor"
+                    :showPing="nowPage"
+                    @donetowpage="doneTowPage"
+                ></HorFloorSpace>
+            </div>
+            <div class="hor-content threeScreen" v-if="nowPage == 3">
+                <div class="topCont flexBetween">
+                    <div class="threeLeft">
+                        <LastAllEnergy screenType="hor"></LastAllEnergy>
+                    </div>
+                    <div class="threeRight">
+                        <LastSaveEnergy screenType="hor"></LastSaveEnergy>
+                    </div>
+                </div>
+                <div class="bottomCont">
+                    <lastEnergyChart screenType="hor"></lastEnergyChart>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+<script lang="ts">
+import { ref, reactive, toRefs, onMounted } from "vue";
+import pageHead from "@/components/pageHead.vue";
+import NowData from "@/components/NowData.vue";
+import LastMonthData from "@/components/LastMonthData.vue";
+import airSwitchVer from "@/components/airSwitchVer.vue";
+import airSwitchHor from "@/components/airSwitchHor.vue";
+import TemChart from "@/components/TemChart.vue";
+import LastAllEnergy from "@/components/LastAllEnergy.vue";
+import LastSaveEnergy from "@/components/LastSaveEnergy.vue";
+import HorFloorSpace from "@/components/HorFloorSpace.vue";
+import lastEnergyChart from "@/components/lastEnergyChart.vue";
+
+import { storeToRefs } from "pinia";
+import useProjectStore from "@/store/useProjectStore";
+
+export default {
+    components: {
+        pageHead: pageHead,
+        NowData: NowData,
+        LastMonthData: LastMonthData,
+        airSwitchVer: airSwitchVer,
+        TemChart: TemChart,
+        HorFloorSpace: HorFloorSpace,
+        LastAllEnergy: LastAllEnergy,
+        lastEnergyChart: lastEnergyChart,
+        airSwitchHor: airSwitchHor,
+        LastSaveEnergy: LastSaveEnergy,
+    },
+    setup() {
+        const allData = reactive({
+            nowPage: 1,
+            showAllPage: 3,
+            doneTowPage() {
+                //第二屏刷新结束 通知
+                if (allData.showAllPage == 3) {
+                    allData.nowPage = 3;
+                } else if (allData.showAllPage == 2) {
+                    allData.nowPage = 1;
+                }
+                allData.timePageShow();
+            },
+            timePageShow() {
+                var timeoutsign = setTimeout(() => {
+                    allData.nowPage = allData.nowPage + 1;
+                    if (allData.nowPage == 4) {
+                        allData.nowPage = 1;
+                    }
+                    if (allData.nowPage == 2) {
+                        clearTimeout(timeoutsign);
+                        return;
+                    }
+                    allData.timePageShow();
+                }, 3000);
+            },
+        });
+        onMounted(() => {
+            allData.timePageShow();
+        });
+        return {
+            ...toRefs(allData),
+        };
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.horizontalScreen {
+    padding: 30px 40px 0;
+    height: 100%;
+    box-sizing: border-box;
+    scrollbar-width: none;
+    position: relative;
+    .container {
+        height: 100%;
+    }
+    .bg {
+        position: absolute;
+        top: 0;
+        left: 0;
+        z-index: -1;
+        right: 0;
+        bottom: 0;
+        overflow: hidden;
+        background: #070a25;
+        img {
+            width: 100%;
+            height: 100%;
+        }
+    }
+    .hor-head {
+        height: 134px;
+        box-sizing: border-box;
+    }
+    .hor-content {
+        height: calc(100% - 134px);
+    }
+    .firstScreen {
+        box-sizing: border-box;
+
+        .content-left {
+            width: calc(100% - 303px);
+            height: 100%;
+        }
+        .content-right {
+            width: 303px;
+            height: 100%;
+        }
+        .content-left-cont {
+            height: 50%;
+            .bottom-left {
+                width: 36%;
+                height: 100%;
+                background: rgba(149, 162, 194, 0.1);
+            }
+            .bottom-right {
+                width: 64%;
+                height: 100%;
+                background: rgba(149, 162, 194, 0.1);
+            }
+        }
+    }
+    .flexBetween {
+        display: flex;
+        justify-content: space-between;
+    }
+}
+.threeScreen {
+    .topCont {
+        height: 50%;
+        .threeLeft {
+            position: relative;
+            height: 100%;
+            width: 40%;
+            box-sizing: border-box;
+            padding-right: 25px;
+            .left-content {
+                text-align: center;
+                height: 390px;
+                width: 100%;
+                margin-top: 20px;
+                position: relative;
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                .lastbg {
+                    position: absolute;
+                }
+            }
+        }
+        .threeRight {
+            position: relative;
+            height: 100%;
+            width: 60%;
+        }
+    }
+    .bottomCont {
+        height: 50%;
+        padding-top: 20px;
+        box-sizing: border-box;
+    }
+}
+</style>

+ 23 - 0
src/views/login/index.vue

@@ -0,0 +1,23 @@
+<template>
+    <h2>login页面</h2>
+</template>
+<script lang="ts">
+import { ref, defineComponent, reactive, toRefs, watch, onMounted } from "vue";
+import { useRouter } from "vue-router";
+import { storeToRefs } from "pinia";
+import useProjectStore from "@/store/useProjectStore";
+import { getToken } from "@/utils/tcookies";
+
+export default defineComponent({
+    setup() {
+        const router = useRouter();
+
+        const allData = reactive({});
+
+        onMounted(() => {});
+        return {};
+    },
+});
+</script>
+
+<style scoped lang="scss"></style>

+ 138 - 0
src/views/verScreen/index.vue

@@ -0,0 +1,138 @@
+<template>
+    <div class="verticalWrap">
+        <div class="bg">
+            <img
+                src="@/assets/image/horImg/hor_big_bg.png"
+                style="display: none"
+            />
+        </div>
+        <div class="container">
+            <div class="hor-head">
+                <pageHead />
+            </div>
+            <div class="hor-content" v-if="nowPage == 1">
+                <NowData screenType="ver"></NowData>
+                <airSwitchVer></airSwitchVer>
+                <TemChart screenType="ver"></TemChart>
+                <LastMonthData screenType="ver"></LastMonthData>
+            </div>
+            <div class="hor-content" v-if="nowPage == 2">
+                <HorFloorSpace
+                    screenType="ver"
+                    :showPing="nowPage"
+                    @donetowpage="doneTowPage"
+                ></HorFloorSpace>
+            </div>
+            <div class="hor-content" v-if="nowPage == 3">
+                <LastAllEnergy screenType="ver"></LastAllEnergy>
+                <LastSaveEnergy screenType="ver"></LastSaveEnergy>
+                <lastEnergyChart
+                    screenType="ver"
+                    :showPing="nowPage"
+                    @donethreepage="doneThreePage"
+                ></lastEnergyChart>
+            </div>
+        </div>
+    </div>
+</template>
+<script lang="ts">
+import { ref, defineComponent, reactive, toRefs, watch, onMounted } from "vue";
+import { storeToRefs } from "pinia";
+import useProjectStore from "@/store/useProjectStore";
+
+import pageHead from "@/components/pageHead.vue";
+import NowData from "@/components/NowData.vue";
+import LastMonthData from "@/components/LastMonthData.vue";
+import airSwitchVer from "@/components/airSwitchVer.vue";
+import airSwitchHor from "@/components/airSwitchHor.vue";
+import TemChart from "@/components/TemChart.vue";
+import LastAllEnergy from "@/components/LastAllEnergy.vue";
+import LastSaveEnergy from "@/components/LastSaveEnergy.vue";
+import HorFloorSpace from "@/components/HorFloorSpace.vue";
+import lastEnergyChart from "@/components/lastEnergyChart.vue";
+
+export default defineComponent({
+    components: {
+        pageHead: pageHead,
+        NowData: NowData,
+        LastMonthData: LastMonthData,
+        airSwitchVer: airSwitchVer,
+        TemChart: TemChart,
+        HorFloorSpace: HorFloorSpace,
+        LastAllEnergy: LastAllEnergy,
+        lastEnergyChart: lastEnergyChart,
+        airSwitchHor: airSwitchHor,
+        LastSaveEnergy: LastSaveEnergy,
+    },
+    setup() {
+        const allData = reactive({
+            nowPage: 1,
+            showAllPage: 3,
+            doneThreePage() {
+                //第三屏刷新结束 通知
+                debugger;
+                allData.nowPage = 1;
+                allData.timePageShow(); //1屏变2屏
+            },
+            doneTowPage() {
+                debugger;
+                //第二屏刷新结束 通知
+                if (allData.showAllPage == 3) {
+                    allData.nowPage = 3;
+                } else if (allData.showAllPage == 2) {
+                    allData.nowPage = 1;
+                    allData.timePageShow(); //1屏变2屏
+                }
+            },
+            timePageShow() {
+                var timeoutsign = setTimeout(() => {
+                    debugger;
+                    allData.nowPage = allData.nowPage + 1;
+                    // if (allData.nowPage == 4) {
+                    //     allData.nowPage = 1;
+                    // }
+                }, 6000);
+            },
+        });
+
+        onMounted(() => {
+            allData.timePageShow();
+        });
+        return { ...toRefs(allData) };
+    },
+});
+</script>
+
+<style scoped lang="scss">
+.verticalWrap {
+    padding: 30px 40px;
+    // height: 100%;
+    box-sizing: border-box;
+    scrollbar-width: none;
+    position: relative;
+    .container {
+        //  height: 100%;
+    }
+    .bg {
+        position: absolute;
+        top: 0;
+        left: 0;
+        z-index: -1;
+        right: 0;
+        bottom: 0;
+        overflow: hidden;
+        background: #070a25;
+        img {
+            width: 100%;
+            height: 100%;
+        }
+    }
+    .hor-head {
+        height: 150px;
+        box-sizing: border-box;
+    }
+    .hor-content {
+        //   height: calc(100% - 134px);
+    }
+}
+</style>

+ 7 - 0
src/vite-env.d.ts

@@ -0,0 +1,7 @@
+/// <reference types="vite/client" />
+
+declare module '*.vue' {
+  import type { DefineComponent } from 'vue'
+  const component: DefineComponent<{}, {}, any>
+  export default component
+}

+ 23 - 0
tsconfig.json

@@ -0,0 +1,23 @@
+{
+  "compilerOptions": {
+    "target": "ESNext",
+    "useDefineForClassFields": true,
+    "module": "ESNext",
+    "moduleResolution": "Node",
+    "strict": true,
+    "jsx": "preserve",
+    "sourceMap": true,
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "esModuleInterop": true,
+    "lib": ["ESNext", "DOM"],
+    "skipLibCheck": true,
+    "paths": {
+        "@/*": [
+          "./src/*"
+        ]
+      }
+  },
+  "include": ["*.ts","src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
+  "references": [{ "path": "./tsconfig.node.json" }]
+}

+ 9 - 0
tsconfig.node.json

@@ -0,0 +1,9 @@
+{
+  "compilerOptions": {
+    "composite": true,
+    "module": "ESNext",
+    "moduleResolution": "Node",
+    "allowSyntheticDefaultImports": true
+  },
+  "include": ["vite.config.ts"]
+}

+ 47 - 0
vite.config.ts

@@ -0,0 +1,47 @@
+import { defineConfig } from "vite";
+import vue from "@vitejs/plugin-vue";
+import { resolve } from "path";
+import fs from "fs";
+import dotenv from "dotenv";
+
+// https://vitejs.dev/config/
+export default defineConfig(({ mode }) => {
+    console.log("mode", mode);
+    const ASR_ENV = dotenv.parse(fs.readFileSync(`.env.${mode}`));
+    console.log("ASR_ENV", ASR_ENV);
+    return {
+        plugins: [vue()],
+        assetsInclude: ["**/*.mov"],
+        base: "/sgdaping/",
+        //publicDir:'dist/sgshow',
+        build: {
+            outDir: "dist/sgdaping",
+        },
+        server: {
+            port: 3000,
+            open: true,
+            //https: true,
+            //cors: true,
+            proxy: {
+                // [ASR_ENV.VITE_BASE_API]: {
+                //     target: `${ASR_ENV.VITE_TARGET_HOST}`,
+                //     changeOrigin: true,
+                // },
+                "/sgdaping/duoduo-service": {
+                    target: "https://duoduoenv.sagacloud.cn",
+                    changeOrigin: true,
+                    rewrite: (path) =>
+                        path.replace(
+                            /^\/sgdaping\/duoduo-service/,
+                            "/duoduo-service"
+                        ),
+                },
+            },
+        },
+        resolve: {
+            alias: {
+                "@": resolve(__dirname, ".", "src"),
+            },
+        },
+    };
+});