Lliuzhengjun初始化仓库
828e1411创建于 2024年6月28日历史提交
<template>
  <div class="packageBug-container sbom-container">
    <div class="query-list">
      <div class="query-item">
        <span class="label">漏洞编号:</span> 
        <el-input 
          v-model="vulId" 
          style="width: 250px"
          placeholder="输入漏洞编号,Enter键回车搜索" 
          :prefix-icon="Search"
          @keyup.enter="search" 
        />
      </div>
      <div class="query-item">
        <span class="label">漏洞级别:</span>
        <el-select v-model="vulSeverity" clearable placeholder="请选择" @change="search">
          <el-option
            v-for="(item, itemIndex) in vulSeverityList"
            :key="itemIndex"
            :label="item.label"
            :value="item.prop"
          />
        </el-select>
      </div>
    </div>
    <div class="sbom-table">
      <el-table
        :data="tableData" 
        stripe 
        border
        highlight-current-row 
        scrollbar-always-on
      >
        <template #empty>
          <div class="no-data">
            <img src="@/assets/images/no-data.png" alt="" />
            <p>暂无相关内容</p>
          </div>
        </template>
        <template v-for="(col,colIndex) in columns" :key="colIndex">
          <el-table-column
            :label="col.label"
            :width="col.width"
            :minWidth="col.minWidth"
            :show-overflow-tooltip="col.showTooltip"
          >
            <template #default="scope">
              <div v-if="col.type === 'link'" @click="openEchart(scope.row)" class="link">{{ scope.row[col.prop] }}</div>
              <div v-else-if="col.hasBgcolor" :class="['bgColor', formatCellColor(scope.row[col.prop])]">{{ scope.row[col.prop] }}</div>
              <div v-else-if="col.type === 'button'" class="link" @click="goPath(scope.row)">查看</div>
              <span v-else>{{ scope.row[col.prop] }}</span>
            </template>
          </el-table-column>
        </template>
      </el-table>
      <div class="sbom-pagination">
        <el-pagination 
          layout="total, sizes, prev, pager, next, jumper" 
          :page-sizes="[10, 15, 20, 25, 30]"
          :total="pagination.total" 
          :page-size="pagination.pageSize" 
          v-model:page-size="pagination.pageSize" 
          v-model:currentPage="pagination.pageNum"
          @current-change="handlePageChange" 
          @size-change="handleSizeChange"
        />
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from "vue";
import SbomDataService from "@/services/SbomDataService";
import ResponseData from "@/types/ResponseData";
import { vulSeverityList } from "@/utils"
import { Search } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus';
import { mapGetters} from 'vuex';
function defaultPagination() {
  return {
    pageNum: 1,
    pageSize: 10,
    total: 0
  }
}
const columns1 = [
  { label: '漏洞编号', prop: 'vulId', type: 'link', minWidth: 250 },
  { label: '受影响分支', prop: 'affectedBranches', width: 200 },
  { label: '未分析分支', prop: 'notAnalyzedBranches', width: 200 },
  { label: '已修复分支', prop: 'affectedBranchesRepair', width: 200 },
  { label: '修复中分支', prop: 'affectedBranchesOpen', width: 200 },
  { label: '未修复分支', prop: 'affectedBranchesUnrepair', width: 200 },
  { label: '操作', prop: 'operate', type: 'button', width: 150 },
]
const columns2 = [
  { label: '漏洞编号', prop: 'vulId', type: 'link', minWidth: 250 },
  { label: '漏洞评分系统', prop: 'scoringSystem', width: 250 },
  { label: '漏洞评分', prop: 'score', width: 250, hasBgcolor: true },
  { label: '漏洞评分向量', prop: 'vector', minWidth: 400, showTooltip: true },
  { label: '漏洞关联组件purl', prop: 'purl', width: 400, showTooltip: true },
  { label: '操作', prop: 'operate', type: 'button', width: 150 },
]
export default defineComponent({
  name: "SbomVulnerabilityTable",
  components: {},
  props: {
    packageId: {
      type: String,
      default: ''
    },
    severity: {
      type: String,
      default: ''
    },
    productName: {
      type: String,
      default: ''
    },
    isByProductName: {
      type: Boolean,
      default: false
    },
  },
  data() {
    return {
      Search: Search,
      pagination: defaultPagination(),
      tableData: [] as Map<string, any>[],
      graphColors: [
        { label: '漏洞', prop: 'vulnerability', color: '#FF0000' },
        { label: '漏洞影响的组件', prop: 'dependency', color: '#0dcfcf' },
        { label: '漏洞影响的软件', prop: 'package', color: '#FF9126' },
        { label: '漏洞影响的传递性依赖', prop: 'transitiveDep', color: '#5A94F8' },
      ],
      colors: {
        vulnerability: '#FF0000',
        dependency: '#0dcfcf',
        package: '#FF9126',
        transitiveDep: '#5A94F8',
      },
      vulSeverityList,
      vulId: '',
      vulSeverity: '',
    };
  },
  computed:{
    ...mapGetters([
      'getProductName'
    ]),
    columns() {
      if(this.isByProductName) {
        return columns1
      } else {
        return columns2
      }
    }
  },
  watch: {
    severity(newVal) {
      this.vulSeverity = newVal
      this.search()
    },
    packageId() {
      this.search()
    },
    productName() {
      if(this.isByProductName) {
        this.queryPackageVulnerability()
      }
    }
  },
  methods: {
    search() {
      this.pagination.pageNum = 1
      this.queryPackageVulnerability()
    },
    handlePageChange(val: number) {
      this.pagination.pageNum = val
      this.queryPackageVulnerability()
    },
    handleSizeChange( val: number) {
      this.pagination.pageNum = 1
      this.pagination.pageSize = val
      this.queryPackageVulnerability()
    },
    queryPackageVulnerability() {
      if(this.isByProductName) {
        let str = `page=${this.pagination.pageNum - 1}&size=${this.pagination.pageSize}`
        if(this.packageId) {
          str = `${str}&packageId=${this.packageId}`
        }
        if(this.vulSeverity) {
          str = `${str}&severity=${this.vulSeverity}`
        }
        if(this.vulId) {
          str = `${str}&vulId=${this.vulId}`
        }
        SbomDataService.queryVulnerability(this.productName, str)
        .then((response: ResponseData) => {
          this.tableData = response.data.content;
          this.pagination.total = response.data.totalElements;
        })
        .catch((e: any) => {
          if (e.response && e.response.status == 500) {
            ElMessage({
            message: e.response.data,
            type: 'error'
            })
          }
          this.tableData = []
          this.pagination.total = 0
        });
      } else {
        let str = `page=${this.pagination.pageNum - 1}&size=${this.pagination.pageSize}`
        if(this.vulSeverity) {
          str = `${str}&severity=${this.vulSeverity}`
        }
        if(this.vulId) {
          str = `${str}&vulId=${this.vulId}`
        }
        SbomDataService.queryPackageVulnerability(
          this.packageId, 
          str
        )
          .then((response: ResponseData) => {
            this.tableData = response.data.content;
            this.pagination.total = response.data.totalElements;
          })
          .catch((e: any) => {
            if (e.response && e.response.status == 500) {
              ElMessage({
              message: e.response.data,
              type: 'error'
              })
            }
            this.tableData = []
            this.pagination.total = 0
          });
      }
    },
    goPath(item: any) {
      if(item.references && item.references.length) {
        const url = item.references[0].second
        window.open(url, '_blank')
      }
    },
    formatCellColor(score: number) {
      if(score <= 0) {
        return 'none'
      } else if (score > 0 && score < 4) {
        return 'low'
      } else if (score >= 4 && score < 7) {
        return 'medium'
      } else if (score >= 7 && score < 9) {
        return 'high'
      } else if (score >= 9) {
        return 'critical'
      } else {
        return ''
      }
    },
    openEchart(rowInfo) {
      const { href } = this.$router.resolve({
        path: "/sbomVulImpactChart",
        query: {
          productName: this.productName,
          vulId: rowInfo.vulId,
        },
      });
      window.open(href, '_blank');
    },
  },
  mounted() {
    this.vulSeverity = this.severity
    this.queryPackageVulnerability();
  },
});
</script>

<style lang="less" scoped>
.packageBug-container{
  padding-top: 20px;
  .query-list{
    margin-bottom: 20px;
    padding-right: 20px;
  }
}
</style>
<style lang="less">
  .el-dialog__body .switch{
    position: absolute;
    top: 20px;
    right: 50px;
  }
</style>