feat(sections): add SectionFormPage demo

Add a dedicated SectionFormPage demo component and view to showcase form fields, detail sections, notices, and page-driver-managed state.

Remove the obsolete SectionSearchPanel demo route and menu entry, and add spacing to SectionFormPage cards for improved layout.feat(sections): add SectionFormPage demo

Add a dedicated SectionFormPage demo component and view to showcase form fields, detail sections, notices, and page-driver-managed state.

Remove the obsolete SectionSearchPanel demo route and menu entry, and add spacing to SectionFormPage cards for improved layout.
This commit is contained in:
skytek_xinliang
2026-05-22 15:41:52 +08:00
parent cad44db4c7
commit ec62fcee51
5 changed files with 107 additions and 12 deletions
@@ -0,0 +1,89 @@
<script setup lang="ts">
import BaseFormSelect from '@/components/base/BaseFormSelect.vue'
import BaseFormTextField from '@/components/base/BaseFormTextField.vue'
import SectionFormPage from '@/components/sections/SectionFormPage.vue'
import type {
DemoFormState,
SectionsDemoPageModel,
} from '@/composables/page-drivers/useSectionsDemoPage'
defineProps<{
page: SectionsDemoPageModel
}>()
// 表單內容由 page driver 持有,Page component 只透過 v-model 呈現與回寫。
const demoForm = defineModel<DemoFormState>('demoForm', { required: true })
// 送出、清除、返回都往上 emit,讓 page driver 統一處理訊息與副作用。
const emit = defineEmits<{
(e: 'back'): void
(e: 'reset'): void
(e: 'submit'): void
}>()
</script>
<template>
<SectionFormPage
back-label="回到列表"
reset-label="清除"
submit-label="送出"
:message="page.formMessage"
title="SectionFormPage 報表申請"
@back="emit('back')"
@reset="emit('reset')"
@submit="emit('submit')"
>
<!-- SectionFormPage 決定表單頁外殼fields slot 放實際欄位組合 -->
<template #fields>
<v-row density="compact">
<v-col cols="12" md="6">
<BaseFormTextField v-model="demoForm.title" label="標題" />
</v-col>
<v-col cols="12" md="3">
<BaseFormSelect v-model="demoForm.owner" label="單位" :items="page.ownerOptions" />
</v-col>
<v-col cols="12" md="3">
<BaseFormSelect v-model="demoForm.category" label="類型" :items="page.categoryOptions" />
</v-col>
<v-col cols="12">
<BaseFormTextField v-model="demoForm.description" label="說明" />
</v-col>
</v-row>
</template>
<!-- sections slot 放表單主欄位以外的子區段例如明細表格或補充資訊 -->
<template #sections>
<v-card class="mb-2">
<v-card-title class="text-title-medium font-weight-bold">明細</v-card-title>
<v-card-text>
<v-table density="compact">
<thead>
<tr>
<th>欄位</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>單位</td>
<td>{{ demoForm.owner }}</td>
</tr>
<tr>
<td>類型</td>
<td>{{ demoForm.category }}</td>
</tr>
</tbody>
</v-table>
</v-card-text>
</v-card>
</template>
<!-- notices slot 放配合事項讓外殼固定內容由頁面決定 -->
<template #notices>
<v-list class="bg-yellow-lighten-5" density="compact">
<v-list-item>送出前確認標題與單位</v-list-item>
<v-list-item>表單狀態由 page driver 管理</v-list-item>
</v-list>
</template>
</SectionFormPage>
</template>
+1 -1
View File
@@ -25,7 +25,7 @@ const emit = defineEmits<{
<template> <template>
<v-form @submit.prevent="emit('submit')"> <v-form @submit.prevent="emit('submit')">
<v-container fluid class="pt-2 px-1"> <v-container fluid class="pt-2 px-1">
<v-card> <v-card class="mb-2">
<v-card-title class="bg-primary text-title-large text-center py-2"> <v-card-title class="bg-primary text-title-large text-center py-2">
{{ title }} {{ title }}
</v-card-title> </v-card-title>
-5
View File
@@ -39,11 +39,6 @@ const fixedMenuItems: LayoutMenuItem[] = [
path: '/demos/sections/query-page', path: '/demos/sections/query-page',
}, },
{ title: 'SectionFormPage', icon: mdiFileDocumentOutline, path: '/demos/sections/form-page' }, { title: 'SectionFormPage', icon: mdiFileDocumentOutline, path: '/demos/sections/form-page' },
{
title: 'SectionSearchPanel',
icon: mdiFileDocumentOutline,
path: '/demos/sections/search-panel',
},
], ],
}, },
{ title: '登入頁', path: '/login' }, { title: '登入頁', path: '/login' },
-6
View File
@@ -65,12 +65,6 @@ export const routes: RouteRecordRaw[] = [
component: () => import('@/views/demos/SectionFormPageDemo.vue'), component: () => import('@/views/demos/SectionFormPageDemo.vue'),
meta: { title: 'SectionFormPage 示範', layout: 'default' }, meta: { title: 'SectionFormPage 示範', layout: 'default' },
}, },
{
path: '/demos/sections/search-panel',
name: 'demo-section-search-panel',
component: () => import('@/views/demos/SectionSearchPanelDemo.vue'),
meta: { title: 'SectionSearchPanel 示範', layout: 'default' },
},
{ {
path: '/:fncId([0-9A-Z]{5,6})', path: '/:fncId([0-9A-Z]{5,6})',
name: 'fnc-page', name: 'fnc-page',
+17
View File
@@ -0,0 +1,17 @@
<script setup lang="ts">
import PageSectionFormPageDemo from '@/components/pages/PageSectionFormPageDemo.vue'
import { useSectionsDemoPage } from '@/composables/page-drivers/useSectionsDemoPage'
// Demo view 維持薄層,只掛 page driver,並把 page model / actions 傳給 page component。
const page = useSectionsDemoPage()
</script>
<template>
<PageSectionFormPageDemo
v-model:demo-form="page.demoForm.value"
:page="page.pageModel.value"
@back="page.handleFormBack"
@reset="page.resetDemoForm"
@submit="page.handleFormSubmit"
/>
</template>