Newer
Older
Nanping_sponge_GCGL / src / views / index.vue
@liyingjing liyingjing on 25 Oct 15 KB 海绵工程管理
<template>
  <div class="app-container home">
    <div class="top">
      <div class="topLeft">
        <div class="tittle flex">
          <img src="../assets/projectCont.png" alt="" />
          <div class="conttittle">项目统计</div>
          <div class="top_time">
            <el-radio-group v-model="classify">
              <el-radio-button label="currentYear">当年</el-radio-button>
              <el-radio-button label="accumulativeTotal">累计</el-radio-button>
            </el-radio-group>
          </div>
        </div>
        <div class="flex cont">
          <div v-for="i in projectList">
            <div class="box">{{ statisticsData[classify][i.value] || 0 }}<span>个</span></div>
            <div
              class="label"
              :style="{ color: i.label == '延期' ? '#FF4F4FFF' : '' }"
            >
              {{ i.label }}
            </div>
          </div>
        </div>
      </div>
      <div class="topRight">
        <div class="tittle flex">
          <img src="../assets/projectMongy.png" alt="" />
          <div class="conttittle">金额统计</div>
        </div>
        <div class="flex cont">
          <div>
            <div class="box">{{ statisticsData.homePageMoney.totalMoney || 0 }} <span>万元</span></div>
            <div class="label">总金额</div>
          </div>
          <div>
            <div class="box">{{ statisticsData.homePageMoney.spongeTotalMoney || 0 }} <span>万元</span></div>
            <div class="label">海绵相关投资</div>
          </div>
          <div>
            <div class="box">{{ statisticsData.homePageMoney.currentYearTotalMoney || 0 }} <span>万元</span></div>
            <div class="label">当年完成项目总金额</div>
          </div>
          <div>
            <div class="box">{{ statisticsData.homePageMoney.currentYearSpongeMoney || 0 }} <span>万元</span></div>
            <div class="label">当年完成海绵相关投资</div>
          </div>
        </div>
      </div>
    </div>
    <div class="center flex">
      <div class="centerLeft">
        <div class="ectittle conttittle">项目类型统计</div>
        <homeEcharts v-if="isChart" :data="data1"></homeEcharts>
      </div>
      <div class="center_div">
        <div class="ectittle conttittle">项目建设状态统计</div>
        <homeEcharts v-if="isChart1" :data="data2"></homeEcharts>
      </div>
      <div class="centerright">
        <div class="ectittle conttittle">项目质量统计</div>
        <queryChat
          v-if="isChart2 && data3.xData.length > 0"
          :data="data3"
        ></queryChat>
        <div style="text-align: center; margin-top: 30%; color: #ddd" v-else>
          暂无数据
        </div>
      </div>
    </div>
    <div class="footer">
      <MapBox id="map" ref="mapRef" :isShowTool="false" @clickMap="clickMap"/>
      <div class="tabs">
        <div
          class="tab_it"
          v-for="tab in tabs"
          @click="tabClick(tab)"
          :class="{ active: curTab === tab }"
        >
          <span>{{ tab.name }}</span>
        </div>
      </div>
      <div class="legendList">
        <div class="legend_item" v-for="(item, i) in legendList">
          <span class="icon" :style="`background-color: ${colorList[i]}`"></span>
          <span>{{ item.name }}</span>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup name="Index">
