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
48dae1c1
Commit
48dae1c1
authored
Aug 07, 2026
by
David Yang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 完善延期申请状态展示与流程标识
parent
5a67a51e
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
334 additions
and
25 deletions
+334
-25
index.jsx
src/pages/problem_rectification/flow-table/index.jsx
+99
-11
index.jsx
src/pages/problem_rectification/list/index.jsx
+230
-13
problem-rectification.business-flow.md
...blem_rectification/problem-rectification.business-flow.md
+5
-1
No files found.
src/pages/problem_rectification/flow-table/index.jsx
View file @
48dae1c1
import
{
Button
}
from
'@/catalyst-ui-kit/javascript/button'
;
import
{
Button
}
from
'@/catalyst-ui-kit/javascript/button'
;
import
{
Badge
}
from
'@/catalyst-ui-kit/javascript/badge'
;
import
{
Input
}
from
'@/catalyst-ui-kit/javascript/input'
;
import
{
Input
}
from
'@/catalyst-ui-kit/javascript/input'
;
import
{
Select
}
from
'@/catalyst-ui-kit/javascript/select'
;
import
{
Select
}
from
'@/catalyst-ui-kit/javascript/select'
;
import
{
import
{
...
@@ -23,7 +24,12 @@ import {
...
@@ -23,7 +24,12 @@ import {
import
{
normalizeText
,
toArray
}
from
'@/utils/subjectView'
;
import
{
normalizeText
,
toArray
}
from
'@/utils/subjectView'
;
import
clsx
from
'clsx'
;
import
clsx
from
'clsx'
;
import
dayjs
from
'dayjs'
;
import
dayjs
from
'dayjs'
;
import
{
LockClosedIcon
}
from
'@heroicons/react/24/outline'
;
import
{
ArrowPathIcon
,
CalendarDaysIcon
,
ClipboardDocumentCheckIcon
,
LockClosedIcon
,
}
from
'@heroicons/react/24/outline'
;
import
{
useContext
,
useEffect
,
useMemo
,
useState
}
from
'react'
;
import
{
useContext
,
useEffect
,
useMemo
,
useState
}
from
'react'
;
import
{
useSearchParams
}
from
'umi'
;
import
{
useSearchParams
}
from
'umi'
;
import
{
UserContext
}
from
'@/wrapper/Auth'
;
import
{
UserContext
}
from
'@/wrapper/Auth'
;
...
@@ -1231,24 +1237,83 @@ export default function ProblemRectificationFlowTablePage() {
...
@@ -1231,24 +1237,83 @@ export default function ProblemRectificationFlowTablePage() {
rows
.
every
((
row
)
=>
!
row
.
isLocked
&&
row
.
auditStatus
===
AUDIT_STATUS_APPROVED
)
&&
rows
.
every
((
row
)
=>
!
row
.
isLocked
&&
row
.
auditStatus
===
AUDIT_STATUS_APPROVED
)
&&
senderId
===
currentUserId
&&
senderId
===
currentUserId
&&
rows
.
some
((
row
)
=>
row
.
finalAuditStatus
!==
AUDIT_STATUS_APPROVED
);
rows
.
some
((
row
)
=>
row
.
finalAuditStatus
!==
AUDIT_STATUS_APPROVED
);
const
flowModeLabel
=
isDelayFlow
?
flowMode
===
FLOW_MODE_DELAY_DEPARTMENT
?
'按责任部门'
:
'问题级申请'
:
flowMode
===
FLOW_MODE_DEPARTMENT
?
'按责任部门'
:
'批量处理'
;
const
flowPresentation
=
isDelayFlow
?
{
badge
:
'延期申请流程'
,
title
:
'问题延期申请'
,
detailTitle
:
'延期申请明细'
,
description
:
'申请新的整改完成时间,并记录延期事由'
,
accentClass
:
'bg-amber-500'
,
iconClass
:
'bg-amber-100 text-amber-700 ring-amber-200'
,
sectionClass
:
'border-amber-200/80 bg-amber-50/50'
,
badgeColor
:
'amber'
,
icon
:
CalendarDaysIcon
,
}
:
{
badge
:
'问题整改流程'
,
title
:
'问题整改处理'
,
detailTitle
:
'问题整改明细'
,
description
:
'更新整改进度、预计完成时间、整改情况与证明材料'
,
accentClass
:
'bg-sky-600'
,
iconClass
:
'bg-sky-100 text-sky-700 ring-sky-200'
,
sectionClass
:
'border-sky-200/80 bg-sky-50/50'
,
badgeColor
:
'sky'
,
icon
:
ClipboardDocumentCheckIcon
,
};
const
FlowIcon
=
flowPresentation
.
icon
;
return
(
return
(
<
div
className=
"space-y-6 p-6"
>
<
div
className=
"space-y-6 p-6"
>
<
section
className=
"rounded-[30px] border border-white/80 bg-white/95 px-6 py-5 shadow-sm"
>
<
section
<
div
className=
"flex flex-wrap items-start justify-between gap-4"
>
className=
{
clsx
(
<
div
>
'overflow-hidden rounded-[30px] border bg-white/95 shadow-sm'
,
<
div
className=
"text-xs font-semibold uppercase tracking-[0.24em] text-rose-600"
>
isDelayFlow
?
'border-amber-200/80'
:
'border-sky-200/80'
,
Problem Rectification Flow
)
}
</
div
>
>
<
div
className=
{
clsx
(
'h-1.5 w-full'
,
flowPresentation
.
accentClass
)
}
/>
<
div
className=
"flex flex-wrap items-start justify-between gap-4 px-6 py-5"
>
<
div
className=
"flex min-w-0 items-start gap-4"
>
<
span
className=
{
clsx
(
'inline-flex size-11 shrink-0 items-center justify-center rounded-lg ring-1'
,
flowPresentation
.
iconClass
,
)
}
>
<
FlowIcon
className=
"size-6"
aria
-
hidden=
"true"
/>
</
span
>
<
div
className=
"min-w-0"
>
<
Badge
color=
{
flowPresentation
.
badgeColor
}
>
{
flowPresentation
.
badge
}
</
Badge
>
<
h1
className=
"mt-2 text-2xl font-semibold tracking-tight text-slate-950"
>
<
h1
className=
"mt-2 text-2xl font-semibold tracking-tight text-slate-950"
>
{
isDelayFlow
?
'延期申请处理'
:
'问题整改表格处理'
}
{
flowPresentation
.
title
}
</
h1
>
</
h1
>
<
p
className=
"mt-2 text-sm text-slate-500"
>
<
p
className=
"mt-1 text-sm font-medium text-slate-600"
>
当前流程:
{
messageId
||
'-'
}
;流程模式:
{
flowPresentation
.
description
}
{
isDelayFlow
?
'问题延期申请'
:
flowMode
===
FLOW_MODE_DEPARTMENT
?
'按责任部门'
:
'批量简单推送'
}
</
p
>
</
p
>
<
dl
className=
"mt-3 flex flex-wrap gap-x-6 gap-y-2 text-xs text-slate-500"
>
<
div
className=
"flex min-w-0 items-center gap-2"
>
<
dt
>
流程编号
</
dt
>
<
dd
className=
"min-w-0 break-all font-mono text-slate-700"
>
{
messageId
||
'-'
}
</
dd
>
</
div
>
<
div
className=
"flex items-center gap-2"
>
<
dt
>
处理方式
</
dt
>
<
dd
className=
"font-medium text-slate-700"
>
{
flowModeLabel
}
</
dd
>
</
div
>
</
dl
>
</
div
>
</
div
>
</
div
>
<
Button
outline
onClick=
{
loadFlow
}
disabled=
{
loading
||
Boolean
(
submittingKey
)
}
>
<
Button
outline
onClick=
{
loadFlow
}
disabled=
{
loading
||
Boolean
(
submittingKey
)
}
>
<
ArrowPathIcon
data
-
slot=
"icon"
/>
刷新
刷新
</
Button
>
</
Button
>
</
div
>
</
div
>
...
@@ -1262,6 +1327,29 @@ export default function ProblemRectificationFlowTablePage() {
...
@@ -1262,6 +1327,29 @@ export default function ProblemRectificationFlowTablePage() {
)
:
null
}
)
:
null
}
<
section
className=
"overflow-hidden rounded-[30px] border border-white/80 bg-white/96 shadow-sm"
>
<
section
className=
"overflow-hidden rounded-[30px] border border-white/80 bg-white/96 shadow-sm"
>
<
div
className=
{
clsx
(
'flex flex-wrap items-center justify-between gap-3 border-b px-5 py-4'
,
flowPresentation
.
sectionClass
,
)
}
>
<
div
className=
"flex min-w-0 items-center gap-3"
>
<
FlowIcon
className=
"size-5 shrink-0"
aria
-
hidden=
"true"
/>
<
div
className=
"min-w-0"
>
<
h2
className=
"text-sm font-semibold text-slate-900"
>
{
flowPresentation
.
detailTitle
}
</
h2
>
<
p
className=
"mt-0.5 text-xs text-slate-600"
>
{
flowPresentation
.
description
}
</
p
>
</
div
>
</
div
>
<
Badge
color=
{
flowPresentation
.
badgeColor
}
>
{
loading
?
'加载中'
:
`${rows.length} 条${isDelayFlow ? '延期申请' : '整改明细'}`
}
</
Badge
>
</
div
>
{
loading
?
(
{
loading
?
(
<
div
className=
"px-6 py-14 text-center text-sm text-slate-500"
>
正在加载流程表格...
</
div
>
<
div
className=
"px-6 py-14 text-center text-sm text-slate-500"
>
正在加载流程表格...
</
div
>
)
:
rows
.
length
===
0
?
(
)
:
rows
.
length
===
0
?
(
...
...
src/pages/problem_rectification/list/index.jsx
View file @
48dae1c1
import
{
Button
}
from
'@/catalyst-ui-kit/javascript/button'
;
import
{
Button
}
from
'@/catalyst-ui-kit/javascript/button'
;
import
{
BadgeButton
}
from
'@/catalyst-ui-kit/javascript/badge'
;
import
{
import
{
Dialog
,
Dialog
,
DialogActions
,
DialogActions
,
...
@@ -34,7 +35,12 @@ import {
...
@@ -34,7 +35,12 @@ import {
}
from
'@/services/DataService'
;
}
from
'@/services/DataService'
;
import
*
as
Headless
from
'@headlessui/react'
;
import
*
as
Headless
from
'@headlessui/react'
;
import
{
ChevronRightIcon
}
from
'@heroicons/react/20/solid'
;
import
{
ChevronRightIcon
}
from
'@heroicons/react/20/solid'
;
import
{
LockClosedIcon
,
LockOpenIcon
,
TrashIcon
}
from
'@heroicons/react/24/outline'
;
import
{
CalendarDaysIcon
,
LockClosedIcon
,
LockOpenIcon
,
TrashIcon
,
}
from
'@heroicons/react/24/outline'
;
import
clsx
from
'clsx'
;
import
clsx
from
'clsx'
;
import
dayjs
from
'dayjs'
;
import
dayjs
from
'dayjs'
;
import
{
useCallback
,
useEffect
,
useMemo
,
useState
}
from
'react'
;
import
{
useCallback
,
useEffect
,
useMemo
,
useState
}
from
'react'
;
...
@@ -48,10 +54,13 @@ import {
...
@@ -48,10 +54,13 @@ import {
import
{
import
{
DEFAULT_PROBLEM_RECTIFICATION_PAGE_SIZE
,
DEFAULT_PROBLEM_RECTIFICATION_PAGE_SIZE
,
PROBLEM_RECTIFICATION_SUBJECT
,
PROBLEM_RECTIFICATION_SUBJECT
,
AUDIT_STATUS_APPROVED
,
AUDIT_STATUS_PENDING
,
AUDIT_STATUS_PENDING
,
AUDIT_STATUS_REJECTED
,
DELAY_REQUEST_FIELD
,
DELAY_REQUEST_FIELD
,
DELAY_REQUEST_ITEMS_FIELD
,
DELAY_REQUEST_ITEMS_FIELD
,
DEPARTMENT_RECTIFICATION_FIELD
,
DEPARTMENT_RECTIFICATION_FIELD
,
EDITOR_STATUS_COMPLETED
,
EDITOR_STATUS_PENDING
,
EDITOR_STATUS_PENDING
,
FLOW_MODE_BATCH
,
FLOW_MODE_BATCH
,
FLOW_MODE_DELAY_DEPARTMENT
,
FLOW_MODE_DELAY_DEPARTMENT
,
...
@@ -127,7 +136,7 @@ const CREATE_FIELD_OPTION_OVERRIDES = {
...
@@ -127,7 +136,7 @@ const CREATE_FIELD_OPTION_OVERRIDES = {
is_repeated_problem
:
[
'是'
,
'否'
],
is_repeated_problem
:
[
'是'
,
'否'
],
};
};
function
StatusPill
({
text
,
tone
=
'default'
})
{
function
StatusPill
({
text
,
tone
=
'default'
,
icon
:
Icon
=
null
,
title
})
{
const
toneClass
=
const
toneClass
=
tone
===
'rose'
tone
===
'rose'
?
'bg-rose-50 text-rose-700 ring-rose-100'
?
'bg-rose-50 text-rose-700 ring-rose-100'
...
@@ -138,12 +147,89 @@ function StatusPill({ text, tone = 'default' }) {
...
@@ -138,12 +147,89 @@ function StatusPill({ text, tone = 'default' }) {
:
'bg-slate-100 text-slate-600 ring-slate-200'
;
:
'bg-slate-100 text-slate-600 ring-slate-200'
;
return
(
return
(
<
span
className=
{
clsx
(
'inline-flex rounded-full px-3 py-1 text-xs font-medium ring-1'
,
toneClass
)
}
>
<
span
className=
{
clsx
(
'inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-medium ring-1'
,
toneClass
,
)
}
title=
{
title
}
>
{
Icon
?
<
Icon
className=
"size-3.5 shrink-0"
aria
-
hidden=
"true"
/>
:
null
}
{
text
||
'-'
}
{
text
||
'-'
}
</
span
>
</
span
>
);
);
}
}
function
getRecordDelayRequests
(
record
)
{
return
[
record
?.
delayRequest
,
...(
record
?.
delayRequestItems
||
[])].
filter
(
Boolean
);
}
function
resolveDelayRequestDisplay
(
record
)
{
const
requests
=
getRecordDelayRequests
(
record
);
if
(
requests
.
length
===
0
)
{
return
null
;
}
const
everyRequestMatches
=
(
field
,
value
)
=>
requests
.
every
((
request
)
=>
request
?.[
field
]
===
value
);
const
anyRequestMatches
=
(
field
,
value
)
=>
requests
.
some
((
request
)
=>
request
?.[
field
]
===
value
);
const
title
=
`共
${
requests
.
length
}
条延期申请`
;
if
(
anyRequestMatches
(
'auditor_status'
,
AUDIT_STATUS_REJECTED
)
||
anyRequestMatches
(
'sender_status'
,
AUDIT_STATUS_REJECTED
)
)
{
return
{
text
:
'延期已退回'
,
tone
:
'rose'
,
title
};
}
if
(
everyRequestMatches
(
'sender_status'
,
AUDIT_STATUS_APPROVED
))
{
return
{
text
:
'延期已生效'
,
tone
:
'emerald'
,
title
};
}
if
(
everyRequestMatches
(
'auditor_status'
,
AUDIT_STATUS_APPROVED
))
{
return
{
text
:
'延期待终审'
,
tone
:
'amber'
,
title
};
}
if
(
everyRequestMatches
(
'editor_status'
,
EDITOR_STATUS_COMPLETED
))
{
return
{
text
:
'延期待审批'
,
tone
:
'amber'
,
title
};
}
const
hasProgressedRequest
=
requests
.
some
(
(
request
)
=>
request
?.
editor_status
===
EDITOR_STATUS_COMPLETED
||
request
?.
auditor_status
===
AUDIT_STATUS_APPROVED
||
request
?.
sender_status
===
AUDIT_STATUS_APPROVED
,
);
return
{
text
:
hasProgressedRequest
?
'延期处理中'
:
'延期已发起'
,
tone
:
'amber'
,
title
,
};
}
function
resolveDelayStatusTone
(
status
=
''
)
{
if
(
status
===
EDITOR_STATUS_COMPLETED
||
status
===
AUDIT_STATUS_APPROVED
)
{
return
'emerald'
;
}
if
(
status
===
AUDIT_STATUS_REJECTED
)
{
return
'rose'
;
}
return
'default'
;
}
function
formatDelayDate
(
value
)
{
if
(
!
value
)
{
return
'待填写'
;
}
const
parsedDate
=
dayjs
(
value
);
return
parsedDate
.
isValid
()
?
parsedDate
.
format
(
'YYYY-MM-DD'
)
:
String
(
value
);
}
function
resolveProgressTone
(
progress
=
''
)
{
function
resolveProgressTone
(
progress
=
''
)
{
if
(
progress
===
'已整改'
||
progress
===
'已优化'
)
{
if
(
progress
===
'已整改'
||
progress
===
'已优化'
)
{
return
'emerald'
;
return
'emerald'
;
...
@@ -656,6 +742,7 @@ export default function ProblemRectificationListPage() {
...
@@ -656,6 +742,7 @@ export default function ProblemRectificationListPage() {
const [showCreateModal, setShowCreateModal] = useState(false);
const [showCreateModal, setShowCreateModal] = useState(false);
const [showPushModal, setShowPushModal] = useState(false);
const [showPushModal, setShowPushModal] = useState(false);
const [showDelayPushModal, setShowDelayPushModal] = useState(false);
const [showDelayPushModal, setShowDelayPushModal] = useState(false);
const [delayDetailRecord, setDelayDetailRecord] = useState(null);
const [cloneTargetRecord, setCloneTargetRecord] = useState(null);
const [cloneTargetRecord, setCloneTargetRecord] = useState(null);
const [formValues, setFormValues] = useState({});
const [formValues, setFormValues] = useState({});
const [fillerUsers, setFillerUsers] = useState([]);
const [fillerUsers, setFillerUsers] = useState([]);
...
@@ -672,7 +759,7 @@ export default function ProblemRectificationListPage() {
...
@@ -672,7 +759,7 @@ export default function ProblemRectificationListPage() {
totalPages: 1,
totalPages: 1,
});
});
const [gridViewCounts, setGridViewCounts] = useState({});
const [gridViewCounts, setGridViewCounts] = useState({});
const [
departmentUserLabels, setDepartment
UserLabels] = useState({});
const [
workflowUserLabels, setWorkflow
UserLabels] = useState({});
const reloadResources = useCallback(async () => {
const reloadResources = useCallback(async () => {
setLoading(true);
setLoading(true);
...
@@ -700,14 +787,21 @@ export default function ProblemRectificationListPage() {
...
@@ -700,14 +787,21 @@ export default function ProblemRectificationListPage() {
useEffect(() => {
useEffect(() => {
const userIds = Array.from(
const userIds = Array.from(
new Set(
new Set(
records.flatMap((record) =>
records
(record.departmentItems || []).flatMap((item) => [item.editor, item.auditor]),
.flatMap((record) => [
).filter(Boolean),
...(record.departmentItems || []).flatMap((item) => [item.editor, item.auditor]),
...getRecordDelayRequests(record).flatMap((item) => [
item.editor,
item.auditor,
item.sender,
]),
])
.filter(Boolean),
),
),
);
);
if (userIds.length === 0) {
if (userIds.length === 0) {
set
Department
UserLabels({});
set
Workflow
UserLabels({});
return;
return;
}
}
...
@@ -717,7 +811,7 @@ export default function ProblemRectificationListPage() {
...
@@ -717,7 +811,7 @@ export default function ProblemRectificationListPage() {
if (cancelled) {
if (cancelled) {
return;
return;
}
}
set
Department
UserLabels(
set
Workflow
UserLabels(
Object.fromEntries(
Object.fromEntries(
(result?.users || []).map((user) => [
(result?.users || []).map((user) => [
user._id,
user._id,
...
@@ -728,7 +822,7 @@ export default function ProblemRectificationListPage() {
...
@@ -728,7 +822,7 @@ export default function ProblemRectificationListPage() {
})
})
.catch(() => {
.catch(() => {
if (!cancelled) {
if (!cancelled) {
set
Department
UserLabels({});
set
Workflow
UserLabels({});
}
}
});
});
...
@@ -854,6 +948,8 @@ export default function ProblemRectificationListPage() {
...
@@ -854,6 +948,8 @@ export default function ProblemRectificationListPage() {
[filteredRecords, selectedIds],
[filteredRecords, selectedIds],
);
);
const hasLockedSelection = selectedRecords.some((record) => record.isLocked);
const hasLockedSelection = selectedRecords.some((record) => record.isLocked);
const selectedDelayRequestDisplay =
selectedRecords.length === 1 ? resolveDelayRequestDisplay(selectedRecords[0]) : null;
useEffect(() => {
useEffect(() => {
const visibleIds = new Set(filteredRecords.map((item) => item.id));
const visibleIds = new Set(filteredRecords.map((item) => item.id));
...
@@ -1594,7 +1690,7 @@ export default function ProblemRectificationListPage() {
...
@@ -1594,7 +1690,7 @@ export default function ProblemRectificationListPage() {
isRowExpandable={(record) => record.departmentItems?.length > 0}
isRowExpandable={(record) => record.departmentItems?.length > 0}
getExpandedRecordRows={({ record }) => (
getExpandedRecordRows={({ record }) => (
(record.departmentItems || []).map((item) =>
(record.departmentItems || []).map((item) =>
buildDepartmentDetailRecord(record, item,
department
UserLabels),
buildDepartmentDetailRecord(record, item,
workflow
UserLabels),
)
)
)}
)}
toolbarActions={[
toolbarActions={[
...
@@ -1614,9 +1710,13 @@ export default function ProblemRectificationListPage() {
...
@@ -1614,9 +1710,13 @@ export default function ProblemRectificationListPage() {
},
},
{
{
key: 'push-delay-request',
key: 'push-delay-request',
label: '推送延期申请',
label:
selectedDelayRequestDisplay?.text ||
'推送延期申请',
variant: 'outline',
variant: 'outline',
disabled: () => selectedIds.length !== 1 || hasLockedSelection || actionLoading,
disabled: () =>
selectedIds.length !== 1 ||
hasLockedSelection ||
Boolean(selectedDelayRequestDisplay) ||
actionLoading,
onClick: openDelayPushModal,
onClick: openDelayPushModal,
},
},
{
{
...
@@ -1649,6 +1749,14 @@ export default function ProblemRectificationListPage() {
...
@@ -1649,6 +1749,14 @@ export default function ProblemRectificationListPage() {
variant: 'plain',
variant: 'plain',
onClick: ({ openDetail, record }) => openDetail(record),
onClick: ({ openDetail, record }) => openDetail(record),
},
},
{
key: 'view-delay-request',
label: '查看延期申请',
icon: CalendarDaysIcon,
variant: 'outline',
hidden: ({ record }) => !resolveDelayRequestDisplay(record),
onClick: ({ record }) => setDelayDetailRecord(record),
},
{
{
key: 'lock',
key: 'lock',
label: '锁定',
label: '锁定',
...
@@ -1748,9 +1856,34 @@ export default function ProblemRectificationListPage() {
...
@@ -1748,9 +1856,34 @@ export default function ProblemRectificationListPage() {
return fieldPreview;
return fieldPreview;
}
}
const delayRequestDisplay = record.isDepartmentDetailRow
? null
: resolveDelayRequestDisplay(record);
return (
return (
<div className="flex flex-wrap items-center gap-x-2 gap-y-1">
<div className="flex flex-wrap items-center gap-x-2 gap-y-1">
{fieldPreview}
{fieldPreview}
{delayRequestDisplay ? (
<BadgeButton
color={
delayRequestDisplay.tone === 'rose'
? 'rose'
: delayRequestDisplay.tone === 'emerald'
? 'emerald'
: 'amber'
}
title={delayRequestDisplay.title}
aria-label={`
查看
$
{
record
.
title
||
record
.
projectName
||
'当前问题'
}
的延期申请详情
`}
onClick={(event) => {
event.stopPropagation();
setDelayDetailRecord(record);
}}
>
<CalendarDaysIcon className="size-3.5 shrink-0" aria-hidden="true" />
{delayRequestDisplay.text}
<span className="sr-only">,点击查看填写数据</span>
</BadgeButton>
) : null}
{!record.isDepartmentDetailRow && record.isLocked ? (
{!record.isDepartmentDetailRow && record.isLocked ? (
<StatusPill text="已锁定" tone="amber" />
<StatusPill text="已锁定" tone="amber" />
) : null}
) : null}
...
@@ -1773,6 +1906,90 @@ export default function ProblemRectificationListPage() {
...
@@ -1773,6 +1906,90 @@ export default function ProblemRectificationListPage() {
}}
}}
/>
/>
{delayDetailRecord ? (
<Dialog
open={Boolean(delayDetailRecord)}
onClose={() => setDelayDetailRecord(null)}
size="5xl"
>
<DialogTitle>延期申请详情</DialogTitle>
<DialogDescription>
{delayDetailRecord.title || delayDetailRecord.projectName || '当前问题'},共{' '}
{getRecordDelayRequests(delayDetailRecord).length} 条延期申请。尚未提交的申请完成时间和延期事由显示为“待填写”。
</DialogDescription>
<DialogBody>
<div className="overflow-hidden rounded-lg border border-zinc-200 bg-white">
<Table bleed dense className="[--gutter:--spacing(4)]">
<TableHead>
<TableRow className="bg-zinc-50">
<TableHeader>责任部门</TableHeader>
<TableHeader>原预计完成时间</TableHeader>
<TableHeader>申请完成时间</TableHeader>
<TableHeader>延期事由</TableHeader>
<TableHeader>填写人</TableHeader>
<TableHeader>一级审批人</TableHeader>
<TableHeader>最终审批人</TableHeader>
<TableHeader>填写状态</TableHeader>
<TableHeader>一级审批状态</TableHeader>
<TableHeader>最终审批状态</TableHeader>
</TableRow>
</TableHead>
<TableBody>
{getRecordDelayRequests(delayDetailRecord).map((request, index) => (
<TableRow key={request.item_id || `
delay
-
request
-
$
{
index
}
`}>
<TableCell className="min-w-40 align-top font-medium text-slate-900">
{request.responsible_department || '整条问题'}
</TableCell>
<TableCell className="align-top tabular-nums">
{formatDelayDate(request.original_due_date)}
</TableCell>
<TableCell className="align-top tabular-nums font-medium text-slate-900">
{formatDelayDate(request.requested_due_date)}
</TableCell>
<TableCell className="min-w-72 max-w-md whitespace-normal align-top text-slate-700">
{request.delay_reason || '待填写'}
</TableCell>
<TableCell className="align-top">
{workflowUserLabels[request.editor] || request.editor || '待填写'}
</TableCell>
<TableCell className="align-top">
{workflowUserLabels[request.auditor] || request.auditor || '待填写'}
</TableCell>
<TableCell className="align-top">
{workflowUserLabels[request.sender] || request.sender || '待填写'}
</TableCell>
<TableCell className="align-top">
<StatusPill
text={request.editor_status || EDITOR_STATUS_PENDING}
tone={resolveDelayStatusTone(request.editor_status)}
/>
</TableCell>
<TableCell className="align-top">
<StatusPill
text={request.auditor_status || AUDIT_STATUS_PENDING}
tone={resolveDelayStatusTone(request.auditor_status)}
/>
</TableCell>
<TableCell className="align-top">
<StatusPill
text={request.sender_status || AUDIT_STATUS_PENDING}
tone={resolveDelayStatusTone(request.sender_status)}
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</DialogBody>
<DialogActions>
<Button outline onClick={() => setDelayDetailRecord(null)}>
关闭
</Button>
</DialogActions>
</Dialog>
) : null}
<Dialog open={showCreateModal} onClose={handleCloseCreateModal} size="5xl">
<Dialog open={showCreateModal} onClose={handleCloseCreateModal} size="5xl">
<DialogTitle>新增问题整改记录</DialogTitle>
<DialogTitle>新增问题整改记录</DialogTitle>
<DialogDescription>
<DialogDescription>
...
...
src/pages/problem_rectification/problem-rectification.business-flow.md
View file @
48dae1c1
...
@@ -79,6 +79,9 @@
...
@@ -79,6 +79,9 @@
-
主列表提供“检查报告出具月份”筛选,用户选择
`YYYY-MM`
后,仅查询
`metadata.inspection_report_date`
位于该月份的记录;该筛选不使用其它检查或整改日期兜底
-
主列表提供“检查报告出具月份”筛选,用户选择
`YYYY-MM`
后,仅查询
`metadata.inspection_report_date`
位于该月份的记录;该筛选不使用其它检查或整改日期兜底
-
主列表支持每页
`10 / 20 / 50 / 100`
条,切换视图、修改筛选或清空筛选时回到第 1 页;表头勾选只选择当前页记录,跨页批量处理需用户逐页确认选择范围
-
主列表支持每页
`10 / 20 / 50 / 100`
条,切换视图、修改筛选或清空筛选时回到第 1 页;表头勾选只选择当前页记录,跨页批量处理需用户逐页确认选择范围
-
主列表视图页签数量通过
`/record/count`
按各视图限制和当前筛选条件计算,表格标题区展示服务端筛选后的总数与当前页记录数
-
主列表视图页签数量通过
`/record/count`
按各视图限制和当前筛选条件计算,表格标题区展示服务端筛选后的总数与当前页记录数
-
主列表标题列直接展示可点击的延期申请状态:存在历史问题级延期或部门级延期明细时,按当前阶段显示“延期已发起 / 延期待审批 / 延期待终审 / 延期处理中 / 延期已生效 / 延期已退回”日历徽标,不能等用户再次点击推送后才提示已发起;状态同时使用图标和文字,不只依赖颜色
-
点击延期状态后打开“延期申请详情”弹窗,按责任部门展示原预计完成时间、申请完成时间、延期事由、填写人、一级审批人、最终审批人以及三级流程状态;申请完成时间或延期事由尚未提交时明确显示“待填写”,历史问题级延期按“整条问题”展示;行操作区同时提供“查看延期申请”日历按钮,保证窄屏下标题列被固定列压缩时仍可进入详情
-
用户单选已有延期申请的记录时,顶部“推送延期申请”按钮改为显示当前延期状态并禁用,避免形成看似可以重复推送的入口
-
主列表滚动到表格区域后,表格工作台吸顶展示;标题栏、操作区、列分组和分页固定在工作台内,数据表格区域独立滚动,表头列名在数据区域内继续吸顶,折叠 / 展开列分组时保留当前表格滚动位置
-
主列表滚动到表格区域后,表格工作台吸顶展示;标题栏、操作区、列分组和分页固定在工作台内,数据表格区域独立滚动,表头列名在数据区域内继续吸顶,折叠 / 展开列分组时保留当前表格滚动位置
-
详情侧栏统一复用
`RecordDetailDrawer`
,通过
`recordName`
、
`subjectName`
、
`preferredViewName`
驱动,不再在各页面重复实现抽屉骨架
-
详情侧栏统一复用
`RecordDetailDrawer`
,通过
`recordName`
、
`subjectName`
、
`preferredViewName`
驱动,不再在各页面重复实现抽屉骨架
-
详情侧栏顶部不展示记录标题、状态和摘要卡片,只保留详情视图切换与全屏 / 关闭操作,字段主体作为主要阅读区域
-
详情侧栏顶部不展示记录标题、状态和摘要卡片,只保留详情视图切换与全屏 / 关闭操作,字段主体作为主要阅读区域
...
@@ -350,7 +353,8 @@
...
@@ -350,7 +353,8 @@
推荐新交互:
推荐新交互:
-
页面顶部显示本次流程步骤和当前身份
-
页面顶部必须以图标、文字标签和独立色调明确区分“问题整改流程”与“延期申请流程”,不能只在流程模式说明中体现;问题整改页提示其处理整改进度、预计完成时间、整改情况和证明材料,延期页提示其处理新的整改完成时间和延期事由
-
明细表顶部再次显示“问题整改明细”或“延期申请明细”及当前行数,用户从 OA 待办直接进入页面或横向浏览表格时仍能识别当前处理类型;流程类型不能只靠颜色表达
-
主体统一使用表格,不再使用旧填写页的详情式编辑
-
主体统一使用表格,不再使用旧填写页的详情式编辑
-
长文本、附件、预计完成时间和整改进度均在表格行内维护
-
长文本、附件、预计完成时间和整改进度均在表格行内维护
-
部门流程的“送审”和各阶段审批作为行级操作展示;多选简单推送的送审、复核和最终审批按钮统一放在表格上方,行内只保留“保存”
-
部门流程的“送审”和各阶段审批作为行级操作展示;多选简单推送的送审、复核和最终审批按钮统一放在表格上方,行内只保留“保存”
...
...
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