9.1 页面生成器架构概览

9.1.1 页面生成器接口

// 页面生成器接口
interface PageGenerator {
  // 页面管理
  createPage(definition: PageDefinition): Promise<Page>;
  updatePage(pageId: string, definition: Partial<PageDefinition>): Promise<Page>;
  deletePage(pageId: string): Promise<void>;
  getPage(pageId: string): Promise<Page | null>;
  listPages(query?: PageQuery): Promise<Page[]>;
  
  // 页面渲染
  renderPage(pageId: string, context?: RenderContext): Promise<string>;
  previewPage(definition: PageDefinition, context?: RenderContext): Promise<string>;
  
  // 页面发布
  publishPage(pageId: string, options?: PublishOptions): Promise<PublishResult>;
  unpublishPage(pageId: string): Promise<void>;
  
  // 页面模板
  createTemplate(template: PageTemplate): Promise<PageTemplate>;
  getTemplate(templateId: string): Promise<PageTemplate | null>;
  listTemplates(): Promise<PageTemplate[]>;
  
  // 事件处理
  on(event: string, handler: Function): void;
  off(event: string, handler: Function): void;
  emit(event: string, data: any): void;
}

// 低代码页面生成器实现
class LowCodePageGenerator implements PageGenerator {
  private pages: Map<string, Page> = new Map();
  private templates: Map<string, PageTemplate> = new Map();
  private renderer: PageRenderer;
  private eventBus: EventBus;
  private componentRegistry: ComponentRegistry;
  private themeManager: ThemeManager;
  
  constructor(options: PageGeneratorOptions) {
    this.eventBus = options.eventBus || new EventBus();
    this.componentRegistry = options.componentRegistry;
    this.themeManager = options.themeManager || new DefaultThemeManager();
    this.renderer = new PageRenderer({
      componentRegistry: this.componentRegistry,
      themeManager: this.themeManager,
      eventBus: this.eventBus
    });
    
    this.initializeBuiltinTemplates();
  }
  
  async createPage(definition: PageDefinition): Promise<Page> {
    // 验证页面定义
    this.validatePageDefinition(definition);
    
    // 创建页面实例
    const page = new Page({
      id: definition.id || this.generatePageId(),
      title: definition.title,
      description: definition.description,
      layout: definition.layout,
      components: definition.components || [],
      styles: definition.styles || {},
      scripts: definition.scripts || [],
      meta: definition.meta || {},
      settings: definition.settings || {},
      createdAt: new Date(),
      updatedAt: new Date()
    });
    
    // 存储页面
    this.pages.set(page.id, page);
    
    // 触发事件
    this.emit('page:created', { page });
    
    return page;
  }
  
  async updatePage(pageId: string, definition: Partial<PageDefinition>): Promise<Page> {
    const page = this.pages.get(pageId);
    if (!page) {
      throw new Error(`Page ${pageId} not found`);
    }
    
    // 更新页面属性
    if (definition.title !== undefined) page.title = definition.title;
    if (definition.description !== undefined) page.description = definition.description;
    if (definition.layout !== undefined) page.layout = definition.layout;
    if (definition.components !== undefined) page.components = definition.components;
    if (definition.styles !== undefined) page.styles = definition.styles;
    if (definition.scripts !== undefined) page.scripts = definition.scripts;
    if (definition.meta !== undefined) page.meta = definition.meta;
    if (definition.settings !== undefined) page.settings = definition.settings;
    
    page.updatedAt = new Date();
    
    // 触发事件
    this.emit('page:updated', { page, changes: definition });
    
    return page;
  }
  
  async deletePage(pageId: string): Promise<void> {
    const page = this.pages.get(pageId);
    if (!page) {
      throw new Error(`Page ${pageId} not found`);
    }
    
    // 删除页面
    this.pages.delete(pageId);
    
    // 触发事件
    this.emit('page:deleted', { pageId, page });
  }
  
  async getPage(pageId: string): Promise<Page | null> {
    return this.pages.get(pageId) || null;
  }
  
  async listPages(query?: PageQuery): Promise<Page[]> {
    let pages = Array.from(this.pages.values());
    
    if (query) {
      // 应用查询过滤
      if (query.title) {
        pages = pages.filter(page => 
          page.title.toLowerCase().includes(query.title!.toLowerCase())
        );
      }
      
      if (query.status) {
        pages = pages.filter(page => page.status === query.status);
      }
      
      if (query.tags && query.tags.length > 0) {
        pages = pages.filter(page => 
          query.tags!.some(tag => page.meta.tags?.includes(tag))
        );
      }
      
      // 排序
      if (query.orderBy) {
        pages.sort((a, b) => {
          const aValue = (a as any)[query.orderBy!];
          const bValue = (b as any)[query.orderBy!];
          
          if (query.orderDirection === 'desc') {
            return bValue > aValue ? 1 : -1;
          }
          return aValue > bValue ? 1 : -1;
        });
      }
      
      // 分页
      if (query.offset !== undefined || query.limit !== undefined) {
        const offset = query.offset || 0;
        const limit = query.limit || 10;
        pages = pages.slice(offset, offset + limit);
      }
    }
    
    return pages;
  }
  
  async renderPage(pageId: string, context?: RenderContext): Promise<string> {
    const page = this.pages.get(pageId);
    if (!page) {
      throw new Error(`Page ${pageId} not found`);
    }
    
    return this.renderer.render(page, context);
  }
  
  async previewPage(definition: PageDefinition, context?: RenderContext): Promise<string> {
    // 创建临时页面实例
    const tempPage = new Page({
      id: 'preview',
      title: definition.title,
      description: definition.description,
      layout: definition.layout,
      components: definition.components || [],
      styles: definition.styles || {},
      scripts: definition.scripts || [],
      meta: definition.meta || {},
      settings: definition.settings || {},
      createdAt: new Date(),
      updatedAt: new Date()
    });
    
    return this.renderer.render(tempPage, context);
  }
  
  async publishPage(pageId: string, options?: PublishOptions): Promise<PublishResult> {
    const page = this.pages.get(pageId);
    if (!page) {
      throw new Error(`Page ${pageId} not found`);
    }
    
    // 渲染页面
    const html = await this.renderPage(pageId, options?.context);
    
    // 发布页面
    const publishResult: PublishResult = {
      pageId,
      url: this.generatePublishUrl(page, options),
      html,
      publishedAt: new Date(),
      version: page.version || '1.0.0'
    };
    
    // 更新页面状态
    page.status = PageStatus.PUBLISHED;
    page.publishedAt = publishResult.publishedAt;
    
    // 触发事件
    this.emit('page:published', { page, result: publishResult });
    
    return publishResult;
  }
  
  async unpublishPage(pageId: string): Promise<void> {
    const page = this.pages.get(pageId);
    if (!page) {
      throw new Error(`Page ${pageId} not found`);
    }
    
    // 更新页面状态
    page.status = PageStatus.DRAFT;
    page.publishedAt = undefined;
    
    // 触发事件
    this.emit('page:unpublished', { page });
  }
  
  async createTemplate(template: PageTemplate): Promise<PageTemplate> {
    // 验证模板
    this.validateTemplate(template);
    
    // 生成模板ID
    if (!template.id) {
      template.id = this.generateTemplateId();
    }
    
    // 存储模板
    this.templates.set(template.id, template);
    
    // 触发事件
    this.emit('template:created', { template });
    
    return template;
  }
  
  async getTemplate(templateId: string): Promise<PageTemplate | null> {
    return this.templates.get(templateId) || null;
  }
  
  async listTemplates(): Promise<PageTemplate[]> {
    return Array.from(this.templates.values());
  }
  
  on(event: string, handler: Function): void {
    this.eventBus.on(event, handler);
  }
  
  off(event: string, handler: Function): void {
    this.eventBus.off(event, handler);
  }
  
  emit(event: string, data: any): void {
    this.eventBus.emit(event, data);
  }
  
  private validatePageDefinition(definition: PageDefinition): void {
    if (!definition.title) {
      throw new Error('Page title is required');
    }
    
    if (!definition.layout) {
      throw new Error('Page layout is required');
    }
    
    // 验证组件
    if (definition.components) {
      for (const component of definition.components) {
        if (!this.componentRegistry.hasComponent(component.type)) {
          throw new Error(`Unknown component type: ${component.type}`);
        }
      }
    }
  }
  
  private validateTemplate(template: PageTemplate): void {
    if (!template.name) {
      throw new Error('Template name is required');
    }
    
    if (!template.definition) {
      throw new Error('Template definition is required');
    }
  }
  
  private generatePageId(): string {
    return `page_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }
  
  private generateTemplateId(): string {
    return `template_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }
  
  private generatePublishUrl(page: Page, options?: PublishOptions): string {
    const baseUrl = options?.baseUrl || 'https://example.com';
    const path = options?.path || page.id;
    return `${baseUrl}/${path}`;
  }
  
  private initializeBuiltinTemplates(): void {
    // 初始化内置模板
    const builtinTemplates: PageTemplate[] = [
      {
        id: 'blank',
        name: '空白页面',
        description: '空白页面模板',
        category: 'basic',
        thumbnail: '/templates/blank.png',
        definition: {
          title: '新页面',
          layout: {
            type: 'container',
            properties: {
              maxWidth: '1200px',
              padding: '20px'
            }
          },
          components: [],
          styles: {},
          scripts: [],
          meta: {},
          settings: {}
        }
      },
      {
        id: 'dashboard',
        name: '仪表板',
        description: '数据仪表板模板',
        category: 'dashboard',
        thumbnail: '/templates/dashboard.png',
        definition: {
          title: '数据仪表板',
          layout: {
            type: 'grid',
            properties: {
              columns: 12,
              gap: '16px'
            }
          },
          components: [
            {
              id: 'header',
              type: 'header',
              properties: {
                title: '数据仪表板',
                subtitle: '实时数据监控'
              },
              layout: {
                grid: { col: 12, row: 1 }
              }
            },
            {
              id: 'chart1',
              type: 'chart',
              properties: {
                type: 'line',
                title: '趋势图',
                dataSource: 'api://charts/trend'
              },
              layout: {
                grid: { col: 6, row: 2 }
              }
            },
            {
              id: 'chart2',
              type: 'chart',
              properties: {
                type: 'pie',
                title: '分布图',
                dataSource: 'api://charts/distribution'
              },
              layout: {
                grid: { col: 6, row: 2 }
              }
            }
          ],
          styles: {
            body: {
              backgroundColor: '#f5f5f5'
            }
          },
          scripts: [],
          meta: {
            tags: ['dashboard', 'charts']
          },
          settings: {
            responsive: true,
            autoRefresh: true,
            refreshInterval: 30000
          }
        }
      }
    ];
    
    for (const template of builtinTemplates) {
      this.templates.set(template.id, template);
    }
  }
}

