优化创建页面类型模板文件页面

This commit is contained in:
jingrow 2025-10-28 00:32:39 +08:00
parent a51018c696
commit bef1955fde
3 changed files with 114 additions and 7 deletions

View File

@ -703,6 +703,7 @@
"Toolbar": "工具栏",
"Sidebar": "侧边栏",
"Page": "页面",
"Select Field Types": "选择字段类型",
"Media Resources": "媒体资源",
"Attachments": "附件",

View File

@ -9,11 +9,23 @@
<n-switch v-model:value="form.createFrontend" @update:value="onFrontendToggle" />
</n-form-item>
<n-form-item v-if="form.createFrontend" label="" style="margin-top: 0;">
<n-checkbox-group v-model:value="form.frontendOptions">
<n-checkbox-group v-model:value="form.frontendOptions" @update:value="onFrontendOptionsChange">
<n-space vertical>
<n-checkbox value="toolbar" :label="t('Toolbar')" />
<n-checkbox value="sidebar" :label="t('Sidebar')" />
<n-checkbox value="field_types" :label="t('Field Types')" />
<div class="field-types-row">
<n-checkbox value="field_types" :label="t('Field Types')" />
<n-select
v-if="form.frontendOptions.includes('field_types')"
v-model:value="form.fieldTypeNames"
:options="fieldTypeOptions"
multiple
filterable
:placeholder="t('Select Field Types')"
style="width: 200px; margin-left: 16px;"
@update:value="updateFieldTypesPreview"
/>
</div>
<n-checkbox value="page" :label="t('Page')" />
</n-space>
</n-checkbox-group>
@ -61,11 +73,43 @@ const loading = ref(false)
const submitting = ref(false)
const result = ref<any>(null)
const formRef = ref<FormInst | null>(null)
const form = ref({ pagetype: '', createFrontend: false, createBackend: true, frontendOptions: ['toolbar'] })
const form = ref({ pagetype: '', createFrontend: false, createBackend: true, frontendOptions: ['toolbar'], fieldTypeNames: [] })
const pagetypeOptions = ref<{ label: string; value: string }[]>([])
// /core/components/form/controls
const fieldTypeOptions = ref<{ label: string; value: string }[]>([])
const appName = ref('')
const moduleName = ref('')
// /core/components/form/controls
const loadFieldTypeOptions = () => {
try {
const modules = import.meta.glob('@/core/components/form/controls/*.vue', { eager: true })
const fileNames = Object.keys(modules)
.map(path => path.split('/').pop()?.replace('.vue', '') || '')
.filter(name => name && !name.startsWith('_')) //
fieldTypeOptions.value = fileNames
.map(name => ({ label: name, value: name }))
.sort((a, b) => a.label.localeCompare(b.label))
} catch (e) {
console.warn('Failed to load field type options from filesystem:', e)
// 使
fieldTypeOptions.value = [
'Attach', 'AttachImage', 'Autocomplete', 'Barcode', 'Button',
'Check', 'Code', 'Color', 'Comment', 'CronEditor', 'Currency',
'Data', 'Date', 'DateRange', 'Datetime', 'Duration', 'DynamicLink',
'Float', 'Geolocation', 'Heading', 'HTML', 'HTMLEditor', 'Icon',
'Image', 'Int', 'Jeditor', 'JSON', 'Link', 'LongText', 'MarkdownEditor',
'MultiCheck', 'MultiSelect', 'MultiSelectList', 'MultiSelectPills',
'Password', 'Percent', 'Phone', 'Rating', 'Select', 'Signature',
'SmallText', 'Table', 'TableMultiSelect', 'Text', 'TextEditor', 'Time'
].map(name => ({ label: name, value: name }))
}
}
loadFieldTypeOptions()
const slug = computed(() => toSnake(form.value.pagetype || ''))
function dotToSlash(s: string): string { return s ? s.split('.').join('/').toLowerCase() : '' }
const frontendPath = computed(() => {
@ -81,7 +125,13 @@ const frontendPath = computed(() => {
files.push(`apps/${appName.value}/frontend/src/views/pagetype/${slug.value}/${slug.value}.vue`)
}
if (form.value.frontendOptions?.includes('field_types')) {
files.push(`apps/${appName.value}/frontend/src/views/pagetype/${slug.value}/form/controls/`)
if (form.value.fieldTypeNames && form.value.fieldTypeNames.length > 0) {
form.value.fieldTypeNames.forEach((name: string) => {
files.push(`apps/${appName.value}/frontend/src/views/pagetype/${slug.value}/form/controls/${name}.vue`)
})
} else {
files.push(`apps/${appName.value}/frontend/src/views/pagetype/${slug.value}/form/controls/`)
}
}
return files.join('\n')
})
@ -120,6 +170,18 @@ function onFrontendToggle(value: boolean) {
form.value.frontendOptions = ['toolbar']
} else if (!value) {
form.value.frontendOptions = []
form.value.fieldTypeNames = []
}
}
function updateFieldTypesPreview() {
//
}
function onFrontendOptionsChange(value: (string | number)[]) {
//
if (!value.includes('field_types')) {
form.value.fieldTypeNames = []
}
}
@ -156,7 +218,8 @@ async function handleSubmit() {
module: moduleName.value,
create_frontend: form.value.createFrontend,
create_backend: form.value.createBackend,
frontend_options: form.value.frontendOptions || []
frontend_options: form.value.frontendOptions || [],
field_type_names: form.value.fieldTypeNames || []
}, { headers: get_session_api_headers(), withCredentials: true })
result.value = res.data
if (res.data?.success) {
@ -192,6 +255,11 @@ async function handleSubmit() {
white-space: pre-wrap;
word-break: break-all;
}
.field-types-row {
display: flex;
align-items: center;
gap: 8px;
}
</style>

View File

@ -17,6 +17,7 @@ async def create_pagetypes(payload: Dict[str, Any]):
create_frontend = bool(payload.get("create_frontend", True))
create_backend = bool(payload.get("create_backend", True))
frontend_options = payload.get("frontend_options", ["toolbar"])
field_type_names = payload.get("field_type_names", [])
if not name:
raise ValueError("pagetype is required")
slug = to_snake(name)
@ -63,11 +64,48 @@ async def create_pagetypes(payload: Dict[str, Any]):
fp.write_text(page_content, encoding="utf-8")
frontend_paths.append(str(fp))
# 字段类型控件目录
# 字段类型控件
if "field_types" in frontend_options:
fp = root / "apps" / app / "frontend" / "src" / "views" / "pagetype" / slug / "form" / "controls"
fp.mkdir(parents=True, exist_ok=True)
frontend_paths.append(f"{str(fp)} (创建自定义字段控件)")
if field_type_names:
# 为每个选中的字段类型创建文件
for field_type_name in field_type_names:
field_file = fp / f"{field_type_name}.vue"
if field_file.exists():
frontend_exists = True
else:
# 创建字段类型组件的模板
field_content = f'''<script setup lang="ts">
import {{ computed }} from 'vue'
const props = defineProps<{{
df: any;
record: Record<string, any>;
canEdit: boolean;
ctx: any
}}>()
// TODO: 实现 {field_type_name} 字段类型逻辑
</script>
<template>
<div class="field-{field_type_name.lower()}">
<!-- TODO: 实现 {field_type_name} 界面 -->
</div>
</template>
<style scoped>
.field-{field_type_name.lower()} {{
/* TODO: 添加样式 */
}}
</style>
'''
field_file.write_text(field_content, encoding="utf-8")
frontend_paths.append(str(field_file))
else:
frontend_paths.append(f"{str(fp)}/ (创建自定义字段控件)")
frontend_path = "\n".join(frontend_paths) if frontend_paths else None
else: