刘嘉威
2022-10-26 e1c28921470ca2a82403ef5a7bc07f1c48619b36
feat: 增加右上 右中图表
10个文件已修改
4个文件已添加
540 ■■■■■ 已修改文件
components.d.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/modules/index.ts 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/datav/capsule-chart/capsule-chart.vue 186 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/datav/capsule-chart/index.d.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/datav/capsule-chart/index.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mock/mock-index.ts 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/echarts.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/public.ts 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/query-param.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/HomeView.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/index/center-bottom.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/index/right-center.vue 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/index/right-top.vue 232 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/setting.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
components.d.ts
@@ -7,6 +7,7 @@
declare module '@vue/runtime-core' {
  export interface GlobalComponents {
    CapsuleChart: typeof import('./src/components/datav/capsule-chart/capsule-chart.vue')['default']
    CountUp: typeof import('./src/components/count-up/count-up.vue')['default']
    ElDrawer: typeof import('element-plus/es')['ElDrawer']
    ElRadio: typeof import('element-plus/es')['ElRadio']
src/api/modules/index.ts
@@ -5,7 +5,7 @@
    "centerBottom":"/bigscreen/installationPlan",
    // 'big3':"/bigscreen/sbtx", //设备提醒
    // 'big4':"/bigscreen/alarmNum", //报警次数
    'rightTop':"/bigscreen/alarmNum", //报警次数
    // 'big5':'/bigscreen/ssyj',//实时预警 
    // 'big7':'/bigscreen/ranking',// 报警排名
    'rightCenter':'/bigscreen/ranking',// 报警排名
}
src/components/datav/capsule-chart/capsule-chart.vue
New file
@@ -0,0 +1,186 @@
<script setup lang="ts">
import { onMounted, reactive, ref, watch } from "vue";
import type { DefaultConfigType } from "./index.d";
import cloneDeep from "lodash/cloneDeep";
import merge from "lodash/merge";
const mergedConfig = ref<any>(null);
const capsuleLength = ref<any>([]);
const capsuleValue = ref<any>([]);
const labelData = ref<any>([]);
// const labelDataLength = ref<any>([]);
const defaultConfig = reactive<DefaultConfigType>({
    // Colors (hex|rgb|rgba|color keywords) ['#000', 'rgb(0, 0, 0)', 'rgba(0, 0, 0, 1)', 'red']
    colors: [
        "#37a2da",
        "#32c5e9",
        "#67e0e3",
        "#9fe6b8",
        "#ffdb5c",
        "#ff9f7f",
        "#fb7293",
    ],
    unit: "",
    showValue: false, // Show item value
});
const props = withDefaults(
    defineProps<{
        config: object | any;
        data: Array<{
            name: string;
            value: string | number;
        }>;
    }>(),
    {
        config: () => { },
        data: () => [],
    }
);
const calcData = () => {
    mergeConfig();
    calcCapsuleLengthAndLabelData();
};
const mergeConfig = () => {
    mergedConfig.value = merge(cloneDeep(defaultConfig), props.config || {});
};
const calcCapsuleLengthAndLabelData = () => {
    if (!props.data.length) return;
    const newcapsuleValue = props.data.map((item: any) => item.value);
    const maxValue = Math.max(...newcapsuleValue);
    capsuleValue.value = newcapsuleValue;
    capsuleLength.value = newcapsuleValue.map((v: any) =>
        maxValue ? v / maxValue : 0
    );
    const oneFifth = maxValue / 5;
    const newlabelData = Array.from(
        new Set(new Array(6).fill(0).map((v, i) => Math.ceil(i * oneFifth)))
    );
    labelData.value = newlabelData;
    // labelDataLength.value = Array.from(newlabelData).map((v) =>
    //     maxValue ? v / maxValue : 0
    // );
    // console.log(labelDataLength.value);
};
watch(
    () => props.data,
    (newval: any) => {
        calcData();
    },
);
watch(
    () => props.config,
    (newval: any) => {
        calcData();
    },
);
onMounted(() => {
    calcData();
});
</script>
<template>
    <div class="dv-capsule-chart">
        <template v-if="mergedConfig">
            <div class="label-column">
                <div v-for="item in data" :key="item.name">
                    {{ item.name }}
                </div>
                <div>&nbsp;</div>
            </div>
            <div class="capsule-container">
                <div class="capsule-item" v-for="(capsule, index) in capsuleLength" :key="index">
                    <div class="capsule-item-column" :style="`width: ${capsule * 100}%; background-color: ${mergedConfig.colors[index % mergedConfig.colors.length]
                    };`">
                        <div v-if="mergedConfig.showValue" class="capsule-item-value">
                            {{ capsuleValue[index] }}
                        </div>
                    </div>
                </div>
                <div class="unit-label">
                    <div v-for="(label, index) in labelData" :key="label + index">
                        {{ label }}
                    </div>
                </div>
            </div>
            <div class="unit-text" v-if="mergedConfig.unit">
                {{ mergedConfig.unit }}
            </div>
        </template>
    </div>
</template>
<style scoped lang="scss">
.dv-capsule-chart {
    position: relative;
    display: flex;
    flex-direction: row;
    box-sizing: border-box;
    padding: 10px;
    color: #fff;
    .label-column {
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        box-sizing: border-box;
        padding-right: 10px;
        text-align: right;
        font-size: 12px;
        div {
            height: 20px;
            line-height: 20px;
        }
    }
    .capsule-container {
        flex: 1;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
    }
    .capsule-item {
        box-shadow: 0 0 3px #999;
        height: 10px;
        margin: 5px 0px;
        border-radius: 5px;
        .capsule-item-column {
            position: relative;
            height: 8px;
            margin-top: 1px;
            border-radius: 5px;
            transition: all 0.3s;
            display: flex;
            justify-content: flex-end;
            align-items: center;
            .capsule-item-value {
                font-size: 12px;
                transform: translateX(100%);
            }
        }
    }
    .unit-label {
        height: 20px;
        font-size: 12px;
        position: relative;
        display: flex;
        justify-content: space-between;
        align-items: center;
    }
    .unit-text {
        text-align: right;
        display: flex;
        align-items: flex-end;
        font-size: 12px;
        line-height: 20px;
        margin-left: 10px;
    }
}
</style>
src/components/datav/capsule-chart/index.d.ts
New file
@@ -0,0 +1,6 @@
export interface DefaultConfigType {
    colors: Array<String>;
      unit:string,
      showValue:Boolean
  }
src/components/datav/capsule-chart/index.ts
New file
@@ -0,0 +1,3 @@
import CapsuleChart from "./capsule-chart.vue"
export * from "./index.d"
export default CapsuleChart
src/mock/mock-index.ts
@@ -57,6 +57,50 @@
            return a
        }
    },
    //右上
    {
        url: "/bigscreen/alarmNum",
        type: "get",
        response: () => {
            const a = Mock.mock({
                success: true,
                data: {
                    dateList: ['2021-11', '2021-12', '2022-01', '2022-02', '2022-03', "2022-04"],
                    "numList|6": [
                        '@integer(0, 1000)'
                    ],
                    "numList2|6": [
                        '@integer(0, 1000)'
                    ]
                }
            })
            return a
        }
    },
    //右中
    {
        url: "/bigscreen/ranking",
        type: "get",
        response: () => {
            let num =Mock.mock({"list|80":[{ value:"@integer(50,1000)",name:"@city()"}]}).list
            //   console.log("ranking",num);
              let newNum:any =[],numObj:any ={}
              num.map((item:any )=>{
                if(!numObj[item.name] && newNum.length<8){
                    numObj[item.name] =true
                    newNum.push(item)
                }
              })
              let arr = newNum.sort((a:any ,b:any )=>{
                return b.value-a.value
              })
              let a ={
                  success:true,
                  data:arr
              }
              return a
        }
    },
    //安装计划
    {
        url: "/bigscreen/installationPlan",
src/plugins/echarts.ts
@@ -14,7 +14,8 @@
    LegendComponent,
    DatasetComponent,
    VisualMapComponent,
    GeoComponent
    GeoComponent,
    MarkPointComponent
  } from 'echarts/components'
  use([
@@ -26,7 +27,8 @@
    TitleComponent,
    DatasetComponent,
    VisualMapComponent,
    GeoComponent
    GeoComponent,
    MarkPointComponent
  ])
  export const registerEcharts= (app:any)=>{
src/utils/public.ts
src/utils/query-param.ts
@@ -11,7 +11,7 @@
        for (var i = 0; i < urlArray.length; i++) {
            var urlItem = urlArray[i];
            var item = urlItem.split("=");
            console.log(item);
            // console.log(item);
            json[item[0]] = item[1];
        }
        return json;
src/views/HomeView.vue
@@ -3,15 +3,14 @@
import { RouterView } from "vue-router";
import ScaleScreen from "@/components/scale-screen";
import Headers from "./header.vue";
import Setting from "./setting.vue"
import Setting from "./setting.vue";
import { useSettingStore } from "@/stores/index";
import { storeToRefs } from 'pinia';
import  MessageContent  from '@/components/Plugins/MessageContent'
import { storeToRefs } from "pinia";
import MessageContent from "@/components/Plugins/MessageContent";
const settingStore = useSettingStore();
const {isScale} =storeToRefs(settingStore)
const { isScale } = storeToRefs(settingStore);
const wrapperStyle = {};
</script>
<template>
@@ -30,11 +29,10 @@
    <div class="content_wrap">
      <Headers />
      <RouterView />
  <MessageContent/>
      <MessageContent />
    </div>
  </scale-screen>
  <Setting/>
  <Setting />
</template>
<style lang="scss" scoped>
.content_wrap {
src/views/index/center-bottom.vue
@@ -17,7 +17,6 @@
  });
};
const setOption =async (newData: any) => {
  await nextTick()
  option.value = {
    tooltip: {
      trigger: "axis",
@@ -150,7 +149,10 @@
    ],
  };
};
onMounted(()=>{
getData();
})
</script>
<template>
src/views/index/right-center.vue
@@ -1,13 +1,39 @@
<script setup lang='ts'>
<script setup lang="ts">
import { ref, reactive } from "vue";
import CapsuleChart from "@/components/datav/capsule-chart";
import { currentGET } from "@/api";
const config = ref({
  showValue: true,
  unit: "次",
});
const data= ref([])
const getData = () => {
  currentGET("rightCenter").then((res) => {
    console.log("报警排名", res);
    if (res.success) {
      data.value =res.data;
    } else {
      window["$message"]({
        text: res.msg,
        type: "warning",
      });
    }
  });
};
getData();
</script>
<template>
  <div class=''>
  <div class="right_bottom">
    <CapsuleChart :config="config" style="width: 100%; height: 260px" :data="data"/>
  </div>
</template>
<style scoped lang='scss'>
<style scoped lang="scss">
</style>
.right_bottom {
  box-sizing: border-box;
  padding: 0 16px;
}
</style>
src/views/index/right-top.vue
@@ -1,13 +1,231 @@
<script setup lang='ts'>
<script setup lang="ts">
import { ref,onMounted} from "vue";
import { currentGET } from "@/api";
import {graphic} from "echarts/core"
const option = ref({});
const getData = () => {
  currentGET("rightTop", {}).then((res) => {
    console.log("报警次数 ", res);
    if (res.success) {
      setOption(res.data.dateList, res.data.numList, res.data.numList2);
    } else {
      window["$message"]({
        text: res.msg,
        type: "warning",
      });
    }
  });
};
const setOption =async (xData:any[], yData:any[], yData2:any[]) => {
  option.value = {
        xAxis: {
          type: "category",
          data: xData,
          boundaryGap: false, // 不留白,从原点开始
          splitLine: {
            show: true,
            lineStyle: {
              color: "rgba(31,99,163,.2)",
            },
          },
          axisLine: {
            // show:false,
            lineStyle: {
              color: "rgba(31,99,163,.1)",
            },
          },
          axisLabel: {
            color: "#7EB7FD",
            fontWeight: "500",
          },
        },
        yAxis: {
          type: "value",
          splitLine: {
            show: true,
            lineStyle: {
              color: "rgba(31,99,163,.2)",
            },
          },
          axisLine: {
            lineStyle: {
              color: "rgba(31,99,163,.1)",
            },
          },
          axisLabel: {
            color: "#7EB7FD",
            fontWeight: "500",
          },
        },
        tooltip: {
          trigger: "axis",
          backgroundColor: "rgba(0,0,0,.6)",
          borderColor: "rgba(147, 235, 248, .8)",
          textStyle: {
            color: "#FFF",
          },
        },
        grid: {
          //布局
          show: true,
          left: "10px",
          right: "30px",
          bottom: "10px",
          top: "32px",
          containLabel: true,
          borderColor: "#1F63A3",
        },
        series: [
          {
            data: yData,
            type: "line",
            smooth: true,
            symbol: "none", //去除点
            name: "报警1次数",
            color: "rgba(252,144,16,.7)",
            areaStyle: {
                //右,下,左,上
                color: new graphic.LinearGradient(
                  0,
                  0,
                  0,
                  1,
                  [
                    {
                      offset: 0,
                      color: "rgba(252,144,16,.7)",
                    },
                    {
                      offset: 1,
                      color: "rgba(252,144,16,.0)",
                    },
                  ],
                  false
                ),
            },
            markPoint: {
              data: [
                {
                  name: "最大值",
                  type: "max",
                  valueDim: "y",
                  symbol: "rect",
                  symbolSize: [60, 26],
                  symbolOffset: [0, -20],
                  itemStyle: {
                    color: "rgba(0,0,0,0)",
                  },
                  label: {
                    color: "#FC9010",
                    backgroundColor: "rgba(252,144,16,0.1)",
                    borderRadius: 6,
                    padding: [7, 14],
                    borderWidth: 0.5,
                    borderColor: "rgba(252,144,16,.5)",
                    formatter: "报警1:{c}",
                  },
                },
                {
                  name: "最大值",
                  type: "max",
                  valueDim: "y",
                  symbol: "circle",
                  symbolSize: 6,
                  itemStyle: {
                    color: "#FC9010",
                    shadowColor: "#FC9010",
                    shadowBlur: 8,
                  },
                  label: {
                    formatter: "",
                  },
                },
              ],
            },
          },
          {
            data: yData2,
            type: "line",
            smooth: true,
            symbol: "none", //去除点
            name: "报警2次数",
            color: "rgba(9,202,243,.7)",
            areaStyle: {
                //右,下,左,上
                color: new graphic.LinearGradient(
                  0,
                  0,
                  0,
                  1,
                  [
                    {
                      offset: 0,
                      color: "rgba(9,202,243,.7)",
                    },
                    {
                      offset: 1,
                      color: "rgba(9,202,243,.0)",
                    },
                  ],
                  false
                ),
            },
            markPoint: {
              data: [
                {
                  name: "最大值",
                  type: "max",
                  valueDim: "y",
                  symbol: "rect",
                  symbolSize: [60, 26],
                  symbolOffset: [0, -20],
                  itemStyle: {
                    color: "rgba(0,0,0,0)",
                  },
                  label: {
                    color: "#09CAF3",
                    backgroundColor: "rgba(9,202,243,0.1)",
                    borderRadius: 6,
                    borderColor: "rgba(9,202,243,.5)",
                    padding: [7, 14],
                    formatter: "报警2:{c}",
                    borderWidth: 0.5,
                  },
                },
                {
                  name: "最大值",
                  type: "max",
                  valueDim: "y",
                  symbol: "circle",
                  symbolSize: 6,
                  itemStyle: {
                    color: "#09CAF3",
                    shadowColor: "#09CAF3",
                    shadowBlur: 8,
                  },
                  label: {
                    formatter: "",
                  },
                },
              ],
            },
          },
        ],
      };
}
onMounted(()=>{
    getData();
})
</script>
<template>
  <div class=''>
  </div>
  <v-chart
    class="chart"
    :option="option"
    v-if="JSON.stringify(option) != '{}'"
  />
</template>
<style scoped lang='scss'>
</style>
<style scoped lang="scss"></style>
src/views/setting.vue
@@ -26,7 +26,7 @@
</script>
<template>
  <el-drawer v-model="settingStore.settingShow" direction="rtl">
  <el-drawer v-model="settingStore.settingShow" direction="rtl" size="360px">
    <template #header>
      <h2 class="setting-title">设置</h2>
    </template>