升鲜宝通用明细列表控件
设计与开发文档
适用于商品、采购、销售、WMS、门店、财务、日志等所有明细列表页面
版本:V1.0
技术栈:Vue3 + Element Plus + Spring Boot + MyBatis-Plus + MySQL 8.0 + Redis
文档性质:研发设计说明 / 通用组件规范 / 可落地开发方案
文档目录
-
建设背景与目标
-
组件定位与边界
-
适用业务场景
-
总体架构设计
-
前端控件设计
-
列设置弹窗设计
-
后端服务设计
-
数据库表结构设计
-
接口设计
-
权限、缓存与多语言设计
-
关键业务流程
-
代码骨架
-
异常处理与校验规则
-
测试用例与验收标准
-
实施路线图
1. 建设背景与目标
在升鲜宝供应链管理系统中,商品明细、订单明细、入库明细、出库明细、盘点明细、采购明细、销售明细、客户账单明细等页面都存在大量表格列。不同岗位、不同业务场景、不同门店和不同用户对列表字段的关注点并不一致。
因此需要建设一套通用的明细列表控件,将"列表渲染、列显示控制、列宽设置、对齐方式、冻结列、拖拽排序、字段权限、数据权限、导入导出、打印、缓存、默认配置、用户个性化配置"等能力统一沉淀为系统基础组件。
1.1 核心目标
- 所有明细类页面统一使用同一套表格控件和列配置规范,减少重复代码。
- 支持每个用户独立配置显示列、列顺序、列宽、对齐方式和冻结列。
- 支持系统默认配置、角色默认配置、用户个人配置三层覆盖。
- 支持与字段权限、数据权限、导出权限、打印模板联动。
- 支持后端统一保存,用户更换电脑后仍然保留个人配置。
- 支持未来扩展多语言列名、低代码列表配置、动态查询条件和移动端适配。
1.2 参考原型
下图为列设置弹窗参考形态:包含列名称、冻结、显示、对齐方式、展示顺序、展示宽度、恢复默认、保存、关闭等能力。

