创建页面类型模板文件页面增加前端要覆盖默认模板的具体选项

This commit is contained in:
jingrow 2025-10-28 00:21:44 +08:00
parent 9e1e922de0
commit a51018c696
3 changed files with 101 additions and 20 deletions

View File

@ -700,6 +700,9 @@
"Create Frontend": "创建前端",
"Create Backend": "创建后端",
"Please select PageType": "请选择页面类型",
"Toolbar": "工具栏",
"Sidebar": "侧边栏",
"Page": "页面",
"Media Resources": "媒体资源",
"Attachments": "附件",

View File

@ -6,7 +6,17 @@
<n-select v-model:value="form.pagetype" :options="pagetypeOptions" filterable clearable :loading="loading" :placeholder="t('Select PageType')" @update:show="onDropdownShow" @update:value="onPagetypeChange" />
</n-form-item>
<n-form-item :label="t('Create Frontend')">
<n-switch v-model:value="form.createFrontend" />
<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-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')" />
<n-checkbox value="page" :label="t('Page')" />
</n-space>
</n-checkbox-group>
</n-form-item>
<n-form-item :label="t('Create Backend')">
<n-switch v-model:value="form.createBackend" />
@ -16,7 +26,10 @@
</n-form-item>
<n-form-item v-if="appName || moduleName" :label="t('Preview')">
<div class="preview">
<div v-if="form.createFrontend && frontendPath">{{ t('Frontend') }}: {{ frontendPath }}</div>
<div v-if="form.createFrontend && frontendPath">
<div><strong>{{ t('Frontend') }}:</strong></div>
<pre class="path-preview">{{ frontendPath }}</pre>
</div>
<div v-if="form.createBackend && backendPath">{{ t('Backend') }}: {{ backendPath }}</div>
</div>
</n-form-item>
@ -37,31 +50,41 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import { NCard, NForm, NFormItem, NSelect, NSwitch, NButton, NSpace, useMessage, type FormInst, type FormRules } from 'naive-ui'
import { NCard, NForm, NFormItem, NSelect, NSwitch, NButton, NSpace, NCheckbox, NCheckboxGroup, useMessage, type FormInst, type FormRules } from 'naive-ui'
import axios from 'axios'
import { t } from '@/shared/i18n'
import { get_session_api_headers } from '@/shared/api/auth'
const router = useRouter()
const message = useMessage()
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 })
const form = ref({ pagetype: '', createFrontend: false, createBackend: true, frontendOptions: ['toolbar'] })
const pagetypeOptions = ref<{ label: string; value: string }[]>([])
const appName = ref('')
const moduleName = ref('')
const slug = computed(() => toSnake(form.value.pagetype || ''))
function dotToSlash(s: string): string { return s ? s.split('.').join('/').toLowerCase() : '' }
const frontendPath = computed(() =>
appName.value && slug.value !== ''
? `apps/${appName.value}/frontend/src/views/pagetype/${slug.value}/${slug.value}_toolbar.vue`
: ''
)
const frontendPath = computed(() => {
if (!appName.value || slug.value === '') return ''
const files = []
if (form.value.frontendOptions?.includes('toolbar')) {
files.push(`apps/${appName.value}/frontend/src/views/pagetype/${slug.value}/${slug.value}_toolbar.vue`)
}
if (form.value.frontendOptions?.includes('sidebar')) {
files.push(`apps/${appName.value}/frontend/src/views/pagetype/${slug.value}/${slug.value}_sidebar.vue`)
}
if (form.value.frontendOptions?.includes('page')) {
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/`)
}
return files.join('\n')
})
const backendPath = computed(() =>
appName.value && slug.value !== ''
? `apps/${appName.value}/${appName.value}/${dotToSlash(moduleName.value)}/pagetype/${slug.value}/${slug.value}.py`
@ -92,6 +115,14 @@ function toSnake(name: string): string {
return name.replace(/\s+/g, '_').replace(/-+/g, '_').toLowerCase()
}
function onFrontendToggle(value: boolean) {
if (value && !form.value.frontendOptions?.length) {
form.value.frontendOptions = ['toolbar']
} else if (!value) {
form.value.frontendOptions = []
}
}
async function onPagetypeChange() {
appName.value = ''
moduleName.value = ''
@ -124,7 +155,8 @@ async function handleSubmit() {
app: appName.value,
module: moduleName.value,
create_frontend: form.value.createFrontend,
create_backend: form.value.createBackend
create_backend: form.value.createBackend,
frontend_options: form.value.frontendOptions || []
}, { headers: get_session_api_headers(), withCredentials: true })
result.value = res.data
if (res.data?.success) {
@ -150,6 +182,16 @@ async function handleSubmit() {
<style scoped>
.page-dev-create-template { padding: 16px; }
.result { margin-top: 16px; font-size: 13px; color: #374151; }
.path-preview {
margin: 4px 0 0 0;
padding: 8px;
background: #f5f5f5;
border-radius: 4px;
font-family: monospace;
font-size: 12px;
white-space: pre-wrap;
word-break: break-all;
}
</style>

View File

@ -16,6 +16,7 @@ async def create_pagetypes(payload: Dict[str, Any]):
module = payload.get("module", "").replace('.', '/').lower()
create_frontend = bool(payload.get("create_frontend", True))
create_backend = bool(payload.get("create_backend", True))
frontend_options = payload.get("frontend_options", ["toolbar"])
if not name:
raise ValueError("pagetype is required")
slug = to_snake(name)
@ -23,19 +24,54 @@ async def create_pagetypes(payload: Dict[str, Any]):
current = Path(__file__).resolve()
root = current.parents[4]
frontend_path = None
frontend_paths = []
backend_path = None
frontend_exists = False
backend_exists = False
if create_frontend:
fp = root / "apps" / app / "frontend" / "src" / "views" / "pagetype" / slug / f"{slug}_toolbar.vue"
fp.parent.mkdir(parents=True, exist_ok=True)
if fp.exists():
frontend_exists = True
else:
fp.write_text("<template>\n <div></div>\n</template>\n<script setup lang=\"ts\">\n</script>\n", encoding="utf-8")
frontend_path = str(fp)
# 工具栏
if "toolbar" in frontend_options:
fp = root / "apps" / app / "frontend" / "src" / "views" / "pagetype" / slug / f"{slug}_toolbar.vue"
fp.parent.mkdir(parents=True, exist_ok=True)
if fp.exists():
frontend_exists = True
else:
toolbar_content = "<template>\n <div></div>\n</template>\n<script setup lang=\"ts\">\n</script>\n"
fp.write_text(toolbar_content, encoding="utf-8")
frontend_paths.append(str(fp))
# 侧边栏
if "sidebar" in frontend_options:
fp = root / "apps" / app / "frontend" / "src" / "views" / "pagetype" / slug / f"{slug}_sidebar.vue"
fp.parent.mkdir(parents=True, exist_ok=True)
if fp.exists():
frontend_exists = True
else:
sidebar_content = "<template>\n <div class=\"sidebar\"></div>\n</template>\n<script setup lang=\"ts\">\n</script>\n<style scoped>\n.sidebar {}\n</style>\n"
fp.write_text(sidebar_content, encoding="utf-8")
frontend_paths.append(str(fp))
# 页面
if "page" in frontend_options:
fp = root / "apps" / app / "frontend" / "src" / "views" / "pagetype" / slug / f"{slug}.vue"
fp.parent.mkdir(parents=True, exist_ok=True)
if fp.exists():
frontend_exists = True
else:
page_content = "<template>\n <div class=\"pagetype-page\"></div>\n</template>\n<script setup lang=\"ts\">\n</script>\n<style scoped>\n.pagetype-page {}\n</style>\n"
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)} (创建自定义字段控件)")
frontend_path = "\n".join(frontend_paths) if frontend_paths else None
else:
frontend_path = None
if create_backend:
bp = root / "apps" / app / app / module / "pagetype" / slug / f"{slug}.py"