import { getCurrentInstance } from "vue";
import homeEcharts from "./homeEcharts/index.vue";
import queryChat from "./homeEcharts/queryChat.vue";
import MapBox from '@/components/Map'
import {
  selectProjectQualityHomePage,
  getHomeStatistics,
  getProjectYearByType,
  getHomePageInfoByType,
  getDicts
} from "@/api/home"
import { projectTypeList } from '@/api/projectInformationNew'
const { proxy } = getCurrentInstance()
const { build_status } = proxy.useDict('build_status')
const colorList = [
  'rgba(84,112,198,1)',
  'rgba(145,204,117,1)',
  'rgba(250,200,88,1)',
  'rgba(238,102,102,1)',
  'rgba(115,192,222,1)',
  'rgba(59,162,114,1)',
  'rgba(252,132,82,1)',
  'rgba(154,96,180,1)',
  'rgba(234,124,204,1)'
]
const isChart = ref(false);
const isChart1 = ref(false);
const isChart2 = ref(false);
const data1 = ref({
  xData: [],
  yData: [],
  tittle: "项目类型统计",
  type: "pie",
  center: ["40%", "50%"],
  padding: [0, 50, 0, 0],
  x:'35%',
  y:'40%',
  // legend: ["",],
  itemStyle: {
    normal: {
      color: function (colors) {
        var colorList = [
          "#fc8251",
          "#5470c6",
          "#9A60B4",
          "#ef6567",
          "#f9c956",
          "#3BA272",
        ];
        return colorList[colors.dataIndex];
      },
    },
  },
});
const data2 = ref({
  xData: [],
  yData: [],
  type: "pie",
  center: ["40%", "50%"],
  x:'35%',
  y:'40%',
  // legend: [""],
  padding: [0, 0, 0, 0],
  itemStyle: {
    normal: {
      color: function (colors) {
        var colorList = [
          "#9A60B4",
          "#f9c956",
          "#3BA272",
          "#fc8251",
          "#5470c6",
          "#ef6567",
        ];
        return colorList[colors.dataIndex];
      },
    },
  },
});
const data3 = ref({
  xData: [],
  yData: [],
  tittle: "",
  type: "bar",
  color: "#0F69FF",
  title: "统计数据",
  interval: 5,
  legend: ["待整改数", "总数"],
});
const projectList = ref([
  { label: "总数", value: "projectCount" },
  { label: "在建", value: "startCount" },
  { label: "已完工", value: "endCount" },
  { label: "延期", value: "postponeCount" },
]);

const classify = ref('currentYear')
const tabs = ref([
  {
    id: 1,
    name: '项目类型'
  },
  {
    id: 2,
    name: '开工年份'
  },
  {
    id: 3,
    name: '竣工年份'
  },
  {
    id: 4,
    name: '任务类型'
  },
  {
    id: 5,
    name: '库内库外项目'
  },
])
const statisticsData = reactive({
  accumulativeTotal: {},
  currentYear: {},
  homePageMoney: {},
  buildTypeStatistics: [],
  projectTypeStatistics: []
})
// const projectTypes = ref([])
const legendList = ref([])
let projectListMap = {}

const curTab = ref(tabs.value[0])
const tabClick = async (tab) => {
  curTab.value = tab
  switch (curTab.value.id) {
    case 1:
      getProjectTypeList(tab.id)
      break;
    case 2:
      getProjectYearByTypes(tab.id)
      break;
    case 3:
      getProjectYearByTypes(tab.id)
      break;
    case 4:
      getDictMaps('task_type', tab.id)
      break;
    case 5:
      getDictMaps('project_library_type', tab.id)
      break;
    default:
      break;
  }
}

const getProjectTypeList = async (id) => {
  const res = await projectTypeList({ status: '0' })
  if(res?.code !== 200) return
  legendList.value = res?.data || []
  legendList.value = legendList.value.map(item => ({
    id: item.id,
    name: item.projectTypeName
  }))
  getHomePageInfoByTypes(id)
}

const getProjectYearByTypes = async (id) => {
  const res = await getProjectYearByType(id)
  if(res?.code !== 200) return
  legendList.value = res?.data || []
  legendList.value = legendList.value.map(item => ({
    id: item,
    name: item
  }))
  getHomePageInfoByTypes(id)
}

const getDictMaps = async (dictType, id) => {
  const res = await getDicts(dictType)
  if(res?.code !== 200) return
  legendList.value = res?.data || []
  legendList.value = legendList.value.map(item => ({
    id: item.dictValue,
    name: item.dictLabel
  }))
  getHomePageInfoByTypes(id)
}

const getHomePageInfoByTypes = async (id) => {
  const res = await getHomePageInfoByType(id)
  if(res?.code !== 200) return
  projectListMap = res?.data || {}
  console.log('接口数据', projectListMap)
  const mapData = []
  for (const key in projectListMap) {
    const index = legendList.value.findIndex(ele => ele.id === key)
    const color = colorList[index] || 'rgba(128, 128, 128, 1)'
    if (Object.hasOwnProperty.call(projectListMap, key)) {
      for (let i = 0; i < projectListMap[key].length; i++) {
        const it = projectListMap[key][i];
        if(!it.projectLocation) continue
        const options = getOptions(it, color)
        mapData.push(options)
      }
    }
  }
  // 地图渲染数据
  console.log('地图数据', mapData)
  if(!mapData.length) return
  proxy.$refs.mapRef.clear()
  setTimeout(() => {
    renderMapData(mapData)
  }, 100)
}