9.1.2 核心数据结构

// 页面定义
interface PageDefinition {
  id?: string;
  title: string;
  description?: string;
  layout: LayoutDefinition;
  components?: ComponentInstance[];
  styles?: StyleDefinition;
  scripts?: ScriptDefinition[];
  meta?: PageMeta;
  settings?: PageSettings;
}

// 页面类
class Page {
  id: string;
  title: string;
  description?: string;
  layout: LayoutDefinition;
  components: ComponentInstance[];
  styles: StyleDefinition;
  scripts: ScriptDefinition[];
  meta: PageMeta;
  settings: PageSettings;
  status: PageStatus;
  version?: string;
  createdAt: Date;
  updatedAt: Date;
  publishedAt?: Date;
  
  constructor(options: PageOptions) {
    this.id = options.id;
    this.title = options.title;
    this.description = options.description;
    this.layout = options.layout;
    this.components = options.components || [];
    this.styles = options.styles || {};
    this.scripts = options.scripts || [];
    this.meta = options.meta || {};
    this.settings = options.settings || {};
    this.status = options.status || PageStatus.DRAFT;
    this.version = options.version;
    this.createdAt = options.createdAt || new Date();
    this.updatedAt = options.updatedAt || new Date();
    this.publishedAt = options.publishedAt;
  }
  
  // 添加组件
  addComponent(component: ComponentInstance, index?: number): void {
    if (index !== undefined) {
      this.components.splice(index, 0, component);
    } else {
      this.components.push(component);
    }
    this.updatedAt = new Date();
  }
  
  // 移除组件
  removeComponent(componentId: string): boolean {
    const index = this.components.findIndex(c => c.id === componentId);
    if (index !== -1) {
      this.components.splice(index, 1);
      this.updatedAt = new Date();
      return true;
    }
    return false;
  }
  
  // 更新组件
  updateComponent(componentId: string, updates: Partial<ComponentInstance>): boolean {
    const component = this.components.find(c => c.id === componentId);
    if (component) {
      Object.assign(component, updates);
      this.updatedAt = new Date();
      return true;
    }
    return false;
  }
  
  // 获取组件
  getComponent(componentId: string): ComponentInstance | undefined {
    return this.components.find(c => c.id === componentId);
  }
  
  // 移动组件
  moveComponent(componentId: string, newIndex: number): boolean {
    const currentIndex = this.components.findIndex(c => c.id === componentId);
    if (currentIndex !== -1 && newIndex >= 0 && newIndex < this.components.length) {
      const [component] = this.components.splice(currentIndex, 1);
      this.components.splice(newIndex, 0, component);
      this.updatedAt = new Date();
      return true;
    }
    return false;
  }
  
  // 克隆页面
  clone(newId?: string): Page {
    return new Page({
      id: newId || `${this.id}_copy`,
      title: `${this.title} (副本)`,
      description: this.description,
      layout: JSON.parse(JSON.stringify(this.layout)),
      components: JSON.parse(JSON.stringify(this.components)),
      styles: JSON.parse(JSON.stringify(this.styles)),
      scripts: JSON.parse(JSON.stringify(this.scripts)),
      meta: JSON.parse(JSON.stringify(this.meta)),
      settings: JSON.parse(JSON.stringify(this.settings)),
      status: PageStatus.DRAFT,
      createdAt: new Date(),
      updatedAt: new Date()
    });
  }
  
  // 导出配置
  export(): PageDefinition {
    return {
      id: this.id,
      title: this.title,
      description: this.description,
      layout: this.layout,
      components: this.components,
      styles: this.styles,
      scripts: this.scripts,
      meta: this.meta,
      settings: this.settings
    };
  }
}

// 页面状态
enum PageStatus {
  DRAFT = 'draft',
  PUBLISHED = 'published',
  ARCHIVED = 'archived'
}

// 页面选项
interface PageOptions {
  id: string;
  title: string;
  description?: string;
  layout: LayoutDefinition;
  components?: ComponentInstance[];
  styles?: StyleDefinition;
  scripts?: ScriptDefinition[];
  meta?: PageMeta;
  settings?: PageSettings;
  status?: PageStatus;
  version?: string;
  createdAt?: Date;
  updatedAt?: Date;
  publishedAt?: Date;
}

// 页面元数据
interface PageMeta {
  author?: string;
  tags?: string[];
  category?: string;
  keywords?: string[];
  description?: string;
  thumbnail?: string;
  [key: string]: any;
}

// 页面设置
interface PageSettings {
  responsive?: boolean;
  theme?: string;
  language?: string;
  seo?: SEOSettings;
  performance?: PerformanceSettings;
  security?: SecuritySettings;
  [key: string]: any;
}

// SEO设置
interface SEOSettings {
  title?: string;
  description?: string;
  keywords?: string[];
  ogTitle?: string;
  ogDescription?: string;
  ogImage?: string;
  canonical?: string;
}

// 性能设置
interface PerformanceSettings {
  lazyLoad?: boolean;
  preload?: string[];
  minify?: boolean;
  compress?: boolean;
  cache?: boolean;
}

// 安全设置
interface SecuritySettings {
  csp?: string;
  xssProtection?: boolean;
  frameOptions?: string;
  contentTypeOptions?: boolean;
}

// 页面查询
interface PageQuery {
  title?: string;
  status?: PageStatus;
  tags?: string[];
  author?: string;
  category?: string;
  createdAfter?: Date;
  createdBefore?: Date;
  orderBy?: string;
  orderDirection?: 'asc' | 'desc';
  offset?: number;
  limit?: number;
}

// 页面模板
interface PageTemplate {
  id: string;
  name: string;
  description?: string;
  category?: string;
  thumbnail?: string;
  definition: PageDefinition;
  variables?: TemplateVariable[];
  createdAt?: Date;
  updatedAt?: Date;
}

// 模板变量
interface TemplateVariable {
  name: string;
  type: 'string' | 'number' | 'boolean' | 'object' | 'array';
  label: string;
  description?: string;
  defaultValue?: any;
  required?: boolean;
  options?: any[];
}

// 渲染上下文
interface RenderContext {
  variables?: Record<string, any>;
  user?: any;
  request?: any;
  theme?: string;
  locale?: string;
  device?: 'desktop' | 'tablet' | 'mobile';
  [key: string]: any;
}

// 发布选项
interface PublishOptions {
  baseUrl?: string;
  path?: string;
  context?: RenderContext;
  minify?: boolean;
  compress?: boolean;
}

// 发布结果
interface PublishResult {
  pageId: string;
  url: string;
  html: string;
  publishedAt: Date;
  version: string;
}

// 页面生成器选项
interface PageGeneratorOptions {
  eventBus?: EventBus;
  componentRegistry: ComponentRegistry;
  themeManager?: ThemeManager;
  storage?: PageStorage;
  cache?: PageCache;
}

9.2 布局系统

9.2.1 布局定义

// 布局定义
interface LayoutDefinition {
  type: LayoutType;
  properties?: LayoutProperties;
  children?: LayoutDefinition[];
  responsive?: ResponsiveLayout;
}

// 布局类型
enum LayoutType {
  CONTAINER = 'container',
  GRID = 'grid',
  FLEX = 'flex',
  ABSOLUTE = 'absolute',
  TABS = 'tabs',
  ACCORDION = 'accordion',
  SPLIT = 'split'
}

// 布局属性
interface LayoutProperties {
  // 容器属性
  maxWidth?: string;
  minWidth?: string;
  padding?: string;
  margin?: string;
  
  // 网格属性
  columns?: number;
  rows?: number;
  gap?: string;
  columnGap?: string;
  rowGap?: string;
  
  // Flex属性
  direction?: 'row' | 'column' | 'row-reverse' | 'column-reverse';
  wrap?: 'nowrap' | 'wrap' | 'wrap-reverse';
  justify?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly';
  align?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline';
  
  // 绝对定位属性
  position?: 'relative' | 'absolute' | 'fixed' | 'sticky';
  top?: string;
  right?: string;
  bottom?: string;
  left?: string;
  zIndex?: number;
  
  // 标签页属性
  tabPosition?: 'top' | 'bottom' | 'left' | 'right';
  tabType?: 'line' | 'card' | 'editable-card';
  
  // 手风琴属性
  accordion?: boolean;
  collapsible?: boolean;
  
  // 分割面板属性
  split?: 'horizontal' | 'vertical';
  resizerStyle?: any;
  
  // 通用样式
  className?: string;
  style?: CSSProperties;
  
  [key: string]: any;
}

// 响应式布局
interface ResponsiveLayout {
  xs?: Partial<LayoutProperties>; // < 576px
  sm?: Partial<LayoutProperties>; // >= 576px
  md?: Partial<LayoutProperties>; // >= 768px
  lg?: Partial<LayoutProperties>; // >= 992px
  xl?: Partial<LayoutProperties>; // >= 1200px
  xxl?: Partial<LayoutProperties>; // >= 1600px
}

// 布局引擎
class LayoutEngine {
  private layouts: Map<LayoutType, LayoutRenderer> = new Map();
  
