From 9e4eacef1058a3027c09dde53bedff0b6e90afd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=B9=8F?= Date: Fri, 29 May 2026 11:17:39 +0800 Subject: [PATCH] Fix page designer validation and generation --- .../src/components/FrontendPageDesigner.vue | 2589 +++++++++++++++++ .../components/frontendPageDesigner.test.mjs | 267 ++ .../src/views/PageDesignerView.vue | 464 +++ .../src/views/pageDesignerView.test.mjs | 64 + .../BusinessBlockGenerationService.java | 759 +++++ .../service/GenProjectServiceImpl.java | 487 +++- .../front/FrontendPageDesignService.java | 1126 +++++++ .../ruoyi/generator/util/VelocityUtils.java | 925 +++++- .../main/resources/qing/controller.java.vm | 186 +- .../src/main/resources/qing/index.vue.vm | 1122 +++++-- .../BusinessBlockGenerationServiceTest.java | 463 +++ .../service/GenProjectServiceImplTest.java | 559 ++++ .../front/FrontendPageDesignServiceTest.java | 564 ++++ .../util/QingTemplateSupportTest.java | 1029 +++++++ 14 files changed, 10355 insertions(+), 249 deletions(-) create mode 100644 RuoYi-Vue/easycode-web/src/components/FrontendPageDesigner.vue create mode 100644 RuoYi-Vue/easycode-web/src/components/frontendPageDesigner.test.mjs create mode 100644 RuoYi-Vue/easycode-web/src/views/PageDesignerView.vue create mode 100644 RuoYi-Vue/easycode-web/src/views/pageDesignerView.test.mjs create mode 100644 RuoYi-Vue/ruoyi-generator/src/main/java/com/ruoyi/generator/service/BusinessBlockGenerationService.java create mode 100644 RuoYi-Vue/ruoyi-generator/src/main/java/com/ruoyi/generator/service/front/FrontendPageDesignService.java create mode 100644 RuoYi-Vue/ruoyi-generator/src/test/java/com/ruoyi/generator/service/BusinessBlockGenerationServiceTest.java create mode 100644 RuoYi-Vue/ruoyi-generator/src/test/java/com/ruoyi/generator/service/front/FrontendPageDesignServiceTest.java create mode 100644 RuoYi-Vue/ruoyi-generator/src/test/java/com/ruoyi/generator/util/QingTemplateSupportTest.java diff --git a/RuoYi-Vue/easycode-web/src/components/FrontendPageDesigner.vue b/RuoYi-Vue/easycode-web/src/components/FrontendPageDesigner.vue new file mode 100644 index 0000000..b340d85 --- /dev/null +++ b/RuoYi-Vue/easycode-web/src/components/FrontendPageDesigner.vue @@ -0,0 +1,2589 @@ + + + + + diff --git a/RuoYi-Vue/easycode-web/src/components/frontendPageDesigner.test.mjs b/RuoYi-Vue/easycode-web/src/components/frontendPageDesigner.test.mjs new file mode 100644 index 0000000..d42e3fa --- /dev/null +++ b/RuoYi-Vue/easycode-web/src/components/frontendPageDesigner.test.mjs @@ -0,0 +1,267 @@ +import test from 'node:test' +import assert from 'node:assert/strict' +import { existsSync, readFileSync } from 'node:fs' +import { fileURLToPath } from 'node:url' +import { dirname, resolve } from 'node:path' + +const currentDir = dirname(fileURLToPath(import.meta.url)) +const srcDir = resolve(currentDir, '..') + +function readSource(relativePath) { + return readFileSync(resolve(srcDir, relativePath), 'utf8') +} + +test('project api exposes frontend page design endpoints', () => { + const source = readSource('api/project.js') + + assert.equal(source.includes('export function listPageDesigns'), true) + assert.equal(source.includes('export function initPageDesigns'), true) + assert.equal(source.includes('export function createPageDesign'), true) + assert.equal(source.includes('export function getPageDesign'), true) + assert.equal(source.includes('export function savePageDesign'), true) + assert.equal(source.includes('export function deletePageDesign'), true) + assert.equal(source.includes('export function listBusinessBlocks'), true) + assert.equal(source.includes('/page-designs/init'), true) + assert.equal(source.includes('url: `/front/project/${projectId}/page-designs`'), true) + assert.equal(source.includes('/business-blocks'), true) + assert.equal(source.includes('scope = \'frontend\''), true) + assert.equal(source.includes('params: { scope }'), true) +}) + +test('frontend page designer edits layouts and emits saves', () => { + assert.equal(existsSync(resolve(srcDir, 'components/FrontendPageDesigner.vue')), true) + const source = readSource('components/FrontendPageDesigner.vue') + + assert.equal(source.includes('defineEmits'), true) + assert.equal(source.includes('update:designs'), true) + assert.equal(source.includes('dirty-change'), true) + assert.equal(source.includes('save-design'), true) + assert.equal(source.includes('create-design'), true) + assert.equal(source.includes('delete-design'), true) + assert.equal(source.includes('init-designs'), true) + assert.equal(source.includes('layoutJson'), true) + assert.equal(source.includes('actionJson'), true) + assert.equal(source.includes('draggable="true"'), true) + assert.equal(source.includes('function commitCurrentDraft'), true) + assert.equal(source.includes('defineExpose'), true) +}) + +test('frontend page designer reports local draft edits as dirty before commit', () => { + const source = readSource('components/FrontendPageDesigner.vue') + + assert.equal(source.includes('function markDirty'), true) + assert.equal(source.includes("emit('dirty-change', true)"), true) + assert.equal(source.includes('const suppressDirty = ref(false)'), true) + assert.equal(source.includes('syncJson({ silent: true })'), true) + assert.equal(source.includes('v-model="draft.pageName" @input="markDirty"'), true) + assert.equal(source.includes('v-model="draft.routePath" @input="markDirty"'), true) +}) + +test('frontend page designer renders page navigation as a normal menu inside the canvas', () => { + const source = readSource('components/FrontendPageDesigner.vue') + + assert.equal(source.includes('