const renderMapData = (mapData) => {
  let geojson = NewFiberMap.Data.ToGeoJSON.beansWktToGeoJson(mapData);
  toCenterByGeoJson(geojson);
  newfiberMap.geojsonToMap(geojson);
}

const toCenterByGeoJson = (geojson) => {
  let coords = turf.getCoords(geojson.features[0].geometry).flat();
  let flag = geojson.features.length == 1 && coords.length == 2;
  if (!!geojson.features.length && !flag) {
    newfiberMap.getMap().camera.flyTo({destination: new Cesium.Rectangle.fromDegrees(...turf.bbox(turf.transformScale(turf.bboxPolygon(turf.bbox(geojson)), 2)))});
  } else {
    newfiberMap.setCenter({
      "roll": 0.01658908985506884,
      "pitch": -87.24924906709752,
      "heading": 5.026928271138224,
      "lng": coords[0],
      "lat": coords[1],
      "height": 943.5996932813425
    })
  }
}

const clickMap = (feature) => {
  console.log(feature)
}

const getOptions = (it, color) => {
  let options = {}
  if (it.projectLocation.includes('POINT')) {
    options = {
      // type: NewFiberMap.Enum.VectorType.ICON,
      type: NewFiberMap.Enum.VectorType.SPECIAL_CIRCLE,
      id: 'point',
      data: it,
      name:(it.projectName || "").substr(0,10) + (it.projectName.length > 10 ? ".....":''),
      style: {
        radius: 10,
        clampToGround: false,
        material: new NewFiberMap.Material.CircleDiffuseMaterialProperty({
          color: Cesium.Color.fromCssColorString(color),
          speed: 20,
        }),
      },
      labelOptions: {
        font: "17px PingFang SC",
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        outlineColor: 'rgba(20,83,154,1)',
        outline: true,
        outlineWidth: 3,
        color: "#ffffff",
        pixelOffset: [0, -6],
        distanceDisplayCondition: [0, 2100000],
      },
      geometrys: it.projectLocation,
    }
  } else if (it.projectLocation.includes('LINE')) {
    options = {
      type: NewFiberMap.Enum.VectorType.POLYLINE,
      id: 'line',
      data: it,
      name:(it.projectName || "").substr(0,10) + (it.projectName.length > 10 ? ".....":''),
      geometrys: it.projectLocation,
      style: {
        width: 5,
        material: color,
        color: color,
        clampToGround: true
      },
      labelOptions: {
        font: "17px PingFang SC",
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        outlineColor: 'rgba(20,83,154,1)',
        outline: true,
        outlineWidth: 3,
        color: "#ffffff",
        pixelOffset: [0, -6],
        distanceDisplayCondition: [0, 2100000],
      },
    }
  } else if (it.projectLocation.includes('POLYGON')) {
    options = {
      type: NewFiberMap.Enum.VectorType.POLYGON,
      style: {
        material: color,
        color: color
      },
      geometrys: it.projectLocation,
      id: 'area',
      data: it,
      name:(it.projectName || "").substr(0,10) + (it.projectName.length > 10 ? ".....":''),
      labelOptions: {
        font: "17px PingFang SC",
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        outlineColor: 'rgba(20,83,154,1)',
        outline: true,
        outlineWidth: 3,
        color: "#ffffff",
        pixelOffset: [0, -6],
        distanceDisplayCondition: [0, 2100000],
      },
    }
  }
  return options
}

const getData = async () => {
  const res = await getHomeStatistics()
  if(res?.code !== 200) return
  const { currentYear, accumulativeTotal, projectTypeStatistics, buildTypeStatistics, homePageMoney } = res.data
  statisticsData.currentYear = currentYear
  statisticsData.accumulativeTotal = accumulativeTotal
  statisticsData.homePageMoney = homePageMoney
  statisticsData.buildTypeStatistics = buildTypeStatistics.map(item => ({
    typeCount: item.typeCount,
    typeName: build_status.value.find(it => it.value === item.typeName)?.label || ''
  }))
  statisticsData.projectTypeStatistics = projectTypeStatistics

  renderPie(statisticsData.projectTypeStatistics, 1)
  renderPie(statisticsData.buildTypeStatistics, 2)
  renderBar()
}