  constructor() {
    this.registerBuiltinLayouts();
  }
  
  // 注册布局渲染器
  registerLayout(type: LayoutType, renderer: LayoutRenderer): void {
    this.layouts.set(type, renderer);
  }
  
  // 渲染布局
  renderLayout(definition: LayoutDefinition, components: ComponentInstance[], context: RenderContext): string {
    const renderer = this.layouts.get(definition.type);
    if (!renderer) {
      throw new Error(`Unknown layout type: ${definition.type}`);
    }
    
    return renderer.render(definition, components, context);
  }
  
  // 获取响应式属性
  getResponsiveProperties(definition: LayoutDefinition, device: string): LayoutProperties {
    const baseProperties = definition.properties || {};
    const responsiveProperties = definition.responsive?.[device as keyof ResponsiveLayout] || {};
    
    return { ...baseProperties, ...responsiveProperties };
  }
  
  private registerBuiltinLayouts(): void {
    // 容器布局
    this.registerLayout(LayoutType.CONTAINER, new ContainerLayoutRenderer());
    
    // 网格布局
    this.registerLayout(LayoutType.GRID, new GridLayoutRenderer());
    
    // Flex布局
    this.registerLayout(LayoutType.FLEX, new FlexLayoutRenderer());
    
    // 绝对定位布局
    this.registerLayout(LayoutType.ABSOLUTE, new AbsoluteLayoutRenderer());
    
    // 标签页布局
    this.registerLayout(LayoutType.TABS, new TabsLayoutRenderer());
    
    // 手风琴布局
    this.registerLayout(LayoutType.ACCORDION, new AccordionLayoutRenderer());
    
    // 分割面板布局
    this.registerLayout(LayoutType.SPLIT, new SplitLayoutRenderer());
  }
}

// 布局渲染器接口
interface LayoutRenderer {
  render(definition: LayoutDefinition, components: ComponentInstance[], context: RenderContext): string;
}

// 容器布局渲染器
class ContainerLayoutRenderer implements LayoutRenderer {
  render(definition: LayoutDefinition, components: ComponentInstance[], context: RenderContext): string {
    const properties = definition.properties || {};
    const style = this.buildContainerStyle(properties);
    const className = this.buildClassName(properties);
    
    const componentHtml = components.map(component => 
      this.renderComponent(component, context)
    ).join('');
    
    return `
      <div class="${className}" style="${style}">
        ${componentHtml}
      </div>
    `;
  }
  
  private buildContainerStyle(properties: LayoutProperties): string {
    const styles: string[] = [];
    
    if (properties.maxWidth) styles.push(`max-width: ${properties.maxWidth}`);
    if (properties.minWidth) styles.push(`min-width: ${properties.minWidth}`);
    if (properties.padding) styles.push(`padding: ${properties.padding}`);
    if (properties.margin) styles.push(`margin: ${properties.margin}`);
    
    // 合并自定义样式
    if (properties.style) {
      const customStyles = Object.entries(properties.style)
        .map(([key, value]) => `${this.camelToKebab(key)}: ${value}`)
        .join('; ');
      styles.push(customStyles);
    }
    
    return styles.join('; ');
  }
  
  private buildClassName(properties: LayoutProperties): string {
    const classes = ['layout-container'];
    
    if (properties.className) {
      classes.push(properties.className);
    }
    
    return classes.join(' ');
  }
  
  private renderComponent(component: ComponentInstance, context: RenderContext): string {
    // 这里应该调用组件渲染器
    // 简化实现
    return `<div data-component="${component.type}" data-id="${component.id}"></div>`;
  }
  
  private camelToKebab(str: string): string {
    return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();
  }
}

// 网格布局渲染器
class GridLayoutRenderer implements LayoutRenderer {
  render(definition: LayoutDefinition, components: ComponentInstance[], context: RenderContext): string {
    const properties = definition.properties || {};
    const style = this.buildGridStyle(properties);
    const className = this.buildClassName(properties);
    
    const componentHtml = components.map(component => 
      this.renderGridItem(component, context)
    ).join('');
    
    return `
      <div class="${className}" style="${style}">
        ${componentHtml}
      </div>
    `;
  }
  
  private buildGridStyle(properties: LayoutProperties): string {
    const styles = ['display: grid'];
    
    if (properties.columns) {
      styles.push(`grid-template-columns: repeat(${properties.columns}, 1fr)`);
    }
    
    if (properties.rows) {
      styles.push(`grid-template-rows: repeat(${properties.rows}, auto)`);
    }
    
    if (properties.gap) {
      styles.push(`gap: ${properties.gap}`);
    } else {
      if (properties.columnGap) styles.push(`column-gap: ${properties.columnGap}`);
      if (properties.rowGap) styles.push(`row-gap: ${properties.rowGap}`);
    }
    
    if (properties.padding) styles.push(`padding: ${properties.padding}`);
    if (properties.margin) styles.push(`margin: ${properties.margin}`);
    
    return styles.join('; ');
  }
  
  private buildClassName(properties: LayoutProperties): string {
    const classes = ['layout-grid'];
    
    if (properties.className) {
      classes.push(properties.className);
    }
    
    return classes.join(' ');
  }
  
  private renderGridItem(component: ComponentInstance, context: RenderContext): string {
    const gridStyle = this.buildGridItemStyle(component.layout?.grid);
    
    return `
      <div class="grid-item" style="${gridStyle}" data-component="${component.type}" data-id="${component.id}">
        <!-- 组件内容 -->
      </div>
    `;
  }
  
  private buildGridItemStyle(grid?: GridItemLayout): string {
    if (!grid) return '';
    
    const styles: string[] = [];
    
    if (grid.col !== undefined) {
      if (typeof grid.col === 'number') {
        styles.push(`grid-column: span ${grid.col}`);
      } else {
        styles.push(`grid-column: ${grid.col}`);
      }
    }
    
    if (grid.row !== undefined) {
      if (typeof grid.row === 'number') {
        styles.push(`grid-row: span ${grid.row}`);
      } else {
        styles.push(`grid-row: ${grid.row}`);
      }
    }
    
    if (grid.area) {
      styles.push(`grid-area: ${grid.area}`);
    }
    
    return styles.join('; ');
  }
}

// 网格项布局
interface GridItemLayout {
  col?: number | string;
  row?: number | string;
  area?: string;
}

// Flex布局渲染器
class FlexLayoutRenderer implements LayoutRenderer {
  render(definition: LayoutDefinition, components: ComponentInstance[], context: RenderContext): string {
    const properties = definition.properties || {};
    const style = this.buildFlexStyle(properties);
    const className = this.buildClassName(properties);
    
    const componentHtml = components.map(component => 
      this.renderFlexItem(component, context)
    ).join('');
    
    return `
      <div class="${className}" style="${style}">
        ${componentHtml}
      </div>
    `;
  }
  
  private buildFlexStyle(properties: LayoutProperties): string {
    const styles = ['display: flex'];
    
    if (properties.direction) {
      styles.push(`flex-direction: ${properties.direction}`);
    }
    
    if (properties.wrap) {
      styles.push(`flex-wrap: ${properties.wrap}`);
    }
    
    if (properties.justify) {
      styles.push(`justify-content: ${properties.justify}`);
    }
    
    if (properties.align) {
      styles.push(`align-items: ${properties.align}`);
    }
    
    if (properties.gap) {
      styles.push(`gap: ${properties.gap}`);
    }
    
    if (properties.padding) styles.push(`padding: ${properties.padding}`);
    if (properties.margin) styles.push(`margin: ${properties.margin}`);
    
    return styles.join('; ');
  }
  
  private buildClassName(properties: LayoutProperties): string {
    const classes = ['layout-flex'];
    
    if (properties.className) {
      classes.push(properties.className);
    }
    
    return classes.join(' ');
  }
  
  private renderFlexItem(component: ComponentInstance, context: RenderContext): string {
    const flexStyle = this.buildFlexItemStyle(component.layout?.flex);
    
    return `
      <div class="flex-item" style="${flexStyle}" data-component="${component.type}" data-id="${component.id}">
        <!-- 组件内容 -->
      </div>
    `;
  }
  
  private buildFlexItemStyle(flex?: FlexItemLayout): string {
    if (!flex) return '';
    
    const styles: string[] = [];
    
    if (flex.grow !== undefined) {
      styles.push(`flex-grow: ${flex.grow}`);
    }
    
    if (flex.shrink !== undefined) {
      styles.push(`flex-shrink: ${flex.shrink}`);
    }
    
    if (flex.basis !== undefined) {
      styles.push(`flex-basis: ${flex.basis}`);
    }
    
    if (flex.align !== undefined) {
      styles.push(`align-self: ${flex.align}`);
    }
    
    if (flex.order !== undefined) {
      styles.push(`order: ${flex.order}`);
    }
    
    return styles.join('; ');
  }
}

// Flex项布局
interface FlexItemLayout {
  grow?: number;
  shrink?: number;
  basis?: string;
  align?: 'auto' | 'flex-start' | 'flex-end' | 'center' | 'baseline' | 'stretch';
  order?: number;
}

9.3 页面渲染器

9.3.1 页面渲染器实现

// 页面渲染器
class PageRenderer {
  private componentRegistry: ComponentRegistry;
  private layoutEngine: LayoutEngine;
  private themeManager: ThemeManager;
  private eventBus: EventBus;
  
  constructor(options: PageRendererOptions) {
    this.componentRegistry = options.componentRegistry;
    this.themeManager = options.themeManager;
    this.eventBus = options.eventBus;
    this.layoutEngine = new LayoutEngine();
  }
  
  async render(page: Page, context?: RenderContext): Promise<string> {
    const renderContext = this.buildRenderContext(page, context);
    
    // 渲染页面结构
    const html = this.renderPageStructure(page, renderContext);
    
    // 触发渲染事件
    this.eventBus.emit('page:rendered', { page, context: renderContext, html });
    
    return html;
  }
  
