董国庆
2026-01-19 fe34cd8218e5e5ec82576e41a68c5510c81b80e1
首页所有
1个文件已删除
1个文件已添加
1个文件已修改
529 ■■■■■ 已修改文件
screen/src/assets/img/project/equipmentBg.png 补丁 | 查看 | 原始文档 | blame | 历史
screen/src/assets/img/project/编组 19备份 3@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
screen/src/view/projectHome/index.vue 529 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
screen/src/assets/img/project/equipmentBg.png
screen/src/assets/img/project/编组 19备份 3@2x.png
Binary files differ
screen/src/view/projectHome/index.vue
@@ -1,6 +1,7 @@
<template>
  <div class="relative">
    <HeaderBox title="石盘安置C地块项目" />
    <!-- 地图 -->
    <div id="container" style="width: 1920px; height: 995px"></div>
    <!-- 左边 内容 -->
    <div class="left-card">
@@ -88,10 +89,10 @@
              <div class="pie-canvas" ref="pieChart"></div>
              <div class="legend">
                <div class="legend-item" v-for="(it, idx) in legendData" :key="idx">
                  <span class="dot" :style="{ background: (it.itemStyle && it.itemStyle.color) || '#6cf' }"></span>
                  <div class="content">
                    <div class="name">{{ it.name }}</div>
                    <div class="value">{{ it.value }}%</div>
                  <div class="dot" :style="{ backgroundColor: it.itemStyle.color }"></div>
                  <div class="legend-info">
                    <div class="legend-name" :title="it.name">{{it.name}}</div>
                    <div class="legend-number">{{it.value}}</div>
                  </div>
                </div>
              </div>
@@ -266,9 +267,66 @@
          </template>
          <template #content>
            <div class="risk-info">
              <div class="risk-top">
                <div class="label card1">序号</div>
                <div class="label card2">风险规模</div>
                <div class="label flex1">风险源内容</div>
                <div class="label card4">实施情况</div>
              </div>
              <div class="risk-body">
                <div class="risk-item" v-for="(item, index) in riskSourceList" :key="index">
                  <div class="label card1">{{ index + 1 }}</div>
                  <div
                    class="label card2"
                    :class="{
                      'merged-cell': item.showRiskScale && item.rowspan > 1,
                      'hidden-cell': !item.showRiskScale
                    }"
                  >
                    <div
                      v-if="item.showRiskScale"
                      class="merged-content"
                      :style="{
                        height: `${item.rowspan * 36}px`,
                        lineHeight: `${item.rowspan * 36}px`
                      }"
                    >
                      {{ item.riskScale }}
                    </div>
                  </div>
                  <div class="label flex1">{{ item.content }}</div>
                  <div class="label card4">{{ item.status }}</div>
                </div>
              </div>
            </div>
          </template>
        </TitleBox>
      </div>
      <div class="mt--30">
        <TitleBox>
          <template #title>项目风险趋势 </template>
          <template #right>
            <div @click="handleClick" class="risk-picker">
              <el-date-picker v-model="dateRange" ref="datePicker" type="monthrange" range-separator=""
                start-placeholder="" end-placeholder="">
              </el-date-picker>
              <div class="risk-ab">
                <img src="../../assets/img/home/Shape@2x (6).png" class="pick-img" />
                <div class="pick-text">
                  {{ dateTxt }}
                </div>
              </div>
            </div>
          </template>
          <template #content>
            <div class="risk-trend">
              <div id="riskTrendChart" style="width: 100%; height: 234px"></div>
            </div>
          </template>
        </TitleBox>
      </div>
