VueJS 从 JSON 数据转置 table 行到列

VueJS transpose table row to column from JSON data

所以我有 JSON 来自 Laravel API 的数据(由 Axios 调用),我想转置这些数据:

{"message":"Data peserta tahap 1 OR XI","data":[
{"nim":1810112048,"nama":"Annisa indra","id_sk1":11,"nilai":30},
{"nim":1810112048,"nama":"Annisa indra","id_sk1":12,"nilai":30},
{"nim":1810112048,"nama":"Annisa indra","id_sk1":13,"nilai":25},
{"nim":1810112048,"nama":"Annisa indra","id_sk1":21,"nilai":72},
{"nim":1810112048,"nama":"Annisa indra","id_sk1":31,"nilai":57},
{"nim":1810522038,"nama":"Muhammad fakhri naufal","id_sk1":11,"nilai":20},
{"nim":1810522038,"nama":"Muhammad fakhri naufal","id_sk1":12,"nilai":20},
{"nim":1810522038,"nama":"Muhammad fakhri naufal","id_sk1":13,"nilai":10},
{"nim":1810522038,"nama":"Muhammad fakhri naufal","id_sk1":21,"nilai":75},
{"nim":1810522038,"nama":"Muhammad fakhri naufal","id_sk1":31,"nilai":57}
]}
有 5 个重复的 NIM,内容不同 nilai(等级)

这是我的目标:

+------------+------------------------+----+----+----+----+----+
|    nim     |         nama           | 11 | 12 | 13 | 21 | 31 |
+------------+------------------------+----+----+----+----+----+
| 1810112048 | Annisa indra           | 30 | 30 | 25 | 72 | 57 |
| 1810522038 | Muhammad fakhri naufal | 20 | 20 | 10 | 75 | 57 |
+------------+------------------------+----+----+----+----+----+

这是我的 VueJS 视图代码:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<table class="table">
  <thead>
    <tr>
      <th>NIM</th>
      <th>Nama</th>
      <th v-for="sk in subkriteria" :key="sk.id_sk1">
          {{ sk.sub_kriteria }}</th>
    </tr>
  </thead>
  <tbody>
    <template v-if="peserta.array != 0">
    <tr v-for="(peserta, index) in penilaian1" :key="index">
        <td>{{ peserta.nim }}</td>
        <td>{{ peserta.nama }}</td>
        <template v-if="peserta.array != penilaian1.array ">
            <td  v-for="sk in subkriteria" :key="sk.id_sk1">
              <i>Tidak ada data</i>
            </td>
        </template>
        <template v-else>   
            <td  v-for="penilaian in penilaian1" :key="penilaian.id_sk1">
                {{ penilaian.nilai }}
            </td>
        </template>
        <td>
        <div class="btn-group">
          <router-link
          :to="{ name: 'penilaian1.show', params:{id: penilaian1.id}}"
          class="btn btn-sm btn-outline-info">Show</router-link>
        </div>
      </td>
    </tr>
    </template>
  </tbody>
  </table>

<script>
import axios from 'axios'


export default {
  computed:{
      countedMhs: function() {
          return this.peserta.filter(penilaian1 => penilaian1.nim==0);
      },          
      rolesByCategory() {
          return _.groupBy(this.penilaian1.nim ) 
      }  
  },
  data: function () {
      return {
          peserta: [],
          penilaian1: [],
          subkriteria: [],
          kriteria: [],
          loading: true,
      }
  },
  mounted() {
      this.loadData();
  },

  watch: {
      selected: {
          handler: function () {
              this.loadData();
          },
          deep: true
      }
  },
  methods: {
      loadData: function () {
          this.loading = true;

          Promise.all([
              this.loadPeserta(),
              this.loadPenilaian1(),
              this.loadTableSK1(),
              this.loadTableK1(),
              false
          ])
          .then(() => {
              [this.peserta, this.penilaian1, this.subkriteria, this.kriteria]
          })
          .catch(function (error) {
              console.log(error);
          });
      },
      loadPeserta: function () {
          axios.get('http://127.0.0.1:8000/api/penilaian1/peserta1', {
                  params: this.selected
              })
              .then((response) => {
                  this.peserta = response.data.data;
              })
              .catch(function (error) {
                  console.log(error);
              });
      },
      loadPenilaian1: function () {
          axios.get('http://127.0.0.1:8000/api/penilaian1', {
                  params: this.selected
              })
              .then((response) => {
                  this.penilaian1 = response.data.data;
              })
              .catch(function (error) {
                  console.log(error);
              });
      },
      loadTableSK1: function () {
          axios.get('http://127.0.0.1:8000/api/penilaian1/table_sk1', {
              params: this.selected
              })
              .then((response) => {
                  this.subkriteria = response.data.data;
                  this.loading = false;
              })
              .catch(function (error) {
                  console.log(error);
              });
      },
      loadTableK1: function () {
          axios.get('http://127.0.0.1:8000/api/penilaian1/table_k1', {
                  params: this.selected
              })
              .then((response) => {
                  this.kriteria = response.data.data;
                  this.loading = false;
              })
              .catch(function (error) {
                  console.log(error);
              });
      },
  }
}
</script>

但预期的结果是这样的:https://i.stack.imgur.com/SgaQo.png

图片显示所有10个nilai被转置到列,但我想基于NIM只转置5个nilai(应该使用groupBy但我不知道)。

那么我如何使用 VueJS 将这个 JSON 数据从行转换到列?就像我的目标一样,提前致谢。