  private buildRenderContext(page: Page, context?: RenderContext): RenderContext {
    return {
      variables: {},
      theme: page.settings.theme || 'default',
      locale: page.settings.language || 'zh-CN',
      device: 'desktop',
      ...context
    };
  }
  
  private renderPageStructure(page: Page, context: RenderContext): string {
    const head = this.renderHead(page, context);
    const body = this.renderBody(page, context);
    const scripts = this.renderScripts(page, context);
    
    return `
<!DOCTYPE html>
<html lang="${context.locale}">
<head>
  ${head}
</head>
<body>
  ${body}
  ${scripts}
</body>
</html>
    `.trim();
  }
  
  private renderHead(page: Page, context: RenderContext): string {
    const meta = this.renderMeta(page);
    const styles = this.renderStyles(page, context);
    const preloadScripts = this.renderPreloadScripts(page);
    
    return `
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>${page.title}</title>
  ${meta}
  ${styles}
  ${preloadScripts}
    `.trim();
  }
  
  private renderMeta(page: Page): string {
    const seo = page.settings.seo || {};
    const meta: string[] = [];
    
    if (seo.description || page.description) {
      meta.push(`<meta name="description" content="${seo.description || page.description}">`);
    }
    
    if (seo.keywords) {
      meta.push(`<meta name="keywords" content="${seo.keywords.join(', ')}">`);
    }
    
    if (seo.ogTitle) {
      meta.push(`<meta property="og:title" content="${seo.ogTitle}">`);
    }
    
    if (seo.ogDescription) {
      meta.push(`<meta property="og:description" content="${seo.ogDescription}">`);
    }
    
    if (seo.ogImage) {
      meta.push(`<meta property="og:image" content="${seo.ogImage}">`);
    }
    
    if (seo.canonical) {
      meta.push(`<link rel="canonical" href="${seo.canonical}">`);
    }
    
    // 安全头
    const security = page.settings.security || {};
    if (security.csp) {
      meta.push(`<meta http-equiv="Content-Security-Policy" content="${security.csp}">`);
    }
    
    if (security.xssProtection) {
      meta.push(`<meta http-equiv="X-XSS-Protection" content="1; mode=block">`);
    }
    
    if (security.contentTypeOptions) {
      meta.push(`<meta http-equiv="X-Content-Type-Options" content="nosniff">`);
    }
    
    return meta.join('\n  ');
  }
  
  private renderStyles(page: Page, context: RenderContext): string {
    const styles: string[] = [];
    
    // 主题样式
    const themeStyles = this.themeManager.getThemeStyles(context.theme);
    if (themeStyles) {
      styles.push(`<style data-theme="${context.theme}">${themeStyles}</style>`);
    }
    
    // 页面样式
    if (page.styles && Object.keys(page.styles).length > 0) {
      const pageStyles = this.buildPageStyles(page.styles);
      styles.push(`<style data-page="${page.id}">${pageStyles}</style>`);
    }
    
    // 组件样式
    const componentStyles = this.buildComponentStyles(page.components);
    if (componentStyles) {
      styles.push(`<style data-components>${componentStyles}</style>`);
    }
    
    // 响应式样式
    const responsiveStyles = this.buildResponsiveStyles(page, context);
    if (responsiveStyles) {
      styles.push(`<style data-responsive>${responsiveStyles}</style>`);
    }
    
    return styles.join('\n  ');
  }
  
  private renderPreloadScripts(page: Page): string {
    const performance = page.settings.performance || {};
    const preloads: string[] = [];
    
    if (performance.preload) {
      for (const resource of performance.preload) {
        preloads.push(`<link rel="preload" href="${resource}" as="script">`);
      }
    }
    
    return preloads.join('\n  ');
  }
  
  private renderBody(page: Page, context: RenderContext): string {
    // 渲染布局和组件
    const content = this.layoutEngine.renderLayout(page.layout, page.components, context);
    
    return `
  <div id="app" data-page="${page.id}">
    ${content}
  </div>
    `.trim();
  }
  
  private renderScripts(page: Page, context: RenderContext): string {
    const scripts: string[] = [];
    
    // 运行时脚本
    scripts.push(this.renderRuntimeScript(page, context));
    
    // 页面脚本
    for (const script of page.scripts) {
      scripts.push(this.renderScript(script, context));
    }
    
    // 组件脚本
    const componentScripts = this.buildComponentScripts(page.components, context);
    if (componentScripts) {
      scripts.push(componentScripts);
    }
    
    return scripts.join('\n  ');
  }
  
  private renderRuntimeScript(page: Page, context: RenderContext): string {
    const runtime = {
      pageId: page.id,
      context,
      components: page.components.map(c => ({
        id: c.id,
        type: c.type,
        properties: c.properties
      }))
    };
    
    return `
<script>
  window.__LOWCODE_RUNTIME__ = ${JSON.stringify(runtime)};
  
  // 初始化运行时
  (function() {
    const runtime = window.__LOWCODE_RUNTIME__;
    
    // 组件初始化
    runtime.components.forEach(component => {
      const element = document.querySelector('[data-id="' + component.id + '"]');
      if (element) {
        element.setAttribute('data-initialized', 'true');
        // 触发组件初始化事件
        element.dispatchEvent(new CustomEvent('component:init', {
          detail: component
        }));
      }
    });
    
    // 页面初始化完成
    document.dispatchEvent(new CustomEvent('page:ready', {
      detail: { pageId: runtime.pageId }
    }));
  })();
</script>
    `.trim();
  }
  
  private renderScript(script: ScriptDefinition, context: RenderContext): string {
    if (script.type === 'inline') {
      return `<script>${script.content}</script>`;
    } else if (script.type === 'external') {
      const attrs = script.async ? ' async' : '';
      const defer = script.defer ? ' defer' : '';
      return `<script src="${script.src}"${attrs}${defer}></script>`;
    }
    return '';
  }
  
  private buildPageStyles(styles: StyleDefinition): string {
    const css: string[] = [];
    
    for (const [selector, rules] of Object.entries(styles)) {
      const ruleStrings = Object.entries(rules)
        .map(([property, value]) => `  ${this.camelToKebab(property)}: ${value};`)
        .join('\n');
      
      css.push(`${selector} {\n${ruleStrings}\n}`);
    }
    
    return css.join('\n\n');
  }
  
  private buildComponentStyles(components: ComponentInstance[]): string {
    const styles: string[] = [];
    
    for (const component of components) {
      const componentDef = this.componentRegistry.getComponent(component.type);
      if (componentDef?.styles) {
        styles.push(componentDef.styles);
      }
      
      // 组件实例样式
      if (component.styles) {
        const instanceStyles = this.buildInstanceStyles(component);
        styles.push(instanceStyles);
      }
    }
    
    return styles.join('\n\n');
  }
  
  private buildInstanceStyles(component: ComponentInstance): string {
    if (!component.styles) return '';
    
    const selector = `[data-id="${component.id}"]`;
    const rules = Object.entries(component.styles)
      .map(([property, value]) => `  ${this.camelToKebab(property)}: ${value};`)
      .join('\n');
    
    return `${selector} {\n${rules}\n}`;
  }
  
  private buildResponsiveStyles(page: Page, context: RenderContext): string {
    if (!page.layout.responsive) return '';
    
    const breakpoints = {
      xs: '(max-width: 575.98px)',
      sm: '(min-width: 576px) and (max-width: 767.98px)',
      md: '(min-width: 768px) and (max-width: 991.98px)',
      lg: '(min-width: 992px) and (max-width: 1199.98px)',
      xl: '(min-width: 1200px) and (max-width: 1599.98px)',
      xxl: '(min-width: 1600px)'
    };
    
    const mediaQueries: string[] = [];
    
    for (const [breakpoint, query] of Object.entries(breakpoints)) {
      const responsiveProps = page.layout.responsive[breakpoint as keyof ResponsiveLayout];
      if (responsiveProps) {
        const styles = Object.entries(responsiveProps)
          .map(([property, value]) => `  ${this.camelToKebab(property)}: ${value};`)
          .join('\n');
        
        mediaQueries.push(`@media ${query} {\n  .layout-container {\n${styles}\n  }\n}`);
      }
    }
    
    return mediaQueries.join('\n\n');
  }
  
  private buildComponentScripts(components: ComponentInstance[], context: RenderContext): string {
    const scripts: string[] = [];
    
    for (const component of components) {
      const componentDef = this.componentRegistry.getComponent(component.type);
      if (componentDef?.script) {
        scripts.push(componentDef.script);
      }
    }
    
    return scripts.length > 0 ? `<script>\n${scripts.join('\n\n')}\n</script>` : '';
  }
  
  private camelToKebab(str: string): string {
    return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();
  }
}

// 页面渲染器选项
interface PageRendererOptions {
  componentRegistry: ComponentRegistry;
  themeManager: ThemeManager;
  eventBus: EventBus;
}

9.4 样式系统

9.4.1 样式定义

// 样式定义
interface StyleDefinition {
  [selector: string]: CSSProperties;
}

// CSS属性
interface CSSProperties {
  // 布局
  display?: string;
  position?: string;
  top?: string;
  right?: string;
  bottom?: string;
  left?: string;
  zIndex?: number;
  
  // 盒模型
  width?: string;
  height?: string;
  minWidth?: string;
  minHeight?: string;
  maxWidth?: string;
  maxHeight?: string;
  margin?: string;
  marginTop?: string;
  marginRight?: string;
  marginBottom?: string;
  marginLeft?: string;
  padding?: string;
  paddingTop?: string;
  paddingRight?: string;
  paddingBottom?: string;
  paddingLeft?: string;
  
  // 边框
  border?: string;
  borderTop?: string;
  borderRight?: string;
  borderBottom?: string;
  borderLeft?: string;
  borderRadius?: string;
  borderColor?: string;
  borderStyle?: string;
  borderWidth?: string;
  