图 1:升鲜宝明细列表列设置参考原型
2. 组件定位与边界
组件名称建议为 SxbDetailTable,列设置子组件命名为 SxbColumnSetting。SxbDetailTable 是列表渲染主体;SxbColumnSetting 是配置弹窗;useColumnSetting 是前端组合式 Hook;后端 system-column-setting 模块负责默认配置、用户配置和权限过滤。
|----------------------------|----------------------------------------------|----------|
| 组件/模块 | 职责 | 是否通用 |
| SxbDetailTable.vue | 统一封装 Element Plus 表格、分页、加载、空状态、汇总行、操作列、动态列渲染 | 是 |
| SxbColumnSettingDialog.vue | 列设置弹窗:显示/隐藏、冻结、对齐、排序、宽度、恢复默认 | 是 |
| SxbColumnSettingButton.vue | 列表右上角列设置入口按钮,可嵌入 toolbar | 是 |
| useColumnSetting.ts | 获取、合并、保存、重置列配置,处理本地缓存和后端同步 | 是 |
| system-column-setting 后端服务 | 保存用户个性化列配置,维护系统默认列配置,执行权限过滤 | 是 |
| 业务页面 | 只声明 tableKey、defaultColumns、查询接口和业务操作列 | 否 |
2.1 组件不应该承担的职责
- 不直接写死任何业务字段,例如 SKU、客户、供应商、订单状态等字段都由业务页面声明。
- 不直接处理复杂业务流程,例如审核、反审核、生成入库单、生成出库单等。
- 不绕过后端权限控制,前端列隐藏只是一种体验优化,安全控制必须以后端为准。
- 不将数据权限和列权限混为一谈,数据权限控制行,字段权限控制列,列设置控制用户偏好。
3. 适用业务场景
|---------|--------------------------|-----------------------------------------------------|
| 业务域 | 典型页面 | 建议 tableKey 示例 |
| 商品 PMS | 商品列表、SKU列表、商品单位关系、商品价格明细 | pms_goods_list / pms_sku_list / pms_sku_unit_detail |
| 采购 PUR | 采购订单明细、采购入库计划、供应商报价明细 | pur_order_detail / pur_stockin_plan_detail |
| 销售 OMS | 销售订单明细、销售出库明细、客户价格明细 | oms_order_detail / oms_stockout_detail |
| 仓库 WMS | 入库单明细、出库单明细、盘点单明细、调拨单明细 | wms_stockin_detail / wms_stocktake_detail |
| 门店 HWMS | 门店库存明细、门店盘点明细、门店销售扣减明细 | hwms_inventory_detail / hwms_stocktake_detail |
| 财务 FIN | 应收明细、应付明细、客户账单、供应商账单 | fin_ar_detail / fin_ap_detail |
| 日志 LOG | 操作日志、接口日志、审计日志、异常日志 | log_operation_list / log_api_list |
4. 总体架构设计
整体采用"业务页面声明列 + 通用组件渲染 + 后端保存配置 + 权限引擎过滤 + 缓存加速"的架构。业务页面不再关心列配置弹窗的实现,只需要提供 tableKey 和默认列定义。
业务页面
├─ 声明 tableKey
├─ 声明 defaultColumns
├─ 绑定查询接口
└─ 声明业务操作列
↓
SxbDetailTable 通用明细列表控件
├─ 动态列渲染
├─ 分页/排序/选择/汇总
├─ 空状态/加载状态
├─ 列设置入口
└─ 导入/导出/打印扩展点
↓
SxbColumnSetting 列设置组件
├─ 显示/隐藏
├─ 冻结列
├─ 对齐方式
├─ 拖拽排序
├─ 列宽设置
└─ 恢复默认
↓
后端 ColumnSettingService
├─ 系统默认配置
├─ 角色默认配置
├─ 用户个人配置
├─ 字段权限过滤
└─ Redis 缓存
↓
MySQL 配置表
├─ sys_table_column_default
├─ sys_role_column_setting
└─ sys_user_column_setting
4.1 三层配置覆盖规则
|--------|----------------------------|---------|
| 层级 | 说明 | 优先级 |
| 系统默认配置 | 由研发或系统管理员预置,保证页面首次打开有合理列结构 | 最低 |
| 角色默认配置 | 按采购员、仓管员、财务、店长等岗位设置默认列 | 中 |
| 用户个人配置 | 用户自行设置的显示列、顺序、宽度、对齐方式等 | 最高 |
最终返回给前端之前,还必须经过字段权限过滤。即使用户配置了某个敏感字段为显示,只要没有字段权限,后端也不能返回该字段配置。
5. 前端控件设计
5.1 目录结构
src/components/sxb-detail-table/
├─ SxbDetailTable.vue # 通用明细列表主体
├─ SxbColumnSettingDialog.vue # 列设置弹窗
├─ SxbColumnSettingButton.vue # 列设置按钮
├─ SxbTableToolbar.vue # 工具栏:刷新、导出、打印、列设置
├─ SxbTablePagination.vue # 分页封装
├─ hooks/
│ ├─ useColumnSetting.ts # 列配置 Hook
│ ├─ useTableQuery.ts # 查询 Hook
│ ├─ useTableSelection.ts # 多选 Hook
│ └─ useTableExport.ts # 导出 Hook
├─ types/
│ └─ table-column.ts # TypeScript 类型定义
└─ api/
└─ column-setting-api.ts # 后端接口封装
5.2 前端列定义模型
export interface SxbColumnConfig {
columnKey: string; // 字段编码,例如 skuCode
columnName: string; // 显示名称,例如 SKU编码
prop?: string; // Element Plus prop,默认等于 columnKey
visible: boolean; // 是否显示
frozen: boolean; // 是否冻结
fixed?: 'left' | 'right' | boolean; // Element Plus fixed
align: 'left' | 'center' | 'right'; // 对齐方式
headerAlign?: 'left' | 'center' | 'right'; // 表头对齐方式
sortNo: number; // 显示顺序
width: number; // 列宽
minWidth?: number; // 最小宽度
required?: boolean; // 是否必显示
sortable?: boolean | 'custom'; // 是否支持排序
formatter?: string; // 格式化器编码,例如 money/date/status
permissionCode?: string; // 字段权限编码
summaryFlag?: boolean; // 是否参与汇总
exportFlag?: boolean; // 是否允许导出
printFlag?: boolean; // 是否允许打印
tooltipFlag?: boolean; // 超长内容是否显示 tooltip
}
5.3 业务页面使用示例
<template>
<SxbDetailTable
table-key="pms_sku_suggest_detail"
row-key="id"
:default-columns="defaultColumns"
:query-api="querySkuSuggestDetail"
:query-params="queryParams"
show-selection
show-index
show-summary
>
<template #toolbar>
<el-button type="primary" @click="handleAdd">新增</el-button>
<el-button @click="handleExport">导出</el-button>
</template>
<template #operation="{ row }">
<el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
<el-button link type="danger" @click="handleDelete(row)">删除</el-button>
</template>
</SxbDetailTable>
</template>
5.4 defaultColumns 示例
const defaultColumns: SxbColumnConfig[] = [
{ columnKey: 'orgName', columnName: '机构', visible: false, frozen: false, align: 'left', sortNo: 10, width: 100 },
{ columnKey: 'shopName', columnName: '门店', visible: true, frozen: false, align: 'left', sortNo: 20, width: 100 },
{ columnKey: 'suggestDate', columnName: '建议日期', visible: true, frozen: false, align: 'left', sortNo: 30, width: 100, formatter: 'date' },
{ columnKey: 'skuCode', columnName: 'SKU编码', visible: true, frozen: false, align: 'left', sortNo: 40, width: 120 },
{ columnKey: 'barcode', columnName: '国际条码', visible: true, frozen: false, align: 'left', sortNo: 50, width: 130 },
{ columnKey: 'skuName', columnName: 'SKU名称', visible: true, frozen: false, align: 'center', sortNo: 60, width: 180, required: true },
{ columnKey: 'processStatusName', columnName: '处理状态', visible: true, frozen: false, align: 'left', sortNo: 70, width: 100 },
{ columnKey: 'suggestQty', columnName: '建议件数', visible: true, frozen: false, align: 'right', sortNo: 80, width: 100, summaryFlag: true },
{ columnKey: 'unitRelation', columnName: '单位关系', visible: true, frozen: false, align: 'right', sortNo: 90, width: 120 }
];
6. 列设置弹窗设计
列设置弹窗用于维护当前表格的展示偏好。弹窗内每一行对应一个列配置项,支持勾选显示、勾选冻结、选择对齐方式、拖拽排序、输入展示宽度。
|--------|-------------|-------------------------------------|
| 字段 | 控件 | 规则 |
| 列名称 | 文本 | 来自 columnName,一般不允许用户修改。 |
| 冻结 | Checkbox | 设置 fixed。冻结列建议限制数量,避免横向滚动异常。 |
| 显示 | Checkbox | 控制 visible。required=true 的列不允许取消显示。 |
| 对齐方式 | Select | 允许 left、center、right,对应居左、居中、居右。 |
| 展示顺序 | 拖拽图标 | 拖拽后重新计算 sortNo,建议间隔 10 保存。 |
| 展示宽度 | InputNumber | 建议 60 到 600,特殊列可配置更大。 |
| 恢复默认 | Button | 清空用户配置,重新加载系统默认配置。 |
| 保存 | Button | 提交当前用户配置到后端。 |
| 关闭 | Button | 关闭弹窗,不保存未提交修改。 |
6.1 列设置交互规则
- 弹窗打开时复制一份临时配置,用户点击保存后才覆盖表格当前配置。
- 勾选显示时,如果该字段被字段权限过滤,则前端不应展示该列配置项。
- 冻结列推荐只允许连续靠左冻结;如支持右侧冻结,需要在列配置中明确 fixed=right。
- 拖拽排序只影响展示顺序,不影响后端查询 SQL 字段。
- 列宽输入需要做数字校验,非法值回退到默认宽度。
- 恢复默认需要二次确认,防止误操作覆盖用户配置。
7. 后端服务设计
7.1 后端包结构
com.sxb.system.columnsetting
├─ controller
│ └─ SysColumnSettingController.java
├─ service
│ ├─ SysColumnSettingService.java
│ └─ impl/SysColumnSettingServiceImpl.java
├─ mapper
│ ├─ SysTableColumnDefaultMapper.java
│ ├─ SysRoleColumnSettingMapper.java
│ └─ SysUserColumnSettingMapper.java
├─ entity
│ ├─ SysTableColumnDefaultEntity.java
│ ├─ SysRoleColumnSettingEntity.java
│ └─ SysUserColumnSettingEntity.java
├─ dto
│ ├─ ColumnSettingQueryDTO.java
│ ├─ ColumnSettingSaveDTO.java
│ └─ ColumnSettingItemDTO.java
├─ vo
│ └─ ColumnSettingVO.java
└─ enums
├─ ColumnAlignEnum.java
└─ ColumnFixedTypeEnum.java
7.2 后端核心服务职责
|-------------------------------------|---------------------------------------------------|
| 方法 | 说明 |
| getUserColumnSetting(tableKey) | 获取当前用户最终列配置,执行系统默认、角色默认、用户配置合并,并进行字段权限过滤。 |
| saveUserColumnSetting(dto) | 保存当前用户列配置,按 userId + tableKey + columnKey 做新增或更新。 |
| resetUserColumnSetting(tableKey) | 删除当前用户个人配置,重新返回默认配置。 |
| initDefaultColumnSetting(dto) | 系统管理员初始化或维护某个 tableKey 的默认列配置。 |
| refreshColumnSettingCache(tableKey) | 刷新 Redis 缓存,避免配置变更后用户仍看到旧配置。 |
8. 数据库表结构设计
第一版建议至少落地两张表:系统默认列配置表和用户列配置表。角色默认配置表可作为第二阶段扩展。如果升鲜宝系统已经有 RBAC 角色体系,角色列配置表可以很自然地接入。
8.1 系统默认列配置表
CREATE TABLE sys_table_column_default (
id BIGINT NOT NULL COMMENT '主键ID',
tenant_id BIGINT DEFAULT NULL COMMENT '租户ID;纯运营系统可为空',
table_key VARCHAR(100) NOT NULL COMMENT '表格业务编码,例如 pms_sku_suggest_detail',
table_name VARCHAR(100) NOT NULL COMMENT '表格名称',
column_key VARCHAR(100) NOT NULL COMMENT '列字段编码',
column_name VARCHAR(100) NOT NULL COMMENT '列显示名称',
prop_name VARCHAR(100) DEFAULT NULL COMMENT '前端绑定属性名,默认等于 column_key',
visible_flag TINYINT NOT NULL DEFAULT 1 COMMENT '默认是否显示:0否,1是',
frozen_flag TINYINT NOT NULL DEFAULT 0 COMMENT '默认是否冻结:0否,1是',
fixed_type VARCHAR(20) NOT NULL DEFAULT 'none' COMMENT '冻结方向:none/left/right',
align_type VARCHAR(20) NOT NULL DEFAULT 'left' COMMENT '对齐方式:left/center/right',
header_align_type VARCHAR(20) DEFAULT NULL COMMENT '表头对齐方式',
sort_no INT NOT NULL DEFAULT 0 COMMENT '默认顺序',
width INT NOT NULL DEFAULT 100 COMMENT '默认宽度',
min_width INT DEFAULT NULL COMMENT '最小宽度',
required_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否必显示:0否,1是',
sortable_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否支持排序:0否,1是',
formatter_type VARCHAR(50) DEFAULT NULL COMMENT '格式化类型:date/money/qty/status等',
summary_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否参与汇总:0否,1是',
export_flag TINYINT NOT NULL DEFAULT 1 COMMENT '是否允许导出:0否,1是',
print_flag TINYINT NOT NULL DEFAULT 1 COMMENT '是否允许打印:0否,1是',
tooltip_flag TINYINT NOT NULL DEFAULT 1 COMMENT '超长内容是否提示:0否,1是',
permission_code VARCHAR(150) DEFAULT NULL COMMENT '字段权限编码',
enable_flag TINYINT NOT NULL DEFAULT 1 COMMENT '启用状态:0停用,1启用',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
create_user BIGINT DEFAULT NULL COMMENT '创建人',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_user BIGINT DEFAULT NULL COMMENT '更新人',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted_flag TINYINT NOT NULL DEFAULT 0 COMMENT '删除标记:0正常,1删除',
PRIMARY KEY (id),
UNIQUE KEY uk_table_column (table_key, column_key),
KEY idx_table_key (table_key),
KEY idx_permission_code (permission_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统默认表格列配置表';
8.2 用户列配置表
CREATE TABLE sys_user_column_setting (
id BIGINT NOT NULL COMMENT '主键ID',
tenant_id BIGINT DEFAULT NULL COMMENT '租户ID;纯运营系统可为空',
user_id BIGINT NOT NULL COMMENT '用户ID',
table_key VARCHAR(100) NOT NULL COMMENT '表格业务编码',
column_key VARCHAR(100) NOT NULL COMMENT '列字段编码',
column_name VARCHAR(100) NOT NULL COMMENT '列显示名称快照',
visible_flag TINYINT NOT NULL DEFAULT 1 COMMENT '是否显示:0否,1是',
frozen_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否冻结:0否,1是',
fixed_type VARCHAR(20) NOT NULL DEFAULT 'none' COMMENT '冻结方向:none/left/right',
align_type VARCHAR(20) NOT NULL DEFAULT 'left' COMMENT '对齐方式:left/center/right',
sort_no INT NOT NULL DEFAULT 0 COMMENT '显示顺序',
width INT NOT NULL DEFAULT 100 COMMENT '展示宽度',
required_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否必显示:0否,1是',
version INT NOT NULL DEFAULT 1 COMMENT '配置版本号',
create_user BIGINT DEFAULT NULL COMMENT '创建人',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_user BIGINT DEFAULT NULL COMMENT '更新人',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted_flag TINYINT NOT NULL DEFAULT 0 COMMENT '删除标记:0正常,1删除',
PRIMARY KEY (id),
UNIQUE KEY uk_user_table_column (user_id, table_key, column_key),
KEY idx_user_table (user_id, table_key),
KEY idx_table_key (table_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表格列配置表';
8.3 角色列配置表(增强版)
CREATE TABLE sys_role_column_setting (
id BIGINT NOT NULL COMMENT '主键ID',
tenant_id BIGINT DEFAULT NULL COMMENT '租户ID;纯运营系统可为空',
role_id BIGINT NOT NULL COMMENT '角色ID',
table_key VARCHAR(100) NOT NULL COMMENT '表格业务编码',
column_key VARCHAR(100) NOT NULL COMMENT '列字段编码',
visible_flag TINYINT NOT NULL DEFAULT 1 COMMENT '是否显示:0否,1是',
frozen_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否冻结:0否,1是',
fixed_type VARCHAR(20) NOT NULL DEFAULT 'none' COMMENT '冻结方向:none/left/right',
align_type VARCHAR(20) NOT NULL DEFAULT 'left' COMMENT '对齐方式:left/center/right',
sort_no INT NOT NULL DEFAULT 0 COMMENT '显示顺序',
width INT NOT NULL DEFAULT 100 COMMENT '展示宽度',
enable_flag TINYINT NOT NULL DEFAULT 1 COMMENT '启用状态:0停用,1启用',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
deleted_flag TINYINT NOT NULL DEFAULT 0 COMMENT '删除标记:0正常,1删除',
PRIMARY KEY (id),
UNIQUE KEY uk_role_table_column (role_id, table_key, column_key),
KEY idx_role_table (role_id, table_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表格列配置表';
9. 接口设计
9.1 获取列配置
GET /api/system/column-setting/get?tableKey=pms_sku_suggest_detail
返回示例:
{
"code": 0,
"msg": "success",
"data": [
{
"columnKey": "skuName",
"columnName": "SKU名称",
"prop": "skuName",
"visible": true,
"frozen": false,
"fixed": "none",
"align": "center",
"sortNo": 60,
"width": 180,
"required": true,
"sortable": false,
"formatter": null,
"summaryFlag": false,
"exportFlag": true,
"printFlag": true,
"tooltipFlag": true
}
]
}
9.2 保存列配置
POST /api/system/column-setting/save
Content-Type: application/json
{
"tableKey": "pms_sku_suggest_detail",
"columns": [
{
"columnKey": "skuName",
"columnName": "SKU名称",
"visible": true,
"frozen": false,
"fixed": "none",
"align": "center",
"sortNo": 60,
"width": 180,
"required": true
}
]
}
9.3 恢复默认配置
POST /api/system/column-setting/reset
Content-Type: application/json
{
"tableKey": "pms_sku_suggest_detail"
}
10. 权限、缓存与多语言设计
10.1 字段权限联动
列设置控制的是"用户想不想看",字段权限控制的是"用户能不能看"。最终返回列配置时,后端必须先按用户权限过滤字段。比如成本价、毛利、供应商结算价、客户授信额度、客户余额等敏感字段,不能只靠前端隐藏。
最终列 = 合并后的列配置 - 当前用户无字段权限的列
10.2 数据权限关系
数据权限控制行,例如只能看本门店、本机构、本仓库、本客户经理的数据;列配置控制列,例如 SKU编码、单位关系、建议件数是否显示。两者必须解耦。
10.3 Redis 缓存设计
|-------------------------------------|-------------------|------------|
| 缓存 Key | 说明 | 建议 TTL |
| sxb:column:user:{userId}:{tableKey} | 用户最终列配置缓存 | 30 分钟 |
| sxb:column:default:{tableKey} | 系统默认列配置缓存 | 2 小时 |
| sxb:field-permission:{userId} | 用户字段权限缓存 | 30 分钟 |
| sxb:column:version:{tableKey} | 配置版本,用于前端判断是否需要刷新 | 长期 |
10.4 多语言列名
如果升鲜宝后续启用多语言,列名不建议直接写死在用户配置表中。用户配置表的 column_name 只作为快照,正式显示应优先从 sys_table_column_default_i18n 或前端 i18n 资源中获取。
11. 关键业务流程
11.1 页面加载流程
用户打开业务页面
↓
前端根据 tableKey 调用 /column-setting/get
↓
后端查询用户配置
↓
没有用户配置则查询角色配置
↓
没有角色配置则查询系统默认配置
↓
执行字段权限过滤
↓
返回最终列配置
↓
SxbDetailTable 按列配置渲染表格
↓
调用业务查询接口加载数据
11.2 保存配置流程
用户点击列设置
↓
弹出 SxbColumnSettingDialog
↓
用户调整显示、冻结、对齐、顺序、宽度
↓
点击保存
↓
前端校验 required 字段、宽度、冻结数量
↓
提交后端 save 接口
↓
后端再次校验合法性
↓
批量 upsert 用户配置
↓
删除 Redis 用户列配置缓存
↓
返回保存成功
↓
前端刷新表格列
12. 代码骨架
12.1 DTO
@Data
public class ColumnSettingSaveDTO {
@NotBlank(message = "表格编码不能为空")
private String tableKey;
@NotEmpty(message = "列配置不能为空")
private List<ColumnSettingItemDTO> columns;
}
@Data
public class ColumnSettingItemDTO {
@NotBlank(message = "列字段编码不能为空")
private String columnKey;
@NotBlank(message = "列名称不能为空")
private String columnName;
@NotNull(message = "显示状态不能为空")
private Boolean visible;
@NotNull(message = "冻结状态不能为空")
private Boolean frozen;
private String fixed;
@NotBlank(message = "对齐方式不能为空")
private String align;
@NotNull(message = "排序号不能为空")
private Integer sortNo;
@NotNull(message = "列宽不能为空")
private Integer width;
private Boolean required;
}
12.2 Controller
@RestController
@RequestMapping("/api/system/column-setting")
public class SysColumnSettingController {
@Resource
private SysColumnSettingService sysColumnSettingService;
@GetMapping("/get")
public Result<List<ColumnSettingVO>> get(@RequestParam String tableKey) {
return Result.ok(sysColumnSettingService.getUserColumnSetting(tableKey));
}
@PostMapping("/save")
public Result<Void> save(@Valid @RequestBody ColumnSettingSaveDTO dto) {
sysColumnSettingService.saveUserColumnSetting(dto);
return Result.ok();
}
@PostMapping("/reset")
public Result<List<ColumnSettingVO>> reset(@RequestBody ColumnSettingResetDTO dto) {
return Result.ok(sysColumnSettingService.resetUserColumnSetting(dto.getTableKey()));
}
}
12.3 Service 关键逻辑伪代码
@Override
public List<ColumnSettingVO> getUserColumnSetting(String tableKey) {
Long userId = LoginUserContext.getUserId();
// 1. 查询缓存
String cacheKey = ColumnCacheKey.user(userId, tableKey);
List<ColumnSettingVO> cached = redisCache.get(cacheKey);
if (CollectionUtils.isNotEmpty(cached)) {
return cached;
}
// 2. 查询用户配置
List<ColumnSettingVO> columns = userColumnSettingMapper.selectByUserAndTable(userId, tableKey);
// 3. 用户配置不存在,则查询角色配置
if (CollectionUtils.isEmpty(columns)) {
columns = roleColumnSettingMapper.selectByUserRoleAndTable(userId, tableKey);
}
// 4. 角色配置不存在,则查询系统默认配置
if (CollectionUtils.isEmpty(columns)) {
columns = tableColumnDefaultMapper.selectByTableKey(tableKey);
}
// 5. 字段权限过滤
columns = fieldPermissionEngine.filterColumns(userId, tableKey, columns);
// 6. 排序并缓存
columns = columns.stream()
.sorted(Comparator.comparing(ColumnSettingVO::getSortNo))
.collect(Collectors.toList());
redisCache.set(cacheKey, columns, Duration.ofMinutes(30));
return columns;
}
13. 异常处理与校验规则
|--------------|-----------------------|-------------------|
| 校验项 | 规则 | 错误提示 |
| tableKey | 不能为空,长度不超过 100 | 表格编码不能为空或长度超限 |
| columnKey | 不能为空,长度不超过 100 | 列字段编码不能为空或长度超限 |
| align | 只能是 left、center、right | 对齐方式不合法 |
| fixed | 只能是 none、left、right | 冻结方向不合法 |
| width | 建议 60 到 600 | 列宽必须在 60 到 600 之间 |
| required | 必显示列不允许隐藏 | 必显示列不能取消显示 |
| frozen count | 冻结列建议不超过 5 个 | 冻结列数量超过限制 |
| permission | 无字段权限的列不能保存为可见 | 无权限显示该字段 |
14. 测试用例与验收标准
14.1 核心测试用例
|--------|---------------|-------------------------|
| 编号 | 测试场景 | 预期结果 |
| TC001 | 首次打开没有用户配置的页面 | 加载系统默认列配置并正常展示。 |
| TC002 | 用户隐藏某一列并保存 | 刷新页面后该列仍保持隐藏。 |
| TC003 | 用户调整列顺序并保存 | 刷新页面后列顺序保持调整后的顺序。 |
| TC004 | 用户修改列宽并保存 | 刷新页面后列宽保持调整后的宽度。 |
| TC005 | 用户设置 SKU名称居中 | 表格 SKU名称列内容居中显示。 |
| TC006 | 用户点击恢复默认 | 删除个人配置并恢复系统默认列。 |
| TC007 | 用户无成本价字段权限 | 列设置弹窗和表格都不出现成本价列。 |
| TC008 | 必显示列取消显示 | 前端禁止取消,后端也拒绝保存。 |
| TC009 | 多端登录同一用户 | 配置保存后另一端刷新可加载最新配置。 |
| TC010 | 导出跟随当前列配置 | 导出字段与当前可见列一致,且不导出无权限字段。 |
14.2 验收标准
- 至少接入一个商品明细页面、一个订单明细页面、一个 WMS 明细页面进行验证。
- 列显示、隐藏、排序、宽度、对齐、冻结、恢复默认全部可用。
- 刷新浏览器、重新登录、更换电脑后用户配置仍然生效。
- 无字段权限的列不能通过接口返回,也不能通过前端列配置绕过。
- 表格数据量较大时,列配置加载不应明显拖慢页面,建议接口耗时小于 200ms。
- 配置表具有唯一索引和必要查询索引,支持长期扩展。
15. 实施路线图
|-----------|-----------------------|------------------------------------------------------------------|
| 阶段 | 目标 | 交付内容 |
| 第一阶段:MVP | 完成通用列设置能力 | SxbColumnSettingDialog、useColumnSetting、两张配置表、get/save/reset 接口。 |
| 第二阶段:组件化 | 完成 SxbDetailTable 主控件 | 统一分页、排序、选择、汇总、空状态、工具栏、操作列插槽。 |
| 第三阶段:权限联动 | 接入字段权限和数据权限 | 字段权限过滤、敏感字段控制、权限缓存刷新。 |
| 第四阶段:生态联动 | 导入导出、打印、低代码配置 | 导出字段跟随列配置、打印字段跟随列配置、系统默认列后台维护。 |
| 第五阶段:高级能力 | 角色配置、多语言、移动端适配 | 角色默认列配置、多语言列名、移动端列折叠策略。 |
附录 A:tableKey 命名规范
建议采用"模块_业务对象_使用场景"的命名方式,全部使用小写字母、数字和下划线。
|--------|-------------------------------------------------------------------|
| 模块 | 命名示例 |
| 商品 | pms_goods_list、pms_sku_list、pms_sku_unit_detail |
| 采购 | pur_order_list、pur_order_detail、pur_stockin_plan_detail |
| 销售 | oms_order_list、oms_order_detail、oms_stockout_detail |
| 仓库 | wms_stockin_detail、wms_stockout_detail、wms_stocktake_detail |
| 门店仓 | hwms_inventory_detail、hwms_stocktake_detail、hwms_pick_task_detail |
| 财务 | fin_customer_bill_detail、fin_supplier_bill_detail |
| 日志 | log_operation_list、log_api_list |
附录 B:推荐开发原则
- 业务页面只声明列,不实现列设置逻辑。
- 前端隐藏不是安全手段,敏感字段必须由后端过滤。
- 组件必须支持插槽,避免为不同业务页面写多个变体。
- 配置数据必须可恢复默认,避免用户误配置后无法找回。
- 字段编码 columnKey 一旦上线应保持稳定,避免用户配置失效。
- 列配置不应该参与业务 SQL 拼接,避免引入 SQL 注入和字段泄露风险。
- 所有 deleted_flag、enable_flag、visible_flag 等字段统一使用 flag 后缀,不使用 is_ 前缀。
结论
通用明细列表控件是升鲜宝供应链管理系统非常重要的基础能力。它可以显著降低各业务模块的列表开发成本,统一用户体验,并为字段权限、数据权限、导入导出、打印、多语言和低代码配置打下基础。建议优先按照 MVP 版本落地,再逐步扩展角色配置、权限联动和生态能力。