Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
P
problem_rectification
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
problem_rectification
Commits
dcdc9689
Commit
dcdc9689
authored
Jun 01, 2026
by
David Yang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 动态详情页
parent
b52ff11f
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
454 additions
and
47 deletions
+454
-47
index.jsx
src/components/record-workbench/index.jsx
+0
-0
useSubjectRecord.js
src/pages/RecordDetailDrawer/hooks/useSubjectRecord.js
+5
-5
index.jsx
src/pages/RecordDetailDrawer/index.jsx
+4
-3
archiveWorkbenchService.js
.../problem_rectification/archive/archiveWorkbenchService.js
+144
-0
index.jsx
src/pages/problem_rectification/archive/index.jsx
+191
-4
index.jsx
src/pages/problem_rectification/dashboard/index.jsx
+0
-0
index.jsx
src/pages/problem_rectification/list/index.jsx
+0
-0
problem-rectification.business-flow.md
...blem_rectification/problem-rectification.business-flow.md
+85
-35
problemRectificationDashboardService.js
...lem_rectification/problemRectificationDashboardService.js
+0
-0
problemRectificationListService.js
.../problem_rectification/problemRectificationListService.js
+0
-0
subjectsDefinition.md
src/services/subjectsDefinition.md
+25
-0
No files found.
src/components/record-workbench/index.jsx
0 → 100644
View file @
dcdc9689
This diff is collapsed.
Click to expand it.
src/pages/RecordDetailDrawer/hooks/useSubjectRecord.js
View file @
dcdc9689
...
@@ -39,7 +39,7 @@ function transformSaveValue(newValue, fieldDef) {
...
@@ -39,7 +39,7 @@ function transformSaveValue(newValue, fieldDef) {
return
newValue
;
return
newValue
;
}
}
export
function
useSubjectRecord
(
recordName
,
refreshKey
,
readonly
)
{
export
function
useSubjectRecord
(
recordName
,
refreshKey
,
readonly
,
subjectName
)
{
const
[
remoteRecord
,
setRemoteRecord
]
=
useState
(
null
);
const
[
remoteRecord
,
setRemoteRecord
]
=
useState
(
null
);
const
[
editableRecord
,
setEditableRecord
]
=
useState
(
null
);
const
[
editableRecord
,
setEditableRecord
]
=
useState
(
null
);
const
[
subject
,
setSubject
]
=
useState
(
null
);
const
[
subject
,
setSubject
]
=
useState
(
null
);
...
@@ -67,9 +67,9 @@ export function useSubjectRecord(recordName, refreshKey, readonly) {
...
@@ -67,9 +67,9 @@ export function useSubjectRecord(recordName, refreshKey, readonly) {
try
{
try
{
const
record
=
await
loadRecord
(
recordName
);
const
record
=
await
loadRecord
(
recordName
);
const
subjectName
=
record
?.
__t
||
record
?.
subject
?.
name
||
record
?.
subject
;
const
resolvedSubjectName
=
subjectName
||
record
?.
__t
||
record
?.
subject
?.
name
||
record
?.
subject
;
const
[
subjectData
,
viewsData
]
=
s
ubjectName
const
[
subjectData
,
viewsData
]
=
resolvedS
ubjectName
?
await
Promise
.
all
([
loadSubject
(
subjectName
),
getSubjectView
(
s
ubjectName
)])
?
await
Promise
.
all
([
loadSubject
(
resolvedSubjectName
),
getSubjectView
(
resolvedS
ubjectName
)])
:
[
null
,
[]];
:
[
null
,
[]];
if
(
!
cancelled
&&
requestIdRef
.
current
===
requestId
)
{
if
(
!
cancelled
&&
requestIdRef
.
current
===
requestId
)
{
...
@@ -98,7 +98,7 @@ export function useSubjectRecord(recordName, refreshKey, readonly) {
...
@@ -98,7 +98,7 @@ export function useSubjectRecord(recordName, refreshKey, readonly) {
return
()
=>
{
return
()
=>
{
cancelled
=
true
;
cancelled
=
true
;
};
};
},
[
recordName
,
refreshKey
]);
},
[
recordName
,
refreshKey
,
subjectName
]);
const
handleFieldUpdate
=
async
(
fieldPath
,
newValue
,
fieldDef
)
=>
{
const
handleFieldUpdate
=
async
(
fieldPath
,
newValue
,
fieldDef
)
=>
{
if
(
readonly
||
!
editableRecord
)
{
if
(
readonly
||
!
editableRecord
)
{
...
...
src/pages/RecordDetailDrawer/index.jsx
View file @
dcdc9689
...
@@ -59,7 +59,8 @@ const RecordDetailDrawer = (props, ref) => {
...
@@ -59,7 +59,8 @@ const RecordDetailDrawer = (props, ref) => {
width
=
860
,
width
=
860
,
open
,
open
,
recordName
,
recordName
,
setCustomComponentClose
,
subjectName
,
onClose
,
onDataChange
,
onDataChange
,
readonly
=
false
,
readonly
=
false
,
filterView
=
[],
filterView
=
[],
...
@@ -79,7 +80,7 @@ const RecordDetailDrawer = (props, ref) => {
...
@@ -79,7 +80,7 @@ const RecordDetailDrawer = (props, ref) => {
handleFieldUpdate
,
handleFieldUpdate
,
isFieldDisabled
,
isFieldDisabled
,
loading
,
loading
,
}
=
useSubjectRecord
(
recordName
,
refreshKey
,
readonly
);
}
=
useSubjectRecord
(
recordName
,
refreshKey
,
readonly
,
subjectName
);
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
open
)
{
if
(
open
)
{
...
@@ -156,7 +157,7 @@ const RecordDetailDrawer = (props, ref) => {
...
@@ -156,7 +157,7 @@ const RecordDetailDrawer = (props, ref) => {
];
];
const
closeDrawer
=
()
=>
{
const
closeDrawer
=
()
=>
{
setCustomComponent
Close
?.();
on
Close
?.();
};
};
return
(
return
(
...
...
src/pages/problem_rectification/archive/archiveWorkbenchService.js
0 → 100644
View file @
dcdc9689
import
{
countRecords
,
getSubjectView
,
loadRecord
,
loadSubject
,
queryRecords
}
from
'@/services/DataService'
;
import
{
buildViewColumns
,
checkViewCondition
,
formatFieldValue
,
getFieldValue
,
isViewAccessible
,
normalizeText
,
recordMatchesRestrictions
,
sortRecordsByView
,
}
from
'@/utils/subjectView'
;
export
const
ISSUE_RECTIFICATION_ARCHIVE_SUBJECT
=
'issue_rectification_archive'
;
export
const
PROBLEM_RECTIFICATION_ARCHIVE_RECORDS_SUBJECT
=
'problem_rectification_archive_records'
;
export
function
normalizeArchiveBatchRecord
(
record
)
{
const
referenceRecords
=
Array
.
isArray
(
record
?.
metadata
?.
reference_records
)
?
record
.
metadata
.
reference_records
:
[];
return
{
id
:
record
?.
_id
||
record
?.
name
||
''
,
name
:
record
?.
name
||
''
,
title
:
record
?.
title
||
record
?.
name
||
'归档批次'
,
archiveCount
:
referenceRecords
.
length
,
referenceRecords
,
raw
:
record
,
};
}
export
async
function
loadArchiveWorkbenchResources
()
{
const
[
archiveRecordsResult
,
archiveSubject
,
archiveViews
]
=
await
Promise
.
all
([
queryRecords
({
subject
:
ISSUE_RECTIFICATION_ARCHIVE_SUBJECT
,
page
:
0
,
page_size
:
1000
,
sort
:
'-updated_at -created_at'
,
mode
:
'full'
,
}),
loadSubject
(
ISSUE_RECTIFICATION_ARCHIVE_SUBJECT
),
getSubjectView
(
ISSUE_RECTIFICATION_ARCHIVE_SUBJECT
),
]);
const
records
=
(
archiveRecordsResult
?.
records
||
[]).
map
(
normalizeArchiveBatchRecord
);
return
{
records
,
subject
:
archiveSubject
,
views
:
archiveViews
||
[],
};
}
export
function
buildArchiveGridViews
(
views
=
[])
{
const
gridViews
=
views
.
filter
((
view
)
=>
view
.
type
===
'grid'
)
.
filter
((
view
)
=>
isViewAccessible
(
view
));
if
(
gridViews
.
length
>
0
)
{
return
gridViews
;
}
return
[
{
title
:
'全部批次'
,
type
:
'grid'
,
name
:
'all'
,
settings
:
{},
},
];
}
export
function
buildArchiveColumns
(
view
,
subject
)
{
return
buildViewColumns
(
view
,
subject
).
filter
((
column
)
=>
column
.
field
!==
'title'
||
!
column
.
hide
);
}
export
function
buildArchiveConfiguredView
(
records
,
filters
,
gridView
,
subject
)
{
const
keyword
=
normalizeText
(
filters
?.
keyword
).
toLowerCase
();
const
columns
=
buildArchiveColumns
(
gridView
,
subject
);
const
filteredRecords
=
records
.
filter
((
record
)
=>
{
const
rawRecord
=
record
.
raw
||
record
;
if
(
!
recordMatchesRestrictions
(
rawRecord
,
gridView
?.
settings
?.
restrictions
))
{
return
false
;
}
if
(
!
checkViewCondition
(
{
relationship
:
gridView
?.
settings
?.
filters
?.
relationship
||
'all'
,
rules
:
gridView
?.
settings
?.
filters
?.
conditions
||
[],
},
rawRecord
,
)
)
{
return
false
;
}
if
(
!
keyword
)
{
return
true
;
}
const
searchText
=
columns
.
map
((
column
)
=>
formatFieldValue
(
getFieldValue
(
rawRecord
,
column
.
field
),
column
.
fieldDef
))
.
join
(
' '
)
.
toLowerCase
();
return
searchText
.
includes
(
keyword
);
});
return
{
filteredRecords
:
sortRecordsByView
(
filteredRecords
,
gridView
),
columns
,
};
}
export
function
buildArchiveViewCountMap
(
records
,
filters
,
views
,
subject
)
{
return
views
.
reduce
((
counts
,
view
)
=>
{
counts
[
view
.
name
]
=
buildArchiveConfiguredView
(
records
,
filters
,
view
,
subject
).
filteredRecords
.
length
;
return
counts
;
},
{});
}
export
async
function
loadArchiveDetailMetrics
(
recordName
)
{
const
batchRecord
=
await
loadRecord
(
recordName
);
const
referenceRecordIds
=
Array
.
isArray
(
batchRecord
?.
metadata
?.
reference_records
)
?
batchRecord
.
metadata
.
reference_records
.
map
((
item
)
=>
(
typeof
item
===
'object'
?
item
.
_id
||
item
.
name
:
item
))
.
filter
(
Boolean
)
:
[];
const
detailCount
=
referenceRecordIds
.
length
>
0
?
await
countRecords
({
subject
:
PROBLEM_RECTIFICATION_ARCHIVE_RECORDS_SUBJECT
,
filter
:
{
_id
:
{
$in
:
referenceRecordIds
},
},
})
:
{
count
:
0
};
return
{
batchRecord
,
detailCount
:
detailCount
?.
count
||
0
,
referenceRecordIds
,
};
}
src/pages/problem_rectification/archive/index.jsx
View file @
dcdc9689
import
ModuleEmptyState
from
'../ModuleEmptyState'
;
import
RecordWorkbench
from
'@/components/record-workbench'
;
import
RecordDetailDrawer
from
'@/pages/RecordDetailDrawer'
;
import
{
useCallback
,
useEffect
,
useMemo
,
useState
}
from
'react'
;
import
{
buildArchiveConfiguredView
,
buildArchiveGridViews
,
buildArchiveViewCountMap
,
ISSUE_RECTIFICATION_ARCHIVE_SUBJECT
,
loadArchiveWorkbenchResources
,
}
from
'./archiveWorkbenchService'
;
export
default
function
ProblemRectificationArchivePage
()
{
export
default
function
ProblemRectificationArchivePage
()
{
const
[
records
,
setRecords
]
=
useState
([]);
const
[
subject
,
setSubject
]
=
useState
(
null
);
const
[
views
,
setViews
]
=
useState
([]);
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
[
error
,
setError
]
=
useState
(
''
);
const
[
filters
,
setFilters
]
=
useState
({
keyword
:
''
,
});
const
[
activeViewName
,
setActiveViewName
]
=
useState
(
''
);
const
[
selectedIds
,
setSelectedIds
]
=
useState
([]);
const
reloadList
=
useCallback
(
async
()
=>
{
setLoading
(
true
);
setError
(
''
);
try
{
const
resources
=
await
loadArchiveWorkbenchResources
();
setRecords
(
resources
.
records
||
[]);
setSubject
(
resources
.
subject
||
null
);
setViews
(
resources
.
views
||
[]);
}
catch
(
requestError
)
{
setRecords
([]);
setSubject
(
null
);
setViews
([]);
setError
(
requestError
?.
message
||
'归档批次列表加载失败,请稍后重试。'
);
}
finally
{
setLoading
(
false
);
}
},
[]);
useEffect
(()
=>
{
reloadList
();
},
[
reloadList
]);
const
gridViews
=
useMemo
(()
=>
buildArchiveGridViews
(
views
),
[
views
]);
useEffect
(()
=>
{
if
(
gridViews
.
length
===
0
)
{
setActiveViewName
(
''
);
return
;
}
if
(
!
gridViews
.
some
((
view
)
=>
view
.
name
===
activeViewName
))
{
setActiveViewName
(
gridViews
[
0
].
name
);
}
},
[
gridViews
,
activeViewName
]);
const
activeGridView
=
useMemo
(
()
=>
gridViews
.
find
((
view
)
=>
view
.
name
===
activeViewName
)
||
gridViews
[
0
]
||
null
,
[
gridViews
,
activeViewName
],
);
const
configuredView
=
useMemo
(
()
=>
buildArchiveConfiguredView
(
records
,
filters
,
activeGridView
,
subject
),
[
records
,
filters
,
activeGridView
,
subject
],
);
const
filteredRecords
=
configuredView
.
filteredRecords
||
[];
useEffect
(()
=>
{
const
visibleIds
=
new
Set
(
filteredRecords
.
map
((
item
)
=>
item
.
id
));
setSelectedIds
((
current
)
=>
current
.
filter
((
id
)
=>
visibleIds
.
has
(
id
)));
},
[
filteredRecords
]);
const
gridViewCounts
=
useMemo
(
()
=>
buildArchiveViewCountMap
(
records
,
filters
,
gridViews
,
subject
),
[
records
,
filters
,
gridViews
,
subject
],
);
const
summaryItems
=
useMemo
(
()
=>
[
{
label
:
'归档批次数'
,
value
:
filteredRecords
.
length
,
hint
:
activeGridView
?.
title
?
`
${
activeGridView
.
title
}
视图`
:
'当前筛选结果'
,
tone
:
'amber'
,
},
{
label
:
'已归档明细数'
,
value
:
filteredRecords
.
reduce
((
total
,
item
)
=>
total
+
(
item
.
archiveCount
||
0
),
0
),
hint
:
'按当前视图统计关联快照数量'
,
tone
:
'emerald'
,
},
{
label
:
'当前已选批次'
,
value
:
selectedIds
.
length
,
hint
:
'支持后续批量操作扩展'
,
tone
:
'rose'
,
},
],
[
filteredRecords
,
selectedIds
.
length
,
activeGridView
],
);
return
(
return
(
<
ModuleEmptyState
<
RecordWorkbench
title=
"往期材料归档"
summaryItems=
{
summaryItems
}
description=
"查看归档批次和归档明细。"
views=
{
gridViews
.
map
((
view
)
=>
({
...
view
,
count
:
gridViewCounts
[
view
.
name
]
||
0
,
}))
}
activeViewName=
{
activeGridView
?.
name
||
''
}
onViewChange=
{
(
viewName
)
=>
{
setActiveViewName
(
viewName
);
setSelectedIds
([]);
}
}
filters=
{
filters
}
filterSchema=
{
[
{
key
:
'keyword'
,
label
:
'关键词搜索'
,
type
:
'text'
,
placeholder
:
'搜索归档批次标题、编码或关联字段...'
,
},
]
}
onFiltersChange=
{
(
key
,
value
)
=>
setFilters
((
current
)
=>
({
...
current
,
[
key
]:
value
}))
}
onClearFilters=
{
()
=>
{
setFilters
({
keyword
:
''
});
setSelectedIds
([]);
}
}
title=
"归档批次"
description=
{
`当前视图显示 ${filteredRecords.length} 条批次记录,已选中 ${selectedIds.length} 条。`
}
columns=
{
configuredView
.
columns
||
[]
}
records=
{
filteredRecords
}
selectedIds=
{
selectedIds
}
onSelectionChange=
{
setSelectedIds
}
toolbarActions=
{
[
{
key
:
'archive-export'
,
label
:
'导出批次'
,
variant
:
'outline'
,
disabled
:
true
,
onClick
:
()
=>
{},
},
{
key
:
'archive-compare'
,
label
:
'批次对比'
,
variant
:
'outline'
,
disabled
:
true
,
onClick
:
()
=>
{},
},
]
}
rowActions=
{
[
{
key
:
'view-detail'
,
label
:
'查看详情'
,
variant
:
'plain'
,
onClick
:
({
openDetail
,
record
})
=>
openDetail
(
record
),
},
]
}
detailPanel=
{
{
getRecordName
:
(
record
)
=>
record
.
name
||
record
.
id
,
onDirtyClose
:
reloadList
,
render
:
({
open
,
recordName
,
onClose
,
onDataChange
})
=>
(
<
RecordDetailDrawer
open=
{
open
}
recordName=
{
recordName
}
subjectName=
{
ISSUE_RECTIFICATION_ARCHIVE_SUBJECT
}
onClose=
{
onClose
}
onDataChange=
{
onDataChange
}
preferredViewName=
{
activeGridView
?.
title
||
activeGridView
?.
name
}
/>
),
}
}
states=
{
{
loading
,
error
,
loadingTitle
:
'正在加载归档批次'
,
loadingDescription
:
'正在读取归档对象、视图配置和批次记录,请稍候。'
,
emptyTitle
:
'暂无归档批次'
,
emptyDescription
:
'当前还没有归档批次记录,后续完成“一键归档”后会在这里展示。'
,
}
}
renderCell=
{
({
record
,
column
})
=>
{
if
(
column
.
field
===
'metadata.reference_records'
)
{
return
(
<
div
className=
"whitespace-normal break-words text-sm text-slate-700"
>
{
record
.
archiveCount
||
0
}
条明细
</
div
>
);
}
return
column
.
render
?
column
.
render
(
record
,
column
)
:
null
;
}
}
/>
/>
);
);
}
}
src/pages/problem_rectification/dashboard/index.jsx
View file @
dcdc9689
This diff is collapsed.
Click to expand it.
src/pages/problem_rectification/list/index.jsx
View file @
dcdc9689
This diff is collapsed.
Click to expand it.
src/pages/problem_rectification/problem-rectification.business-flow.md
View file @
dcdc9689
...
@@ -64,6 +64,13 @@
...
@@ -64,6 +64,13 @@
因此前端新增字段展示、部门视图调整、列顺序变化时,应优先改 Subject View 配置,而不是直接修改页面常量。
因此前端新增字段展示、部门视图调整、列顺序变化时,应优先改 Subject View 配置,而不是直接修改页面常量。
当前项目实现约定补充:
-
`problem_rectification`
与
`issue_rectification_archive`
列表页统一复用
`RecordWorkbench`
作为“结构化表格 + 工具栏 + 详情抽屉入口”的工作台容器
-
页面本身只负责提供 subject 对应的数据加载、统计口径、筛选 schema、行操作与批量操作
-
详情侧栏统一复用
`RecordDetailDrawer`
,通过
`recordName`
、
`subjectName`
、
`preferredViewName`
驱动,不再在各页面重复实现抽屉骨架
-
新增同类列表页时,优先复用工作台与详情抽屉组合,避免再次复制问题整改页 JSX
### 3.1 目标页面拆分
### 3.1 目标页面拆分
为便于当前项目直接重构,建议把模块拆成以下 4 个页面入口:
为便于当前项目直接重构,建议把模块拆成以下 4 个页面入口:
...
@@ -229,8 +236,20 @@
...
@@ -229,8 +236,20 @@
-
问题类型
-
问题类型
-
反馈单位
-
反馈单位
-
问题涉及业务领域
-
问题涉及业务领域
3.
可预先填写预计整改完成时间
3.
根据 2026 年整改驾驶舱要求,补录扩展治理字段:
4.
初始时可不指定填报人、复核人
-
问题后果:是否造成经济损失、对应经济损失、是否造成外部影响、处罚机构、是否涉及员工问责、问责人数
-
问题画像:问题综合严重程度、问题一级至四级分类、问题原因
-
整改质效:整改时间评估、整改证明材料质量、是否涉及制度修订、制度名称、是否涉及系统建设、系统名称、是否为往期发现问题、问题是否重复出现、综合整改评定等级
-
责任识别:主责部门、实际整改完成时间、实际检查完成日期
4.
可预先填写预计整改完成时间
5.
初始时可不指定填报人、复核人
推荐新交互:
-
工作台筛选区增加严重程度、整改评级、主责部门、问题来源、问题原因、重点关注等维度
-
列表标题列增加风险标签,优先暴露“高严重程度”“重点后果问题”“已逾期”等重点状态
-
新增弹窗除基础字段外,还应补充严重程度、分类、原因和整改质效字段,避免驾驶舱后续无数据可用
-
摘要卡优先展示高严重程度、重点后果问题、往期/重复问题、逾期未完成、整改评级偏低等指标
### 7.2 发起整改填报
### 7.2 发起整改填报
...
@@ -369,12 +388,12 @@
...
@@ -369,12 +388,12 @@
## 9. 驾驶舱展示规则
## 9. 驾驶舱展示规则
旧驾驶舱页面以
`problem_rectification`
为唯一数据源,主要分为三部分
:
当前驾驶舱页面以
`problem_rectification`
为唯一数据源,围绕 2026 年整改驾驶舱需求分为四层
:
1.
按反馈单位分组的统计看板
1.
宏观总览层
2.
临近整改问题列表
2.
问题分析与风险定位层
3.
整改逾期问题列表
3.
问题责任追踪与执行层
4.
问题涉及业务领域词云
4.
审计整改质效层
### 9.1 顶部标签分组
### 9.1 顶部标签分组
...
@@ -399,47 +418,78 @@
...
@@ -399,47 +418,78 @@
-
页面文案可以更贴近业务,例如“资产管理部”与“鑫沅资产”统一命名
-
页面文案可以更贴近业务,例如“资产管理部”与“鑫沅资产”统一命名
-
分组不必写死在组件内部,建议抽为配置映射
-
分组不必写死在组件内部,建议抽为配置映射
推荐新实现:
当前实现约定:
-
顶部继续保留按
`feedback_unit`
分组的轻量 tabs
-
tabs 下方分为 KPI 卡片、ECharts 图表区和重点问题清单区
-
驾驶舱仅负责统计展示,不承接编辑动作
-
如果线上 Subject 后续把新增字段从
`text`
升级为
`select`
/
`date`
/
`boolean`
,驾驶舱统计口径无需调整,只需复用标准字段值
### 9.2 宏观总览层
当前 KPI 统计口径:
-
问题总数:当前分组内问题总数
-
已完成整改数:
`rectification_progress`
为
`已整改`
或
`已优化`
-
整改完成率:
`已完成整改数 / 问题总数`
-
逾期未完成数:
`the_time_of_rectification`
早于当前日期且未闭环的问题数
-
逾期率:
`逾期未完成数 / 问题总数`
-
顶部使用轻量 tabs
整改进度分布:
-
tabs 下方展示 KPI 卡片
-
页面中下部拆成“临近整改”“整改逾期”“问题领域分布”三个区块
-
若词云阅读性差,可直接换成条形排名,不影响业务含义
### 9.2 统计指标口径
-
以
`rectification_progress`
为维度统计数量和占比
-
当前页面使用环形图表达,不再沿用旧版折线趋势表达
旧
`MainPanel`
已确认的统计口径:
### 9.3 问题分析与风险定位层
-
已整改问题:
`rectification_progress`
为
`已整改`
或
`已优化`
当前图表与字段映射:
-
问题数量:当前分组内问题总数
-
历史问题累计整改率:
`(已整改或已优化数量 / 问题总数) * 100`
-
本年度问题整改率:
当年
`check_the_implementation_time`
所属问题中,已整改或已优化的占比
其中“当年”是通过
`check_the_implementation_time`
中提取四位年份数字判断,不是通过日期字段直接计算。
-
问题类型 / 业务领域分布:优先使用
`problem_category_level_1`
至
`problem_category_level_4`
生成矩形树图;若分类未填写,则回退到
`related_issue_domain`
-
问题根本原因分析:使用
`problem_root_cause`
聚合
-
问题来源对比:以
`problem_from`
为横轴,并按
`inspect_the_implementing_unit`
做堆叠比较
-
重点问题集中展示:
-
经济损失问题:
`has_economic_loss`
+
`economic_loss_amount`
-
外部影响问题:
`has_external_impact`
+
`penalty_organization`
-
员工问责问题:
`has_employee_accountability`
+
`accountability_person_count`
-
重点问题清单中同时展示
`problem_severity_level`
### 9.
3 临近整改问题
### 9.
4 问题责任追踪与执行层
筛选逻辑
:
当前图表与字段映射
:
-
`the_time_of_rectification`
在当前时间之后
-
逾期问题排行:按
`responsible_department`
聚合逾期未完成问题数
-
`the_time_of_rectification`
在未来 1 个月内
-
部门整改责任矩阵:
-
`rectification_progress !== "已整改"`
-
X 轴:责任部门问题总数
-
Y 轴:整改完成率
-
气泡大小:逾期问题数
-
整改时效分析散点图:
-
X 轴:
`the_time_of_rectification - inspection_completed_at`
-
Y 轴:
`actual_rectification_completed_at - inspection_completed_at`
-
仅统计同时填写了预计整改时间、实际整改完成时间、实际检查完成日期且天数非负的问题
### 9.4 整改逾期问题
当前逾期 / 延期判定说明:
筛选逻辑:
-
当前项目线上尚无稳定使用的显式“是否延期”字段,因此页面暂以三类规则综合判断:
-
整改进度文案包含“延期”
-
实际整改完成时间晚于预计整改完成时间
-
截止当前日期预计整改完成时间已到且问题尚未闭环
-
其中 KPI 和逾期排行的“逾期未完成”使用第三条规则
-
`the_time_of_rectification`
早于当前时间
### 9.5 审计整改质效层
-
`rectification_progress !== "已整改"`
### 9.5 问题涉及业务领域统计
当前图表与字段映射:
-
使用
`related_issue_domain`
做聚合统计
-
问题整改时效:按责任部门计算
`rectification_timeliness_level`
平均分,低=1、中=2、高=3
-
旧应用通过
`subjectSearch('problem_rectification', ...)`
获取 bucket
-
问题整改质量:按责任部门计算
`rectification_material_quality_level`
平均分,低=1、中=2、高=3
-
新项目可以保留词云,也可以替换成更轻量的条形列表或标签热度图
-
问题整改助力总结:
-
如果追求性能和可读性,优先推荐横向条形图或排名卡片,而不是强依赖词云
-
制度修订数量:
`involves_policy_revision = 是`
-
系统建设数量:
`involves_system_construction = 是`
-
风险-质量热力图:
-
X 轴:
`problem_severity_level`
-
Y 轴:
`rectification_overall_rating`
-
部门综合整改评定等级排行:
-
以责任部门为维度统计
`rectification_overall_rating`
的低/中/高占比
-
按高评级占比降序展示
---
---
...
...
src/pages/problem_rectification/problemRectificationDashboardService.js
View file @
dcdc9689
This diff is collapsed.
Click to expand it.
src/pages/problem_rectification/problemRectificationListService.js
View file @
dcdc9689
This diff is collapsed.
Click to expand it.
src/services/subjectsDefinition.md
View file @
dcdc9689
...
@@ -125,6 +125,30 @@ type Record = {
...
@@ -125,6 +125,30 @@ type Record = {
| 最终审批状态 |
`final_audit_status`
| select | 否 | 否 | 否 |
| 最终审批状态 |
`final_audit_status`
| select | 否 | 否 | 否 |
| 备注 |
`remark`
| long_text | 否 | 否 | 否 |
| 备注 |
`remark`
| long_text | 否 | 否 | 否 |
| 整改证明材料 |
`rectification_proof_materials`
| file | 否 | 否 | 否 |
| 整改证明材料 |
`rectification_proof_materials`
| file | 否 | 否 | 否 |
| 是否造成经济损失 |
`has_economic_loss`
| text | 否 | 否 | 否 |
| 对应经济损失 |
`economic_loss_amount`
| text | 否 | 否 | 否 |
| 是否造成外部影响 |
`has_external_impact`
| text | 否 | 否 | 否 |
| 处罚机构 |
`penalty_organization`
| text | 否 | 否 | 否 |
| 是否涉及员工问责 |
`has_employee_accountability`
| text | 否 | 否 | 否 |
| 问责人数 |
`accountability_person_count`
| text | 否 | 否 | 否 |
| 问题综合严重程度 |
`problem_severity_level`
| text | 否 | 否 | 否 |
| 问题一级分类 |
`problem_category_level_1`
| text | 否 | 否 | 否 |
| 问题二级分类 |
`problem_category_level_2`
| text | 否 | 否 | 否 |
| 问题三级分类 |
`problem_category_level_3`
| text | 否 | 否 | 否 |
| 问题四级分类 |
`problem_category_level_4`
| text | 否 | 否 | 否 |
| 问题原因 |
`problem_root_cause`
| text | 否 | 否 | 否 |
| 整改时间评估 |
`rectification_timeliness_level`
| text | 否 | 否 | 否 |
| 整改证明材料质量 |
`rectification_material_quality_level`
| text | 否 | 否 | 否 |
| 是否涉及制度修订 |
`involves_policy_revision`
| text | 否 | 否 | 否 |
| 制度名称 |
`policy_revision_name`
| text | 否 | 否 | 否 |
| 是否涉及系统建设 |
`involves_system_construction`
| text | 否 | 否 | 否 |
| 系统名称 |
`system_construction_name`
| text | 否 | 否 | 否 |
| 是否为往期发现问题 |
`is_historical_problem`
| text | 否 | 否 | 否 |
| 问题是否重复出现 |
`is_repeated_problem`
| text | 否 | 否 | 否 |
| 综合整改评定等级 |
`rectification_overall_rating`
| text | 否 | 否 | 否 |
| 实际整改完成时间 |
`actual_rectification_completed_at`
| text | 否 | 否 | 否 |
| 实际检查完成日期 |
`inspection_completed_at`
| text | 否 | 否 | 否 |
| 主责部门 |
`primary_responsible_department`
| text | 否 | 否 | 否 |
### 3.1.1 字段说明
### 3.1.1 字段说明
...
@@ -133,6 +157,7 @@ type Record = {
...
@@ -133,6 +157,7 @@ type Record = {
-
`audit_status`
用于复核阶段结果,旧应用已使用
`已审批`
、
`已驳回`
-
`audit_status`
用于复核阶段结果,旧应用已使用
`已审批`
、
`已驳回`
-
`final_audit_status`
用于最终审批阶段结果,旧应用已使用
`已审批`
、
`已驳回`
-
`final_audit_status`
用于最终审批阶段结果,旧应用已使用
`已审批`
、
`已驳回`
-
`rectification_progress`
在旧驾驶舱统计中已使用
`已整改`
、
`已优化`
两个值判断“已整改问题”
-
`rectification_progress`
在旧驾驶舱统计中已使用
`已整改`
、
`已优化`
两个值判断“已整改问题”
-
新增驾驶舱扩展字段当前在线上 Subject 中大多仍为
`text`
类型,前端工作台按标准值引导录入,用于支持后续严重程度、问题分类、问题原因和整改质效分析
-
其余
`select`
类型的可选值必须以线上 Subject 配置中的
`settings.options`
为准,禁止在页面内硬编码
-
其余
`select`
类型的可选值必须以线上 Subject 配置中的
`settings.options`
为准,禁止在页面内硬编码
### 3.1.2 metadata 示例
### 3.1.2 metadata 示例
...
...
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