编辑: 我尝试了 Nikola 的 Composition API 和 Axios 解决方案,但没有显示数据:

import axios from 'axios'
import { onMounted, ref, computed } from 'vue'
import SideBar from './../../../components/SideBar.vue'

export default {
    components: {
        SideBar,
    },

    setup() {
        let peserta1 = ref([])
        let result = ref([])
        let penilaian1 = ref([])
        let subkriteria = ref([])

        onMounted(() => {
            axios
                .get('http://127.0.0.1:8000/api/penilaian1')
                .then((result) => {
                    penilaian1.value = result.data
                })
                .catch((err) => {
                    console.log(err.response)
                })
        })

        onMounted(() => {
            axios
                .get('http://127.0.0.1:8000/api/penilaian1/table_sk1')
                .then((result) => {
                    subkriteria.value = result.data
                })
                .catch((err) => {
                    console.log(err.response)
                })
        })
        onMounted(() => {
            axios
                .get('http://127.0.0.1:8000/api/penilaian1/peserta1')
                .then((result) => {
                    peserta1.value = result.data
                })
                .catch((err) => {
                    console.log(err.response)
                })
        })
        const transpose = () => {
            penilaian1.value.forEach((dat) => {
                if (!result.value.find((r) => r.nim === dat.nim)) {
                    result.value.push({ nim: dat.nim, nama: dat.nama })
                }
            })
            penilaian1.value.forEach((dat) => {
                let res = result.value.find((r) => r.nim === dat.nim)
                res[dat.id_sk1] = dat.nilai
            })
            console.log(result)
        }

        return {
            peserta1,
            penilaian1,
            subkriteria,
            transpose,
        }
    },
}
<template>
  <div class="relative min-h-screen md:flex">
    <SideBar />
    <div class="flex-1">
      <div class="col-12">
        <h1 class="px-6 py-6 mb-6 text-3xl font-extrabold">
            Data Pendaftar
        </h1>
      </div>
      <div class="col-12">
        <div class="flex-1">
          <div class="overflow-y-auto sm:-mx-6 lg:-mx-8">
            <div class="py-2 inline-clip sm:px-6 lg:px-12">
              <div class="overflow-hidden shadow-md sm:rounded-lg">
                <table class="min-w-full">
                  <thead class="bg-gray-100 dark:bg-gray-700">
                    <tr>
                      <th
                          scope="col"
                          class="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-700 uppercase  dark:text-gray-400"
                      >
                          NIM
                      </th>
                      <th
                          scope="col"
                          class="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-700 uppercase  dark:text-gray-400"
                      >
                          Nama
                      </th>

                      <th
                          scope="col"
                          class="relative px-6 py-3"
                      >
                          <span class="sr-only"
                              >Edit</span
                          >
                      </th>
                    </tr>
                </thead>
                <tbody>
                    <!-- Product 1 -->
                  <tr
                      v-for="peserta1 in transpose"
                      class="bg-white border-b  dark:bg-gray-800 dark:border-gray-600"
                  >
                      <td
                          class="px-6 py-4 text-sm font-medium text-gray-900  whitespace-nowrap dark:text-white"
                      >
                          {{ peserta1.nim }}
                      </td>
                      <td
                          class="px-6 py-4 text-sm text-gray-500  whitespace-nowrap dark:text-gray-400"
                      >
                          {{ peserta1.nama }}
                      </td>

                      <td
                          class="px-6 py-4 text-sm font-medium text-right  whitespace-nowrap"
                      ></td>
                    </tr>
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

更新 2,代码现在可以使用 watchEffect 运行:

watchEffect(() => {
            state.penilaian1.forEach((dat) => {
                if (!state.result.find((r) => r.nim === dat.nim)) {
                    state.result.push({ nim: dat.nim, nama: dat.nama })
                }
            })
            state.penilaian1.forEach((dat) => {
                let res = state.result.find((r) => r.nim === dat.nim)
                res[dat.id_sk1] = dat.nilai
            })
            console.log(state.result)
        })

结果如下: Overall result Detailed console.log result

现在我会想办法用v-for调用成绩数据,但让我在下一个问题中回答

尝试如下:

const data = [
  {"nim":1810112048,"nama":"Annisa indra","id_sk1":11,"nilai":30},
  {"nim":1810112048,"nama":"Annisa indra","id_sk1":12,"nilai":30},
  {"nim":1810112048,"nama":"Annisa indra","id_sk1":13,"nilai":25},
  {"nim":1810112048,"nama":"Annisa indra","id_sk1":21,"nilai":72},
  {"nim":1810112048,"nama":"Annisa indra","id_sk1":31,"nilai":57},
  {"nim":1810522038,"nama":"Muhammad fakhri naufal","id_sk1":11,"nilai":20},
  {"nim":1810522038,"nama":"Muhammad fakhri naufal","id_sk1":12,"nilai":20},
  {"nim":1810522038,"nama":"Muhammad fakhri naufal","id_sk1":13,"nilai":10},
  {"nim":1810522038,"nama":"Muhammad fakhri naufal","id_sk1":21,"nilai":75},
  {"nim":1810522038,"nama":"Muhammad fakhri naufal","id_sk1":31,"nilai":57}
]
const result = [];
data.forEach(dat => {
  if(!result.find(r => r.nim === dat.nim)) {
    result.push({"nim":dat.nim, "nama": dat.nama})
  }
});
data.forEach(dat => {
  let res = result.find(r => r.nim === dat.nim)
  res[dat.id_sk1] = dat.nilai
});

console.log(result)