Commit c2458d09 authored by drigle's avatar drigle

feat: support configurable view filter fields

parent a67d1567
...@@ -6,7 +6,7 @@ import { ...@@ -6,7 +6,7 @@ import {
cloneRecord, cloneRecord,
} from '@/services/DataService'; } from '@/services/DataService';
import { Copy, Delete, Edit, PlusIcon } from '@/components/AppIcons'; import { Copy, Delete, Edit, PlusIcon } from '@/components/AppIcons';
import { getReferenceSubjectName, getSelectOptions, isDateFieldType, isReferenceFieldType } from '@/utils/subjectView'; import { buildViewColumns, getReferenceSubjectName, getSelectOptions, isDateFieldType, isReferenceFieldType } from '@/utils/subjectView';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import DynamicRecordDialog from './DynamicRecordDialog'; import DynamicRecordDialog from './DynamicRecordDialog';
import { import {
...@@ -23,6 +23,33 @@ const BOOLEAN_FILTER_OPTIONS = [ ...@@ -23,6 +23,33 @@ const BOOLEAN_FILTER_OPTIONS = [
{ label: '否', value: 'false' }, { label: '否', value: 'false' },
]; ];
function normalizeFilterFieldPath(field) {
const value = typeof field === 'string' ? field.trim() : '';
if (!value) return '';
return value === 'title' || value.startsWith('metadata.')
? value
: `metadata.${value}`;
}
function resolveFilterColumns(view, columns = [], subject) {
const configuredFields = view?.settings?.filters?.fields;
// Preserve the existing visible-column fallback when the setting is absent.
if (!Array.isArray(configuredFields)) return columns;
const allViewColumns = buildViewColumns(view, subject, { includeHidden: true });
const columnsByField = new Map(
[...allViewColumns, ...columns].map((column) => [column.field, column]),
);
return configuredFields
.map((item) => {
const configuredField = typeof item === 'string'
? item
: item?.field || item?.path || item?.name;
return columnsByField.get(normalizeFilterFieldPath(configuredField));
})
.filter(Boolean);
}
function buildFilterSchema(columns = []) { function buildFilterSchema(columns = []) {
return columns.reduce((fields, column) => { return columns.reduce((fields, column) => {
const fieldDef = column?.fieldDef || {}; const fieldDef = column?.fieldDef || {};
...@@ -204,8 +231,8 @@ export default function SubjectRecordWorkbench({ ...@@ -204,8 +231,8 @@ export default function SubjectRecordWorkbench({
}, [filteredRecords]); }, [filteredRecords]);
const filterSchema = useMemo(() => { const filterSchema = useMemo(() => {
return buildFilterSchema(visibleColumns); return buildFilterSchema(resolveFilterColumns(activeView, visibleColumns, subject));
}, [visibleColumns]); }, [activeView, subject, visibleColumns]);
const feedbackHelpers = useMemo(() => ({ const feedbackHelpers = useMemo(() => ({
reload, reload,
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
## 2. 项目列表与详情 ## 2. 项目列表与详情
1. 页面通过 `loadSubject`、`getSubjectView` 和 `POST /record/query` 读取字段、视图和记录。 1. 页面通过 `loadSubject`、`getSubjectView` 和 `POST /record/query` 读取字段、视图和记录。
2. 表格列、视图限制、排序、选择字段选项和字段分组来自服务端配置;字段分组读取当前 Grid View 的 `settings.groups`,按配置展示分组表头并支持展开或收起。当前 Grid View 的 `settings.shortTitle === true` 时隐藏通用 `title` 展示列及新建/编辑弹窗中的根记录标题字段;`false` 或未配置时正常展示。隐藏时不校验或提交根级 `title`,`title` 数据仍可参与排序、详情和其他保存流程,详情入口保留在项目名称和固定操作列。筛选清单根据当前 View 的字段配置和类型自动生成,文本类字段使用模糊匹配,选择/布尔字段使用枚举值,日期使用当天范围,数字使用精确值,引用/用户字段使用 ID;用户填写或选择条件后点击“查询”才提交,所有字段筛选与分页均通过 `POST /record/query` 远程执行,浏览器不再加载全部记录后本地过滤。 2. 表格列、视图限制、排序、选择字段选项和字段分组来自服务端配置;字段分组读取当前 Grid View 的 `settings.groups`,按配置展示分组表头并支持展开或收起。当前 Grid View 的 `settings.shortTitle === true` 时隐藏通用 `title` 展示列及新建/编辑弹窗中的根记录标题字段;`false` 或未配置时正常展示。筛选清单默认使用当前 Grid View 的可见列;如 View 的 `settings.filters.fields` 配置了字段数组,则仅按该数组顺序展示筛选控件,显式配置可引用 View 中的隐藏列。数组项支持字段路径字符串(如 `metadata.project_status` 或 `project_status`)及 `{ field }` 对象;配置为空数组表示该视图不展示筛选控件,未配置该属性时才回退到可见列。无效字段会被忽略,固定条件仍由 `settings.filters.conditions` 执行。文本类字段使用模糊匹配,选择/布尔字段使用枚举值,日期使用当天范围,数字使用精确值,引用/用户字段使用 ID;用户填写或选择条件后点击“查询”才提交,所有字段筛选与分页均通过 `POST /record/query` 远程执行,浏览器不再加载全部记录后本地过滤。
切换 Grid View 时立即切换当前视图、清空跨视图选择并回到第一页,同时重新读取 Subject、视图配置和 `/record/query` 数据;不再额外写死项目状态筛选,当前视图配置包含该字段时才自动生成对应的选择筛选,视图标签仍用于切换服务端配置的视图限制;刷新期间不展示上一次请求的记录行,表格在当前可视区域中心显示加载状态,失败时保留错误反馈并清空不可确认的旧数据。 切换 Grid View 时立即切换当前视图、清空跨视图选择并回到第一页,同时重新读取 Subject、视图配置和 `/record/query` 数据;不再额外写死项目状态筛选,当前视图配置包含该字段时才自动生成对应的选择筛选,视图标签仍用于切换服务端配置的视图限制;刷新期间不展示上一次请求的记录行,表格在当前可视区域中心显示加载状态,失败时保留错误反馈并清空不可确认的旧数据。
项目列表表格使用限定高度的内部滚动区域,支持纵向和横向滚动;表头在表格滚动区域内吸顶,分页位于滚动区域外,避免页面因记录行过多持续向下延伸。 项目列表表格使用限定高度的内部滚动区域,支持纵向和横向滚动;表头在表格滚动区域内吸顶,分页位于滚动区域外,避免页面因记录行过多持续向下延伸。
View 中兼容历史字段 `metadata.project_finish_time` 时按数据定义显示为“项目完成时间”; View 中兼容历史字段 `metadata.project_finish_time` 时按数据定义显示为“项目完成时间”;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment