优化创建页面类型模板文件页面
This commit is contained in:
parent
a51018c696
commit
bef1955fde
@ -703,6 +703,7 @@
|
||||
"Toolbar": "工具栏",
|
||||
"Sidebar": "侧边栏",
|
||||
"Page": "页面",
|
||||
"Select Field Types": "选择字段类型",
|
||||
|
||||
"Media Resources": "媒体资源",
|
||||
"Attachments": "附件",
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user