Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
I
integrity_practice_management_new
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
David Yang
integrity_practice_management_new
Commits
f99189d9
Commit
f99189d9
authored
Oct 09, 2026
by
drigle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: 完善引用选择与表格列分组显示
parent
b08715fd
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
149 additions
and
51 deletions
+149
-51
manifest.json
public/manifest.json
+1
-1
ReferenceSearchSelect.jsx
src/components/ReferenceSearchSelect.jsx
+58
-48
index.jsx
src/components/record-workbench/index.jsx
+0
-0
shell.css
src/design-system/shell.css
+45
-0
SubjectWorkbench.jsx
src/pages/integrity_practice_management/SubjectWorkbench.jsx
+16
-2
integrity-practice-management.business-flow.md
...management/integrity-practice-management.business-flow.md
+13
-0
subjectView.js
src/utils/subjectView.js
+1
-0
tableFieldDisplay.test.mjs
tests/tableFieldDisplay.test.mjs
+15
-0
No files found.
public/manifest.json
View file @
f99189d9
{
{
"name"
:
"integrity_practice_management_new"
,
"name"
:
"integrity_practice_management_new"
,
"version"
:
"1.0.1
1
"
,
"version"
:
"1.0.1
3
"
,
"build"
:
"abc"
,
"build"
:
"abc"
,
"description"
:
"廉洁从业管理"
,
"description"
:
"廉洁从业管理"
,
"date"
:
"2025-07-14 19:27:20"
,
"date"
:
"2025-07-14 19:27:20"
,
...
...
src/components/ReferenceSearchSelect.jsx
View file @
f99189d9
import
XinyuanAutocomplete
from
'@/components/XinyuanAutocomplete
'
;
import
{
ChevronDown
,
Close
,
Search
}
from
'@/components/AppIcons
'
;
import
useFeedbackState
from
'@/hooks/useFeedbackState'
;
import
useFeedbackState
from
'@/hooks/useFeedbackState'
;
import
{
queryRecords
}
from
'@/services/DataService'
;
import
{
queryRecords
}
from
'@/services/DataService'
;
import
{
Label
}
from
'@heroui/react'
;
import
{
Button
,
Label
,
ListBox
,
Popover
,
SearchField
,
Spinner
}
from
'@heroui/react'
;
import
{
useEffect
,
useMemo
,
useRef
,
useState
}
from
'react'
;
import
{
useEffect
,
useMemo
,
useRef
,
useState
}
from
'react'
;
const
DEFAULT_ID_LOOKUP_CHUNK_SIZE
=
50
;
const
DEFAULT_ID_LOOKUP_CHUNK_SIZE
=
50
;
...
@@ -541,26 +541,16 @@ export default function ReferenceSearchSelect({
...
@@ -541,26 +541,16 @@ export default function ReferenceSearchSelect({
.
join
(
'、'
)}
等
${
selectedOptions
.
length
}
项`
.
join
(
'、'
)}
等
${
selectedOptions
.
length
}
项`
:
selectedOptions
[
0
]?.
label
||
placeholder
;
:
selectedOptions
[
0
]?.
label
||
placeholder
;
const
selectionProps
=
multiple
const
handleSelectionChange
=
(
keys
)
=>
{
?
{
const
nextIds
=
keys
===
'all'
?
menuOptions
.
map
((
item
)
=>
item
.
id
)
:
Array
.
from
(
keys
||
[]).
map
(
String
);
selectedKeys
:
new
Set
(
selectedIds
),
onSelectionChange
:
(
keys
)
=>
{
const
nextIds
=
keys
===
'all'
?
menuOptions
.
map
((
item
)
=>
item
.
id
)
:
[...
keys
];
commitChange
(
nextIds
);
commitChange
(
nextIds
);
},
if
(
!
multiple
)
handleOpenChange
(
false
);
}
:
{
selectedKey
:
selectedIds
[
0
]
||
null
,
onSelectionChange
:
(
key
)
=>
{
const
nextKey
=
key
?
String
(
key
)
:
''
;
commitChange
(
nextKey
?
[
String
(
nextKey
)]
:
[]);
setActive
(
false
);
},
};
};
const
handleOpenChange
=
(
isOpen
)
=>
{
const
handleOpenChange
=
(
isOpen
)
=>
{
if
(
disabled
)
return
;
setActive
(
isOpen
);
setActive
(
isOpen
);
if
(
isOpen
)
setLoading
(
true
);
if
(
!
isOpen
)
{
if
(
!
isOpen
)
{
setQuery
(
''
);
setQuery
(
''
);
setError
(
''
);
setError
(
''
);
...
@@ -568,42 +558,62 @@ export default function ReferenceSearchSelect({
...
@@ -568,42 +558,62 @@ export default function ReferenceSearchSelect({
};
};
return
(
return
(
<
XinyuanAutocomplete
<
Popover
.
Root
isOpen=
{
active
}
onOpenChange=
{
handleOpenChange
}
>
{
...
selectionProps
}
<
Button
aria
-
label=
{
placeholder
}
aria
-
label=
{
placeholder
}
emptyText=
"无匹配结果"
className=
"rc-reference-select-trigger"
errorText=
{
error
}
fullWidth
inputValue=
{
query
}
isDisabled=
{
disabled
}
isDisabled=
{
disabled
}
isClearable=
{
allowClear
}
variant=
{
variant
||
'secondary'
}
isLoading=
{
loading
}
isOpen=
{
active
}
options=
{
menuOptions
}
placement=
{
optionsAnchor
||
'bottom start'
}
placeholder=
{
placeholder
}
searchPlaceholder=
{
placeholder
}
selectionMode=
{
multiple
?
'multiple'
:
'single'
}
shouldFilter=
{
false
}
valueText=
{
displayText
}
variant=
{
variant
}
onInputChange=
{
setQuery
}
onClear=
{
clearSelection
}
onOpenChange=
{
handleOpenChange
}
renderOption=
{
(
option
)
=>
(
<
div
className=
"min-w-0 flex-1 overflow-hidden"
>
<
Label
className=
"block truncate"
title=
{
option
.
label
}
>
{
option
.
label
}
</
Label
>
{
option
.
description
?
(
<
div
className=
"truncate text-xs text-muted"
title=
{
option
.
description
}
>
>
{
option
.
description
}
<
span
className=
"rc-reference-select-trigger__value"
title=
{
selectedOptions
.
map
((
option
)
=>
option
.
label
).
join
(
'、'
)
||
placeholder
}
>
{
displayText
}
</
span
>
<
span
className=
"rc-reference-select-trigger__indicator"
><
ChevronDown
size=
{
16
}
/></
span
>
</
Button
>
<
Popover
.
Content
className=
"rc-reference-select-popover"
placement=
{
optionsAnchor
||
'bottom start'
}
>
<
Popover
.
Dialog
aria
-
label=
{
placeholder
}
className=
"min-w-0 p-0"
>
<
div
className=
"flex items-center justify-between gap-3 px-3 pb-2 pt-3"
>
<
span
className=
"text-sm text-muted"
>
已选择
{
selectedIds
.
length
}
项
</
span
>
{
allowClear
?
<
Button
size=
"sm"
variant=
"tertiary"
onPress=
{
clearSelection
}
>
清空
</
Button
>
:
null
}
</
div
>
</
div
>
)
:
null
}
<
div
className=
"px-2 pb-2"
>
<
SearchField
aria
-
label=
"搜索引用记录"
fullWidth
value=
{
query
}
onChange=
{
setQuery
}
variant=
{
variant
||
'secondary'
}
>
<
SearchField
.
Group
>
<
SearchField
.
SearchIcon
><
Search
size=
{
16
}
/></
SearchField
.
SearchIcon
>
<
SearchField
.
Input
autoFocus
placeholder=
{
placeholder
}
/>
<
SearchField
.
ClearButton
aria
-
label=
"清空搜索"
><
Close
size=
{
14
}
/></
SearchField
.
ClearButton
>
</
SearchField
.
Group
>
</
SearchField
>
</
div
>
</
div
>
{
loading
?
(
<
div
className=
"grid min-h-24 place-items-center"
role=
"status"
><
Spinner
size=
"sm"
aria
-
label=
"搜索中"
/></
div
>
)
:
error
?
(
<
div
className=
"px-3 py-4 text-sm text-danger"
role=
"alert"
>
{
error
}
</
div
>
)
:
menuOptions
.
length
===
0
?
(
<
div
className=
"px-3 py-4 text-center text-sm text-muted"
role=
"status"
>
无匹配结果
</
div
>
)
:
(
<
ListBox
aria
-
label=
{
placeholder
}
className=
"rc-reference-select-options"
items=
{
menuOptions
}
selectedKeys=
{
new
Set
(
selectedIds
)
}
selectionMode=
{
multiple
?
'multiple'
:
'single'
}
onSelectionChange=
{
handleSelectionChange
}
>
{
(
option
)
=>
(
<
ListBox
.
Item
className=
"rc-reference-select-option"
id=
{
option
.
id
}
textValue=
{
option
.
label
}
>
<
div
className=
"min-w-0 flex-1 overflow-hidden"
>
<
Label
className=
"block truncate"
title=
{
option
.
label
}
>
{
option
.
label
}
</
Label
>
{
option
.
description
?
<
div
className=
"truncate text-xs text-muted"
title=
{
option
.
description
}
>
{
option
.
description
}
</
div
>
:
null
}
</
div
>
<
ListBox
.
ItemIndicator
/>
</
ListBox
.
Item
>
)
}
</
ListBox
>
)
}
)
}
/>
</
Popover
.
Dialog
>
</
Popover
.
Content
>
</
Popover
.
Root
>
);
);
}
}
src/components/record-workbench/index.jsx
View file @
f99189d9
This diff is collapsed.
Click to expand it.
src/design-system/shell.css
View file @
f99189d9
...
@@ -1716,3 +1716,48 @@
...
@@ -1716,3 +1716,48 @@
outline
:
2px
solid
var
(
--rc-sidebar-focus
);
outline
:
2px
solid
var
(
--rc-sidebar-focus
);
outline-offset
:
2px
;
outline-offset
:
2px
;
}
}
.rc-reference-select-trigger
{
display
:
flex
;
justify-content
:
space-between
;
width
:
100%
;
min-width
:
0
;
height
:
40px
;
padding
:
0
12px
;
border
:
1px
solid
var
(
--rc-field-border
,
var
(
--rc-border-default
));
border-radius
:
8px
;
background
:
var
(
--rc-field-background
);
color
:
var
(
--rc-text-primary
);
font-weight
:
400
;
}
.rc-reference-select-trigger__value
{
min-width
:
0
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.rc-reference-select-trigger__indicator
{
display
:
inline-grid
;
place-items
:
center
;
flex
:
0
0
16px
;
color
:
var
(
--rc-text-muted
);
}
.rc-reference-select-popover
{
width
:
var
(
--trigger-width
);
max-width
:
min
(
24rem
,
calc
(
100vw
-
24px
));
border
:
1px
solid
var
(
--rc-border-default
);
border-radius
:
12px
;
background
:
var
(
--rc-bg-surface
);
}
.rc-reference-select-options
{
max-height
:
288px
;
overflow-y
:
auto
;
}
.rc-reference-select-option
[
data-selected
]
{
background
:
var
(
--rc-brand-primary-soft
,
var
(
--accent-soft
));
color
:
var
(
--rc-brand-primary
);
}
src/pages/integrity_practice_management/SubjectWorkbench.jsx
View file @
f99189d9
...
@@ -10,6 +10,7 @@ import { useLocation } from 'umi';
...
@@ -10,6 +10,7 @@ import { useLocation } from 'umi';
import
UserAssignmentDialog
from
'./UserAssignmentDialog'
;
import
UserAssignmentDialog
from
'./UserAssignmentDialog'
;
import
XinyuanAutocomplete
from
'@/components/XinyuanAutocomplete'
;
import
XinyuanAutocomplete
from
'@/components/XinyuanAutocomplete'
;
import
FormDatePicker
from
'@/components/FormDatePicker'
;
import
FormDatePicker
from
'@/components/FormDatePicker'
;
import
ReferenceSearchSelect
from
'@/components/ReferenceSearchSelect'
;
import
{
import
{
getSubjectNameFromPath
,
getSubjectNameFromPath
,
INTEGRITY_PRACTICE_SUBJECT_CONFIG
,
INTEGRITY_PRACTICE_SUBJECT_CONFIG
,
...
@@ -27,7 +28,7 @@ import {
...
@@ -27,7 +28,7 @@ import {
buildIntegrityCreatePayload
,
buildIntegrityCreatePayload
,
}
from
'./integrityPracticeWorkbenchService'
;
}
from
'./integrityPracticeWorkbenchService'
;
import
{
createRecord
}
from
'@/services/DataService'
;
import
{
createRecord
}
from
'@/services/DataService'
;
import
{
getViewRestrictionDefaults
,
getSelectOptions
,
emptyValueForField
,
toArray
}
from
'@/utils/subjectView'
;
import
{
getViewRestrictionDefaults
,
getSelectOptions
,
getReferenceSubjectName
,
isReferenceFieldType
,
emptyValueForField
,
toArray
}
from
'@/utils/subjectView'
;
const
EMPTY_ARRAY
=
[];
const
EMPTY_ARRAY
=
[];
const
MUTATING_ACTION_PATTERN
=
/delete|archive|create|push/i
;
const
MUTATING_ACTION_PATTERN
=
/delete|archive|create|push/i
;
...
@@ -347,6 +348,8 @@ export default function SubjectWorkbench() {
...
@@ -347,6 +348,8 @@ export default function SubjectWorkbench() {
:
'字段、列顺序和视图均来自当前 Subject 配置。'
:
'字段、列顺序和视图均来自当前 Subject 配置。'
}
}
columns=
{
columns
}
columns=
{
columns
}
columnGroups=
{
activeView
?.
settings
?.
groups
||
EMPTY_ARRAY
}
columnGroupScope=
{
`${subjectName}:${activeView?.name || ''}`
}
records=
{
records
}
records=
{
records
}
selectedIds=
{
selectedIds
}
selectedIds=
{
selectedIds
}
onSelectionChange=
{
hasAccessibleView
?
setSelectedIds
:
undefined
}
onSelectionChange=
{
hasAccessibleView
?
setSelectedIds
:
undefined
}
...
@@ -446,7 +449,18 @@ export default function SubjectWorkbench() {
...
@@ -446,7 +449,18 @@ export default function SubjectWorkbench() {
key=
{
field
.
field
}
key=
{
field
.
field
}
>
>
<
Label
>
{
fieldLabel
}
</
Label
>
<
Label
>
{
fieldLabel
}
</
Label
>
{
options
.
length
?
(
{
isReferenceFieldType
(
fieldType
)
?
(
<
ReferenceSearchSelect
subject=
{
getReferenceSubjectName
(
field
.
fieldDef
)
}
value=
{
value
}
multiple=
{
isMultiple
}
disabled=
{
isFieldDisabled
||
actionLoading
}
placeholder=
{
`搜索并选择${fieldLabel}`
}
optionsAnchor=
"bottom start"
selectedSummaryMode=
{
isMultiple
?
'count'
:
'labels'
}
onChange=
{
(
nextValue
)
=>
setCreateValues
((
current
)
=>
({
...
current
,
[
name
]:
nextValue
}))
}
/>
)
:
options
.
length
?
(
<
XinyuanAutocomplete
<
XinyuanAutocomplete
aria
-
label=
{
fieldLabel
}
aria
-
label=
{
fieldLabel
}
isClearable
isClearable
...
...
src/pages/integrity_practice_management/integrity-practice-management.business-flow.md
View file @
f99189d9
...
@@ -33,6 +33,7 @@
...
@@ -33,6 +33,7 @@
9.
当前 Detail 有有效
`settings.auth`
或
`settings.disableColumns`
时,字段权限整套使用 Detail;两项都未配置或没有实际 Detail 时,整体回退打开详情的当前 Grid。两套权限不合并、不逐字段回退;
`disableColumns`
对管理员也始终只读,普通用户在选定权限来源中缺少字段
`auth`
时只读。切换 Detail 后立即重算字段状态和编辑入口,编辑入口只检查当前 Detail 展示字段。Grid
`viewAuth`
只控制 Tab 可见性,不隐藏详情字段。
9.
当前 Detail 有有效
`settings.auth`
或
`settings.disableColumns`
时,字段权限整套使用 Detail;两项都未配置或没有实际 Detail 时,整体回退打开详情的当前 Grid。两套权限不合并、不逐字段回退;
`disableColumns`
对管理员也始终只读,普通用户在选定权限来源中缺少字段
`auth`
时只读。切换 Detail 后立即重算字段状态和编辑入口,编辑入口只检查当前 Detail 展示字段。Grid
`viewAuth`
只控制 Tab 可见性,不隐藏详情字段。
10.
编辑态远程引用字段通过 HeroUI 弹层搜索选择。多值字段在触发器中显示已选数量,可在弹层内连续选择、取消或清空;单值字段选中后关闭弹层。候选标题过长时单行省略但保留全文提示,写入值仍严格为
`_id`
或
`_id[]`
,不改变保存时机和
`metadata`
协议。
10.
编辑态远程引用字段通过 HeroUI 弹层搜索选择。多值字段在触发器中显示已选数量,可在弹层内连续选择、取消或清空;单值字段选中后关闭弹层。候选标题过长时单行省略但保留全文提示,写入值仍严格为
`_id`
或
`_id[]`
,不改变保存时机和
`metadata`
协议。
11.
编辑态的单选和多选属性使用 HeroUI Select/Autocomplete,日期使用 DatePicker,附件使用 HeroUI Pro DropZone;选择后立即更新当前弹窗草稿,最终仍由弹窗底部统一“保存”提交。
11.
编辑态的单选和多选属性使用 HeroUI Select/Autocomplete,日期使用 DatePicker,附件使用 HeroUI Pro DropZone;选择后立即更新当前弹窗草稿,最终仍由弹窗底部统一“保存”提交。
12.
自查底稿填写表的“模板”和“项目结果”等引用字段使用独立受控的 HeroUI Popover + ListBox,点击即打开,候选尚未加载或当前值为空也可展开。打开后显示加载状态并查询目标对象,支持远程搜索、单选/多选与清空;失败时显示错误并可重新搜索或关闭后重开。修改只更新弹窗草稿,取消不写入,保存仍通过
`PUT /record/:name`
提交引用
`_id`
/
`_id[]`
。
异常处理:
异常处理:
...
@@ -40,8 +41,18 @@
...
@@ -40,8 +41,18 @@
-
没有可访问
`grid`
视图时不创建兜底 View、不查询记录,并隐藏新增、批量和行操作;只有一个可访问 View 时隐藏 Tabs 轨道。
-
没有可访问
`grid`
视图时不创建兜底 View、不查询记录,并隐藏新增、批量和行操作;只有一个可访问 View 时隐藏 Tabs 轨道。
-
配置动作执行期间禁用重复点击;成功后使用顶部 Toast,失败时保留当前列表并显示服务端错误。
-
配置动作执行期间禁用重复点击;成功后使用顶部 Toast,失败时保留当前列表并显示服务端错误。
### 2.0 字段分组表头与显示控制
-
各业务列表读取当前 Grid View 的
`settings.groups`
;兼容
`children`
/
`fields`
/
`columns`
字段列表及带或不带
`metadata.`
的字段路径,仅显示当前视图中有效的列,空分组忽略。
-
同组字段按配置顺序相邻展示,并保留固定列区域。表头采用与廉洁风险防控一致的上下两行:上方为弱化组名,下方为字段名称;未分组字段保留普通表头。
-
表格上方提供分组开关和列数,默认全部展开。点击可隐藏整组字段,再次点击恢复;悬停或键盘聚焦显示字段清单,并突出对应表头。隐藏后保留分组开关,可随时恢复。
-
分组切换只改变当前表格展示,保留勾选、筛选、分页和记录数据,并按可见列宽重新计算横向滚动与固定列;切换 Subject 或视图后恢复默认展开。分组字段全部隐藏时保留选择及操作列。
-
本交互不新增请求、不修改 Subject 配置,也不改变
`metadata`
、审批或导出协议。
### 2.1 新建记录与 View 限制
### 2.1 新建记录与 View 限制
-
自查底稿模板列表点击“新增记录”后,“填写项目”(
`entry_item`
)按字段配置远程查询
`self_check_the_working_draft`
,使用共享引用选择器搜索、多选、取消选择或清空,草稿和最终
`metadata.entry_item`
只保存
`_id[]`
。其它引用字段同样读取目标 Subject 和
`multiple`
配置,单值保存
`_id`
,选择后关闭弹层;多值可连续选择。
-
引用候选查询通过
`POST /record/query`
,搜索期间显示加载状态,无结果或失败时显示对应提示,可重新搜索。选择仅更新新建草稿,点击弹窗保存才调用创建接口;视图限制字段及提交期间禁用选择器。
-
新建记录默认继承当前 Grid View 的
`settings.restrictions`
。
`$eq`
或单值
`$in`
条件会将唯一值写入
`metadata`
,对应控件禁用;即使字段未列入弹窗,也会随请求写入。
-
新建记录默认继承当前 Grid View 的
`settings.restrictions`
。
`$eq`
或单值
`$in`
条件会将唯一值写入
`metadata`
,对应控件禁用;即使字段未列入弹窗,也会随请求写入。
-
多值集合、否定条件或同一字段互相冲突时无法确定唯一值,禁止创建并提示“请先调整视图配置”。
-
多值集合、否定条件或同一字段互相冲突时无法确定唯一值,禁止创建并提示“请先调整视图配置”。
-
新建请求使用
`POST /record`
,所有业务字段放在
`metadata`
;编辑已有记录只提交用户修改字段,不使用 Grid View 限制覆盖原值。
-
新建请求使用
`POST /record`
,所有业务字段放在
`metadata`
;编辑已有记录只提交用户修改字段,不使用 Grid View 限制覆盖原值。
...
@@ -50,6 +61,8 @@
...
@@ -50,6 +61,8 @@
入口为 streams-admin 的应用布局配置或 Subject 的 Grid 视图配置,作用于本模块七个业务列表的共享 RecordWorkbench 表格中的引用、选择、子对象及 form 字段。页面加载应用及视图配置后按列渲染,切换视图时使用该视图的配置。
入口为 streams-admin 的应用布局配置或 Subject 的 Grid 视图配置,作用于本模块七个业务列表的共享 RecordWorkbench 表格中的引用、选择、子对象及 form 字段。页面加载应用及视图配置后按列渲染,切换视图时使用该视图的配置。
-
视图中配置的
`metadata.*`
业务列必须存在于当前 Subject 字段定义中;残留的无效列不展示,也不作为默认筛选项。Record 根级标题、创建时间等系统列保留原规则。“附件1:廉洁从业自查底稿”对应
`self_inspection_submission_form`
,不包含
`archive_status`
,因此不显示“归档状态”列;自查底稿填写表中真实定义的归档状态字段继续显示。
-
应用默认值读取
`layouts.default.subjects.<subjectName>.gridRecordConfig.displayConfig`
,兼容 streams-admin 的
`displayConfig.maxTagCount`
。
-
应用默认值读取
`layouts.default.subjects.<subjectName>.gridRecordConfig.displayConfig`
,兼容 streams-admin 的
`displayConfig.maxTagCount`
。
-
视图默认值读取
`settings.displayConfig`
,同名属性覆盖应用默认值;
`settings.columns[]`
中的单列
`displayConfig`
再覆盖视图默认值,列上的
`displayMode`
、
`maxTagCount`
、
`titleField`
优先级最高。
-
视图默认值读取
`settings.displayConfig`
,同名属性覆盖应用默认值;
`settings.columns[]`
中的单列
`displayConfig`
再覆盖视图默认值,列上的
`displayMode`
、
`maxTagCount`
、
`titleField`
优先级最高。
-
`displayMode: "labels"`
显示已选选项或关联标题;选项文案来自字段
`settings.options`
,仅展示当前记录实际选中的值。
-
`displayMode: "labels"`
显示已选选项或关联标题;选项文案来自字段
`settings.options`
,仅展示当前记录实际选中的值。
...
...
src/utils/subjectView.js
View file @
f99189d9
...
@@ -286,6 +286,7 @@ export function buildViewColumns(view, subject, { includeHidden = false, display
...
@@ -286,6 +286,7 @@ export function buildViewColumns(view, subject, { includeHidden = false, display
return
configuredColumns
return
configuredColumns
.
filter
((
column
)
=>
.
filter
((
column
)
=>
(
includeHidden
||
!
column
.
hide
)
&&
(
!
hideTitleColumn
||
column
.
field
!==
'title'
))
(
includeHidden
||
!
column
.
hide
)
&&
(
!
hideTitleColumn
||
column
.
field
!==
'title'
))
.
filter
((
column
)
=>
!
column
.
field
?.
startsWith
(
'metadata.'
)
||
getFieldDefinition
(
column
.
field
,
subject
))
.
map
((
column
)
=>
{
.
map
((
column
)
=>
{
const
fieldDef
=
getFieldDefinition
(
column
.
field
,
subject
);
const
fieldDef
=
getFieldDefinition
(
column
.
field
,
subject
);
const
label
=
getFieldLabel
(
column
.
field
,
fieldDef
,
column
.
label
);
const
label
=
getFieldLabel
(
column
.
field
,
fieldDef
,
column
.
label
);
...
...
tests/tableFieldDisplay.test.mjs
View file @
f99189d9
...
@@ -35,6 +35,21 @@ const { getTableFieldDisplay, getTableFieldDisplayConfig, formatTableFieldValue
...
@@ -35,6 +35,21 @@ const { getTableFieldDisplay, getTableFieldDisplayConfig, formatTableFieldValue
const
{
buildViewColumns
}
=
loadModule
(
'utils/subjectView.js'
);
const
{
buildViewColumns
}
=
loadModule
(
'utils/subjectView.js'
);
const
column
=
(
type
,
config
=
{})
=>
({
field
:
'metadata.values'
,
fieldDef
:
{
type
},
...
config
});
const
column
=
(
type
,
config
=
{})
=>
({
field
:
'metadata.values'
,
fieldDef
:
{
type
},
...
config
});
test
(
'view columns omit stale metadata fields while retaining real archive and system fields'
,
()
=>
{
const
view
=
{
settings
:
{
columns
:
[
{
field
:
'title'
},
{
field
:
'metadata.inspection_item'
},
{
field
:
'metadata.archive_status'
},
{
field
:
'created_at'
},
]
}
};
const
subject
=
{
fields
:
[{
name
:
'inspection_item'
,
type
:
'select'
}]
};
assert
.
deepEqual
(
buildViewColumns
(
view
,
subject
).
map
(({
field
})
=>
field
),
[
'title'
,
'metadata.inspection_item'
,
'created_at'
,
]);
subject
.
fields
.
push
({
name
:
'archive_status'
,
type
:
'select'
});
assert
.
equal
(
buildViewColumns
(
view
,
subject
)[
2
].
field
,
'metadata.archive_status'
);
});
test
(
'count mode counts selected values, including zero, and excludes empty entries'
,
()
=>
{
test
(
'count mode counts selected values, including zero, and excludes empty entries'
,
()
=>
{
const
config
=
column
(
'select'
,
{
displayMode
:
'count'
});
const
config
=
column
(
'select'
,
{
displayMode
:
'count'
});
assert
.
equal
(
formatTableFieldValue
([
0
,
'选中'
,
null
,
undefined
,
''
,
' '
],
config
),
'2'
);
assert
.
equal
(
formatTableFieldValue
([
0
,
'选中'
,
null
,
undefined
,
''
,
' '
],
config
),
'2'
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment