Skip to content

JPwise 布局优化规则

本文档与 列表配置规范 相互配合,提供完整的布局优化解决方案。

表单布局智能优化

字段分组策略

javascript
const fieldGrouping = {
  // 基本信息组
  basic: {
    title: "基本信息",
    patterns: ['NAME', 'CODE', 'TYPE', 'STATUS', 'TITLE'],
    icon: "icon-ym icon-ym-generator-group",
    span: 12,
    priority: 1
  },
  
  // 联系信息组
  contact: {
    title: "联系信息", 
    patterns: ['PHONE', 'EMAIL', 'ADDRESS', 'CONTACT', 'TEL'],
    icon: "icon-ym icon-ym-generator-group",
    span: 8,
    priority: 3
  },
  
  // 财务信息组
  financial: {
    title: "财务信息",
    patterns: ['AMOUNT', 'PRICE', 'COST', 'TAX', 'CURRENCY', 'FEE', 'MONEY'],
    icon: "icon-ym icon-ym-generator-group",
    span: 8,
    priority: 2
  },
  
  // 时间信息组
  timeline: {
    title: "时间信息",
    patterns: ['DATE', 'TIME', 'START', 'END', 'DEADLINE', 'PERIOD'],
    icon: "icon-ym icon-ym-generator-group",
    span: 12,
    priority: 4
  },
  
  // 人员信息组
  personnel: {
    title: "人员信息",
    patterns: ['USER', 'PERSON', 'STAFF', 'EMPLOYEE', 'CREATOR', 'MODIFIER'],
    icon: "icon-ym icon-ym-generator-group",
    span: 8,
    priority: 2
  },
  
  // 组织信息组
  organization: {
    title: "组织信息",
    patterns: ['DEPT', 'DEPARTMENT', 'ORGANIZE', 'BRANCH', 'DIVISION'],
    icon: "icon-ym icon-ym-generator-group",
    span: 8,
    priority: 3
  },
  
  // 附加信息组
  additional: {
    title: "附加信息",
    patterns: ['REMARK', 'NOTE', 'ATTACHMENT', 'COMMENT', 'DESC', 'DETAIL'],
    icon: "icon-ym icon-ym-generator-group",
    span: 24,
    priority: 5
  }
}

自动分组算法

javascript
function autoGroupFields(fields) {
  const groups = {};
  const ungrouped = [];
  
  fields.forEach(field => {
    let grouped = false;
    
    // 检查字段是否匹配任何分组模式
    for (const [groupKey, groupConfig] of Object.entries(fieldGrouping)) {
      if (matchesGroupPattern(field.name, groupConfig.patterns)) {
        if (!groups[groupKey]) {
          groups[groupKey] = {
            ...groupConfig,
            fields: []
          };
        }
        groups[groupKey].fields.push(field);
        grouped = true;
        break;
      }
    }
    
    if (!grouped) {
      ungrouped.push(field);
    }
  });
  
  // 将未分组的字段添加到基本信息组
  if (ungrouped.length > 0) {
    if (!groups.basic) {
      groups.basic = { ...fieldGrouping.basic, fields: [] };
    }
    groups.basic.fields.push(...ungrouped);
  }
  
  return groups;
}

栅格布局优化

javascript
const spanCalculation = {
  // 基于组件类型
  byComponent: {
    'comInput': 8,      // 普通输入框
    'numInput': 8,      // 数字输入框
    'JPWInput': 8,      // 统计数值
    'select': 8,        // 下拉选择
    'date': 8,          // 日期选择
    'userSelect': 8,    // 用户选择
    'depSelect': 8,     // 部门选择
    'switch': 8,        // 开关
    'textarea': 24,     // 多行文本
    'editor': 24,       // 富文本
    'uploadFz': 24,     // 文件上传
    'uploadImg': 24,    // 图片上传
    'table': 24,        // 子表
    'popupSelect': 12   // 弹窗选择
  },
  
  // 基于字段重要性
  byImportance: {
    'high': 12,     // 重要字段(名称、编号等)
    'medium': 8,    // 普通字段
    'low': 6        // 次要字段
  },
  
  // 基于字段组
  byGroup: {
    'basic': 8,         // 基本信息
    'financial': 8,     // 财务信息
    'contact': 8,       // 联系信息
    'timeline': 12,     // 时间信息
    'additional': 24    // 附加信息
  }
}