  // 背景
  background?: string;
  backgroundColor?: string;
  backgroundImage?: string;
  backgroundSize?: string;
  backgroundPosition?: string;
  backgroundRepeat?: string;
  
  // 文字
  color?: string;
  fontSize?: string;
  fontFamily?: string;
  fontWeight?: string;
  fontStyle?: string;
  lineHeight?: string;
  textAlign?: string;
  textDecoration?: string;
  textTransform?: string;
  letterSpacing?: string;
  wordSpacing?: string;
  
  // Flex
  flexDirection?: string;
  flexWrap?: string;
  justifyContent?: string;
  alignItems?: string;
  alignContent?: string;
  flex?: string;
  flexGrow?: number;
  flexShrink?: number;
  flexBasis?: string;
  alignSelf?: string;
  order?: number;
  
  // Grid
  gridTemplateColumns?: string;
  gridTemplateRows?: string;
  gridTemplateAreas?: string;
  gridColumn?: string;
  gridRow?: string;
  gridArea?: string;
  gap?: string;
  columnGap?: string;
  rowGap?: string;
  
  // 变换
  transform?: string;
  transformOrigin?: string;
  transition?: string;
  animation?: string;
  
  // 其他
  opacity?: number;
  visibility?: string;
  overflow?: string;
  overflowX?: string;
  overflowY?: string;
  cursor?: string;
  userSelect?: string;
  pointerEvents?: string;
  
  [property: string]: any;
}

// 主题管理器
interface ThemeManager {
  getTheme(name: string): Theme | null;
  setTheme(name: string, theme: Theme): void;
  getThemeStyles(name: string): string;
  listThemes(): string[];
}

// 主题定义
interface Theme {
  name: string;
  displayName: string;
  description?: string;
  colors: ThemeColors;
  typography: ThemeTypography;
  spacing: ThemeSpacing;
  breakpoints: ThemeBreakpoints;
  shadows: ThemeShadows;
  borders: ThemeBorders;
  variables?: Record<string, any>;
}

// 主题颜色
interface ThemeColors {
  primary: string;
  secondary: string;
  success: string;
  warning: string;
  error: string;
  info: string;
  background: string;
  surface: string;
  text: {
    primary: string;
    secondary: string;
    disabled: string;
  };
  border: string;
  divider: string;
  [key: string]: any;
}

// 主题字体
interface ThemeTypography {
  fontFamily: {
    primary: string;
    secondary: string;
    monospace: string;
  };
  fontSize: {
    xs: string;
    sm: string;
    base: string;
    lg: string;
    xl: string;
    '2xl': string;
    '3xl': string;
    '4xl': string;
  };
  fontWeight: {
    light: number;
    normal: number;
    medium: number;
    semibold: number;
    bold: number;
  };
  lineHeight: {
    tight: number;
    normal: number;
    relaxed: number;
  };
}

// 主题间距
interface ThemeSpacing {
  xs: string;
  sm: string;
  md: string;
  lg: string;
  xl: string;
  '2xl': string;
  '3xl': string;
  '4xl': string;
}

// 主题断点
interface ThemeBreakpoints {
  xs: string;
  sm: string;
  md: string;
  lg: string;
  xl: string;
  xxl: string;
}

// 主题阴影
interface ThemeShadows {
  sm: string;
  md: string;
  lg: string;
  xl: string;
  '2xl': string;
}

// 主题边框
interface ThemeBorders {
  width: {
    thin: string;
    medium: string;
    thick: string;
  };
  radius: {
    none: string;
    sm: string;
    md: string;
    lg: string;
    xl: string;
    full: string;
  };
}

// 默认主题管理器
class DefaultThemeManager implements ThemeManager {
  private themes: Map<string, Theme> = new Map();
  
  constructor() {
    this.initializeDefaultThemes();
  }
  
  getTheme(name: string): Theme | null {
    return this.themes.get(name) || null;
  }
  
  setTheme(name: string, theme: Theme): void {
    this.themes.set(name, theme);
  }
  
  getThemeStyles(name: string): string {
    const theme = this.getTheme(name);
    if (!theme) return '';
    
    return this.generateThemeCSS(theme);
  }
  
  listThemes(): string[] {
    return Array.from(this.themes.keys());
  }
  
  private generateThemeCSS(theme: Theme): string {
    const css: string[] = [];
    
    // CSS变量定义
    const variables: string[] = [];
    
    // 颜色变量
    variables.push(`--color-primary: ${theme.colors.primary};`);
    variables.push(`--color-secondary: ${theme.colors.secondary};`);
    variables.push(`--color-success: ${theme.colors.success};`);
    variables.push(`--color-warning: ${theme.colors.warning};`);
    variables.push(`--color-error: ${theme.colors.error};`);
    variables.push(`--color-info: ${theme.colors.info};`);
    variables.push(`--color-background: ${theme.colors.background};`);
    variables.push(`--color-surface: ${theme.colors.surface};`);
    variables.push(`--color-text-primary: ${theme.colors.text.primary};`);
    variables.push(`--color-text-secondary: ${theme.colors.text.secondary};`);
    variables.push(`--color-text-disabled: ${theme.colors.text.disabled};`);
    variables.push(`--color-border: ${theme.colors.border};`);
    variables.push(`--color-divider: ${theme.colors.divider};`);
    
    // 字体变量
    variables.push(`--font-family-primary: ${theme.typography.fontFamily.primary};`);
    variables.push(`--font-family-secondary: ${theme.typography.fontFamily.secondary};`);
    variables.push(`--font-family-monospace: ${theme.typography.fontFamily.monospace};`);
    
    // 字体大小变量
    Object.entries(theme.typography.fontSize).forEach(([key, value]) => {
      variables.push(`--font-size-${key}: ${value};`);
    });
    
    // 字体粗细变量
    Object.entries(theme.typography.fontWeight).forEach(([key, value]) => {
      variables.push(`--font-weight-${key}: ${value};`);
    });
    
    // 间距变量
    Object.entries(theme.spacing).forEach(([key, value]) => {
      variables.push(`--spacing-${key}: ${value};`);
    });
    
    // 阴影变量
    Object.entries(theme.shadows).forEach(([key, value]) => {
      variables.push(`--shadow-${key}: ${value};`);
    });
    
    // 边框变量
    Object.entries(theme.borders.width).forEach(([key, value]) => {
      variables.push(`--border-width-${key}: ${value};`);
    });
    
    Object.entries(theme.borders.radius).forEach(([key, value]) => {
      variables.push(`--border-radius-${key}: ${value};`);
    });
    
    // 自定义变量
    if (theme.variables) {
      Object.entries(theme.variables).forEach(([key, value]) => {
        variables.push(`--${key}: ${value};`);
      });
    }
    
    // 根元素样式
    css.push(`:root {\n  ${variables.join('\n  ')}\n}`);
    
    // 基础样式
    css.push(`
body {
  font-family: var(--font-family-primary);
  font-size: var(--font-size-base);
  line-height: var(--line-height-normal, 1.5);
  color: var(--color-text-primary);
  background-color: var(--color-background);
  margin: 0;
  padding: 0;
}

* {
  box-sizing: border-box;
}

a {
  color: var(--color-primary);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

button {
  font-family: inherit;
  font-size: inherit;
}

input, textarea, select {
  font-family: inherit;
  font-size: inherit;
}
    `);
    
    return css.join('\n');
  }
  
  private initializeDefaultThemes(): void {
    // 默认主题
    const defaultTheme: Theme = {
      name: 'default',
      displayName: '默认主题',
      description: '系统默认主题',
      colors: {
        primary: '#1976d2',
        secondary: '#dc004e',
        success: '#388e3c',
        warning: '#f57c00',
        error: '#d32f2f',
        info: '#0288d1',
        background: '#ffffff',
        surface: '#f5f5f5',
        text: {
          primary: '#212121',
          secondary: '#757575',
          disabled: '#bdbdbd'
        },
        border: '#e0e0e0',
        divider: '#e0e0e0'
      },
      typography: {
        fontFamily: {
          primary: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
          secondary: 'Georgia, "Times New Roman", Times, serif',
          monospace: '"SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace'
        },
        fontSize: {
          xs: '0.75rem',
          sm: '0.875rem',
          base: '1rem',
          lg: '1.125rem',
          xl: '1.25rem',
          '2xl': '1.5rem',
          '3xl': '1.875rem',
          '4xl': '2.25rem'
        },
        fontWeight: {
          light: 300,
          normal: 400,
          medium: 500,
          semibold: 600,
          bold: 700
        },
        lineHeight: {
          tight: 1.25,
          normal: 1.5,
          relaxed: 1.75
        }
      },
      spacing: {
        xs: '0.25rem',
        sm: '0.5rem',
        md: '1rem',
        lg: '1.5rem',
        xl: '2rem',
        '2xl': '3rem',
        '3xl': '4rem',
        '4xl': '6rem'
      },
      breakpoints: {
        xs: '0px',
        sm: '576px',
        md: '768px',
        lg: '992px',
        xl: '1200px',
        xxl: '1600px'
      },
      shadows: {
        sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
        md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
        lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
        xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
        '2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)'
      },
      borders: {
        width: {
          thin: '1px',
          medium: '2px',
          thick: '4px'
        },
        radius: {
          none: '0',
          sm: '0.125rem',
          md: '0.375rem',
          lg: '0.5rem',
          xl: '0.75rem',
          full: '9999px'
        }
      }
    };
    
    this.setTheme('default', defaultTheme);
    
    // 暗色主题
    const darkTheme: Theme = {
      ...defaultTheme,
      name: 'dark',
      displayName: '暗色主题',
      description: '暗色模式主题',
      colors: {
        ...defaultTheme.colors,
        background: '#121212',
        surface: '#1e1e1e',
        text: {
          primary: '#ffffff',
          secondary: '#b3b3b3',
          disabled: '#666666'
        },
        border: '#333333',
        divider: '#333333'
      }
    };
    
    this.setTheme('dark', darkTheme);
  }
}

