Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
I
internal_regulation_manager_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
internal_regulation_manager_new
Commits
64fcb2ae
Commit
64fcb2ae
authored
Sep 15, 2026
by
drigle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: 优化列表分页并移除页面描述
parent
ae0fc992
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
165 additions
and
25 deletions
+165
-25
ListPagination.jsx
src/components/ListPagination.jsx
+88
-0
ArchiveList.jsx
src/pages/internal_regulation_manager/ArchiveList.jsx
+9
-5
InternalRegulationManager.jsx
...internal_regulation_manager/InternalRegulationManager.jsx
+0
-1
RegulationGraph.jsx
src/pages/internal_regulation_manager/RegulationGraph.jsx
+1
-1
RegulationList.jsx
src/pages/internal_regulation_manager/RegulationList.jsx
+13
-4
RevisionList.jsx
src/pages/internal_regulation_manager/RevisionList.jsx
+9
-4
internal-regulation.business-flow.md
...l_regulation_manager/internal-regulation.business-flow.md
+1
-0
ForwardApprovals.jsx
src/pages/project_manager_xy/ForwardApprovals.jsx
+0
-1
ModelBatchData.jsx
src/pages/project_manager_xy/ModelBatchData.jsx
+1
-1
ModelBatches.jsx
src/pages/project_manager_xy/ModelBatches.jsx
+1
-1
ModelOverview.jsx
src/pages/project_manager_xy/ModelOverview.jsx
+0
-1
Models.jsx
src/pages/project_manager_xy/Models.jsx
+1
-1
internalRegulationService.js
src/services/internalRegulationService.js
+41
-5
No files found.
src/components/ListPagination.jsx
0 → 100644
View file @
64fcb2ae
import
{
Pagination
}
from
'@heroui/react'
;
import
XinyuanAutocomplete
from
'@/components/XinyuanAutocomplete'
;
const
MAX_PAGE_BUTTONS
=
5
;
const
PAGE_SIZE_OPTIONS
=
[
20
,
50
,
100
];
export
default
function
ListPagination
({
page
=
0
,
pageSize
,
total
=
0
,
totalPages
:
totalPagesProp
,
isDisabled
=
false
,
onPageChange
,
onPageSizeChange
,
})
{
const
computedTotalPages
=
Math
.
max
(
1
,
Math
.
ceil
(
total
/
pageSize
));
const
totalPages
=
Math
.
max
(
1
,
numberOr
(
totalPagesProp
,
computedTotalPages
));
const
currentPage
=
Math
.
min
(
Math
.
max
(
0
,
numberOr
(
page
,
0
)),
totalPages
-
1
);
const
windowStart
=
Math
.
max
(
0
,
Math
.
min
(
currentPage
-
2
,
totalPages
-
MAX_PAGE_BUTTONS
));
const
windowEnd
=
Math
.
min
(
totalPages
,
windowStart
+
MAX_PAGE_BUTTONS
);
const
pageNumbers
=
Array
.
from
({
length
:
windowEnd
-
windowStart
},
(
_
,
index
)
=>
windowStart
+
index
);
const
pageSizeOptions
=
PAGE_SIZE_OPTIONS
.
map
((
value
)
=>
({
value
,
label
:
`
${
value
}
条/页`
}));
if
(
total
<=
0
)
return
null
;
return
(
<
div
className=
"flex min-w-0 flex-wrap items-center justify-between gap-3 border-t border-separator pt-4"
>
<
div
className=
"flex min-w-0 shrink-0 items-center gap-3"
>
<
Pagination
.
Summary
className=
"text-sm text-muted"
>
共
{
total
}
条,第
{
currentPage
+
1
}
/
{
totalPages
}
页
</
Pagination
.
Summary
>
<
XinyuanAutocomplete
aria
-
label=
"每页条数"
className=
"w-32 shrink-0"
isDisabled=
{
isDisabled
}
options=
{
pageSizeOptions
}
placeholder=
"每页条数"
selectedKey=
{
String
(
pageSize
)
}
showSearch=
{
false
}
valueText=
{
`${pageSize} 条/页`
}
variant=
"secondary"
onSelectionChange=
{
(
value
)
=>
{
const
nextPageSize
=
Number
(
value
);
if
(
PAGE_SIZE_OPTIONS
.
includes
(
nextPageSize
))
onPageSizeChange
?.(
nextPageSize
);
}
}
/>
</
div
>
<
Pagination
aria
-
label=
"列表分页"
className=
"ml-auto w-auto shrink-0"
size=
"lg"
>
<
Pagination
.
Content
>
<
Pagination
.
Item
>
<
Pagination
.
Previous
isDisabled=
{
isDisabled
||
currentPage
<=
0
}
onPress=
{
()
=>
onPageChange
(
currentPage
-
1
)
}
>
<
Pagination
.
PreviousIcon
/>
<
span
>
上一页
</
span
>
</
Pagination
.
Previous
>
</
Pagination
.
Item
>
{
pageNumbers
.
map
((
pageNumber
)
=>
(
<
Pagination
.
Item
key=
{
pageNumber
}
>
<
Pagination
.
Link
isActive=
{
pageNumber
===
currentPage
}
isDisabled=
{
isDisabled
}
onPress=
{
()
=>
onPageChange
(
pageNumber
)
}
>
{
pageNumber
+
1
}
</
Pagination
.
Link
>
</
Pagination
.
Item
>
))
}
<
Pagination
.
Item
>
<
Pagination
.
Next
isDisabled=
{
isDisabled
||
currentPage
+
1
>=
totalPages
}
onPress=
{
()
=>
onPageChange
(
currentPage
+
1
)
}
>
<
span
>
下一页
</
span
>
<
Pagination
.
NextIcon
/>
</
Pagination
.
Next
>
</
Pagination
.
Item
>
</
Pagination
.
Content
>
</
Pagination
>
</
div
>
);
}
function
numberOr
(
value
,
fallback
)
{
const
number
=
Number
(
value
);
return
Number
.
isFinite
(
number
)
?
number
:
fallback
;
}
src/pages/internal_regulation_manager/ArchiveList.jsx
View file @
64fcb2ae
import
{
Button
,
Input
,
Label
,
Pagination
,
Spinner
,
TextField
}
from
'@heroui/react'
;
import
{
Button
,
Input
,
Label
,
Spinner
,
TextField
}
from
'@heroui/react'
;
import
{
Download
,
Search
}
from
'@/components/AppIcons'
;
import
ListPagination
from
'@/components/ListPagination'
;
import
XinyuanAutocomplete
from
'@/components/XinyuanAutocomplete'
;
import
{
useEffect
,
useState
}
from
'react'
;
import
{
history
}
from
'umi'
;
...
...
@@ -12,20 +13,23 @@ export default function ArchiveList() {
const
[
searchText
,
setSearchText
]
=
useState
(
''
);
const
[
keyword
,
setKeyword
]
=
useState
(
''
);
const
[
page
,
setPage
]
=
useState
(
0
);
const
[
pageSize
,
setPageSize
]
=
useState
(
20
);
const
[
records
,
setRecords
]
=
useState
([]);
const
[
total
,
setTotal
]
=
useState
(
0
);
const
[
totalPages
,
setTotalPages
]
=
useState
(
1
);
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
error
,
setError
]
=
useState
(
''
);
const
refresh
=
async
()
=>
{
try
{
setLoading
(
true
);
const
result
=
await
loadArchivedRegulations
({
archive
,
keyword
,
page
,
pageSize
:
20
});
setRecords
(
result
.
records
);
setTotal
(
result
.
total
);
setError
(
''
);
const
result
=
await
loadArchivedRegulations
({
archive
,
keyword
,
page
,
pageSize
});
setRecords
(
result
.
records
);
setTotal
(
result
.
total
);
set
TotalPages
(
result
.
totalPages
);
set
Error
(
''
);
}
catch
(
loadError
)
{
setError
(
loadError
?.
message
||
'归档历史加载失败。'
);
}
finally
{
setLoading
(
false
);
}
};
useEffect
(()
=>
{
loadArchiveOptions
().
then
((
values
)
=>
setArchiveOptions
(
values
.
map
((
value
)
=>
({
value
,
label
:
value
})))).
catch
(()
=>
setArchiveOptions
([]));
},
[]);
useEffect
(()
=>
{
refresh
();
},
[
archive
,
keyword
,
page
]);
const
changePageSize
=
(
nextPageSize
)
=>
{
setPageSize
(
nextPageSize
);
setPage
(
0
);
};
useEffect
(()
=>
{
refresh
();
},
[
archive
,
keyword
,
page
,
pageSize
]);
const
submitSearch
=
()
=>
{
setPage
(
0
);
...
...
@@ -49,5 +53,5 @@ export default function ArchiveList() {
}
catch
(
exportError
)
{
setError
(
exportError
?.
message
||
'导出失败。'
);
}
};
return
<
div
className=
"space-y-4"
><
div
className=
"flex flex-col gap-3 lg:flex-row lg:items-end lg:justify-between"
><
div
className=
"flex flex-col gap-3 sm:flex-row sm:items-end"
><
XinyuanAutocomplete
className=
"w-full sm:w-56"
label=
"归档批次"
options=
{
[{
value
:
''
,
label
:
'全部归档'
},
...
archiveOptions
]
}
selectedKey=
{
archive
}
onSelectionChange=
{
(
value
)
=>
{
setArchive
(
String
(
value
||
''
));
setPage
(
0
);
}
}
/><
div
className=
"flex w-full items-end gap-2 sm:w-72"
><
TextField
className=
"min-w-0 flex-1"
fullWidth
value=
{
searchText
}
onChange=
{
setSearchText
}
onKeyDown=
{
(
event
)
=>
{
if
(
event
.
key
===
'Enter'
)
{
event
.
preventDefault
();
submitSearch
();
}
}
}
><
Label
className=
"sr-only"
>
搜索归档制度
</
Label
><
div
className=
"relative"
><
Search
className=
"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted"
size=
{
16
}
/><
Input
className=
"pl-9"
fullWidth
placeholder=
"搜索制度名称"
variant=
"secondary"
/></
div
></
TextField
><
Button
isDisabled=
{
loading
}
variant=
"secondary"
onPress=
{
submitSearch
}
>
查询
</
Button
></
div
></
div
><
div
className=
"flex items-center gap-3"
><
span
className=
"text-sm text-muted"
>
归档记录只读展示,不会修改现行制度
</
span
><
Button
variant=
"tertiary"
onPress=
{
exportList
}
><
Download
size=
{
16
}
/>
批量下载
</
Button
></
div
></
div
>
{
error
?
<
div
className=
"rounded-xl border border-danger/30 bg-danger/5 p-3 text-sm text-danger"
>
{
error
}
</
div
>
:
null
}{
loading
?
<
div
className=
"flex min-h-48 items-center justify-center"
><
Spinner
label=
"正在加载归档记录..."
/></
div
>
:
records
.
length
===
0
?
<
div
className=
"rounded-2xl border border-dashed border-separator p-10 text-center text-sm text-muted"
>
暂无归档记录
</
div
>
:
<
div
className=
"overflow-x-auto rounded-2xl border border-separator"
><
table
className=
"w-full min-w-[900px] text-left text-sm"
><
thead
className=
"bg-surface-secondary text-muted"
><
tr
>
{
[
'制度名称'
,
'时效性'
,
'效力位阶'
,
'审批主体'
,
'制定部门'
,
'发文日期'
,
'归档批次'
,
'操作'
].
map
((
title
)
=>
<
th
className=
"px-4 py-3 font-medium"
key=
{
title
}
>
{
title
}
</
th
>)
}
</
tr
></
thead
><
tbody
className=
"divide-y divide-separator"
>
{
records
.
map
((
record
)
=>
{
const
metadata
=
record
.
metadata
||
{};
return
<
tr
key=
{
record
.
_id
||
record
.
name
}
><
td
className=
"px-4 py-3"
><
button
className=
"font-medium text-accent hover:underline"
onClick=
{
()
=>
history
.
push
(
`/internal_regulation/${metadata.origin_regulation_id || record.name}`
)
}
>
{
metadata
.
regulation_name
||
record
.
title
||
'-'
}
</
button
></
td
><
td
className=
"px-4 py-3"
>
{
metadata
.
effective_status
||
'-'
}
</
td
><
td
className=
"px-4 py-3"
>
{
metadata
.
level
||
'-'
}
</
td
><
td
className=
"max-w-48 truncate px-4 py-3"
>
{
Array
.
isArray
(
metadata
.
approve
)
?
metadata
.
approve
.
join
(
'、'
)
:
metadata
.
approve
||
'-'
}
</
td
><
td
className=
"max-w-48 truncate px-4 py-3"
>
{
Array
.
isArray
(
metadata
.
departments
)
?
metadata
.
departments
.
join
(
'、'
)
:
metadata
.
departments
||
'-'
}
</
td
><
td
className=
"px-4 py-3"
>
{
metadata
.
public_date
?
new
Date
(
metadata
.
public_date
).
toLocaleDateString
(
'zh-CN'
)
:
'-'
}
</
td
><
td
className=
"px-4 py-3"
>
{
metadata
.
archive
||
'-'
}
</
td
><
td
className=
"px-4 py-3"
><
Button
size=
"sm"
variant=
"tertiary"
onPress=
{
()
=>
history
.
push
(
`/internal_regulation/${metadata.origin_regulation_id || record.name}`
)
}
>
查看详情
</
Button
></
td
></
tr
>;
})
}
</
tbody
></
table
></
div
>
}
{
total
>
20
?
<
Pagination
className=
"justify-end"
size=
"sm"
><
Pagination
.
Content
><
Pagination
.
Item
><
Pagination
.
Previous
isDisabled=
{
page
===
0
}
onPress=
{
()
=>
setPage
((
value
)
=>
Math
.
max
(
0
,
value
-
1
))
}
/></
Pagination
.
Item
><
Pagination
.
Item
><
Pagination
.
Link
isActive
>
{
page
+
1
}
</
Pagination
.
Link
></
Pagination
.
Item
><
Pagination
.
Item
><
Pagination
.
Next
isDisabled=
{
(
page
+
1
)
*
20
>=
total
}
onPress=
{
()
=>
setPage
((
value
)
=>
value
+
1
)
}
/></
Pagination
.
Item
></
Pagination
.
Content
></
Pagination
>
:
null
}
</
div
>;
return
<
div
className=
"space-y-4"
><
div
className=
"flex flex-col gap-3 lg:flex-row lg:items-end lg:justify-between"
><
div
className=
"flex flex-col gap-3 sm:flex-row sm:items-end"
><
XinyuanAutocomplete
className=
"w-full sm:w-56"
label=
"归档批次"
options=
{
[{
value
:
''
,
label
:
'全部归档'
},
...
archiveOptions
]
}
selectedKey=
{
archive
}
onSelectionChange=
{
(
value
)
=>
{
setArchive
(
String
(
value
||
''
));
setPage
(
0
);
}
}
/><
div
className=
"flex w-full items-end gap-2 sm:w-72"
><
TextField
className=
"min-w-0 flex-1"
fullWidth
value=
{
searchText
}
onChange=
{
setSearchText
}
onKeyDown=
{
(
event
)
=>
{
if
(
event
.
key
===
'Enter'
)
{
event
.
preventDefault
();
submitSearch
();
}
}
}
><
Label
className=
"sr-only"
>
搜索归档制度
</
Label
><
div
className=
"relative"
><
Search
className=
"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted"
size=
{
16
}
/><
Input
className=
"pl-9"
fullWidth
placeholder=
"搜索制度名称"
variant=
"secondary"
/></
div
></
TextField
><
Button
isDisabled=
{
loading
}
variant=
"secondary"
onPress=
{
submitSearch
}
>
查询
</
Button
></
div
></
div
><
div
className=
"flex items-center gap-3"
><
span
className=
"text-sm text-muted"
>
归档记录只读展示,不会修改现行制度
</
span
><
Button
variant=
"tertiary"
onPress=
{
exportList
}
><
Download
size=
{
16
}
/>
批量下载
</
Button
></
div
></
div
>
{
error
?
<
div
className=
"rounded-xl border border-danger/30 bg-danger/5 p-3 text-sm text-danger"
>
{
error
}
</
div
>
:
null
}{
loading
?
<
div
className=
"flex min-h-48 items-center justify-center"
><
Spinner
label=
"正在加载归档记录..."
/></
div
>
:
records
.
length
===
0
?
<
div
className=
"rounded-2xl border border-dashed border-separator p-10 text-center text-sm text-muted"
>
暂无归档记录
</
div
>
:
<
div
className=
"overflow-x-auto rounded-2xl border border-separator"
><
table
className=
"w-full min-w-[900px] text-left text-sm"
><
thead
className=
"bg-surface-secondary text-muted"
><
tr
>
{
[
'制度名称'
,
'时效性'
,
'效力位阶'
,
'审批主体'
,
'制定部门'
,
'发文日期'
,
'归档批次'
,
'操作'
].
map
((
title
)
=>
<
th
className=
"px-4 py-3 font-medium"
key=
{
title
}
>
{
title
}
</
th
>)
}
</
tr
></
thead
><
tbody
className=
"divide-y divide-separator"
>
{
records
.
map
((
record
)
=>
{
const
metadata
=
record
.
metadata
||
{};
return
<
tr
key=
{
record
.
_id
||
record
.
name
}
><
td
className=
"px-4 py-3"
><
button
className=
"font-medium text-accent hover:underline"
onClick=
{
()
=>
history
.
push
(
`/internal_regulation/${metadata.origin_regulation_id || record.name}`
)
}
>
{
metadata
.
regulation_name
||
record
.
title
||
'-'
}
</
button
></
td
><
td
className=
"px-4 py-3"
>
{
metadata
.
effective_status
||
'-'
}
</
td
><
td
className=
"px-4 py-3"
>
{
metadata
.
level
||
'-'
}
</
td
><
td
className=
"max-w-48 truncate px-4 py-3"
>
{
Array
.
isArray
(
metadata
.
approve
)
?
metadata
.
approve
.
join
(
'、'
)
:
metadata
.
approve
||
'-'
}
</
td
><
td
className=
"max-w-48 truncate px-4 py-3"
>
{
Array
.
isArray
(
metadata
.
departments
)
?
metadata
.
departments
.
join
(
'、'
)
:
metadata
.
departments
||
'-'
}
</
td
><
td
className=
"px-4 py-3"
>
{
metadata
.
public_date
?
new
Date
(
metadata
.
public_date
).
toLocaleDateString
(
'zh-CN'
)
:
'-'
}
</
td
><
td
className=
"px-4 py-3"
>
{
metadata
.
archive
||
'-'
}
</
td
><
td
className=
"px-4 py-3"
><
Button
size=
"sm"
variant=
"tertiary"
onPress=
{
()
=>
history
.
push
(
`/internal_regulation/${metadata.origin_regulation_id || record.name}`
)
}
>
查看详情
</
Button
></
td
></
tr
>;
})
}
</
tbody
></
table
></
div
>
}
<
ListPagination
isDisabled=
{
loading
}
page=
{
page
}
pageSize=
{
pageSize
}
total=
{
total
}
totalPages=
{
totalPages
}
onPageChange=
{
setPage
}
onPageSizeChange=
{
changePageSize
}
></
ListPagination
>
</
div
>;
}
src/pages/internal_regulation_manager/InternalRegulationManager.jsx
View file @
64fcb2ae
...
...
@@ -64,7 +64,6 @@ export default function InternalRegulationManager() {
<
div
>
<
p
className=
"text-sm text-muted"
>
内部制度管理
</
p
>
<
h1
className=
"mt-1 text-2xl font-semibold tracking-tight"
>
内部制度
</
h1
>
<
p
className=
"mt-2 max-w-3xl text-sm leading-6 text-muted"
>
统一管理制度目录、修订计划和归档历史,所有业务字段均通过平台 Record 的 metadata 保存。
</
p
>
</
div
>
</
div
>
<
Card
className=
"rc-card-surface"
>
...
...
src/pages/internal_regulation_manager/RegulationGraph.jsx
View file @
64fcb2ae
...
...
@@ -455,7 +455,7 @@ export default function RegulationGraph() {
if
(
loading
)
return
<
div
className=
"flex min-h-72 items-center justify-center"
><
Spinner
label=
"正在加载制度拓扑图..."
/></
div
>;
return
(
<
div
className=
"flex h-[calc(100dvh-7.5rem)] min-h-0 flex-col gap-4 overflow-hidden"
onClick=
{
()
=>
setContextMenu
(
null
)
}
>
<
div
><
h1
className=
"text-2xl font-semibold"
>
制度拓扑图
</
h1
><
p
className=
"mt-1 text-sm text-muted"
>
节点、连线、状态筛选、版本切换和 XMind 流程归类均可直接编辑。
</
p
><
/
div
>
<
div
><
h1
className=
"text-2xl font-semibold"
>
制度拓扑图
</
h1
></
div
>
{
error
?
<
div
role=
"alert"
className=
"rounded-xl border border-danger/30 bg-danger/5 p-3 text-sm text-danger"
>
{
error
}
</
div
>
:
null
}
{
notice
?
<
div
role=
"status"
className=
"rounded-xl border border-success/30 bg-success/5 p-3 text-sm text-success"
>
{
notice
}
</
div
>
:
null
}
<
div
className=
"flex min-h-0 flex-1 overflow-hidden rounded-2xl border border-separator bg-background shadow-sm"
ref=
{
canvasRef
}
>
...
...
src/pages/internal_regulation_manager/RegulationList.jsx
View file @
64fcb2ae
import
{
Button
,
Chip
,
Input
,
Label
,
Pagination
,
Spinner
,
TextArea
,
TextField
}
from
'@heroui/react'
;
import
{
Button
,
Chip
,
Input
,
Label
,
Spinner
,
TextArea
,
TextField
}
from
'@heroui/react'
;
import
{
Download
,
Edit
,
Eye
,
PlusIcon
,
Search
}
from
'@/components/AppIcons'
;
import
ListPagination
from
'@/components/ListPagination'
;
import
XinyuanAutocomplete
from
'@/components/XinyuanAutocomplete'
;
import
XinyuanModal
from
'@/components/XinyuanModal'
;
import
{
useEffect
,
useMemo
,
useState
}
from
'react'
;
...
...
@@ -32,7 +33,9 @@ export default function RegulationList({ options = {} }) {
const
[
searchText
,
setSearchText
]
=
useState
(
''
);
const
[
keyword
,
setKeyword
]
=
useState
(
''
);
const
[
page
,
setPage
]
=
useState
(
0
);
const
[
pageSize
,
setPageSize
]
=
useState
(
PAGE_SIZE
);
const
[
total
,
setTotal
]
=
useState
(
0
);
const
[
totalPages
,
setTotalPages
]
=
useState
(
1
);
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
[
error
,
setError
]
=
useState
(
''
);
const
[
dialogOpen
,
setDialogOpen
]
=
useState
(
false
);
...
...
@@ -45,9 +48,10 @@ export default function RegulationList({ options = {} }) {
try
{
setLoading
(
true
);
const
activeFilters
=
Object
.
fromEntries
(
Object
.
entries
(
filters
).
filter
(([,
value
])
=>
value
).
map
(([
key
,
value
])
=>
[
`metadata.
${
key
}
`
,
[
'departments'
,
'approve'
].
includes
(
key
)
?
{
$in
:
[
value
]
}
:
value
]));
const
result
=
await
loadRegulations
({
page
,
pageSize
:
PAGE_SIZE
,
keyword
,
filters
:
activeFilters
});
const
result
=
await
loadRegulations
({
page
,
pageSize
,
keyword
,
filters
:
activeFilters
});
setRecords
(
result
.
records
);
setTotal
(
result
.
total
);
setTotalPages
(
result
.
totalPages
);
setError
(
''
);
}
catch
(
loadError
)
{
setError
(
loadError
?.
message
||
'制度目录加载失败。'
);
...
...
@@ -61,7 +65,12 @@ export default function RegulationList({ options = {} }) {
setKeyword
(
searchText
.
trim
());
};
useEffect
(()
=>
{
refresh
();
},
[
page
,
keyword
,
filters
]);
const
changePageSize
=
(
nextPageSize
)
=>
{
setPageSize
(
nextPageSize
);
setPage
(
0
);
};
useEffect
(()
=>
{
refresh
();
},
[
page
,
pageSize
,
keyword
,
filters
]);
useEffect
(()
=>
{
const
open
=
()
=>
{
setEditing
(
null
);
setForm
(
INITIAL_FORM
);
setDialogOpen
(
true
);
};
window
.
addEventListener
(
'internal-regulation:create'
,
open
);
...
...
@@ -142,7 +151,7 @@ export default function RegulationList({ options = {} }) {
</
table
>
</
div
>
)
}
{
total
>
PAGE_SIZE
?
<
Pagination
className=
"justify-end"
size=
"sm"
><
Pagination
.
Content
><
Pagination
.
Item
><
Pagination
.
Previous
isDisabled=
{
page
===
0
}
onPress=
{
()
=>
setPage
((
value
)
=>
Math
.
max
(
0
,
value
-
1
))
}
/></
Pagination
.
Item
><
Pagination
.
Item
><
Pagination
.
Link
isActive
>
{
page
+
1
}
</
Pagination
.
Link
></
Pagination
.
Item
><
Pagination
.
Item
><
Pagination
.
Next
isDisabled=
{
(
page
+
1
)
*
PAGE_SIZE
>=
total
}
onPress=
{
()
=>
setPage
((
value
)
=>
value
+
1
)
}
/></
Pagination
.
Item
></
Pagination
.
Content
></
Pagination
>
:
null
}
<
ListPagination
isDisabled=
{
loading
}
page=
{
page
}
pageSize=
{
pageSize
}
total=
{
total
}
totalPages=
{
totalPages
}
onPageChange=
{
setPage
}
onPageSizeChange=
{
changePageSize
}
/>
<
XinyuanModal
isOpen=
{
dialogOpen
}
onOpenChange=
{
setDialogOpen
}
size=
"2xl"
title=
{
editing
?
'编辑修订计划'
:
'创建修订计划'
}
footer=
{
<
div
className=
"flex justify-end gap-2"
><
Button
variant=
"tertiary"
onPress=
{
()
=>
setDialogOpen
(
false
)
}
>
取消
</
Button
><
Button
isDisabled=
{
saving
||
!
form
.
regulation_name
.
trim
()
}
variant=
"primary"
onPress=
{
submit
}
>
{
saving
?
'保存中...'
:
'保存'
}
</
Button
></
div
>
}
>
<
div
className=
"grid gap-4 sm:grid-cols-2"
>
<
TextField
className=
"sm:col-span-2"
fullWidth
isRequired
value=
{
form
.
regulation_name
}
onChange=
{
(
value
)
=>
setForm
((
current
)
=>
({
...
current
,
regulation_name
:
value
}))
}
><
Label
>
制度名称
</
Label
><
Input
fullWidth
placeholder=
"请输入制度名称"
variant=
"secondary"
/></
TextField
>
...
...
src/pages/internal_regulation_manager/RevisionList.jsx
View file @
64fcb2ae
import
{
Button
,
Chip
,
Input
,
Label
,
Pagination
,
Spinner
,
TextArea
,
TextField
}
from
'@heroui/react'
;
import
{
Button
,
Chip
,
Input
,
Label
,
Spinner
,
TextArea
,
TextField
}
from
'@heroui/react'
;
import
{
Archive
,
Check
,
Close
,
Download
,
Edit
,
FileText
,
PaperClipIcon
,
Search
,
Upload
}
from
'@/components/AppIcons'
;
import
ListPagination
from
'@/components/ListPagination'
;
import
XinyuanAutocomplete
from
'@/components/XinyuanAutocomplete'
;
import
XinyuanModal
from
'@/components/XinyuanModal'
;
import
{
useEffect
,
useState
}
from
'react'
;
...
...
@@ -41,6 +42,8 @@ export default function RevisionList({ options = {} }) {
const
[
records
,
setRecords
]
=
useState
([]);
const
[
total
,
setTotal
]
=
useState
(
0
);
const
[
page
,
setPage
]
=
useState
(
0
);
const
[
pageSize
,
setPageSize
]
=
useState
(
20
);
const
[
totalPages
,
setTotalPages
]
=
useState
(
1
);
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
[
error
,
setError
]
=
useState
(
''
);
const
[
editing
,
setEditing
]
=
useState
(
null
);
...
...
@@ -55,15 +58,17 @@ export default function RevisionList({ options = {} }) {
const
load
=
async
()
=>
{
try
{
setLoading
(
true
);
const
result
=
await
loadRevisions
({
status
,
keyword
,
page
,
pageSize
:
20
});
const
result
=
await
loadRevisions
({
status
,
keyword
,
page
,
pageSize
});
setRecords
(
result
.
records
);
setTotal
(
result
.
total
);
setTotalPages
(
result
.
totalPages
);
setError
(
''
);
}
catch
(
loadError
)
{
setError
(
loadError
?.
message
||
'修订计划加载失败。'
);
}
finally
{
setLoading
(
false
);
}
};
useEffect
(()
=>
{
load
();
},
[
status
,
keyword
,
page
]);
const
changePageSize
=
(
nextPageSize
)
=>
{
setPageSize
(
nextPageSize
);
setPage
(
0
);
};
useEffect
(()
=>
{
load
();
},
[
status
,
keyword
,
page
,
pageSize
]);
const
submitSearch
=
()
=>
{
setPage
(
0
);
...
...
@@ -131,7 +136,7 @@ export default function RevisionList({ options = {} }) {
{
loading
?
<
div
className=
"flex min-h-48 items-center justify-center"
><
Spinner
label=
"正在加载修订计划..."
/></
div
>
:
records
.
length
===
0
?
<
div
className=
"rounded-2xl border border-dashed border-separator p-10 text-center text-sm text-muted"
>
当前状态暂无修订计划
</
div
>
:
(
<
div
className=
"overflow-x-auto rounded-2xl border border-separator"
><
table
className=
"w-full min-w-[1120px] text-left text-sm"
><
thead
className=
"bg-surface-secondary text-muted"
><
tr
>
{
[
'类型'
,
'制度名称'
,
'OA流程制度'
,
'发起日期'
,
'审批主体'
,
'制定部门'
,
'附件'
,
'状态'
,
'操作'
].
map
((
title
)
=>
<
th
className=
"px-4 py-3 font-medium"
key=
{
title
}
>
{
title
}
</
th
>)
}
</
tr
></
thead
><
tbody
className=
"divide-y divide-separator"
>
{
records
.
map
((
record
)
=>
{
const
metadata
=
record
.
metadata
||
{};
const
attachments
=
Array
.
isArray
(
metadata
.
attachments
)
?
metadata
.
attachments
:
metadata
.
attachments
?
[
metadata
.
attachments
]
:
[];
return
<
tr
className=
"hover:bg-surface-secondary/50"
key=
{
record
.
_id
||
record
.
name
}
><
td
className=
"px-4 py-3"
><
Chip
color=
{
metadata
.
type
===
'修订'
?
'warning'
:
metadata
.
type
===
'废止'
?
'default'
:
'accent'
}
size=
"sm"
variant=
"soft"
><
Chip
.
Label
>
待
{
metadata
.
type
||
'-'
}
</
Chip
.
Label
></
Chip
></
td
><
td
className=
"px-4 py-3 font-medium"
>
{
metadata
.
regulation_name
||
record
.
title
||
'-'
}
</
td
><
td
className=
"max-w-48 truncate px-4 py-3 text-muted"
>
{
metadata
.
regulation_name_oa
||
metadata
.
regulation_name_oa_submitted
||
'-'
}
</
td
><
td
className=
"px-4 py-3"
>
{
formatDate
(
metadata
.
created_at
)
}
</
td
><
td
className=
"max-w-48 truncate px-4 py-3"
>
{
Array
.
isArray
(
metadata
.
approve
)
?
metadata
.
approve
.
join
(
'、'
)
:
metadata
.
approve
||
'-'
}
</
td
><
td
className=
"max-w-48 truncate px-4 py-3"
>
{
Array
.
isArray
(
metadata
.
departments
)
?
metadata
.
departments
.
join
(
'、'
)
:
metadata
.
departments
||
'-'
}
</
td
><
td
className=
"px-4 py-3"
>
{
attachments
.
length
?
<
div
className=
"flex flex-col gap-1"
>
{
attachments
.
map
((
attachment
,
index
)
=>
{
const
href
=
typeof
attachment
===
'string'
?
attachment
:
attachment
.
url
;
const
title
=
typeof
attachment
===
'string'
?
`附件 ${index + 1}`
:
attachment
.
title
||
attachment
.
name
||
`附件 ${index + 1}`
;
return
href
?
<
a
className=
"flex items-center gap-1 text-accent hover:underline"
href=
{
href
}
key=
{
attachment
.
_id
||
attachment
.
name
||
index
}
rel=
"noreferrer"
target=
"_blank"
><
PaperClipIcon
size=
{
14
}
/>
{
title
}
</
a
>
:
<
span
className=
"text-muted"
key=
{
attachment
.
_id
||
attachment
.
name
||
index
}
>
{
title
}
</
span
>;
})
}
</
div
>
:
'-'
}
</
td
><
td
className=
"px-4 py-3"
><
Chip
color=
{
statusColor
(
metadata
.
status
)
}
size=
"sm"
variant=
"soft"
><
Chip
.
Label
>
{
metadata
.
status
}
</
Chip
.
Label
></
Chip
></
td
><
td
className=
"px-4 py-3"
><
div
className=
"flex items-center gap-1"
>
{
status
===
'起草中'
?
<><
Button
isIconOnly
aria
-
label=
"取消修订"
isDisabled=
{
saving
}
size=
"sm"
variant=
"tertiary"
onPress=
{
()
=>
submitStatus
(
record
,
'已取消'
)
}
><
Close
size=
{
16
}
/></
Button
><
Button
isIconOnly
aria
-
label=
"提交审核"
isDisabled=
{
saving
}
size=
"sm"
variant=
"tertiary"
onPress=
{
()
=>
submitStatus
(
record
,
'已提交'
)
}
><
Check
size=
{
16
}
/></
Button
><
Button
isIconOnly
aria
-
label=
"编辑修订"
size=
"sm"
variant=
"tertiary"
onPress=
{
()
=>
openEdit
(
record
)
}
><
Edit
size=
{
16
}
/></
Button
></>
:
null
}{
status
===
'已提交'
?
<><
Button
isIconOnly
aria
-
label=
"取消审核"
isDisabled=
{
saving
}
size=
"sm"
variant=
"tertiary"
onPress=
{
()
=>
submitStatus
(
record
,
'已取消'
)
}
><
Close
size=
{
16
}
/></
Button
><
Button
isIconOnly
aria
-
label=
"提交发文"
isDisabled=
{
saving
}
size=
"sm"
variant=
"tertiary"
onPress=
{
()
=>
{
setEditing
(
record
);
setPublishForm
({
public_date
:
''
,
attachments
:
[],
content
:
''
});
setPublishOpen
(
true
);
}
}
><
FileText
size=
{
16
}
/></
Button
></>
:
null
}{
status
===
'已取消'
?
<
Button
isIconOnly
aria
-
label=
"查看修订"
size=
"sm"
variant=
"tertiary"
onPress=
{
()
=>
openEdit
(
record
)
}
><
Edit
size=
{
16
}
/></
Button
>
:
null
}
</
div
></
td
></
tr
>;
})
}
</
tbody
></
table
></
div
>
)
}
{
total
>
20
?
<
Pagination
className=
"justify-end"
size=
"sm"
><
Pagination
.
Content
><
Pagination
.
Item
><
Pagination
.
Previous
isDisabled=
{
page
===
0
}
onPress=
{
()
=>
setPage
((
value
)
=>
Math
.
max
(
0
,
value
-
1
))
}
/></
Pagination
.
Item
><
Pagination
.
Item
><
Pagination
.
Link
isActive
>
{
page
+
1
}
</
Pagination
.
Link
></
Pagination
.
Item
><
Pagination
.
Item
><
Pagination
.
Next
isDisabled=
{
(
page
+
1
)
*
20
>=
total
}
onPress=
{
()
=>
setPage
((
value
)
=>
value
+
1
)
}
/></
Pagination
.
Item
></
Pagination
.
Content
></
Pagination
>
:
null
}
<
ListPagination
isDisabled=
{
loading
}
page=
{
page
}
pageSize=
{
pageSize
}
total=
{
total
}
totalPages=
{
totalPages
}
onPageChange=
{
setPage
}
onPageSizeChange=
{
changePageSize
}
/>
<
XinyuanModal
isOpen=
{
editOpen
}
onOpenChange=
{
setEditOpen
}
size=
"2xl"
title=
{
editing
?
'编辑修订计划'
:
'创建修订计划'
}
footer=
{
<
div
className=
"flex justify-end gap-2"
><
Button
variant=
"tertiary"
onPress=
{
()
=>
setEditOpen
(
false
)
}
>
取消
</
Button
><
Button
isDisabled=
{
saving
||
!
form
.
regulation_name
.
trim
()
}
variant=
"primary"
onPress=
{
saveEdit
}
>
{
saving
?
'保存中...'
:
'保存'
}
</
Button
></
div
>
}
>
<
div
className=
"grid gap-4 sm:grid-cols-2"
><
TextField
className=
"sm:col-span-2"
fullWidth
isRequired
value=
{
form
.
regulation_name
}
onChange=
{
(
value
)
=>
setForm
((
current
)
=>
({
...
current
,
regulation_name
:
value
}))
}
><
Label
>
制度名称
</
Label
><
Input
fullWidth
variant=
"secondary"
/></
TextField
><
XinyuanAutocomplete
label=
"类型"
options=
{
[
'新增'
,
'修订'
,
'废止'
].
map
((
value
)
=>
({
value
,
label
:
value
}))
}
selectedKey=
{
form
.
type
}
onSelectionChange=
{
(
value
)
=>
setForm
((
current
)
=>
({
...
current
,
type
:
String
(
value
)
}))
}
/><
XinyuanAutocomplete
label=
"层级"
options=
{
REGULATION_LEVELS
.
map
((
value
)
=>
({
value
,
label
:
value
}))
}
selectedKey=
{
form
.
level
}
onSelectionChange=
{
(
value
)
=>
setForm
((
current
)
=>
({
...
current
,
level
:
String
(
value
)
}))
}
/><
XinyuanAutocomplete
label=
"审批主体"
options=
{
optionsFor
(
'approve'
)
}
selectedKeys=
{
new
Set
(
form
.
approve
||
[])
}
selectionMode=
"multiple"
onSelectionChange=
{
(
values
)
=>
setForm
((
current
)
=>
({
...
current
,
approve
:
values
===
'all'
?
optionsFor
(
'approve'
).
map
((
item
)
=>
item
.
value
)
:
Array
.
from
(
values
||
[])
}))
}
/><
XinyuanAutocomplete
label=
"制定部门"
options=
{
optionsFor
(
'departments'
)
}
selectedKeys=
{
new
Set
(
form
.
departments
||
[])
}
selectionMode=
"multiple"
onSelectionChange=
{
(
values
)
=>
setForm
((
current
)
=>
({
...
current
,
departments
:
values
===
'all'
?
optionsFor
(
'departments'
).
map
((
item
)
=>
item
.
value
)
:
Array
.
from
(
values
||
[])
}))
}
/><
TextField
className=
"sm:col-span-2"
fullWidth
value=
{
form
.
comment
}
onChange=
{
(
value
)
=>
setForm
((
current
)
=>
({
...
current
,
comment
:
value
}))
}
><
Label
>
备注
</
Label
><
TextArea
fullWidth
rows=
{
4
}
variant=
"secondary"
/></
TextField
></
div
>
...
...
src/pages/internal_regulation_manager/internal-regulation.business-flow.md
View file @
64fcb2ae
...
...
@@ -39,5 +39,6 @@
## 加载、错误与限制
-
Subject、Record、附件请求均显示 loading、success 或 error 状态;错误保留在当前页面,不使用演示数据或 localStorage 回退。
-
制度目录、修订计划和归档历史列表使用服务端分页;每页条数可选
`20 / 50 / 100`
,切换条数后回到第 1 页。页码和页数读取
`/record/query`
返回的
`current_page`
与
`total_pages`
,列表总数读取当前筛选条件对应的
`total_records`
。
-
保存、提交、发文期间禁用重复提交按钮;失败时保留表单内容。
-
归档记录不修改现行制度;不存在的制度或修订计划显示明确空状态。
src/pages/project_manager_xy/ForwardApprovals.jsx
View file @
64fcb2ae
...
...
@@ -454,7 +454,6 @@ export default function ForwardApprovals() {
<
HeroBanner
eyebrow=
"模型监控"
title=
"转发审批"
description=
"集中处理从模型批次数据发起的转发、填写和两级顺序审批。终审只能在接收人完成填写且一级审批通过后推进。"
/>
{
loading
?
<
NoticeBanner
>
正在加载转发审批记录...
</
NoticeBanner
>
:
null
}
...
...
src/pages/project_manager_xy/ModelBatchData.jsx
View file @
64fcb2ae
...
...
@@ -223,7 +223,7 @@ export default function ModelBatchData() {
return
(
<
div
className=
"space-y-5"
>
<
PageHeader
eyebrow=
{
batch
?.
batchCode
||
'模型批次'
}
title=
{
batch
?.
batchName
||
'批次数据'
}
description=
"展示当前批次已同步的全部业务字段。页面不提供字段筛选或图表分析,勾选记录后可隐藏或进入转发审批。"
/>
<
PageHeader
eyebrow=
{
batch
?.
batchCode
||
'模型批次'
}
title=
{
batch
?.
batchName
||
'批次数据'
}
/>
{
loading
?
<
NoticeBanner
>
正在加载批次数据和转发状态...
</
NoticeBanner
>
:
null
}
{
error
?
<
NoticeBanner
tone=
"error"
>
{
error
}
</
NoticeBanner
>
:
null
}
{
!
error
&&
notice
?
<
NoticeBanner
tone=
"success"
>
{
notice
}
</
NoticeBanner
>
:
null
}
...
...
src/pages/project_manager_xy/ModelBatches.jsx
View file @
64fcb2ae
...
...
@@ -150,7 +150,7 @@ export default function ModelBatches() {
return
(
<
div
className=
"space-y-5"
>
<
PageHeader
eyebrow=
{
model
?.
modelCode
||
'模型'
}
title=
{
model
?.
modelName
||
'模型批次'
}
description=
"这里仅展示已经同步到本系统的批次。外部未同步批次通过右侧同步入口选择。"
/>
<
PageHeader
eyebrow=
{
model
?.
modelCode
||
'模型'
}
title=
{
model
?.
modelName
||
'模型批次'
}
/>
{
loading
?
<
NoticeBanner
>
正在加载模型批次...
</
NoticeBanner
>
:
null
}
{
error
?
<
NoticeBanner
tone=
"error"
>
{
error
}
</
NoticeBanner
>
:
null
}
...
...
src/pages/project_manager_xy/ModelOverview.jsx
View file @
64fcb2ae
...
...
@@ -120,7 +120,6 @@ export default function ModelOverview() {
<
PageHeader
eyebrow=
"模型监控"
title=
"模型运行概览"
description=
"集中查看已同步模型、批次数据量与最近同步结果。这里仅呈现运行状态,不再提供字段分析或图表配置。"
/>
{
loading
?
<
NoticeBanner
>
正在初始化模型监控对象并加载概览...
</
NoticeBanner
>
:
null
}
...
...
src/pages/project_manager_xy/Models.jsx
View file @
64fcb2ae
...
...
@@ -455,7 +455,7 @@ export default function Models() {
return
(
<
div
>
<
PageHeader
eyebrow=
"模型监控"
title=
"全部模型"
description=
"模型由同步自动创建。你可以用无限级分组、标签和说明整理模型,点击模型后进入独立批次页面。"
/>
<
PageHeader
eyebrow=
"模型监控"
title=
"全部模型"
/>
<
div
className=
"space-y-8"
>
{
loading
?
<
NoticeBanner
>
正在初始化模型对象并加载列表...
</
NoticeBanner
>
:
null
}
{
error
?
<
NoticeBanner
tone=
"error"
>
{
error
}
</
NoticeBanner
>
:
null
}
...
...
src/services/internalRegulationService.js
View file @
64fcb2ae
...
...
@@ -19,7 +19,38 @@ const REGULATION_LEVELS = ['1级', '2级', '3级', '4级'];
const
REVISION_TYPES
=
[
'新增'
,
'修订'
,
'废止'
];
function
recordsOf
(
response
)
{
return
Array
.
isArray
(
response
?.
records
)
?
response
.
records
:
[];
if
(
Array
.
isArray
(
response
?.
records
))
return
response
.
records
;
if
(
Array
.
isArray
(
response
?.
data
?.
records
))
return
response
.
data
.
records
;
return
Array
.
isArray
(
response
?.
data
)
?
response
.
data
:
[];
}
function
totalOf
(
response
,
records
=
[])
{
const
candidates
=
[
response
?.
total_records
,
response
?.
data
?.
total_records
,
response
?.
total_count
,
response
?.
data
?.
total_count
,
response
?.
total
,
response
?.
data
?.
total
,
response
?.
count
,
response
?.
data
?.
count
,
];
const
total
=
candidates
.
find
((
value
)
=>
value
!==
null
&&
value
!==
undefined
&&
Number
.
isFinite
(
Number
(
value
)));
return
total
===
undefined
?
records
.
length
:
Number
(
total
);
}
function
numberOr
(
value
,
fallback
)
{
const
number
=
Number
(
value
);
return
Number
.
isFinite
(
number
)
?
number
:
fallback
;
}
function
paginationOf
(
response
,
fallbackPage
,
fallbackPageSize
,
total
)
{
const
pageSize
=
numberOr
(
response
?.
page_size
,
fallbackPageSize
);
return
{
currentPage
:
numberOr
(
response
?.
current_page
,
fallbackPage
),
pageSize
,
totalPages
:
numberOr
(
response
?.
total_pages
,
Math
.
max
(
1
,
Math
.
ceil
(
total
/
pageSize
))),
};
}
function
metadataOf
(
record
)
{
...
...
@@ -73,7 +104,7 @@ export async function queryAll(subject, { filter = {}, sort = '', select = null
const
result
=
await
queryRecords
({
subject
,
page
,
page_size
:
1000
,
filter
,
sort
,
select
,
mode
:
'full'
});
const
records
=
recordsOf
(
result
);
all
.
push
(...
records
);
if
(
records
.
length
<
1000
||
all
.
length
>=
Number
(
result
?.
total_records
||
result
?.
total
||
0
))
break
;
if
(
records
.
length
<
1000
||
all
.
length
>=
totalOf
(
result
))
break
;
}
return
all
;
}
...
...
@@ -116,7 +147,8 @@ export async function loadRegulations({ page = 0, pageSize = 20, keyword = '', f
revisions
:
histories
,
};
}),
total
:
Number
(
result
?.
total_records
||
result
?.
total
||
records
.
length
),
total
:
totalOf
(
result
,
records
),
...
paginationOf
(
result
,
page
,
pageSize
,
totalOf
(
result
,
records
)),
};
}
...
...
@@ -130,7 +162,9 @@ export async function loadRevisions({ page = 0, pageSize = 20, status = '起草
const
filter
=
{
'metadata.status'
:
status
};
if
(
keyword
.
trim
())
filter
[
'metadata.regulation_name'
]
=
{
$regex
:
keyword
.
trim
()
};
const
result
=
await
queryRecords
({
subject
:
REVISION_SUBJECT
,
page
,
page_size
:
pageSize
,
filter
,
sort
:
'-metadata.created_at'
,
mode
:
'full'
});
return
{
records
:
recordsOf
(
result
),
total
:
Number
(
result
?.
total_records
||
result
?.
total
||
recordsOf
(
result
).
length
)
};
const
records
=
recordsOf
(
result
);
const
total
=
totalOf
(
result
,
records
);
return
{
records
,
total
,
...
paginationOf
(
result
,
page
,
pageSize
,
total
)
};
}
export
async
function
loadArchiveOptions
()
{
...
...
@@ -143,7 +177,9 @@ export async function loadArchivedRegulations({ archive = '', page = 0, pageSize
if
(
archive
)
filter
[
'metadata.archive'
]
=
archive
;
if
(
keyword
.
trim
())
filter
[
'metadata.regulation_name'
]
=
{
$regex
:
keyword
.
trim
()
};
const
result
=
await
queryRecords
({
subject
:
ARCHIVE_SUBJECT
,
page
,
page_size
:
pageSize
,
filter
,
sort
:
'-metadata.public_date'
,
mode
:
'full'
});
return
{
records
:
recordsOf
(
result
),
total
:
Number
(
result
?.
total_records
||
result
?.
total
||
recordsOf
(
result
).
length
)
};
const
records
=
recordsOf
(
result
);
const
total
=
totalOf
(
result
,
records
);
return
{
records
,
total
,
...
paginationOf
(
result
,
page
,
pageSize
,
total
)
};
}
export
async
function
createRevision
(
values
=
{})
{
...
...
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