// 智能span计算(与 component-mapping.md 中的策略保持一致)
function calculateSpan(field, component, group) {
  // 1. 检查特殊组件类型(最高优先级)
  if (spanCalculation.byComponent[component]) {
    return spanCalculation.byComponent[component];
  }
  
  // 2. 检查字段类型模式
  if (spanCalculation.byFieldType) {
    for (const [pattern, span] of Object.entries(spanCalculation.byFieldType)) {
      if (field.field && field.field.includes(pattern)) {
        return span;
      }
    }
  }
  
  // 3. 检查字段重要性
  const importance = getFieldImportance(field);
  if (spanCalculation.byImportance[importance]) {
    return spanCalculation.byImportance[importance];
  }
  
  // 4. 检查字段组
  if (spanCalculation.byGroup[group]) {
    return spanCalculation.byGroup[group];
  }
  
  // 5. 默认值(统一为 12)
  return 12;
}

// 字段重要性判断函数
function getFieldImportance(field) {
  const criticalPatterns = ['TITLE', 'CONTENT', 'DETAIL', 'REMARK', 'NOTE', 'DESC'];
  const highPatterns = ['NAME', 'CODE', 'NO'];
  const fieldName = field.field || field.fieldName || '';
  
  if (criticalPatterns.some(pattern => fieldName.includes(pattern))) {
    return 'critical';
  }
  if (highPatterns.some(pattern => fieldName.includes(pattern))) {
    return 'high';
  }
  return 'medium';
}

折叠面板生成规则

javascript
function generateCollapsePanels(groupedFields) {
  const panels = [];
  
  // 按优先级排序分组
  const sortedGroups = Object.entries(groupedFields)
    .sort((a, b) => a[1].priority - b[1].priority);
  
  sortedGroups.forEach(([groupKey, groupConfig], index) => {
    panels.push({
      title: groupConfig.title,
      name: index.toString(),
      isHide: ["pc", "app"],
      __config__: {
        children: groupConfig.fields.map(field => 
          generateFormComponent(field, groupConfig.span)
        )
      }
    });
  });
  
  return panels;
}

列表布局优化

详细的列表配置规范请参考 列表配置规范,本节重点介绍布局优化算法。

列宽智能计算

javascript
const columnWidthRules = {
  // 基于字段类型
  byFieldType: {
    'ID': 0,           // ID列隐藏
    'CODE': 120,       // 编码列
    'NAME': 150,       // 名称列
    'TITLE': 200,      // 标题列
    'AMOUNT': 100,     // 金额列
    'DATE': 120,       // 日期列
    'TIME': 100,       // 时间列
    'STATUS': 80,      // 状态列
    'STATE': 80,       // 状态列
    'TYPE': 100,       // 类型列
    'REMARK': 200,     // 备注列
    'NOTE': 200,       // 说明列
    'USER': 100,       // 用户列
    'PERSON': 100,     // 人员列
    'DEPT': 120,       // 部门列
    'PHONE': 120,      // 电话列
    'EMAIL': 150,      // 邮箱列
    'ADDRESS': 200     // 地址列
  },
  
  // 基于数据类型
  byDataType: {
    'varchar': (length) => Math.min(Math.max(length * 1.2, 80), 300),
    'decimal': 100,
    'int': 80,
    'datetime': 120,
    'date': 100,
    'time': 80,
    'text': 200
  },
  
  // 基于字段名长度
  byLabelLength: (label) => Math.max(label.length * 12, 80)
}

function calculateColumnWidth(field) {
  // 1. 检查字段名称模式
  for (const [pattern, width] of Object.entries(columnWidthRules.byFieldType)) {
    if (field.field.includes(pattern)) {
      return width;
    }
  }
  
  // 2. 检查数据类型
  const typeRule = columnWidthRules.byDataType[field.dataType];
  if (typeRule) {
    return typeof typeRule === 'function' 
      ? typeRule(field.dataLength) 
      : typeRule;
  }
  
  // 3. 基于标签长度
  return columnWidthRules.byLabelLength(field.fieldName || field.field);
}

搜索字段智能选择

javascript
const searchFieldRules = {
  // 自动添加搜索的字段模式
  autoSearch: [
    { pattern: /.*NAME.*/, type: 'LK', component: 'comInput' },
    { pattern: /.*TITLE.*/, type: 'LK', component: 'comInput' },
    { pattern: /.*CODE.*/, type: 'EQ', component: 'comInput' },
    { pattern: /.*NO.*/, type: 'EQ', component: 'comInput' },
    { pattern: /.*STATUS.*/, type: 'EQ', component: 'select' },
    { pattern: /.*STATE.*/, type: 'EQ', component: 'select' },
    { pattern: /.*TYPE.*/, type: 'EQ', component: 'select' },
    { pattern: /.*DATE.*/, type: 'RANGE', component: 'date' },
    { pattern: /.*TIME.*/, type: 'RANGE', component: 'date' }
  ],
  
  // 快速查询字段
  quickQuery: [
    /.*NAME.*/,
    /.*TITLE.*/,
    /.*CODE.*/
  ]
}

function generateSearchConfig(fields) {
  const searchList = [];
  const quickQueryFields = [];
  
  fields.forEach(field => {
    // 检查是否应该添加搜索
    searchFieldRules.autoSearch.forEach(rule => {
      if (rule.pattern.test(field.field)) {
        searchList.push({
          ...field,
          searchType: rule.type,
          searchJnpfKey: rule.component,
          search: true
        });
      }
    });
    
    // 检查是否应该添加到快速查询
    searchFieldRules.quickQuery.forEach(pattern => {
      if (pattern.test(field.field)) {
        quickQueryFields.push(field.field);
      }
    });
  });
  
  // 智能统计字段选择
  const summaryFields = fields
    .filter(field => {
      const isNumericField = ['decimal', 'int', 'float', 'number'].includes(field.dataType);
      const isAmountField = ['AMOUNT', 'MONEY', 'PRICE', 'COST', 'FEE', 'SALARY'].some(pattern => 
        field.field.includes(pattern)
      );
      return isNumericField && isAmountField;
    })
    .map(field => field.field);
  
  return {
    searchList,
    quickQuery: quickQueryFields.join(','),
    summaryFields // 添加统计字段
  };
}

列显示优化

javascript
const columnDisplayRules = {
  // 默认隐藏的字段
  hidden: [
    'ID',
    'CREATORUSER',
    'LASTMODIFYUSER',
    'DELETEUSER',
    'ORGANIZE',
    'SORTCODE'
  ],
  
  // 默认显示的字段(按优先级)
  visible: {
    high: ['NAME', 'TITLE', 'CODE', 'STATUS'],
    medium: ['TYPE', 'AMOUNT', 'DATE', 'USER', 'DEPT'],
    low: ['REMARK', 'NOTE', 'CREATETIME']
  },
  
  // 固定列配置
  fixed: {
    left: ['NAME', 'CODE'],
    right: ['OPERATION']
  }
}

function optimizeColumnDisplay(fields) {
  return fields.map(field => {
    const isHidden = columnDisplayRules.hidden.some(pattern => 
      field.field.includes(pattern)
    );
    
    const fixedPosition = getFixedPosition(field.field);
    
    return {
      ...field,
      showtable: !isHidden,
      fixed: fixedPosition,
      sortable: !isHidden && field.dataType !== 'text'
    };
  });
}

按钮配置智能优化

javascript
const buttonOptimizationRules = {
  // 按钮显示优先级
  buttonPriority: {
    // 行按钮优先级(数字越小优先级越高)
    row: {
      'btn_row_detail': 1,    // 详情按钮优先显示
      'btn_row_edit': 2,      // 编辑按钮
      'btn_row_remove': 3,    // 删除按钮
      'btn_row_copy': 4       // 复制按钮可选
    },
    
    // 顶部按钮优先级
    top: {
      'btn_top_add': 1,           // 新增按钮优先
      'btn_top_refresh': 2,       // 刷新按钮
      'btn_top_download': 3,      // 导出按钮
      'btn_top_edit': 4,          // 批量编辑
      'btn_top_batchRemove': 5,   // 批量删除
      'btn_top_importExcel': 6,   // 导入按钮
      'btn_top_search': 7         // 高级搜索
    }
  },
  
  // 基于业务场景的按钮配置
  scenarioButtons: {
    financial: {
      required: ['btn_row_detail', 'btn_top_add', 'btn_top_download'],
      optional: ['btn_row_edit', 'btn_top_batchRemove', 'btn_top_importExcel'],
      hidden: ['btn_row_remove'] // 财务数据通常不允许直接删除
    },
    
    workflow: {
      required: ['btn_row_detail', 'btn_top_add', 'btn_top_refresh'],
      optional: ['btn_row_edit', 'btn_top_download'],
      hidden: ['btn_top_batchRemove'] // 工作流数据不允许批量删除
    },
    
    general: {
      required: ['btn_row_edit', 'btn_row_detail', 'btn_top_add', 'btn_top_refresh'],
      optional: ['btn_row_remove', 'btn_top_batchRemove', 'btn_top_download'],
      hidden: []
    }
  }
}

// 智能按钮配置生成算法
function optimizeButtonConfiguration(businessScenario, permissions) {
  const scenario = buttonOptimizationRules.scenarioButtons[businessScenario] || 
                  buttonOptimizationRules.scenarioButtons.general;
  
  const buttonConfig = {
    customBtnsList: [],
    customTopBtnsList: []
  };
  
  // 生成行按钮配置
  const rowButtons = [...scenario.required, ...scenario.optional]
    .filter(btnValue => btnValue.startsWith('btn_row_'))
    .filter(btnValue => !scenario.hidden.includes(btnValue))
    .filter(btnValue => hasButtonPermission(permissions, btnValue))
    .sort((a, b) => 
      (buttonOptimizationRules.buttonPriority.row[a] || 99) - 
      (buttonOptimizationRules.buttonPriority.row[b] || 99)
    );
    
  rowButtons.forEach(btnValue => {
    const button = generateOptimizedRowButton(btnValue, businessScenario);
    if (button) {
      buttonConfig.customBtnsList.push(button);
    }
  });
  
  // 生成顶部按钮配置
  const topButtons = [...scenario.required, ...scenario.optional]
    .filter(btnValue => btnValue.startsWith('btn_top_'))
    .filter(btnValue => !scenario.hidden.includes(btnValue))
    .filter(btnValue => hasButtonPermission(permissions, btnValue))
    .sort((a, b) => 
      (buttonOptimizationRules.buttonPriority.top[a] || 99) - 
      (buttonOptimizationRules.buttonPriority.top[b] || 99)
    );
    
  topButtons.forEach(btnValue => {
    const button = generateOptimizedTopButton(btnValue, businessScenario);
    if (button) {
      buttonConfig.customTopBtnsList.push(button);
    }
  });
  
  return buttonConfig;
}

// 权限检查辅助函数
function hasButtonPermission(permissions, buttonValue) {
  const permissionMapping = {
    'btn_row_edit': 'edit',
    'btn_row_remove': 'delete',
    'btn_row_detail': 'read',
    'btn_row_copy': 'add',
    'btn_top_add': 'add',
    'btn_top_edit': 'edit',
    'btn_top_batchRemove': 'delete',
    'btn_top_download': 'export',
    'btn_top_importExcel': 'import'
  };
  
  const requiredPermission = permissionMapping[buttonValue];
  return !requiredPermission || permissions.includes(requiredPermission);
}

综合布局优化算法

javascript
// 综合布局优化主函数
function optimizeCompleteLayout(fields, businessScenario, permissions) {
  return {
    // 表单布局优化
    formLayout: {
      groupedFields: autoGroupFields(fields),
      collapsePanels: generateCollapsePanels(autoGroupFields(fields)),
      spanOptimization: fields.map(field => ({
        ...field,
        span: calculateSpan(field, getOptimalComponent(field), getFieldGroup(field))
      }))
    },
    
    // 列表布局优化
    listLayout: {
      columnConfig: generateSearchConfig(fields),
      columnDisplay: optimizeColumnDisplay(fields),
      columnWidths: fields.map(field => ({
        ...field,
        width: calculateColumnWidth(field)
      })),
      buttonConfig: optimizeButtonConfiguration(businessScenario, permissions)
    }
  };
}