9.5 脚本系统

9.5.1 脚本定义

// 脚本定义
interface ScriptDefinition {
  id?: string;
  type: 'inline' | 'external';
  content?: string;
  src?: string;
  async?: boolean;
  defer?: boolean;
  module?: boolean;
  dependencies?: string[];
  position?: 'head' | 'body';
  condition?: string;
}

// 脚本管理器
class ScriptManager {
  private scripts: Map<string, ScriptDefinition> = new Map();
  private loadedScripts: Set<string> = new Set();
  private eventBus: EventBus;
  
  constructor(eventBus: EventBus) {
    this.eventBus = eventBus;
  }
  
  // 注册脚本
  registerScript(script: ScriptDefinition): void {
    const id = script.id || this.generateScriptId();
    script.id = id;
    this.scripts.set(id, script);
  }
  
  // 加载脚本
  async loadScript(scriptId: string): Promise<void> {
    if (this.loadedScripts.has(scriptId)) {
      return; // 已加载
    }
    
    const script = this.scripts.get(scriptId);
    if (!script) {
      throw new Error(`Script ${scriptId} not found`);
    }
    
    // 检查依赖
    if (script.dependencies) {
      for (const dep of script.dependencies) {
        await this.loadScript(dep);
      }
    }
    
    // 加载脚本
    if (script.type === 'external') {
      await this.loadExternalScript(script);
    } else {
      this.executeInlineScript(script);
    }
    
    this.loadedScripts.add(scriptId);
    this.eventBus.emit('script:loaded', { scriptId, script });
  }
  
  // 卸载脚本
  unloadScript(scriptId: string): void {
    const script = this.scripts.get(scriptId);
    if (!script) return;
    
    if (script.type === 'external' && script.src) {
      const element = document.querySelector(`script[src="${script.src}"]`);
      if (element) {
        element.remove();
      }
    }
    
    this.loadedScripts.delete(scriptId);
    this.eventBus.emit('script:unloaded', { scriptId, script });
  }
  
  // 执行脚本
  executeScript(content: string, context?: any): any {
    try {
      // 创建执行上下文
      const func = new Function('context', content);
      return func(context);
    } catch (error) {
      this.eventBus.emit('script:error', { content, error });
      throw error;
    }
  }
  
  // 检查脚本是否已加载
  isScriptLoaded(scriptId: string): boolean {
    return this.loadedScripts.has(scriptId);
  }
  
  // 获取已加载的脚本
  getLoadedScripts(): string[] {
    return Array.from(this.loadedScripts);
  }
  
  private async loadExternalScript(script: ScriptDefinition): Promise<void> {
    return new Promise((resolve, reject) => {
      const element = document.createElement('script');
      element.src = script.src!;
      
      if (script.async) element.async = true;
      if (script.defer) element.defer = true;
      if (script.module) element.type = 'module';
      
      element.onload = () => resolve();
      element.onerror = () => reject(new Error(`Failed to load script: ${script.src}`));
      
      const target = script.position === 'head' ? document.head : document.body;
      target.appendChild(element);
    });
  }
  
  private executeInlineScript(script: ScriptDefinition): void {
    if (!script.content) return;
    
    try {
      // 检查条件
      if (script.condition && !this.evaluateCondition(script.condition)) {
        return;
      }
      
      // 执行脚本
      if (script.module) {
        // 模块脚本
        const blob = new Blob([script.content], { type: 'application/javascript' });
        const url = URL.createObjectURL(blob);
        import(url).finally(() => URL.revokeObjectURL(url));
      } else {
        // 普通脚本
        const func = new Function(script.content);
        func();
      }
    } catch (error) {
      this.eventBus.emit('script:error', { script, error });
      throw error;
    }
  }
  
  private evaluateCondition(condition: string): boolean {
    try {
      const func = new Function('return ' + condition);
      return Boolean(func());
    } catch {
      return false;
    }
  }
  
