不同数据对比下的差异化展示表格

103 阅读3分钟

需求:新旧数据对比,以表格展示两组数据差异的地方

1) 删除的数据在旧数据表格中整行显示红色背景

2) 新增的数据在新数据表格中整行显示黄色背景

3) 修改的数据在单个单元格中显示橙色背景

直接上代码:

  <div class="table-container">
    <!-- 原始数据表格 -->
    <table border class="tableBox">
      <thead>
        <tr>
          <th v-for="(header, index) in headers" :key="index">{{ header }}</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(row, rowIndex) in originalData" :key="rowIndex" :class="{ 'deleted': isDeleted(rowIndex) }">
          <td v-for="(cell, cellKey) in row" :key="cellKey">
            {{ cell }}
          </td>
        </tr>
      </tbody>
    </table>

    <!-- 新数据表格 -->
    <table border class="tableBox">
      <thead>
        <tr>
          <th v-for="(header, index) in headers" :key="index">{{ header }}</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(row, rowIndex) in newData" :key="rowIndex" :class="{ 'added': isAdded(rowIndex) }">
          <td v-for="(cell, cellKey) in row" :key="cellKey" :class="{ 'modified': isModified(rowIndex, cellKey) && !isAdded(rowIndex) }">
            {{ cell }}
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        headers: ['下筒模式', '程序类型', '程序总时长', '下筒洗涤温度', '下筒漂洗次数', '其他信息', '下筒主洗涤时间设置(增/减)'],
        originalData: [
          { mode: '标准', type: '日常', duration: '60分钟', temp: '30℃', rinse: '2次', otherInfo: '标准清洗', timeAdjust: '+10' },
          { mode: '节能', type: '深度', duration: '90分钟', temp: '40℃', rinse: '3次', otherInfo: '深层清洁', timeAdjust: '-5' },
          { mode: '快速', type: '轻柔', duration: '30分钟', temp: '20℃', rinse: '1次', otherInfo: '快速洗涤', timeAdjust: '+0' }
        ],
        newData: [
          { mode: '标准', type: '日常', duration: '60分钟', temp: '30℃', rinse: '2次', otherInfo: '标准清洗', timeAdjust: '+15' }, // 修改的数据
          { mode: '节能', type: '深度', duration: '120分钟', temp: '40℃', rinse: '3次', otherInfo: '深层清洁', timeAdjust: '-5' }, // 修改的数据
          { mode: '强力', type: '除菌', duration: '180分钟', temp: '60℃', rinse: '4次', otherInfo: '高温杀菌', timeAdjust: '+30' } // 新增的数据
        ]
      }
    },
    methods: {
    // 判断是否为修改数据
      isModified(rowIndex, cellKey) {
        const origCell = this.originalData[rowIndex]?.[cellKey]
        const newCell = this.newData[rowIndex]?.[cellKey]
        return origCell !== newCell
      },
    // 判断是否为删除数据
      isDeleted(rowIndex) {
        const mode = this.originalData[rowIndex]?.mode
        return !this.newData.some(newRow => newRow.mode === mode)
      },
    // 判断是否为新增数据
      isAdded(rowIndex) {
        const mode = this.newData[rowIndex]?.mode
        return !this.originalData.some(origRow => origRow.mode === mode)
      }
    }
  }
  </script>

<style scoped>
  .modified {
    background-color: orange !important; /* 修改的数据 */
  }

  .deleted {
    background-color: red !important; /* 删除的数据 */
  }

  .added {
    background-color: yellow !important; /* 新增的数据 */
  }
  .tableBox{
    text-align: center;
    td{
      padding: 10px;
    }
  }
  </style>

增加需求点:以每行第一列为判断点,不看顺序

