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
b52ff11f
Commit
b52ff11f
authored
May 28, 2026
by
David Yang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: bugs
parent
40f35588
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
145 additions
and
21 deletions
+145
-21
TailwindEditableField.jsx
...s/RecordDetailDrawer/components/TailwindEditableField.jsx
+79
-3
index.jsx
src/pages/RecordDetailDrawer/index.jsx
+12
-1
Layout.jsx
src/pages/problem_rectification/Layout.jsx
+8
-17
index.jsx
src/pages/problem_rectification/list/index.jsx
+0
-0
problem-rectification.business-flow.md
...blem_rectification/problem-rectification.business-flow.md
+21
-0
problemRectificationListService.js
.../problem_rectification/problemRectificationListService.js
+25
-0
No files found.
src/pages/RecordDetailDrawer/components/TailwindEditableField.jsx
View file @
b52ff11f
...
...
@@ -27,6 +27,10 @@ function asSaveValue(value, fieldDef) {
return
value
;
}
function
getClearedValue
(
fieldDef
)
{
return
fieldDef
?.
multiple
?
[]
:
null
;
}
function
Pill
({
children
,
tone
=
'zinc'
})
{
const
toneClass
=
tone
===
'rose'
...
...
@@ -241,6 +245,12 @@ export default function TailwindEditableField({
}
};
const
clearValue
=
async
()
=>
{
const
clearedValue
=
getClearedValue
(
fieldDef
);
setDraft
(
clearedValue
);
await
save
(
clearedValue
);
};
const
cancel
=
()
=>
{
setDraft
(
value
);
setError
(
''
);
...
...
@@ -259,7 +269,8 @@ export default function TailwindEditableField({
try
{
const
uploaded
=
await
uploadFile
(
file
);
const
fileValue
=
uploaded
?.
file
||
uploaded
?.
data
||
uploaded
;
const
nextValue
=
fieldDef
?.
multiple
?
[...
toArray
(
value
),
fileValue
]
:
fileValue
;
const
nextValue
=
fieldDef
?.
multiple
?
[...
toArray
(
draft
),
fileValue
]
:
fileValue
;
setDraft
(
nextValue
);
await
onSave
(
nextValue
);
setEditing
(
false
);
}
catch
(
uploadError
)
{
...
...
@@ -269,6 +280,25 @@ export default function TailwindEditableField({
}
};
const
handleRemoveFile
=
async
(
indexToRemove
)
=>
{
setError
(
''
);
const
nextValue
=
fieldDef
?.
multiple
?
toArray
(
draft
).
filter
((
_
,
index
)
=>
index
!==
indexToRemove
)
:
null
;
try
{
setDraft
(
nextValue
);
await
onSave
(
nextValue
);
if
(
!
fieldDef
?.
multiple
)
{
setEditing
(
false
);
}
}
catch
(
saveError
)
{
setDraft
(
draft
);
setError
(
saveError
?.
message
||
'删除附件失败,请稍后重试。'
);
}
};
if
(
!
editing
)
{
return
(
<
button
...
...
@@ -300,7 +330,10 @@ export default function TailwindEditableField({
<
div
className=
"flex items-center gap-3 rounded-2xl border border-zinc-200 bg-white px-3 py-2"
>
<
Checkbox
checked=
{
Boolean
(
draft
)
}
onChange=
{
(
checked
)
=>
setDraft
(
checked
)
}
color=
"rose"
/>
<
span
className=
"text-sm text-zinc-700"
>
{
draft
?
'是'
:
'否'
}
</
span
>
<
button
type=
"button"
onClick=
{
()
=>
save
(
Boolean
(
draft
))
}
className=
"ml-auto text-sm font-medium text-rose-700"
>
<
button
type=
"button"
onClick=
{
clearValue
}
className=
"ml-auto text-sm font-medium text-rose-600"
>
清空
</
button
>
<
button
type=
"button"
onClick=
{
()
=>
save
(
Boolean
(
draft
))
}
className=
"text-sm font-medium text-rose-700"
>
保存
</
button
>
<
button
type=
"button"
onClick=
{
cancel
}
className=
"text-sm text-zinc-500"
>
...
...
@@ -334,6 +367,7 @@ export default function TailwindEditableField({
))
}
</
Select
>
<
div
className=
"flex justify-end gap-2"
>
<
button
type=
"button"
onClick=
{
clearValue
}
className=
"text-sm font-medium text-rose-600"
>
清空
</
button
>
<
button
type=
"button"
onClick=
{
cancel
}
className=
"text-sm text-zinc-500"
>
取消
</
button
>
<
button
type=
"button"
onClick=
{
()
=>
save
()
}
className=
"text-sm font-medium text-rose-700"
>
保存
</
button
>
</
div
>
...
...
@@ -347,6 +381,7 @@ export default function TailwindEditableField({
<
div
className=
"space-y-3"
>
<
UserSelector
value=
{
draft
}
onChange=
{
setDraft
}
multiple=
{
fieldDef
?.
multiple
}
/>
<
div
className=
"flex justify-end gap-2"
>
<
button
type=
"button"
onClick=
{
clearValue
}
className=
"text-sm font-medium text-rose-600"
>
清空
</
button
>
<
button
type=
"button"
onClick=
{
cancel
}
className=
"text-sm text-zinc-500"
>
取消
</
button
>
<
button
type=
"button"
onClick=
{
()
=>
save
()
}
className=
"text-sm font-medium text-rose-700"
>
保存
</
button
>
</
div
>
...
...
@@ -364,6 +399,7 @@ export default function TailwindEditableField({
onChange=
{
setDraft
}
/>
<
div
className=
"flex justify-end gap-2"
>
<
button
type=
"button"
onClick=
{
clearValue
}
className=
"text-sm font-medium text-rose-600"
>
清空
</
button
>
<
button
type=
"button"
onClick=
{
cancel
}
className=
"text-sm text-zinc-500"
>
取消
</
button
>
<
button
type=
"button"
onClick=
{
()
=>
save
()
}
className=
"text-sm font-medium text-rose-700"
>
保存
</
button
>
</
div
>
...
...
@@ -375,10 +411,47 @@ export default function TailwindEditableField({
if
(
fieldType
===
'file'
)
{
return
(
<
div
className=
"space-y-3 rounded-2xl border border-zinc-200 bg-white p-3"
>
<
FieldValue
value=
{
value
}
fieldDef=
{
fieldDef
}
/>
<
div
className=
"space-y-2"
>
{
toArray
(
draft
).
length
===
0
?
(
<
span
className=
"text-zinc-400"
>
未上传
</
span
>
)
:
(
toArray
(
draft
).
map
((
file
,
index
)
=>
{
const
label
=
file
?.
name
||
file
?.
title
||
file
?.
url
||
`附件 ${index + 1}`
;
return
(
<
div
key=
{
`${label}-${index}`
}
className=
"flex items-center justify-between gap-3 rounded-2xl border border-zinc-100 bg-zinc-50 px-3 py-2"
>
<
div
className=
"min-w-0 flex-1"
>
{
file
?.
url
?
(
<
a
href=
{
file
.
url
}
target=
"_blank"
rel=
"noreferrer"
className=
"text-sm font-medium text-sky-700 transition hover:text-sky-800"
>
{
label
}
</
a
>
)
:
(
<
div
className=
"text-sm font-medium text-zinc-700"
>
{
label
}
</
div
>
)
}
</
div
>
<
button
type=
"button"
onClick=
{
()
=>
handleRemoveFile
(
index
)
}
className=
"shrink-0 text-sm font-medium text-rose-600"
>
删除
</
button
>
</
div
>
);
})
)
}
</
div
>
<
input
type=
"file"
onChange=
{
handleFileUpload
}
disabled=
{
uploading
}
className=
"block w-full text-sm text-zinc-600"
/>
{
error
?
<
div
className=
"text-sm text-rose-600"
>
{
error
}
</
div
>
:
null
}
<
div
className=
"flex justify-end gap-2"
>
<
button
type=
"button"
onClick=
{
clearValue
}
className=
"text-sm font-medium text-rose-600"
>
清空
</
button
>
<
button
type=
"button"
onClick=
{
cancel
}
className=
"text-sm text-zinc-500"
>
取消
</
button
>
<
span
className=
"text-sm text-zinc-400"
>
{
uploading
?
'上传中...'
:
'选择文件后自动保存'
}
</
span
>
</
div
>
...
...
@@ -393,6 +466,7 @@ export default function TailwindEditableField({
<
Textarea
rows=
{
8
}
value=
{
jsonValue
}
onChange=
{
(
event
)
=>
setDraft
(
event
.
target
.
value
)
}
resizable
/>
{
error
?
<
div
className=
"text-sm text-rose-600"
>
{
error
}
</
div
>
:
null
}
<
div
className=
"flex justify-end gap-2"
>
<
button
type=
"button"
onClick=
{
clearValue
}
className=
"text-sm font-medium text-rose-600"
>
清空
</
button
>
<
button
type=
"button"
onClick=
{
cancel
}
className=
"text-sm text-zinc-500"
>
取消
</
button
>
<
button
type=
"button"
...
...
@@ -411,6 +485,7 @@ export default function TailwindEditableField({
<
div
className=
"space-y-3"
>
<
Textarea
rows=
{
5
}
value=
{
draft
||
''
}
onChange=
{
(
event
)
=>
setDraft
(
event
.
target
.
value
)
}
autoFocus
/>
<
div
className=
"flex justify-end gap-2"
>
<
button
type=
"button"
onClick=
{
clearValue
}
className=
"text-sm font-medium text-rose-600"
>
清空
</
button
>
<
button
type=
"button"
onClick=
{
cancel
}
className=
"text-sm text-zinc-500"
>
取消
</
button
>
<
button
type=
"button"
onClick=
{
()
=>
save
()
}
className=
"text-sm font-medium text-rose-700"
>
保存
</
button
>
</
div
>
...
...
@@ -433,6 +508,7 @@ export default function TailwindEditableField({
autoFocus
/>
<
div
className=
"flex justify-end gap-2"
>
<
button
type=
"button"
onClick=
{
clearValue
}
className=
"text-sm font-medium text-rose-600"
>
清空
</
button
>
<
button
type=
"button"
onClick=
{
cancel
}
className=
"text-sm text-zinc-500"
>
取消
</
button
>
<
button
type=
"button"
onClick=
{
()
=>
save
()
}
className=
"text-sm font-medium text-rose-700"
>
保存
</
button
>
</
div
>
...
...
src/pages/RecordDetailDrawer/index.jsx
View file @
b52ff11f
...
...
@@ -63,6 +63,7 @@ const RecordDetailDrawer = (props, ref) => {
onDataChange
,
readonly
=
false
,
filterView
=
[],
preferredViewName
,
}
=
props
;
const
[
refreshKey
,
setRefreshKey
]
=
useState
(()
=>
Date
.
now
());
...
...
@@ -112,11 +113,21 @@ const RecordDetailDrawer = (props, ref) => {
return
;
}
if
(
preferredViewName
)
{
const
matchedView
=
detailViews
.
find
(
(
view
)
=>
view
.
name
===
preferredViewName
||
view
.
title
===
preferredViewName
,
);
if
(
matchedView
&&
matchedView
.
name
!==
activeTabKey
)
{
setActiveTabKey
(
matchedView
.
name
);
return
;
}
}
const
currentTab
=
detailViews
.
find
((
view
)
=>
view
.
name
===
activeTabKey
);
if
(
!
currentTab
)
{
setActiveTabKey
(
detailViews
[
0
].
name
);
}
},
[
detailViews
,
activeTabKey
]);
},
[
detailViews
,
activeTabKey
,
preferredViewName
]);
useImperativeHandle
(
ref
,
...
...
src/pages/problem_rectification/Layout.jsx
View file @
b52ff11f
import
xyLogo
from
'@/assets/xy-logo.png'
;
import
xyLogoSmall
from
'@/assets/xy-logo_small.png'
;
import
{
UserContext
}
from
'@/wrapper/Auth'
;
import
{
...
...
@@ -244,16 +243,13 @@ export default function ProblemRectificationLayout() {
sidebarCollapsed
?
'justify-center'
:
'gap-3 px-1'
,
)
}
>
<
img
src=
{
sidebarCollapsed
?
xyLogoSmall
:
xyLogo
}
alt=
"XY Logo"
className=
{
clsx
(
'shrink-0 object-contain'
,
sidebarCollapsed
?
'h-8 w-auto max-w-8'
:
'h-8 w-auto max-w-[140px]'
,
)
}
/>
{
sidebarCollapsed
?
(
<
img
src=
{
xyLogoSmall
}
alt=
"XY Logo"
className=
"h-8 w-auto max-w-8 shrink-0 object-contain"
/>
)
:
null
}
{
!
sidebarCollapsed
?
(
<
div
className=
"min-w-0"
>
<
h1
className=
"truncate text-sm font-semibold tracking-[0.02em] text-white/95"
>
...
...
@@ -327,12 +323,7 @@ export default function ProblemRectificationLayout() {
close=
{
()
=>
setIsMobileSidebarOpen
(
false
)
}
>
<
div
className=
"px-5 pt-6"
>
<
div
className=
"flex items-center gap-2"
>
<
img
src=
{
xyLogo
}
alt=
"XY Logo"
className=
"h-8 w-auto max-w-[140px] shrink-0 object-contain"
/>
<
div
>
<
div
>
<
h1
className=
"text-base font-semibold tracking-[0.02em] text-white"
>
{
APP_NAME
}
...
...
src/pages/problem_rectification/list/index.jsx
View file @
b52ff11f
This diff is collapsed.
Click to expand it.
src/pages/problem_rectification/problem-rectification.business-flow.md
View file @
b52ff11f
...
...
@@ -51,6 +51,19 @@
-
新增、编辑、查看详情优先采用抽屉或弹窗,不走重型嵌套表格交互
-
批量操作放在顶部工具栏,不再依赖右键菜单作为唯一入口
### 3.3 视图配置驱动约定
问题整改主列表与详情抽屉统一以
`getSubjectView(subjectName)`
返回的视图配置驱动,不再在页面内写死部门标签和字段顺序:
-
`type = "grid"`
的视图用于主列表顶部视图切换,替代原先写死的 tab
-
`settings.columns`
决定列表列顺序、宽度和排序优先级
-
`settings.restrictions`
与
`settings.filters.conditions`
共同决定该视图下可见的数据范围
-
`settings.viewAuth`
决定当前用户是否能看到该视图
-
`type = "detail"`
的视图用于详情抽屉字段编排,按
`columns`
顺序渲染字段
-
`settings.auth`
与
`disableColumns`
用于控制详情抽屉内字段是否允许编辑
因此前端新增字段展示、部门视图调整、列顺序变化时,应优先改 Subject View 配置,而不是直接修改页面常量。
### 3.1 目标页面拆分
为便于当前项目直接重构,建议把模块拆成以下 4 个页面入口:
...
...
@@ -179,6 +192,13 @@
-
表格内分组拖拽
-
全屏容器能力
替代实现约定:
-
列表页保留表格浏览、搜索、筛选、批量选择
-
字段编辑统一进入右侧详情抽屉
-
长文本、附件、状态类字段在详情抽屉中直接维护
-
详情抽屉内字段顺序与显示权限跟随
`detail view`
配置
---
## 6. 流程角色
...
...
@@ -624,6 +644,7 @@ const result = await queryUsers(0, 20, {
布局层负责:
-
左侧菜单
-
桌面展开态仅展示模块名称,去掉大 Logo;仅在桌面折叠态展示小 Logo
-
顶部用户区
-
内容容器
-
移动端侧栏开关
...
...
src/pages/problem_rectification/problemRectificationListService.js
View file @
b52ff11f
...
...
@@ -7,6 +7,7 @@ import {
import
{
DEPARTMENT_GROUPS
}
from
'./problemRectificationDashboardService'
;
import
{
buildViewColumns
,
checkViewCondition
,
emptyValueForField
,
formatFieldValue
,
getFieldNameFromPath
,
...
...
@@ -162,6 +163,18 @@ export function buildProblemRectificationConfiguredListView(records, filters, gr
return
false
;
}
if
(
!
checkViewCondition
(
{
relationship
:
gridView
?.
settings
?.
filters
?.
relationship
||
'all'
,
rules
:
gridView
?.
settings
?.
filters
?.
conditions
||
[],
},
rawRecord
,
)
)
{
return
false
;
}
if
(
nextProgress
&&
record
.
progress
!==
nextProgress
)
{
return
false
;
}
...
...
@@ -200,6 +213,18 @@ export function buildProblemRectificationConfiguredListView(records, filters, gr
};
}
export
function
buildGridViewCountMap
(
records
,
filters
,
views
,
subject
)
{
return
views
.
reduce
((
counts
,
view
)
=>
{
counts
[
view
.
name
]
=
buildProblemRectificationConfiguredListView
(
records
,
filters
,
view
,
subject
,
).
filteredRecords
.
length
;
return
counts
;
},
{});
}
function
matchesDepartmentGroup
(
record
,
groupKey
)
{
if
(
!
groupKey
||
groupKey
===
'all'
)
{
return
true
;
...
...
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