@@ -295,17 +353,74 @@
        { name: "正常", value: 10, itemStyle: { color: "#00FF00" } },
        { name: "异常", value: 20, itemStyle: { color: "#FF0000" } },
        { name: "待处理", value: 30, itemStyle: { color: "#FFA500" } },
        { name: "待完成", value: 30, itemStyle: { color: "#FF00FF" } },
        { name: "已完成", value: 30, itemStyle: { color: "#00FFFF" } },
      ],
      dateTxt: '',
      riskTrandList: [],
      // 风险源数据
      riskSourceData: [
        { riskScale: '一般', content: '项目风险源内容1', status: '未开始' },
        { riskScale: '一般', content: '项目风险源内容2', status: '进行中' },
        { riskScale: '一般', content: '项目风险源内容3', status: '已完成' },
        { riskScale: '重大', content: '项目风险源内容4', status: '未开始' },
        { riskScale: '重大', content: '项目风险源内容5', status: '进行中' },
      ]
    };
  },
  computed: {
    // 处理风险源数据,添加合并单元格的逻辑
    riskSourceList() {
      if (!this.riskSourceData || this.riskSourceData.length === 0) {
        return [];
      }
      const result = [];
      let i = 0;
      while (i < this.riskSourceData.length) {
        const currentRiskScale = this.riskSourceData[i].riskScale;
        let rowspan = 1;
        // 计算相同风险规模的行数
        for (let j = i + 1; j < this.riskSourceData.length; j++) {
          if (this.riskSourceData[j].riskScale === currentRiskScale) {
            rowspan++;
          } else {
            break;
          }
        }
        // 添加第一行,显示风险规模
        result.push({
          ...this.riskSourceData[i],
          showRiskScale: true,
          rowspan: rowspan
        });
        // 添加后续相同风险规模的行,不显示风险规模
        for (let k = 1; k < rowspan; k++) {
          result.push({
            ...this.riskSourceData[i + k],
            showRiskScale: false,
            rowspan: 0
          });
        }
        i += rowspan;
      }
      return result;
    }
  },
  watch: {
    dateRange: {
      handler(newVal, oldVal) {
        if (newVal.length > 0) {
          this.dateTxt =
            moment(newVal[0]).format("YYYY年MM月DD日") +
            " ~ " +
            moment(newVal[1]).format("YYYY年MM月DD日");
            moment(newVal[0]).format("YYYY -MM") +
            " - " +
            moment(newVal[1]).format("YYYY -MM");
        }
      },
      immediate: true,
@@ -313,9 +428,9 @@
  },
  created() { },
  mounted() {
    this.setMapload();
    this.setMapload()
    this.initPie3D()
    this.initRiskChart()
  },
  beforeDestroy() {
  },
@@ -326,7 +441,17 @@
        version: "2.0",
      })
        .then((AMap) => {
          // 微信建筑图层
          let satellite = new AMap.TileLayer.Satellite();
          //创建路网图层
          let roadNet = new AMap.TileLayer.RoadNet();
          this.mapView = new AMap.Map("container", {
            zoom: 13,
            center: [108.357471, 22.828643], // 初始化地图中心点
            // mapStyle: "amap://styles/darkblue",
            layers: [satellite],
          });
          this.initCategoryMarkers(AMap);
        })
        .catch((e) => {
          console.error(e); //加载错误提示
@@ -672,10 +797,131 @@
      //   },
      // });
      return series;
    }
    },
    handleClick() {
      this.$refs.datePicker.focus();
    },
    // 初始化折线图
    initRiskChart() {
      const riskChart = echarts.init(document.getElementById('riskTrendChart'))
      // 文本换行处理函数
      const formatLabel = (text, maxWidth = 4) => {
        if (!text) return ''
        const textStr = String(text)
        // 如果文本长度超过最大宽度,进行换行
        if (textStr.length > maxWidth) {
          let result = ''
          for (let i = 0; i < textStr.length; i += maxWidth) {
            result += textStr.substring(i, i + maxWidth) + '\n'
          }
          return result.trim()
        }
        return textStr
      }
      let option = {
        tooltip: {
          trigger: 'axis',
          show: false
        },
        legend: {
          show: false
        },
        grid: {
          top: '5%',
          bottom: '5%',
          left: '5%',
          right: '5%',
          containLabel: true
        },
        xAxis: {
          data: ['2025年1月检查', '2025年2月检查', '2025年3月检查', '2025年4月检查', '2025年5月检查'],
          axisTick: { show: true, alignWithLabel: true },
          axisLine: {
            lineStyle: {
              color: '#666'
            }
          },
          axisLabel: {
            color: '#fff',
            fontSize: 12,
            interval: 0, // 强制显示所有标签
            rotate: 0, // 不旋转
            formatter: function (value) {
              // X轴标签格式化,最多7个字符,超出换行
              return formatLabel(value, 7)
            },
            // 文本对齐方式
            align: 'center',
            verticalAlign: 'top',
            lineHeight: 14,
            // 设置标签的最大宽度
            width: 60,
            overflow: 'break' // 超出换行
          }
        },
        yAxis: {
          type: 'value',
          splitLine: {
            show: true,
            lineStyle: {
              type: 'dashed', // 虚线
              color: 'rgba(255, 255, 255, .2)' // 固定灰色
            }
          },
          axisLine: {
            show: false
          },
          axisTick: {
            show: false
          },
          axisLabel: {
            color: '#fff',
            fontSize: 12,
            formatter: function (value) {
              // Y轴标签格式化,最多3个字符,超出换行
              const text = String(value)
              return formatLabel(text, 3)
            },
            // 文本对齐方式
            align: 'right',
            verticalAlign: 'middle',
            lineHeight: 14,
            // 设置标签的最大宽度
            width: 30,
            overflow: 'break' // 超出换行
          }
        },
        series: [
          {
            name: '风险等级',
            type: 'line',
            data: [10, 52, 20, 33, 39],
            smooth: false, // 不使用圆滑过渡
            showSymbol: false, // 不显示转折点
            lineStyle: {
              width: 5, // 线条宽度
              color: {
                type: 'linear',
                x: 0,
                y: 0,
                x2: 1,
                y2: 0,
                colorStops: [
                  { offset: 0, color: 'rgba(36, 81, 242, 1)' }, // 起始颜色
                  { offset: 0.5, color: 'rgba(11, 204, 254, 1)' }, // 中间颜色
                  { offset: 1, color: 'rgba(199, 160, 254, 1)' } // 结束颜色
                ]
              }
            }
          }
        ]
      }
      riskChart.setOption(option)
    }
  }
};
}
</script>
<style lang="less" scoped>
@@ -773,15 +1019,6 @@
      left: 0;
    }
    //   .chart-area {
    //   width: 470px;
    //   height: 188px;
    //   position: relative;
    //   padding-right: 180px; // 右侧为图例预留更多空间
    //   background: radial-gradient(circle at center, rgba(0, 191, 255, 0.15) 0%, transparent 70%);
    //   border-radius: 8px;
    // }
    .pie-canvas {
      position: absolute;
      left: -37px;
@@ -793,59 +1030,86 @@
    .legend {
      position: absolute;
      right: 20px;
      top: 28px;
      width: 200px;
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
    }
      right: 23px;
      bottom: 5px;
      max-height: 126px; // 3个item的高度:(32px + 10px) * 3 = 126px
      overflow-y: auto;
      overflow-x: hidden;
      z-index: 33;
    .legend-item {
      display: flex;
      align-items: center;
      // 自定义滚动条样式
      &::-webkit-scrollbar {
        width: 4px;
      }
      color: #F0FAFF;
      font-size: 11px;
      font-weight: 400;
      &::-webkit-scrollbar-track {
        background: rgba(255, 255, 255, 0.1);
        border-radius: 2px;
      }
      &:nth-child(2n+1) {
        margin-right: 37px;
      &::-webkit-scrollbar-thumb {
        background: rgba(59, 130, 246, 0.6);
        border-radius: 2px;
        &:hover {
          background: rgba(59, 130, 246, 0.8);
        }
      }
      .legend-item {
        display: flex;
        margin-bottom: 10px;
        width: 180px;
        height: 32px;
        background-image: url('../../../src/assets/img/project/equipmentBg.png');
        background-size: 100% 100%;
        position: relative;
        align-items: center;
        justify-content: space-between;
        .dot {
          width: 6px;
          height: 6px;
          margin-left: 5px;
          flex-shrink: 0;
        }
        .legend-info {
          width: 130px;
          height: 32px;
          padding: 7px 11px;
          display: flex;
          align-items: center;
          justify-content: space-between;
          .legend-name {
            max-width: 70px;
            font-weight: 400;
            font-size: 14px;
            color: #CCE0F8;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap; // 确保单行显示
            cursor: pointer; // 鼠标悬停时显示手型
            transition: color 0.3s ease;
            &:hover {
              color: #FFFFFF; // 悬停时文字变亮
            }
          }
          .legend-number {
            font-weight: bold;
            font-size: 18px;
            color: #1BDDFF;
            flex-shrink: 0;
          }
        }
      }
    }
    .legend-item .dot {
      width: 8px;
      height: 8px;
      border-radius: 2px;
      margin-right: 8px;
      margin-top: 2px;
      display: inline-block;
      box-shadow: 0 0 3px rgba(255, 255, 255, 0.2);
      flex-shrink: 0;
    }
    .legend-item .content {
      display: flex;
      flex-direction: column;
      line-height: 1.2;
    }
    .legend-item .name {
      font-family: SourceHanSansCN, SourceHanSansCN;
      font-weight: 400;
      font-size: 14px;
      color: rgba(255, 255, 255, .5);
      line-height: 24px;
    }
    .legend-item .value {
      font-family: SourceHanSansCN, SourceHanSansCN;
      font-weight: bold;
      font-size: 14px;
      color: #FFFFFF;
      line-height: 24px;
    }
  }
@@ -1194,17 +1458,136 @@
      width: 107px;
    }
    .label {
      font-weight: 400;
      font-size: 12px;
      color: #FFFFFF;
      text-align: center;
    }
    .card4 {
      width: 72px;
      text-align: left;
    }
    .risk-top {
      padding: 6px 0;
      display: flex;
      align-items: center;
      margin-bottom: 7px;
    }
      .title {
        font-weight: 400;
        font-size: 12px;
        color: #FFFFFF;
        text-align: center;
    .risk-body {
      .risk-item {
        display: flex;
        align-items: stretch;
        &:nth-last-child(1) {
          // border-right: 1px solid #337AB6;
          .label {
            border-bottom: 1px solid #337AB6;
          }
        }
        .label {
          &:nth-last-child(1) {
            border-right: 1px solid #337AB6;
            border-left: unset !important;
            padding-left: 6px;
            font-weight: bold;
            font-size: 12px;
            color: #66FFFF;
            font-style: normal;
          }
          line-height: 36px;
          border-top: 1px solid #337AB6;
          border-left: 1px solid #337AB6;
          position: relative;
          &.merged-cell {
            position: relative;
            .merged-content {
              position: absolute;
              top: 0;
              left: 0;
              width: 100%;
              display: flex;
              align-items: center;
              justify-content: center;
              // border-bottom: 1px solid #337AB6;
            }
          }
          &.hidden-cell {
            border-top: none;
            // border-left: none;
          }
        }
      }
    }
  }
  .risk-trend {
    height: 234px;
  }
  .risk-picker {
    width: 190px;
    height: 26px;
    background: rgba(14, 93, 251, 0.5);
    border-radius: 4px;
    position: relative;
    display: flex;
    align-items: center;
    ::v-deep .el-input__icon {
      display: none;
    }
    ::v-deep .el-input__inner {
      background: transparent;
      border: none;
      color: transparent;
    }
    ::v-deep .el-range-input {
      background: transparent;
      border: none;
      color: transparent;
    }
    .risk-ab {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      padding: 6px 26px 6px 10px;
      display: flex;
      align-items: center;
      justify-content: space-between;
    }
    .pick-text {
      font-weight: 400;
      font-size: 12px;
      color: #FFFFFF;
      line-height: 18px;
    }
    .pick-img {
      width: 12px;
      height: 12px;
      margin-right: 12px;
    }
  }
}
</style>