目標
這個段落分兩篇講述 大部分是先前鐵人文章已經講過的作法
我們一樣用草稿規劃到資料整理方式匯出至Supabase
並呈現在畫面上
最後會提到我們下一篇需要整理出的資料 用作查詢使用
步驟
1.
因為當初線稿及資料沒規劃到這一塊
所以現在來補做
線稿如下圖 我們這次要做的是D組件和R組件
按下條件查詢時 只會顯示D和R組件
簡易版Schema和資料規劃如下圖
接著把CSV檔案匯至Supabase
上述資料的架構設計 參考當初線稿的畫面2.1
列出條件查詢需要篩選的項目
我們拿前兩筆資料的資料來看
行動方式和敵人屬性 如下圖
為了呈現這個畫面 資料結構需要轉換一下
我們需要將剛才匯入Supabase的資料
[
{
"id": 1,
"name": "行動方式",
"coditionType": "行動方式",
"eleType": "0",
"order": 1,
"memo": ""
},
{
"id": 2,
"name": "先制",
"coditionType": "行動方式",
"eleType": "3",
"order": 1,
"memo": ""
},
{
"id": 3,
"name": "一般",
"coditionType": "行動方式",
"eleType": "3",
"order": 1,
"memo": ""
},
{
"id": 4,
"name": "憤怒",
"coditionType": "行動方式",
"eleType": "3",
"order": 1,
"memo": ""
},
{
"id": 5,
"name": "死亡",
"coditionType": "行動方式",
"eleType": "3",
"order": 1,
"memo": ""
},
{
"id": 6,
"name": "敵人屬性",
"coditionType": "敵人屬性",
"eleType": "0",
"order": 2,
"memo": ""
},
{
"id": 7,
"name": "水",
"coditionType": "敵人屬性",
"eleType": "3",
"order": 2,
"memo": ""
},
{
"id": 8,
"name": "火",
"coditionType": "敵人屬性",
"eleType": "3",
"order": 2,
"memo": ""
},
{
"id": 9,
"name": "雷",
"coditionType": "敵人屬性",
"eleType": "3",
"order": 2,
"memo": ""
},
{
"id": 10,
"name": "光",
"coditionType": "敵人屬性",
"eleType": "3",
"order": 2,
"memo": ""
},
{
"id": 11,
"name": "暗",
"coditionType": "敵人屬性",
"eleType": "3",
"order": 2,
"memo": ""
},
{
"id": 12,
"name": "無",
"coditionType": "敵人屬性",
"eleType": "3",
"order": 2,
"memo": ""
}
]
整理成以下架構
先以coditionType分組
再以eleType分組
[
{
"coditionType": "行動方式",
"info": [
{ "eleType": "0", "name": ["行動方式"] },
{ "eleType": "3", "name": ["先制","一般", "憤怒", "死亡"] }
]
},
{
"coditionType": "敵人屬性",
"info": [
{ "eleType": "0", "name": ["敵人屬性"] },
{ "eleType": "3", "name": ["水","火", "雷", "光", "暗", "無"] }
]
}
]
將D組件的script增加為以下程式架構
而searchList是我們將Supabase取資料後轉換的結果
<script setup>
import { supabase } from "../supabase.js";
import { ref, onMounted,computed } from "vue";
const result = ref([]);
const searchResult = ref([]);
const searchCondition = ref(
[
{ checked: false, name: "" ,coditionType:"行動方式",value:"1"},
{ checked: false, name: "" ,coditionType:"敵人屬性",value:"2"},
{ checked: false, name: "" ,coditionType:"種族",value:"3"},
{ checked: false, name: "" ,coditionType:"標記",value:"4"},
{ checked: false, name: "" ,coditionType:"負面狀態",value:"5"},
{ checked: false, name: "" ,coditionType:"詛咒",value:"5"},
{ checked: false, name: "" ,coditionType:"其他行動",value:"5"},
{ checked: false, name: "" ,coditionType:"關卡效果",value:"6"},
{ checked: false, name: "" ,coditionType:"憤怒條件",value:"7"},
{ checked: false, name: "" ,coditionType:"攻擊方式",value:"5"}
]
);
onMounted(async () => {
const { data, error } = await supabase
.from("skillSearch")
.select("*");
if (error) {
console.error(error);
} else {
result.value = data;
}
});
const searchList = computed(() => {
const sorted = [...result.value].sort((a, b) => a.order - b.order);
const grouped = {};
sorted.forEach(item => {
if (!grouped[item.coditionType]) {
grouped[item.coditionType] = {};
}
if (!grouped[item.coditionType][item.eleType]) {
grouped[item.coditionType][item.eleType] = [];
}
grouped[item.coditionType][item.eleType].push(item.name);
});
return Object.keys(grouped).map(type => {
const info = Object.keys(grouped[type]).map(ele => ({
eleType: ele,
name: grouped[type][ele]
}));
return { coditionType: type, info };
});
})
</script>
template程式架構如下
<template>
<div style="overflow:auto">
<div class="row" v-for="(item,index) in searchList" :key="item.coditionType">
<div class="col-6">
<div class="form-check">
<input class="form-check-input" type="checkbox" v-model="searchCondition[index].checked" :id="'title'+index">
<label class="form-check-label" :for="'title'+index">
{{item.info[0].name[0]}}
</label>
</div>
</div>
<div class="col-6">
<div class="row">
<div class="col-6" v-for="(child,index2) in item.info[1].name" :key="index2">
<div class="form-check">
<input class="form-check-input" type="radio" :value="child" :name="item.coditionType"
:id=" item.coditionType + index2" v-model="searchCondition[index].name">
<label class="form-check-label" :for="item.coditionType + index2">
{{child}}
</label>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
下圖是目前呈現的畫面
因為我們預期的效果是
當前面有勾選且後面的值也有選時 才會進入查詢條件
所以我們用了v-model
去綁定searchCondition
來方便管理我們查詢條件的狀態
到這一步,D組件的畫面已經幾乎完成,剩下取資料給R組件
我們留到下一篇繼續敘述
備註
這一篇其實有跳過一些父組件和子組件的架構
由於前面的篇數已經提過 這篇主要著重資料的處理;
另外使用searchCondition這個屬性去管理除了方便外
主要是為了下一篇取Supabase資料做準備
這邊講一下searchCondition這個屬性的架構
可以看到searchCondition 初始的定義是這樣
如下圖 當我們在畫面上勾選行動方式、敵人屬性
且後面也有選值時
searchCondition屬性則會變化如下圖紅框處