<script setup lang="ts">
import { inject, provide, defineAsyncComponent, useRoute } from 'vue';
import type { Component } from 'vue';
import {
FormPageHeaderKey,
FormContentKey,
FormActionsKey,
PageSectionRegistryKey,
SectionKeyMap,
} from '@core/composables/useSections';
import DefaultFormPageHeader from '@core/views/components/FormPageHeader.vue';
import DefaultFormContent from '@core/views/components/FormContent.vue';
import DefaultFormActions from '@core/views/components/FormActions.vue';
interface FormField {
key: string;
label: string;
type: 'text' | 'email' | 'tel' | 'select' | 'textarea' | 'radio';
required?: boolean;
fullWidth?: boolean;
placeholder?: string;
options?: Array<{ value: string; label: string }>;
error?: string;
}
interface Props {
title?: string;
subtitle?: string;
fields?: FormField[];
modelValue?: Record<string, unknown>;
showContinue?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
showContinue: true,
});
const emit = defineEmits<{
submit: [];
continue: [];
cancel: [];
'update:modelValue': [val: Record<string, unknown>];
}>();
// ─── 约定式自动发现 ───────────────────────────────────────────────
const route = useRoute();
const registry = inject(
PageSectionRegistryKey,
{} as Record<string, Record<string, () => Promise<{ default: unknown }>>>,
);
const pageOverrides = registry[route.path] ?? {};
for (const [name, loader] of Object.entries(pageOverrides)) {
const key = SectionKeyMap[name];
if (key) {
provide(key, defineAsyncComponent(loader as () => Promise<{ default: Component }>));
}
}
// ─── inject 回退到框架默认 ────────────────────────────────────────
const PageHeaderComp = inject(FormPageHeaderKey, DefaultFormPageHeader);
const FormContentComp = inject(FormContentKey, DefaultFormContent);
const FormActionsComp = inject(FormActionsKey, DefaultFormActions);
</script>
<template>
<div class="form-page">
<!-- 页头 -->
<slot name="header">
<component :is="PageHeaderComp" :title="title" :subtitle="subtitle" />
</slot>
<div class="fp-body">
<!-- 表单内容 -->
<slot name="form">
<component
:is="FormContentComp"
:fields="fields"
:model-value="modelValue"
@update:model-value="emit('update:modelValue', $event)"
/>
</slot>
<!-- 操作区 -->
<slot name="actions">
<component
:is="FormActionsComp"
:show-continue="showContinue"
@submit="emit('submit')"
@continue="emit('continue')"
@cancel="emit('cancel')"
/>
</slot>
</div>
</div>
</template>
<style lang="scss" scoped>
.form-page {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}
.fp-body {
flex: 1;
overflow-y: auto;
padding: 20px 24px;
display: flex;
flex-direction: column;
gap: 16px;
background: var(--bg);
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #c8d4c8;
border-radius: 3px;
}
}
</style>
|