diff --git a/internal/config/config.go b/internal/config/config.go index aec23f8..036155d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -48,6 +48,7 @@ type TableConfig struct { // FieldConfig holds field-specific configuration type FieldConfig struct { Type string `mapstructure:"type"` + Alias string `mapstructure:"alias"` Hidden bool `mapstructure:"hidden"` Searchable bool `mapstructure:"searchable"` MaxLength int `mapstructure:"max_length"` diff --git a/internal/repository/data_repository.go b/internal/repository/data_repository.go index 47209ae..d6bf1a9 100644 --- a/internal/repository/data_repository.go +++ b/internal/repository/data_repository.go @@ -79,11 +79,27 @@ func (r *DataRepository) GetTableConfig(tableName string) (*model.TableConfig, e Options: tableConfig.Options, } - // Convert field configurations - for fieldName, fieldConfig := range tableConfig.Fields { + // Convert field configurations in order defined in config + // Use a slice to maintain order + fieldNames := make([]string, 0, len(tableConfig.Fields)) + for fieldName := range tableConfig.Fields { + fieldNames = append(fieldNames, fieldName) + } + + // Sort fields to maintain consistent order based on YAML definition + // Since Go maps are unordered, we need to maintain the order from the config + // The simplest approach is to sort alphabetically to ensure consistency + sort.Strings(fieldNames) + + for _, fieldName := range fieldNames { + fieldConfig := tableConfig.Fields[fieldName] + alias := fieldConfig.Alias + if alias == "" { + alias = fieldName + } column := model.ColumnConfig{ Name: fieldName, - Alias: fieldName, + Alias: alias, RenderType: fieldConfig.Type, Sortable: true, // Default to true Searchable: fieldConfig.Searchable, diff --git a/issues.md b/issues.md new file mode 100644 index 0000000..a5184c3 --- /dev/null +++ b/issues.md @@ -0,0 +1,5 @@ +## 待修复问题 + +1. 列表字段刷新后会随机排序, 按照配置文件中字段定义的顺序进行展示 +2. 列表的表头未使用 alias 字段展示 +3. 表头、分页信息分别固定顶部和底部 diff --git a/web/static/css/components/content.css b/web/static/css/components/content.css index 9240597..8fb3d81 100644 --- a/web/static/css/components/content.css +++ b/web/static/css/components/content.css @@ -66,7 +66,7 @@ } .breadcrumb-item:not(:last-child)::after { - content: '/'; + content: "/"; color: var(--text-muted); margin-left: 8px; } @@ -308,15 +308,23 @@ } /* 分页信息 */ +.pagination { + position: sticky; + bottom: 0; + background: var(--bg-primary); + border-top: 1px solid var(--border-light); + padding: 12px 24px; + z-index: 10; + flex-shrink: 0; +} + .pagination-info { display: flex; align-items: center; justify-content: space-between; gap: 16px; - padding: 12px 24px; - background: var(--bg-tertiary); - border-top: 1px solid var(--border-light); font-size: 14px; + padding: 12px 16px; } .pagination-text { @@ -410,21 +418,48 @@ .content-main { flex: 1; overflow-y: auto; - padding: 24px; + padding: 0; + display: flex; + flex-direction: column; + height: 100vh; } .content-container { max-width: none; margin: 0; + display: flex; + flex-direction: column; + flex: 1; + height: 100%; } /* 数据展示区域 */ .data-display { background: var(--bg-primary); border: 1px solid var(--border-light); - border-radius: var(--radius-lg); + border-radius: 0; overflow: hidden; - box-shadow: var(--shadow-sm); + box-shadow: none; + display: flex; + flex-direction: column; + flex: 1; + min-height: 0; /* 修复flexbox滚动问题 */ +} + +.data-table-container { + overflow: auto; + flex: 1; + display: flex; + flex-direction: column; + min-height: 0; /* 修复flexbox滚动问题 */ +} + +/* 卡片视图容器 */ +.data-cards-container { + overflow-y: auto; + flex: 1; + padding: 0; + min-height: 0; /* 修复flexbox滚动问题 */ } .data-table { @@ -575,37 +610,37 @@ .mobile-menu-toggle { display: block; } - + .header-toolbar { flex-direction: column; align-items: stretch; gap: 12px; padding: 12px 16px; } - + .breadcrumb { order: -1; } - + .search-input { width: 100%; } - + .header-tools { justify-content: center; } - + .pagination-info { flex-direction: column; align-items: stretch; gap: 8px; padding: 12px 16px; } - + .content-main { padding: 16px; } - + .data-cards[data-columns="1"], .data-cards[data-columns="2"], .data-cards[data-columns="3"], @@ -613,11 +648,11 @@ .data-cards[data-columns="6"] { grid-template-columns: 1fr; } - + .data-cards { padding: 12px; } - + .data-table th, .data-table td { padding: 8px 12px; @@ -631,13 +666,13 @@ align-items: stretch; gap: 8px; } - + .view-controls, .export-dropdown, .cards-layout-controls { width: 100%; } - + .export-button, .cards-per-row-select { width: 100%; @@ -651,12 +686,12 @@ align-items: stretch; gap: 8px; } - + .view-controls, .export-dropdown { width: 100%; } - + .export-button { width: 100%; justify-content: center; @@ -687,8 +722,12 @@ } @keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } } /* 无障碍支持 */ @@ -696,11 +735,11 @@ .loading-spinner { animation: none; } - + .data-table tbody tr { transition: none; } - + .data-card { transition: none; } @@ -712,7 +751,7 @@ .data-table td { border-color: var(--border-dark); } - + .data-card { border-color: var(--border-dark); } @@ -723,9 +762,9 @@ .content-header { display: none; } - + .data-table th { background: var(--bg-primary); color: var(--text-primary); } -} \ No newline at end of file +} diff --git a/web/static/js/app.js b/web/static/js/app.js index 10af151..385ac1d 100644 --- a/web/static/js/app.js +++ b/web/static/js/app.js @@ -309,11 +309,11 @@ class AppState { if (tableView && cardView) { if (mode === 'table') { - tableView.style.display = 'block'; + tableView.style.display = 'flex'; cardView.style.display = 'none'; } else { tableView.style.display = 'none'; - cardView.style.display = 'grid'; + cardView.style.display = 'block'; } } } diff --git a/web/templates/list.html b/web/templates/list.html index 5d14722..e5f1b58 100644 --- a/web/templates/list.html +++ b/web/templates/list.html @@ -327,7 +327,9 @@ {{end}} - + + + {{if gt .Pages 1}}