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

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 Frontend": "创建前端",
"Create Backend": "创建后端", "Create Backend": "创建后端",
"Please select PageType": "请选择页面类型", "Please select PageType": "请选择页面类型",
"Toolbar": "工具栏",
"Sidebar": "侧边栏",
"Page": "页面",
"Media Resources": "媒体资源", "Media Resources": "媒体资源",
"Attachments": "附件", "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-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>
<n-form-item :label="t('Create Frontend')"> <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>
<n-form-item :label="t('Create Backend')"> <n-form-item :label="t('Create Backend')">
<n-switch v-model:value="form.createBackend" /> <n-switch v-model:value="form.createBackend" />
@ -16,7 +26,10 @@
</n-form-item> </n-form-item>
<n-form-item v-if="appName || moduleName" :label="t('Preview')"> <n-form-item v-if="appName || moduleName" :label="t('Preview')">
<div class="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 v-if="form.createBackend && backendPath">{{ t('Backend') }}: {{ backendPath }}</div>
</div> </div>
</n-form-item> </n-form-item>
@ -37,31 +50,41 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { useRouter } from 'vue-router' import { NCard, NForm, NFormItem, NSelect, NSwitch, NButton, NSpace, NCheckbox, NCheckboxGroup, useMessage, type FormInst, type FormRules } from 'naive-ui'
import { NCard, NForm, NFormItem, NSelect, NSwitch, NButton, NSpace, useMessage, type FormInst, type FormRules } from 'naive-ui'
import axios from 'axios' import axios from 'axios'
import { t } from '@/shared/i18n' import { t } from '@/shared/i18n'
import { get_session_api_headers } from '@/shared/api/auth' import { get_session_api_headers } from '@/shared/api/auth'
const router = useRouter()
const message = useMessage() const message = useMessage()
const loading = ref(false) const loading = ref(false)
const submitting = ref(false) const submitting = ref(false)
const result = ref<any>(null) const result = ref<any>(null)
const formRef = ref<FormInst | null>(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 pagetypeOptions = ref<{ label: string; value: string }[]>([])
const appName = ref('') const appName = ref('')
const moduleName = ref('') const moduleName = ref('')
const slug = computed(() => toSnake(form.value.pagetype || '')) const slug = computed(() => toSnake(form.value.pagetype || ''))
function dotToSlash(s: string): string { return s ? s.split('.').join('/').toLowerCase() : '' } function dotToSlash(s: string): string { return s ? s.split('.').join('/').toLowerCase() : '' }
const frontendPath = computed(() => const frontendPath = computed(() => {
appName.value && slug.value !== '' if (!appName.value || slug.value === '') return ''
? `apps/${appName.value}/frontend/src/views/pagetype/${slug.value}/${slug.value}_toolbar.vue` 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(() => const backendPath = computed(() =>
appName.value && slug.value !== '' appName.value && slug.value !== ''
? `apps/${appName.value}/${appName.value}/${dotToSlash(moduleName.value)}/pagetype/${slug.value}/${slug.value}.py` ? `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() 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() { async function onPagetypeChange() {
appName.value = '' appName.value = ''
moduleName.value = '' moduleName.value = ''
@ -124,7 +155,8 @@ async function handleSubmit() {
app: appName.value, app: appName.value,
module: moduleName.value, module: moduleName.value,
create_frontend: form.value.createFrontend, 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 }) }, { headers: get_session_api_headers(), withCredentials: true })
result.value = res.data result.value = res.data
if (res.data?.success) { if (res.data?.success) {
@ -150,6 +182,16 @@ async function handleSubmit() {
<style scoped> <style scoped>
.page-dev-create-template { padding: 16px; } .page-dev-create-template { padding: 16px; }
.result { margin-top: 16px; font-size: 13px; color: #374151; } .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> </style>

View File

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