const renderPie = (data, type) => {
  let array = [];
  data.forEach((i) => {
    array.push({ name: i.typeName, value: i.typeCount });
  });
  switch (type) {
    case 1:
      data1.value.xData = array;
      isChart.value = true;
      break;
    case 2:
      data2.value.xData = array;
      isChart1.value = true;
      break;
    default:
      break;
  }

}

const renderBar = async () => {
  let { data } = await selectProjectQualityHomePage();
  data3.value.xData = [];
  data3.value.yData = [];
  let arr1 = [];
  let arr2 = [];
  data.forEach((i) => {
    data3.value.xData.push(i.name || "无标题");
    arr1.push(i.count);
    arr2.push(i.noRectifiedCount);
    data3.value.yData = {
      contractMoney: arr1,
      paymentMoney: arr2,
    };
    isChart2.value = true;
  });
}

onMounted(() => {
  getData()
  tabClick(curTab.value)
});
</script>
<style scoped lang="scss">
.home {
  height: 91vh;
  width: 100%;
  overflow: hidden;
  .top {
    height: 13vh;
    display: flex;
    justify-content: space-between;
    flex-shrink: 0;
    .topLeft,
    .topRight {
      height: 100%;
      box-shadow: 0px 2px 6px 0px rgba(28, 52, 92, 0.1);
      border-radius: 6px;
      margin: 5px 7px;
      flex: 1;
      .tittle {
        font-weight: bold;
        color: #333333;
        padding: 5px;
        position: relative;
        .top_time {
          position: absolute;
          right: 0.5%;
        }
        div {
          margin-left: 10px;
        }
      }
      .label {
        font-size: 14px;
      }
    }
  }
  .ectittle {
    font-size: 18px;
    font-weight: bold;
    color: #464646;
    position: absolute;
    left: 3%;
    top: 2%;
  }
}
.center {
  justify-content: space-between;
  margin: 10px;
  height: 27vh;
  .center_div,
  .centerLeft,
  .centerright {
    height: 100%;
    flex: 1;
    box-shadow: 0px 2px 6px 0px rgba(28, 52, 92, 0.1);
    position: relative;

    .center_time {
      position: absolute;
      right: 0.5%;
      z-index: 1;
    }
  }

  .center_div {
    margin: 10px 20px;
    padding: 0 10px;
  }
}

.footer {
  position: relative;
  height: 45vh;
  .tabs {
    position: absolute;
    bottom: 10px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    color: #fff;
    z-index: 10;
    .tab_it {
      margin-right: 10px;
      width: 150px;
      height: 30px;
      line-height: 30px;
      background-color: rgb(240, 128, 0, 1);
      text-align: center;
      cursor: pointer;
      &:last-of-type {
        margin-right: 0;
      }
      &:hover {
        background-color: rgb(240, 128, 0, 0.5);
      }
      &.active {
        background-color: rgb(240, 128, 0, 0.5);
      }
    }
  }
  .legendList {
    min-width: 160px;
    background-color: #fff;
    border-radius: 6px;
    font-size: 16px;
    position: absolute;
    left: 10px;
    bottom: 10px;
    z-index: 10;
    padding: 8px 15px;
    box-shadow: 0px 0px 12px rgba(0, 0, 0, .12);
    .legend_item {
      line-height: 30px;
      display: flex;
      align-items: center;
      .icon {
        width: 16px;
        height: 16px;
        margin-right: 10px;
      }
    }
  }
}

.flex {
  display: flex;
  align-items: center;
}

.cont {
  justify-content: center;
  text-align: center;

  div {
    flex: 1;
  }

  .box {
    border-right: none;
    font-size: 22px;
    font-family: Source Han Sans CN;
    font-weight: bold;
    color: #333333;
    span {
      color: "#666666";
      font-size: 14px;
      font-weight: 500;
    }
  }
}

::v-deep .el-tabs__nav-wrap::after {
  background-color: #fff;
}

::v-deep .el-tabs__item.is-active {
  font-size: 16px;
  font-weight: bold;
}

::v-deep .el-tabs__active-bar {
  bottom: 0;
  left: 35px;
  height: 3px;
  width: 30px !important;
}
.conttittle {
  font-weight: 800;
  font-size: 18px;
}
</style>