166 lines
5.7 KiB
Vue
166 lines
5.7 KiB
Vue
<script setup lang="ts">
|
||
import TreeSelect from '~/components/pub/my-ui/select-tree/tree-select.vue'
|
||
|
||
/**
|
||
* DEMO COMPONENT - Tree Select dengan Lazy Loading
|
||
*
|
||
* Komponen ini adalah contoh penggunaan TreeSelect dengan data teknologi.
|
||
* Untuk penggunaan dalam aplikasi nyata, lihat komponen content/division/entry.vue
|
||
* yang menggunakan tree select untuk data divisi rumah sakit.
|
||
*/
|
||
|
||
// Tipe data untuk konsistensi
|
||
interface TreeItem {
|
||
value: string
|
||
label: string
|
||
hasChildren: boolean
|
||
children?: TreeItem[]
|
||
}
|
||
|
||
// State untuk data pohon demo - data teknologi sebagai contoh
|
||
const treeData = ref<TreeItem[]>([
|
||
{ value: 'frontend', label: 'Frontend Development', hasChildren: true },
|
||
{ value: 'backend', label: 'Backend Development', hasChildren: true },
|
||
{ value: 'mobile', label: 'Mobile Development', hasChildren: true },
|
||
{ value: 'devops', label: 'DevOps & Infrastructure', hasChildren: false },
|
||
])
|
||
|
||
// State untuk menampung nilai yang dipilih
|
||
const selectedValue = ref<string>()
|
||
|
||
// --- DEMO LOGIC: SIMULASI API DAN MANIPULASI DATA ---
|
||
|
||
// Helper: Fungsi rekursif untuk mencari dan menyisipkan data anak ke dalam state
|
||
function findAndInsertChildren(nodes: TreeItem[], parentId: string, newChildren: TreeItem[]): boolean {
|
||
for (let i = 0; i < nodes.length; i++) {
|
||
const node = nodes[i]
|
||
if (node && node.value === parentId) {
|
||
// Gunakan Vue.set equivalent untuk memastikan reactivity
|
||
node.children = [...newChildren]
|
||
console.log(`[findAndInsertChildren] Updated children for ${parentId}:`, node.children)
|
||
return true
|
||
}
|
||
if (node && node.children && findAndInsertChildren(node.children, parentId, newChildren)) {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// Fungsi demo untuk simulasi fetch data dari API
|
||
async function handleFetchChildren(parentId: string): Promise<void> {
|
||
console.log(`[DEMO] Mengambil data anak untuk parent: ${parentId}`)
|
||
|
||
// Simulasi delay API call
|
||
await new Promise(resolve => setTimeout(resolve, 600))
|
||
|
||
let childrenData: TreeItem[] = []
|
||
|
||
// Sample data berdasarkan parent ID
|
||
switch (parentId) {
|
||
case 'frontend':
|
||
childrenData = [
|
||
{ value: 'vue', label: 'Vue.js', hasChildren: true },
|
||
{ value: 'react', label: 'React.js', hasChildren: true },
|
||
{ value: 'angular', label: 'Angular', hasChildren: false },
|
||
{ value: 'svelte', label: 'Svelte', hasChildren: false },
|
||
]
|
||
break
|
||
case 'backend':
|
||
childrenData = [
|
||
{ value: 'nodejs', label: 'Node.js', hasChildren: true },
|
||
{ value: 'python', label: 'Python', hasChildren: true },
|
||
{ value: 'golang', label: 'Go', hasChildren: false },
|
||
{ value: 'rust', label: 'Rust', hasChildren: false },
|
||
]
|
||
break
|
||
case 'mobile':
|
||
childrenData = [
|
||
{ value: 'flutter', label: 'Flutter', hasChildren: false },
|
||
{ value: 'react-native', label: 'React Native', hasChildren: false },
|
||
{ value: 'ionic', label: 'Ionic', hasChildren: false },
|
||
]
|
||
break
|
||
case 'vue':
|
||
childrenData = [
|
||
{ value: 'nuxt', label: 'Nuxt.js', hasChildren: false },
|
||
{ value: 'quasar', label: 'Quasar', hasChildren: false },
|
||
]
|
||
break
|
||
case 'react':
|
||
childrenData = [
|
||
{ value: 'nextjs', label: 'Next.js', hasChildren: false },
|
||
{ value: 'gatsby', label: 'Gatsby', hasChildren: false },
|
||
]
|
||
break
|
||
case 'nodejs':
|
||
childrenData = [
|
||
{ value: 'express', label: 'Express.js', hasChildren: false },
|
||
{ value: 'nestjs', label: 'NestJS', hasChildren: false },
|
||
{ value: 'fastify', label: 'Fastify', hasChildren: false },
|
||
]
|
||
break
|
||
case 'python':
|
||
childrenData = [
|
||
{ value: 'django', label: 'Django', hasChildren: false },
|
||
{ value: 'fastapi', label: 'FastAPI', hasChildren: false },
|
||
{ value: 'flask', label: 'Flask', hasChildren: false },
|
||
]
|
||
break
|
||
}
|
||
|
||
// Insert data ke dalam tree state
|
||
const success = findAndInsertChildren(treeData.value, parentId, childrenData)
|
||
console.log(`[DEMO] Insert children result:`, success)
|
||
|
||
// Force trigger reactivity
|
||
triggerRef(treeData)
|
||
console.log(`[DEMO] Current tree data:`, JSON.stringify(treeData.value, null, 2))
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div class="p-10 max-w-2xl mx-auto">
|
||
<div class="mb-6">
|
||
<h1 class="mb-2 text-3xl font-bold text-slate-800">Demo: Tree Select dengan Lazy Loading</h1>
|
||
<p class="text-slate-600">
|
||
Contoh penggunaan komponen TreeSelect dengan data teknologi.
|
||
Pilih item untuk melihat sub-kategori yang dimuat secara lazy.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="mb-6 p-4 bg-blue-50 border border-blue-200 rounded-lg">
|
||
<h3 class="font-semibold text-blue-800 mb-2">💡 Catatan untuk Developer:</h3>
|
||
<p class="text-sm text-blue-700">
|
||
Untuk implementasi nyata dengan data divisi rumah sakit,
|
||
lihat komponen <code class="px-1 bg-blue-100 rounded">content/division/entry.vue</code>
|
||
</p>
|
||
</div>
|
||
|
||
<div class="space-y-4">
|
||
<div>
|
||
<label class="block text-sm font-medium text-slate-700 mb-2">
|
||
Pilih Teknologi:
|
||
</label>
|
||
<TreeSelect
|
||
v-model="selectedValue"
|
||
:data="treeData"
|
||
:on-fetch-children="handleFetchChildren"
|
||
/>
|
||
</div>
|
||
|
||
<div class="p-4 bg-slate-50 rounded-lg">
|
||
<p class="text-sm text-slate-600 mb-1">Value yang terpilih:</p>
|
||
<span class="px-3 py-1 font-mono text-sm bg-white border rounded-md">
|
||
{{ selectedValue || 'Belum ada yang dipilih' }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mt-8 text-xs text-slate-500">
|
||
<p>🔄 Data dimuat secara lazy saat node parent dibuka</p>
|
||
<p>⏱️ Simulasi delay 600ms untuk menampilkan loading state</p>
|
||
</div>
|
||
</div>
|
||
</template>
|