直接上代码:

  <div class="table-container">
    <table>
      <thead>
        <tr>
          <th v-for="(header, index) in headers" :key="index">{{ header }}</th>
        </tr>
      </thead>
      <tbody>
        <tr
          v-for="(row) in originalData"
          :key="row.mode"
          :class="{ 'deleted': isDeleted(row.mode) }">
          <td v-for="(cell, cellKey) in row" :key="cellKey">
            {{ cell }}
          </td>
        </tr>
      </tbody>
    </table>
    <table>
      <thead>
        <tr>
          <th v-for="(header, index) in headers" :key="index">{{ header }}</th>
        </tr>
      </thead>
      <tbody>
        <tr
          v-for="(row, rowIndex) in newData"
          :key="row.mode"
          :class="{ 'added': isNew(row.mode) }">
          <td
            v-for="(cell, cellKey) in row"
            :key="cellKey"
            :class="{ 'modified': isModified(rowIndex, cellKey) }">
            {{ cell }}
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        headers: [
          '下筒模式',
          '程序类型',
          '程序总时长',
          '下筒洗涤温度',
          '下筒漂洗次数',
          '其他信息',
          '下筒主洗涤时间设置(增/减)'
        ],
        originalData: [
          {
            mode: '标准',
            type: '日常',
            duration: '60分钟',
            temp: '30℃',
            rinse: '2次',
            otherInfo: '标准清洗',
            timeAdjust: '+10'
          },
          {
            mode: '快速',
            type: '轻柔',
            duration: '30分钟',
            temp: '20℃',
            rinse: '1次',
            otherInfo: '快速洗涤',
            timeAdjust: '+0'
          },
          {
            mode: '节能',
            type: '深度',
            duration: '90分钟',
            temp: '40℃',
            rinse: '3次',
            otherInfo: '深层清洁',
            timeAdjust: '-5'
          }
        ],
        newData: [
          {
            mode: '标准',
            type: '日常',
            duration: '60分钟',
            temp: '30℃',
            rinse: '2次',
            otherInfo: '标准清洗',
            timeAdjust: '+15'
          }, // 修改的数据
          {
            mode: '节能',
            type: '深度',
            duration: '120分钟',
            temp: '40℃',
            rinse: '3次',
            otherInfo: '深层清洁',
            timeAdjust: '-5'
          }, // 修改的数据
          // {
          //   mode: '快速',
          //   type: '轻柔',
          //   duration: '30分钟',
          //   temp: '20℃',
          //   rinse: '1次',
          //   otherInfo: '快速洗涤',
          //   timeAdjust: '+0'
          // }, // 未修改的数据
          {
            mode: '强力',
            type: '除菌',
            duration: '180分钟',
            temp: '60℃',
            rinse: '4次',
            otherInfo: '高温杀菌',
            timeAdjust: '+30'
          } // 新增的数据
        ]
      }
    },
    computed: {
      statusMap() {
        const status = {}

        this.originalData.forEach(row => {
          status[row?.mode] = {
            mode: row?.mode,
            deleted: true,
            modified: {}
          }
        })

        this.newData.forEach(row => {
          const mode = row?.mode
          if (status[mode]) {
            status[mode].deleted = false // 已经存在于原始数据中,不是删除的
            const origRow = this.originalData.find(
              origRow => origRow?.mode === mode
            )

            if (origRow) {
              for (const key in row) {
                if (key === 'mode') continue // 不比较 mode 字段
                status[mode].modified[key] = origRow[key] !== row[key]
              }
            }
          } else {
            status[mode] = {
              mode: mode,
              added: true, // 新增的数据
              modified: {}
            }
          }
        })
        console.log(status)

        return status
      }
    },
    methods: {
      isDeleted(mode) {
        const entry = this.statusMap[mode]
        return entry && entry.deleted
      },
      isNew(mode) {
        const entry = this.statusMap[mode]

        return entry && entry.added
      },
      isModified(rowIndex, cellKey) {
        const row = this.newData[rowIndex]
        if (!row || !row?.mode) {
          return false
        }

        const mode = row?.mode
        const entry = this.statusMap[mode]
        return entry && entry?.modified[cellKey]
      }
    }
  }
  </script>

<style scoped>
  .modified {
    background-color: orange !important; /* 修改的数据 */
  }

  .deleted {
    background-color: red !important; /* 删除的数据 */
  }

  .added {
    background-color: yellow !important; /* 新增的数据 */
  }
  .tableBox{
    text-align: center;
    td{
      padding: 10px;
    }
  }
  </style>
结束~谢谢!