257 lines
9.7 KiB
Markdown
257 lines
9.7 KiB
Markdown
|
|
# Frontend Page Designer Design
|
||
|
|
|
||
|
|
## Goal
|
||
|
|
|
||
|
|
Build a user-facing frontend page designer inside the EasyCode generation workbench. The designer lets a user configure generated portal pages visually, then stores the result in an independent `front_project_page_design` table so project generation can produce Vue frontend pages from the saved layout.
|
||
|
|
|
||
|
|
## Scope
|
||
|
|
|
||
|
|
The first phase covers generated user-facing frontend pages only.
|
||
|
|
|
||
|
|
Included:
|
||
|
|
|
||
|
|
- Initialize page design records from confirmed `appBlueprint.frontendPages`.
|
||
|
|
- Show a menu/page tree for frontend pages.
|
||
|
|
- Edit page metadata, bound table, route path, page type, layout regions, displayed fields, query fields, form fields, table row actions, and toolbar actions.
|
||
|
|
- Save page design records independently from `appBlueprint`.
|
||
|
|
- Use saved page designs during generated project preview and download.
|
||
|
|
- Keep existing generation behavior as a fallback when no page design exists.
|
||
|
|
|
||
|
|
Excluded from phase one:
|
||
|
|
|
||
|
|
- RuoYi admin page visual design.
|
||
|
|
- Free-form nested low-code containers.
|
||
|
|
- Runtime page rendering inside EasyCode beyond lightweight preview/wireframe.
|
||
|
|
- Page design version history beyond a simple `version` field for optimistic locking.
|
||
|
|
- Multi-user collaborative editing.
|
||
|
|
|
||
|
|
## Current Context
|
||
|
|
|
||
|
|
The project already has these concepts:
|
||
|
|
|
||
|
|
- `AppBlueprintDesign` contains roles, `frontendMenus`, `adminMenus`, and `frontendPages`.
|
||
|
|
- `AppPageDesign` names generated frontend pages with `code`, `menuCode`, `path`, `pageType`, and `tableName`.
|
||
|
|
- `BusinessActionDesign.uiBindings` can attach generated business actions to frontend page slots.
|
||
|
|
- `GenerateView.vue` already orchestrates app blueprint generation, database design, business blueprint generation, and preview generation.
|
||
|
|
- Qing templates already generate a Vue frontend shell and table-oriented frontend pages.
|
||
|
|
|
||
|
|
The new designer should sit between app blueprint/database design and project preview generation.
|
||
|
|
|
||
|
|
## Architecture
|
||
|
|
|
||
|
|
Add a persistent page design layer:
|
||
|
|
|
||
|
|
```text
|
||
|
|
appBlueprint.frontendPages
|
||
|
|
|
|
||
|
|
v
|
||
|
|
front_project_page_design
|
||
|
|
|
|
||
|
|
v
|
||
|
|
FrontendPageDesigner.vue
|
||
|
|
|
|
||
|
|
v
|
||
|
|
FrontProjectConverter / GenProject
|
||
|
|
|
|
||
|
|
v
|
||
|
|
Velocity templates
|
||
|
|
```
|
||
|
|
|
||
|
|
`appBlueprint` remains the source for application structure: menus, route entry points, and page codes. `front_project_page_design` becomes the source for how each generated frontend page is composed.
|
||
|
|
|
||
|
|
The generator reads page designs by project ID and exposes them to Velocity alongside tables, frontend pages, and business actions. If a page has no saved design, the generator builds a default design from the table columns and existing table CRUD flags.
|
||
|
|
|
||
|
|
## Database
|
||
|
|
|
||
|
|
Create `front_project_page_design`.
|
||
|
|
|
||
|
|
Columns:
|
||
|
|
|
||
|
|
- `design_id` bigint primary key.
|
||
|
|
- `project_id` bigint, required.
|
||
|
|
- `user_id` bigint, required.
|
||
|
|
- `page_code` varchar(100), required. Matches `AppPageDesign.code`.
|
||
|
|
- `menu_code` varchar(100), optional. Matches `AppMenuDesign.code`.
|
||
|
|
- `page_name` varchar(100), required.
|
||
|
|
- `route_path` varchar(255), required.
|
||
|
|
- `page_type` varchar(50), required. Supported values: `list`, `detail`, `form`, `current_user_list`.
|
||
|
|
- `table_name` varchar(100), required for table-backed pages.
|
||
|
|
- `layout_json` longtext, required.
|
||
|
|
- `action_json` longtext, optional.
|
||
|
|
- `status` char(1), default `0`.
|
||
|
|
- `version` int, default `1`.
|
||
|
|
- RuoYi audit columns: `create_by`, `create_time`, `update_by`, `update_time`, `remark`.
|
||
|
|
|
||
|
|
Indexes:
|
||
|
|
|
||
|
|
- Unique key on `(project_id, page_code)`.
|
||
|
|
- Normal index on `(project_id, menu_code)`.
|
||
|
|
- Normal index on `(project_id, table_name)`.
|
||
|
|
|
||
|
|
Deletion behavior:
|
||
|
|
|
||
|
|
- Deleting a project deletes its page designs.
|
||
|
|
- Regenerating app blueprint does not automatically delete existing designs. The user can run initialization again to add missing designs and mark orphaned designs as detached.
|
||
|
|
|
||
|
|
## Page Design DSL
|
||
|
|
|
||
|
|
`layout_json` stores layout composition:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"canvas": "frontend-list-v1",
|
||
|
|
"regions": [
|
||
|
|
{
|
||
|
|
"id": "query",
|
||
|
|
"type": "query",
|
||
|
|
"fields": ["title", "category", "status"]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "toolbar",
|
||
|
|
"type": "toolbar",
|
||
|
|
"actions": ["create", "export", "batchDelete"]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "table",
|
||
|
|
"type": "table",
|
||
|
|
"fields": ["cover", "title", "author", "stock", "status"],
|
||
|
|
"rowActions": ["view", "edit", "delete"]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "form",
|
||
|
|
"type": "dialogForm",
|
||
|
|
"fields": ["title", "author", "category", "price"]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
`action_json` stores button/action configuration that is local to the page:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"toolbarActions": [
|
||
|
|
{ "code": "create", "label": "Create", "type": "primary", "builtin": true },
|
||
|
|
{ "code": "export", "label": "Export", "type": "default", "builtin": true }
|
||
|
|
],
|
||
|
|
"rowActions": [
|
||
|
|
{ "code": "view", "label": "View", "builtin": true },
|
||
|
|
{ "code": "borrow", "label": "Borrow", "businessActionCode": "borrow_book" }
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Field names in `layout_json` reference `DatabaseColumnDesign.javaField`. The backend accepts database column names too, normalizes them to Java field names, and rejects unknown fields.
|
||
|
|
|
||
|
|
## Backend API
|
||
|
|
|
||
|
|
Add routes under `FrontProjectController`:
|
||
|
|
|
||
|
|
- `GET /front/project/{projectId}/page-designs`
|
||
|
|
Returns all active page designs for the project, sorted by menu/page order.
|
||
|
|
|
||
|
|
- `POST /front/project/{projectId}/page-designs/init`
|
||
|
|
Creates missing page design records from `appBlueprint.frontendPages`. Existing records are preserved. Detached records are returned so the UI can show them separately.
|
||
|
|
|
||
|
|
- `GET /front/project/{projectId}/page-designs/{designId}`
|
||
|
|
Returns one page design with normalized layout and field metadata.
|
||
|
|
|
||
|
|
- `PUT /front/project/{projectId}/page-designs/{designId}`
|
||
|
|
Validates and saves metadata, `layout_json`, `action_json`, and `version`.
|
||
|
|
|
||
|
|
Validation rules:
|
||
|
|
|
||
|
|
- The project must belong to the current frontend user.
|
||
|
|
- `page_code` must be unique per project.
|
||
|
|
- `page_type` must be one of the supported values.
|
||
|
|
- `table_name` must exist in the saved database design when the page type is table-backed.
|
||
|
|
- Region IDs must be unique inside a page.
|
||
|
|
- Region types must be supported by the selected page type.
|
||
|
|
- Fields must exist in the bound table.
|
||
|
|
- Built-in actions must be allowed by table operation flags.
|
||
|
|
- `businessActionCode` must exist in saved business blueprint when present.
|
||
|
|
- Save rejects stale `version` values.
|
||
|
|
|
||
|
|
## Frontend UI
|
||
|
|
|
||
|
|
Add `FrontendPageDesigner.vue` and integrate it into `GenerateView.vue` after database design and before business blueprint/preview.
|
||
|
|
|
||
|
|
Layout:
|
||
|
|
|
||
|
|
- Left panel: frontend menu/page tree from page designs, grouped by menu and child pages.
|
||
|
|
- Center panel: canvas with fixed first-phase regions based on page type.
|
||
|
|
- Right panel: property editor for page metadata, bound table, fields, and actions.
|
||
|
|
- Bottom toolbar: initialize from blueprint, save, reset to default, and show JSON.
|
||
|
|
|
||
|
|
First-phase interactions:
|
||
|
|
|
||
|
|
- Select a page.
|
||
|
|
- Add missing page designs from blueprint.
|
||
|
|
- Reorder fields inside query/table/form regions.
|
||
|
|
- Toggle fields visible/hidden.
|
||
|
|
- Configure action labels and placement.
|
||
|
|
- Bind business actions already present in `businessActions.uiBindings`.
|
||
|
|
- View JSON for debugging and advanced edits.
|
||
|
|
|
||
|
|
Drag-and-drop is scoped to field/action ordering in phase one. The region list itself is fixed by page type to keep templates deterministic.
|
||
|
|
|
||
|
|
## Generation
|
||
|
|
|
||
|
|
Extend project conversion/generation so `GenProject` includes page designs.
|
||
|
|
|
||
|
|
Generation behavior:
|
||
|
|
|
||
|
|
- `FrontProjectConverter` loads saved page designs for the project.
|
||
|
|
- `GenProjectServiceImpl` exposes page designs to Velocity context.
|
||
|
|
- Qing frontend templates resolve the current table page design by page code or table name.
|
||
|
|
- If a page design exists, templates render query fields, table columns, form fields, toolbar actions, and row actions from `layout_json` and `action_json`.
|
||
|
|
- If no page design exists, templates use current behavior based on table columns and operation flags.
|
||
|
|
|
||
|
|
This keeps old projects compatible and lets users opt into page design gradually.
|
||
|
|
|
||
|
|
## Error Handling
|
||
|
|
|
||
|
|
UI behavior:
|
||
|
|
|
||
|
|
- If initialization cannot find `frontendPages`, show a warning asking the user to generate or apply the system module blueprint first.
|
||
|
|
- If no database tables exist, allow menu/page metadata editing but disable table field regions.
|
||
|
|
- If a bound table was deleted, mark the page as needing repair and block preview generation until fixed.
|
||
|
|
- If save returns a stale version error, ask the user to reload the page design before saving again.
|
||
|
|
|
||
|
|
Backend behavior:
|
||
|
|
|
||
|
|
- Return clear `ServiceException` messages for invalid field, table, page type, action, or stale version errors.
|
||
|
|
- Do not mutate existing page designs when initialization fails midway.
|
||
|
|
|
||
|
|
## Tests
|
||
|
|
|
||
|
|
Backend tests:
|
||
|
|
|
||
|
|
- SQL schema script includes `front_project_page_design`.
|
||
|
|
- Mapper inserts, updates, lists, and deletes project page designs.
|
||
|
|
- Initialization creates designs from `frontendPages` and preserves existing records.
|
||
|
|
- Validation rejects unknown fields, unknown tables, invalid page types, and stale versions.
|
||
|
|
- Project deletion removes page designs.
|
||
|
|
- Generator uses saved page design when present and falls back when absent.
|
||
|
|
|
||
|
|
Frontend tests:
|
||
|
|
|
||
|
|
- Designer initializes and renders page tree from API data.
|
||
|
|
- Field visibility and ordering update `layout_json`.
|
||
|
|
- Saving sends normalized payload with `version`.
|
||
|
|
- Generate page disables preview when page design validation reports repair-required state.
|
||
|
|
|
||
|
|
Template tests:
|
||
|
|
|
||
|
|
- Qing `index.vue.vm` renders query fields, table columns, form fields, toolbar actions, and row actions from page design.
|
||
|
|
- Existing template output remains valid when no page design exists.
|
||
|
|
|
||
|
|
## Rollout
|
||
|
|
|
||
|
|
1. Add database script and backend domain/mapper/service/API.
|
||
|
|
2. Add frontend API functions and `FrontendPageDesigner.vue`.
|
||
|
|
3. Integrate the designer into `GenerateView.vue`.
|
||
|
|
4. Extend conversion and template generation.
|
||
|
|
5. Add tests around validation and template output.
|
||
|
|
6. Keep existing JSON editor paths available for app and business blueprints.
|