  private generateScriptId(): string {
    return `script_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }
}

9.6 组件系统

9.6.1 组件注册器

// 组件注册器
interface ComponentRegistry {
  registerComponent(type: string, definition: ComponentDefinition): void;
  getComponent(type: string): ComponentDefinition | null;
  listComponents(): string[];
  unregisterComponent(type: string): void;
}

// 组件定义
interface ComponentDefinition {
  type: string;
  name: string;
  description?: string;
  category: string;
  icon?: string;
  properties: ComponentPropertyDefinition[];
  events?: ComponentEventDefinition[];
  methods?: ComponentMethodDefinition[];
  styles?: string;
  script?: string;
  template: string;
  defaultProps?: Record<string, any>;
  validation?: ComponentValidation;
}

// 组件属性定义
interface ComponentPropertyDefinition {
  name: string;
  type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'function';
  label: string;
  description?: string;
  defaultValue?: any;
  required?: boolean;
  options?: Array<{ label: string; value: any }>;
  validation?: PropertyValidation;
  group?: string;
  editor?: PropertyEditor;
}

// 组件事件定义
interface ComponentEventDefinition {
  name: string;
  description?: string;
  parameters?: EventParameter[];
}

// 组件方法定义
interface ComponentMethodDefinition {
  name: string;
  description?: string;
  parameters?: MethodParameter[];
  returnType?: string;
}

// 组件验证
interface ComponentValidation {
  rules?: ValidationRule[];
  custom?: (component: ComponentInstance) => ValidationResult;
}

// 属性验证
interface PropertyValidation {
  min?: number;
  max?: number;
  pattern?: string;
  custom?: (value: any) => boolean;
}

// 属性编辑器
interface PropertyEditor {
  type: 'input' | 'textarea' | 'select' | 'checkbox' | 'radio' | 'color' | 'date' | 'file' | 'custom';
  options?: any;
  component?: string;
}

// 事件参数
interface EventParameter {
  name: string;
  type: string;
  description?: string;
}

// 方法参数
interface MethodParameter {
  name: string;
  type: string;
  description?: string;
  required?: boolean;
  defaultValue?: any;
}

// 默认组件注册器
class DefaultComponentRegistry implements ComponentRegistry {
  private components: Map<string, ComponentDefinition> = new Map();
  private eventBus: EventBus;
  
  constructor(eventBus: EventBus) {
    this.eventBus = eventBus;
    this.initializeBuiltinComponents();
  }
  
  registerComponent(type: string, definition: ComponentDefinition): void {
    this.components.set(type, definition);
    this.eventBus.emit('component:registered', { type, definition });
  }
  
  getComponent(type: string): ComponentDefinition | null {
    return this.components.get(type) || null;
  }
  
  listComponents(): string[] {
    return Array.from(this.components.keys());
  }
  
  unregisterComponent(type: string): void {
    const definition = this.components.get(type);
    if (definition) {
      this.components.delete(type);
      this.eventBus.emit('component:unregistered', { type, definition });
    }
  }
  
  private initializeBuiltinComponents(): void {
    // 文本组件
    this.registerComponent('text', {
      type: 'text',
      name: '文本',
      description: '显示文本内容',
      category: 'basic',
      icon: 'text',
      properties: [
        {
          name: 'content',
          type: 'string',
          label: '文本内容',
          description: '要显示的文本内容',
          defaultValue: '文本内容',
          required: true,
          editor: { type: 'textarea' }
        },
        {
          name: 'tag',
          type: 'string',
          label: 'HTML标签',
          description: '文本的HTML标签',
          defaultValue: 'p',
          options: [
            { label: '段落 (p)', value: 'p' },
            { label: '标题1 (h1)', value: 'h1' },
            { label: '标题2 (h2)', value: 'h2' },
            { label: '标题3 (h3)', value: 'h3' },
            { label: '行内 (span)', value: 'span' }
          ],
          editor: { type: 'select' }
        }
      ],
      template: '<{{tag}} class="text-component">{{content}}</{{tag}}>',
      styles: `
.text-component {
  margin: 0;
  padding: 8px;
}
      `
    });
    
    // 按钮组件
    this.registerComponent('button', {
      type: 'button',
      name: '按钮',
      description: '可点击的按钮',
      category: 'basic',
      icon: 'button',
      properties: [
        {
          name: 'text',
          type: 'string',
          label: '按钮文本',
          description: '按钮显示的文本',
          defaultValue: '按钮',
          required: true
        },
        {
          name: 'type',
          type: 'string',
          label: '按钮类型',
          description: '按钮的样式类型',
          defaultValue: 'primary',
          options: [
            { label: '主要', value: 'primary' },
            { label: '次要', value: 'secondary' },
            { label: '成功', value: 'success' },
            { label: '警告', value: 'warning' },
            { label: '危险', value: 'danger' }
          ],
          editor: { type: 'select' }
        },
        {
          name: 'disabled',
          type: 'boolean',
          label: '禁用状态',
          description: '是否禁用按钮',
          defaultValue: false,
          editor: { type: 'checkbox' }
        }
      ],
      events: [
        {
          name: 'click',
          description: '按钮点击事件',
          parameters: [
            { name: 'event', type: 'MouseEvent', description: '鼠标事件对象' }
          ]
        }
      ],
      template: '<button class="btn btn-{{type}}" {{#if disabled}}disabled{{/if}} onclick="handleClick(event)">{{text}}</button>',
      styles: `
.btn {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.2s;
}

.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.btn-primary {
  background-color: var(--color-primary);
  color: white;
}

.btn-secondary {
  background-color: var(--color-secondary);
  color: white;
}

.btn-success {
  background-color: var(--color-success);
  color: white;
}

.btn-warning {
  background-color: var(--color-warning);
  color: white;
}

.btn-danger {
  background-color: var(--color-error);
  color: white;
}
      `,
      script: `
function handleClick(event) {
  const component = event.target.closest('[data-component="button"]');
  if (component) {
    component.dispatchEvent(new CustomEvent('component:click', {
      detail: { event, component }
    }));
  }
}
      `
    });
    
    // 输入框组件
    this.registerComponent('input', {
      type: 'input',
      name: '输入框',
      description: '文本输入框',
      category: 'form',
      icon: 'input',
      properties: [
        {
          name: 'placeholder',
          type: 'string',
          label: '占位符',
          description: '输入框的占位符文本',
          defaultValue: '请输入内容'
        },
        {
          name: 'value',
          type: 'string',
          label: '默认值',
          description: '输入框的默认值',
          defaultValue: ''
        },
        {
          name: 'type',
          type: 'string',
          label: '输入类型',
          description: '输入框的类型',
          defaultValue: 'text',
          options: [
            { label: '文本', value: 'text' },
            { label: '密码', value: 'password' },
            { label: '邮箱', value: 'email' },
            { label: '数字', value: 'number' },
            { label: '电话', value: 'tel' },
            { label: 'URL', value: 'url' }
          ],
          editor: { type: 'select' }
        },
        {
          name: 'required',
          type: 'boolean',
          label: '必填',
          description: '是否为必填字段',
          defaultValue: false,
          editor: { type: 'checkbox' }
        },
        {
          name: 'disabled',
          type: 'boolean',
          label: '禁用',
          description: '是否禁用输入框',
          defaultValue: false,
          editor: { type: 'checkbox' }
        }
      ],
      events: [
        {
          name: 'input',
          description: '输入事件',
          parameters: [
            { name: 'event', type: 'InputEvent', description: '输入事件对象' },
            { name: 'value', type: 'string', description: '输入值' }
          ]
        },
        {
          name: 'change',
          description: '值变化事件',
          parameters: [
            { name: 'event', type: 'Event', description: '事件对象' },
            { name: 'value', type: 'string', description: '新值' }
          ]
        }
      ],
      template: '<input class="input-component" type="{{type}}" placeholder="{{placeholder}}" value="{{value}}" {{#if required}}required{{/if}} {{#if disabled}}disabled{{/if}} oninput="handleInput(event)" onchange="handleChange(event)">',
      styles: `
.input-component {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  font-size: 14px;
  transition: border-color 0.2s;
}

.input-component:focus {
  outline: none;
  border-color: var(--color-primary);
}

.input-component:disabled {
  background-color: var(--color-surface);
  cursor: not-allowed;
}
      `,
      script: `
function handleInput(event) {
  const component = event.target.closest('[data-component="input"]');
  if (component) {
    component.dispatchEvent(new CustomEvent('component:input', {
      detail: { event, value: event.target.value, component }
    }));
  }
}

function handleChange(event) {
  const component = event.target.closest('[data-component="input"]');
  if (component) {
    component.dispatchEvent(new CustomEvent('component:change', {
      detail: { event, value: event.target.value, component }
    }));
  }
}
      `
    });
    
    // 图片组件
    this.registerComponent('image', {
      type: 'image',
      name: '图片',
      description: '显示图片',
      category: 'media',
      icon: 'image',
      properties: [
        {
          name: 'src',
          type: 'string',
          label: '图片地址',
          description: '图片的URL地址',
          defaultValue: 'https://via.placeholder.com/300x200',
          required: true,
          editor: { type: 'input' }
        },
        {
          name: 'alt',
          type: 'string',
          label: '替代文本',
          description: '图片的替代文本',
          defaultValue: '图片',
          editor: { type: 'input' }
        },
        {
          name: 'width',
          type: 'string',
          label: '宽度',
          description: '图片宽度',
          defaultValue: 'auto',
          editor: { type: 'input' }
        },
        {
          name: 'height',
          type: 'string',
          label: '高度',
          description: '图片高度',
          defaultValue: 'auto',
          editor: { type: 'input' }
        }
      ],
      events: [
        {
          name: 'load',
          description: '图片加载完成事件',
          parameters: [
            { name: 'event', type: 'Event', description: '加载事件对象' }
          ]
        },
        {
          name: 'error',
          description: '图片加载错误事件',
          parameters: [
            { name: 'event', type: 'Event', description: '错误事件对象' }
          ]
        }
      ],
      template: '<img class="image-component" src="{{src}}" alt="{{alt}}" style="width: {{width}}; height: {{height}};" onload="handleLoad(event)" onerror="handleError(event)">',
      styles: `
.image-component {
  max-width: 100%;
  height: auto;
  display: block;
}
      `,
      script: `
function handleLoad(event) {
  const component = event.target.closest('[data-component="image"]');
  if (component) {
    component.dispatchEvent(new CustomEvent('component:load', {
      detail: { event, component }
    }));
  }
}

function handleError(event) {
  const component = event.target.closest('[data-component="image"]');
  if (component) {
    component.dispatchEvent(new CustomEvent('component:error', {
      detail: { event, component }
    }));
  }
}
      `
    });
  }
}

9.7 页面生成器使用示例

9.7.1 完整使用示例

// 页面生成器使用示例
class LowCodePageGeneratorDemo {
  private pageGenerator: LowCodePageGenerator;
  private eventBus: EventBus;
  
  constructor() {
    this.eventBus = new EventBus();
    this.setupEventListeners();
    
    // 初始化页面生成器
    this.pageGenerator = new LowCodePageGenerator({
      eventBus: this.eventBus,
      templateEngine: new DefaultTemplateEngine(),
      themeManager: new DefaultThemeManager(),
      componentRegistry: new DefaultComponentRegistry(this.eventBus)
    });
  }
  
  async runDemo(): Promise<void> {
    console.log('=== 低代码页面生成器演示 ===');
    
    try {
      // 1. 创建产品展示页面
      await this.createProductPage();
      
      // 2. 创建用户注册页面
      await this.createRegistrationPage();
      
      // 3. 创建仪表板页面
      await this.createDashboardPage();
      
      // 4. 页面管理操作
      await this.demonstratePageManagement();
      
      // 5. 模板管理
      await this.demonstrateTemplateManagement();
      
    } catch (error) {
      console.error('演示过程中发生错误:', error);
    }
  }
  
  private async createProductPage(): Promise<void> {
    console.log('\n--- 创建产品展示页面 ---');
    
    // 创建页面定义
    const pageDefinition: PageDefinition = {
      title: '产品展示',
      description: '展示公司产品的页面',
      layout: {
        type: 'grid',
        properties: {
          columns: '1fr 2fr 1fr',
          rows: 'auto 1fr auto',
          gap: '20px',
          padding: '20px'
        },
        responsive: {
          md: {
            columns: '1fr',
            rows: 'auto auto auto auto auto'
          }
        }
      },
      components: [
        {
          id: 'header',
          type: 'text',
          properties: {
            content: '我们的产品',
            tag: 'h1'
          },
          layout: {
            grid: { area: '1 / 1 / 2 / 4' }
          },
          styles: {
            textAlign: 'center',
            color: 'var(--color-primary)',
            marginBottom: '20px'
          }
        },
        {
          id: 'product-image',
          type: 'image',
          properties: {
            src: 'https://via.placeholder.com/400x300',
            alt: '产品图片',
            width: '100%'
          },
          layout: {
            grid: { area: '2 / 1 / 3 / 2' }
          }
        },
        {
          id: 'product-description',
          type: 'text',
          properties: {
            content: '这是一款革命性的产品,具有出色的性能和用户体验。它采用最新的技术,为用户提供前所未有的便利。',
            tag: 'p'
          },
          layout: {
            grid: { area: '2 / 2 / 3 / 3' }
          },
          styles: {
            fontSize: '16px',
            lineHeight: '1.6',
            padding: '20px'
          }
        },
        {
          id: 'product-features',
          type: 'text',
          properties: {
            content: '<ul><li>高性能处理器</li><li>超长续航</li><li>精美设计</li><li>智能功能</li></ul>',
            tag: 'div'
          },
          layout: {
            grid: { area: '2 / 3 / 3 / 4' }
          },
          styles: {
            padding: '20px'
          }
        },
        {
          id: 'buy-button',
          type: 'button',
          properties: {
            text: '立即购买',
            type: 'primary'
          },
          layout: {
            grid: { area: '3 / 2 / 4 / 3' }
          },
          styles: {
            justifySelf: 'center',
            padding: '12px 24px',
            fontSize: '16px'
          }
        }
      ],
      styles: {
        'body': {
          fontFamily: 'Arial, sans-serif',
          margin: '0',
          padding: '0'
        },
        '.product-page': {
          minHeight: '100vh',
          backgroundColor: '#f5f5f5'
        }
      },
      scripts: [
        {
          type: 'inline',
          content: `
            document.addEventListener('component:click', function(event) {
              if (event.detail.component.dataset.id === 'buy-button') {
                alert('感谢您的购买!');
              }
            });
          `
        }
      ],
      settings: {
        theme: 'default',
        language: 'zh-CN',
        seo: {
          description: '查看我们最新的产品,了解其特性和优势',
          keywords: ['产品', '购买', '科技'],
          ogTitle: '产品展示 - 我们的公司',
          ogDescription: '发现我们的革命性产品'
        },
        performance: {
          preload: []
        },
        security: {
          csp: "default-src 'self' 'unsafe-inline' https:"
        }
      }
    };
    
    // 创建页面
    const page = await this.pageGenerator.createPage(pageDefinition);
    console.log('产品页面创建成功:', page.id);
    
    // 渲染页面
    const html = await this.pageGenerator.renderPage(page.id);
    console.log('页面HTML长度:', html.length);
    
    // 发布页面
    const publishResult = await this.pageGenerator.publishPage(page.id, {
      environment: 'production',
      version: '1.0.0'
    });
    console.log('页面发布成功:', publishResult.url);
  }
  
  private async createRegistrationPage(): Promise<void> {
    console.log('\n--- 创建用户注册页面 ---');
    
    const pageDefinition: PageDefinition = {
      title: '用户注册',
      description: '新用户注册页面',
      layout: {
        type: 'flex',
        properties: {
          direction: 'column',
          align: 'center',
          justify: 'center',
          minHeight: '100vh',
          padding: '20px'
        }
      },
      components: [
        {
          id: 'form-title',
          type: 'text',
          properties: {
            content: '用户注册',
            tag: 'h2'
          },
          styles: {
            marginBottom: '30px',
            color: 'var(--color-primary)'
          }
        },
        {
          id: 'username-input',
          type: 'input',
          properties: {
            placeholder: '请输入用户名',
            type: 'text',
            required: true
          },
          styles: {
            marginBottom: '15px',
            width: '300px'
          }
        },
        {
          id: 'email-input',
          type: 'input',
          properties: {
            placeholder: '请输入邮箱',
            type: 'email',
            required: true
          },
          styles: {
            marginBottom: '15px',
            width: '300px'
          }
        },
        {
          id: 'password-input',
          type: 'input',
          properties: {
            placeholder: '请输入密码',
            type: 'password',
            required: true
          },
          styles: {
            marginBottom: '20px',
            width: '300px'
          }
        },
        {
          id: 'register-button',
          type: 'button',
          properties: {
            text: '注册',
            type: 'primary'
          },
          styles: {
            width: '300px',
            padding: '12px'
          }
        }
      ],
      scripts: [
        {
          type: 'inline',
          content: `
            document.addEventListener('component:click', function(event) {
              if (event.detail.component.dataset.id === 'register-button') {
                const username = document.querySelector('[data-id="username-input"] input').value;
                const email = document.querySelector('[data-id="email-input"] input').value;
                const password = document.querySelector('[data-id="password-input"] input').value;
                
                if (username && email && password) {
                  alert('注册成功!欢迎 ' + username);
                } else {
                  alert('请填写所有必填字段');
                }
              }
            });
          `
        }
      ],
      settings: {
        theme: 'default',
        language: 'zh-CN'
      }
    };
    
    const page = await this.pageGenerator.createPage(pageDefinition);
    console.log('注册页面创建成功:', page.id);
    
    const html = await this.pageGenerator.renderPage(page.id);
    console.log('页面HTML长度:', html.length);
  }
  
  private async createDashboardPage(): Promise<void> {
    console.log('\n--- 创建仪表板页面 ---');
    
    // 使用内置模板
    const page = await this.pageGenerator.createPageFromTemplate('dashboard', {
      title: '管理仪表板',
      description: '系统管理仪表板',
      variables: {
        userName: '管理员',
        totalUsers: '1,234',
        totalOrders: '5,678',
        revenue: '¥123,456'
      }
    });
    
    console.log('仪表板页面创建成功:', page.id);
    
    // 添加自定义组件
    await this.pageGenerator.updatePage(page.id, {
      components: [
        ...page.components,
        {
          id: 'chart-container',
          type: 'text',
          properties: {
            content: '<div id="chart" style="width: 100%; height: 300px; background: #f0f0f0; display: flex; align-items: center; justify-content: center;">图表占位符</div>',
            tag: 'div'
          },
          styles: {
            marginTop: '20px',
            padding: '20px',
            backgroundColor: 'white',
            borderRadius: '8px',
            boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
          }
        }
      ]
    });
    
    console.log('仪表板页面更新完成');
  }
  
  private async demonstratePageManagement(): Promise<void> {
    console.log('\n--- 页面管理演示 ---');
    
    // 查询页面
    const pages = await this.pageGenerator.queryPages({
      status: 'published',
      limit: 10
    });
    console.log('已发布页面数量:', pages.length);
    
    // 获取页面详情
    if (pages.length > 0) {
      const pageDetail = await this.pageGenerator.getPage(pages[0].id);
      console.log('页面详情:', {
        id: pageDetail.id,
        title: pageDetail.title,
        status: pageDetail.status,
        componentCount: pageDetail.components.length
      });
      
      // 复制页面
      const copiedPage = await this.pageGenerator.duplicatePage(pages[0].id, {
        title: pageDetail.title + ' (副本)'
      });
      console.log('页面复制成功:', copiedPage.id);
      
      // 删除副本
      await this.pageGenerator.deletePage(copiedPage.id);
      console.log('副本页面已删除');
    }
  }
  
  private async demonstrateTemplateManagement(): Promise<void> {
    console.log('\n--- 模板管理演示 ---');
    
    // 创建自定义模板
    const template: PageTemplate = {
      id: 'blog-post',
      name: '博客文章',
      description: '博客文章页面模板',
      category: 'content',
      variables: [
        {
          name: 'title',
          type: 'string',
          label: '文章标题',
          required: true
        },
        {
          name: 'author',
          type: 'string',
          label: '作者',
          required: true
        },
        {
          name: 'content',
          type: 'string',
          label: '文章内容',
          required: true
        },
        {
          name: 'publishDate',
          type: 'string',
          label: '发布日期',
          required: true
        }
      ],
      definition: {
        title: '{{title}}',
        description: '{{author}}的博客文章',
        layout: {
          type: 'container',
          properties: {
            maxWidth: '800px',
            margin: '0 auto',
            padding: '40px 20px'
          }
        },
        components: [
          {
            id: 'article-title',
            type: 'text',
            properties: {
              content: '{{title}}',
              tag: 'h1'
            },
            styles: {
              marginBottom: '10px'
            }
          },
          {
            id: 'article-meta',
            type: 'text',
            properties: {
              content: '作者:{{author}} | 发布时间:{{publishDate}}',
              tag: 'p'
            },
            styles: {
              color: 'var(--color-text-secondary)',
              marginBottom: '30px',
              fontSize: '14px'
            }
          },
          {
            id: 'article-content',
            type: 'text',
            properties: {
              content: '{{content}}',
              tag: 'div'
            },
            styles: {
              lineHeight: '1.8',
              fontSize: '16px'
            }
          }
        ],
        settings: {
          theme: 'default',
          language: 'zh-CN'
        }
      }
    };
    
    // 注册模板
    await this.pageGenerator.registerTemplate(template);
    console.log('博客模板注册成功');
    
    // 使用模板创建页面
    const blogPage = await this.pageGenerator.createPageFromTemplate('blog-post', {
      title: '低代码平台的未来',
      variables: {
        title: '低代码平台的未来',
        author: '技术专家',
        content: '低代码平台正在改变软件开发的方式,让更多人能够参与到应用程序的创建中来...',
        publishDate: '2024-01-15'
      }
    });
    
    console.log('博客页面创建成功:', blogPage.id);
    
    // 列出所有模板
    const templates = await this.pageGenerator.listTemplates();
    console.log('可用模板:', templates.map(t => t.name));
  }
  
  private setupEventListeners(): void {
    // 页面事件监听
    this.eventBus.on('page:created', (event) => {
      console.log('页面创建事件:', event.page.title);
    });
    
    this.eventBus.on('page:updated', (event) => {
      console.log('页面更新事件:', event.page.title);
    });
    
    this.eventBus.on('page:published', (event) => {
      console.log('页面发布事件:', event.page.title, '-> URL:', event.result.url);
    });
    
    this.eventBus.on('page:deleted', (event) => {
      console.log('页面删除事件:', event.pageId);
    });
    
    // 组件事件监听
    this.eventBus.on('component:registered', (event) => {
      console.log('组件注册事件:', event.type);
    });
    
    // 模板事件监听
    this.eventBus.on('template:registered', (event) => {
      console.log('模板注册事件:', event.template.name);
    });
    
    // 渲染事件监听
    this.eventBus.on('page:rendered', (event) => {
      console.log('页面渲染完成:', event.page.title);
    });
  }
}

// 运行演示
const demo = new LowCodePageGeneratorDemo();
demo.runDemo().then(() => {
  console.log('\n=== 演示完成 ===');
}).catch(error => {
  console.error('演示失败:', error);
});

9.8 小结

本章详细介绍了低代码平台的页面生成器与动态页面系统,涵盖了以下核心要点:

9.8.1 架构设计

  • 页面生成器架构:设计了完整的页面生成器接口和实现,支持页面的创建、更新、渲染、发布和管理
  • 布局系统:实现了多种布局类型(容器、网格、Flex),支持响应式设计
  • 组件系统:建立了组件注册机制,支持自定义组件和内置组件
  • 模板系统:提供了页面模板功能,支持变量替换和模板复用

9.8.2 核心功能

  • 页面管理:完整的页面生命周期管理,包括创建、编辑、发布、删除
  • 动态渲染:支持服务端渲染和客户端渲染,生成完整的HTML页面
  • 样式系统:集成主题管理,支持CSS变量和响应式样式
  • 脚本系统:支持内联脚本和外部脚本,提供依赖管理

9.8.3 技术特色

  • 类型安全:使用TypeScript提供完整的类型定义和检查
  • 事件驱动:基于事件总线的松耦合架构设计
  • 插件化:支持自定义组件、布局和模板的扩展
  • 性能优化:支持脚本预加载、样式优化和响应式设计
  • SEO友好:支持元数据管理、结构化数据和搜索引擎优化

9.8.4 最佳实践

  1. 组件设计:遵循单一职责原则,保持组件的简洁和可复用性
  2. 布局规划:合理使用网格和Flex布局,确保响应式设计
  3. 性能考虑:优化资源加载,减少不必要的重渲染
  4. 安全防护:实施内容安全策略,防范XSS攻击
  5. 用户体验:提供直观的页面编辑界面和实时预览功能

9.8.5 扩展方向

  • 可视化编辑器:开发拖拽式页面编辑器
  • 动画系统:集成CSS动画和JavaScript动画
  • 国际化支持:多语言内容管理和本地化
  • 版本控制:页面版本管理和回滚功能
  • 协作功能:多人协作编辑和权限管理

通过本章的学习,你已经掌握了如何构建一个功能完整的页面生成器系统。下一章我们将学习权限管理与安全控制,了解如何为低代码平台添加完善的安全机制。 “`